2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
10 * Most Codeparts are taken from the TuxBox Teletext plugin which is based
11 * upon videotext-0.6.19991029 and written by Thomas Loewe (LazyT),
12 * Roland Meier and DBLuelle. See http://www.tuxtxt.net/ for more information.
13 * Many thanks to the TuxBox Teletext Team for this great work.
18 #include "application/ApplicationComponents.h"
19 #include "application/ApplicationPlayer.h"
20 #include "filesystem/SpecialProtocol.h"
21 #include "input/actions/Action.h"
22 #include "input/actions/ActionIDs.h"
23 #include "input/keyboard/KeyIDs.h"
24 #include "utils/log.h"
25 #include "windowing/GraphicContext.h"
27 #include <harfbuzz/hb-ft.h>
29 using namespace std::chrono_literals
;
30 using KODI::UTILS::COLOR::Color
;
32 static inline void SDL_memset4(uint32_t* dst
, uint32_t val
, size_t len
)
34 for (; len
> 0; --len
)
37 #define SDL_memcpy4(dst, src, len) memcpy(dst, src, (len) << 2)
39 static const char *TeletextFont
= "special://xbmc/media/Fonts/teletext.ttf";
41 /* spacing attributes */
42 #define alpha_black 0x00
43 #define alpha_red 0x01
44 #define alpha_green 0x02
45 #define alpha_yellow 0x03
46 #define alpha_blue 0x04
47 #define alpha_magenta 0x05
48 #define alpha_cyan 0x06
49 #define alpha_white 0x07
53 #define start_box 0x0B
54 #define normal_size 0x0C
55 #define double_height 0x0D
56 #define double_width 0x0E
57 #define double_size 0x0F
58 #define mosaic_black 0x10
59 #define mosaic_red 0x11
60 #define mosaic_green 0x12
61 #define mosaic_yellow 0x13
62 #define mosaic_blue 0x14
63 #define mosaic_magenta 0x15
64 #define mosaic_cyan 0x16
65 #define mosaic_white 0x17
67 #define contiguous_mosaic 0x19
68 #define separated_mosaic 0x1A
70 #define black_background 0x1C
71 #define new_background 0x1D
72 #define hold_mosaic 0x1E
73 #define release_mosaic 0x1F
75 #define RowAddress2Row(row) ((row == 40) ? 24 : (row - 40))
77 // G2 Set as defined in ETS 300 706
78 const unsigned short int G2table
[5][6*16] =
80 // Latin G2 Supplementary Set
81 { 0x0020, 0x00A1, 0x00A2, 0x00A3, 0x0024, 0x00A5, 0x0023, 0x00A7, 0x00A4, 0x2018, 0x201C, 0x00AB, 0x2190, 0x2191, 0x2192, 0x2193,
82 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00D7, 0x00B5, 0x00B6, 0x00B7, 0x00F7, 0x2019, 0x201D, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
83 0x0020, 0x0300, 0x0301, 0x02C6, 0x0303, 0x02C9, 0x02D8, 0x02D9, 0x00A8, 0x002E, 0x02DA, 0x00B8, 0x005F, 0x02DD, 0x02DB, 0x02C7,
84 0x2014, 0x00B9, 0x00AE, 0x00A9, 0x2122, 0x266A, 0x20AC, 0x2030, 0x03B1, 0x0020, 0x0020, 0x0020, 0x215B, 0x215C, 0x215D, 0x215E,
85 0x2126, 0x00C6, 0x00D0, 0x00AA, 0x0126, 0x0020, 0x0132, 0x013F, 0x0141, 0x00D8, 0x0152, 0x00BA, 0x00DE, 0x0166, 0x014A, 0x0149,
86 0x0138, 0x00E6, 0x0111, 0x00F0, 0x0127, 0x0131, 0x0133, 0x0140, 0x0142, 0x00F8, 0x0153, 0x00DF, 0x00FE, 0x0167, 0x014B, 0x25A0},
87 // Cyrillic G2 Supplementary Set
88 { 0x0020, 0x00A1, 0x00A2, 0x00A3, 0x0024, 0x00A5, 0x0020, 0x00A7, 0x0020, 0x2018, 0x201C, 0x00AB, 0x2190, 0x2191, 0x2192, 0x2193,
89 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00D7, 0x00B5, 0x00B6, 0x00B7, 0x00F7, 0x2019, 0x201D, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
90 0x0020, 0x0300, 0x0301, 0x02C6, 0x02DC, 0x02C9, 0x02D8, 0x02D9, 0x00A8, 0x002E, 0x02DA, 0x00B8, 0x005F, 0x02DD, 0x02DB, 0x02C7,
91 0x2014, 0x00B9, 0x00AE, 0x00A9, 0x2122, 0x266A, 0x20AC, 0x2030, 0x03B1, 0x0141, 0x0142, 0x00DF, 0x215B, 0x215C, 0x215D, 0x215E,
92 0x0044, 0x0045, 0x0046, 0x0047, 0x0049, 0x004A, 0x004B, 0x004C, 0x004E, 0x0051, 0x0052, 0x0053, 0x0055, 0x0056, 0x0057, 0x005A,
93 0x0064, 0x0065, 0x0066, 0x0067, 0x0069, 0x006A, 0x006B, 0x006C, 0x006E, 0x0071, 0x0072, 0x0073, 0x0075, 0x0076, 0x0077, 0x007A},
94 // Greek G2 Supplementary Set
95 { 0x0020, 0x0061, 0x0062, 0x00A3, 0x0065, 0x0068, 0x0069, 0x00A7, 0x003A, 0x2018, 0x201C, 0x006B, 0x2190, 0x2191, 0x2192, 0x2193,
96 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00D7, 0x006D, 0x006E, 0x0070, 0x00F7, 0x2019, 0x201D, 0x0074, 0x00BC, 0x00BD, 0x00BE, 0x0078,
97 0x0020, 0x0300, 0x0301, 0x02C6, 0x02DC, 0x02C9, 0x02D8, 0x02D9, 0x00A8, 0x002E, 0x02DA, 0x00B8, 0x005F, 0x02DD, 0x02DB, 0x02C7,
98 0x003F, 0x00B9, 0x00AE, 0x00A9, 0x2122, 0x266A, 0x20AC, 0x2030, 0x03B1, 0x038A, 0x038E, 0x038F, 0x215B, 0x215C, 0x215D, 0x215E,
99 0x0043, 0x0044, 0x0046, 0x0047, 0x004A, 0x004C, 0x0051, 0x0052, 0x0053, 0x0055, 0x0056, 0x0057, 0x0059, 0x005A, 0x0386, 0x0389,
100 0x0063, 0x0064, 0x0066, 0x0067, 0x006A, 0x006C, 0x0071, 0x0072, 0x0073, 0x0075, 0x0076, 0x0077, 0x0079, 0x007A, 0x0388, 0x25A0},
102 { 0x0020, 0x0639, 0xFEC9, 0xFE83, 0xFE85, 0xFE87, 0xFE8B, 0xFE89, 0xFB7C, 0xFB7D, 0xFB7A, 0xFB58, 0xFB59, 0xFB56, 0xFB6D, 0xFB8E,
103 0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667, 0x0668, 0x0669, 0xFECE, 0xFECD, 0xFEFC, 0xFEEC, 0xFEEA, 0xFEE9,
104 0x00E0, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
105 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005A, 0x00EB, 0x00EA, 0x00F9, 0x00EE, 0xFECA,
106 0x00E9, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
107 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x00E2, 0x00F4, 0x00FB, 0x00E7, 0x25A0}
110 //const (avoid warnings :<)
111 TextPageAttr_t Text_AtrTable
[] =
113 { TXT_ColorWhite
, TXT_ColorBlack
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_WB */
114 { TXT_ColorWhite
, TXT_ColorBlack
, C_G0P
, 0, 0, 1 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_PassiveDefault */
115 { TXT_ColorWhite
, TXT_ColorRed
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_L250 */
116 { TXT_ColorBlack
, TXT_ColorGreen
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_L251 */
117 { TXT_ColorBlack
, TXT_ColorYellow
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_L252 */
118 { TXT_ColorWhite
, TXT_ColorBlue
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_L253 */
119 { TXT_ColorMagenta
, TXT_ColorBlack
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_TOPMENU0 */
120 { TXT_ColorGreen
, TXT_ColorBlack
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_TOPMENU1 */
121 { TXT_ColorYellow
, TXT_ColorBlack
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_TOPMENU2 */
122 { TXT_ColorCyan
, TXT_ColorBlack
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_TOPMENU3 */
123 { TXT_ColorMenu2
, TXT_ColorMenu3
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSG0 */
124 { TXT_ColorYellow
, TXT_ColorMenu3
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSG1 */
125 { TXT_ColorMenu2
, TXT_ColorTransp
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSG2 */
126 { TXT_ColorWhite
, TXT_ColorMenu3
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSG3 */
127 { TXT_ColorMenu2
, TXT_ColorMenu1
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSGDRM0 */
128 { TXT_ColorYellow
, TXT_ColorMenu1
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSGDRM1 */
129 { TXT_ColorMenu2
, TXT_ColorBlack
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSGDRM2 */
130 { TXT_ColorWhite
, TXT_ColorMenu1
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSGDRM3 */
131 { TXT_ColorMenu1
, TXT_ColorBlue
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENUHIL0 5a Z */
132 { TXT_ColorWhite
, TXT_ColorBlue
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENUHIL1 58 X */
133 { TXT_ColorMenu2
, TXT_ColorTransp
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENUHIL2 9b õ */
134 { TXT_ColorMenu2
, TXT_ColorMenu1
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENU0 ab ´ */
135 { TXT_ColorYellow
, TXT_ColorMenu1
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENU1 a4 § */
136 { TXT_ColorMenu2
, TXT_ColorTransp
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENU2 9b õ */
137 { TXT_ColorMenu2
, TXT_ColorMenu3
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENU3 cb À */
138 { TXT_ColorCyan
, TXT_ColorMenu3
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENU4 c7 « */
139 { TXT_ColorWhite
, TXT_ColorMenu3
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENU5 c8 » */
140 { TXT_ColorWhite
, TXT_ColorMenu1
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENU6 a8 ® */
141 { TXT_ColorYellow
, TXT_ColorMenu1
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_CATCHMENU0 a4 § */
142 { TXT_ColorWhite
, TXT_ColorMenu1
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f} /* ATR_CATCHMENU1 a8 ® */
149 S_FHL
, /* full horizontal line: y-offset */
150 S_FVL
, /* full vertical line: x-offset */
151 S_BOX
, /* rectangle: x-offset, y-offset, width, height */
152 S_TRA
, /* trapez: x0, y0, l0, x1, y1, l1 */
153 S_BTR
, /* trapez in bgcolor: x0, y0, l0, x1, y1, l1 */
155 S_LNK
, /* call other shape: shapenumber */
156 S_CHR
, /* Character from freetype hibyte, lowbyte */
157 S_ADT
, /* Character 2F alternating raster */
158 S_FLH
, /* flip horizontal */
159 S_FLV
/* flip vertical */
162 /* shape coordinates */
165 S_W13
= 5, /* width*1/3 */
166 S_W12
, /* width*1/2 */
167 S_W23
, /* width*2/3 */
170 S_H13
, /* height*1/3 */
171 S_H12
, /* height*1/2 */
172 S_H23
, /* height*2/3 */
178 unsigned char aG3_20
[] = { S_TRA
, 0, S_H23
, 1, 0, S_H11
, S_W12
, S_END
};
179 unsigned char aG3_21
[] = { S_TRA
, 0, S_H23
, 1, 0, S_H11
, S_W11
, S_END
};
180 unsigned char aG3_22
[] = { S_TRA
, 0, S_H12
, 1, 0, S_H11
, S_W12
, S_END
};
181 unsigned char aG3_23
[] = { S_TRA
, 0, S_H12
, 1, 0, S_H11
, S_W11
, S_END
};
182 unsigned char aG3_24
[] = { S_TRA
, 0, 0, 1, 0, S_H11
, S_W12
, S_END
};
183 unsigned char aG3_25
[] = { S_TRA
, 0, 0, 1, 0, S_H11
, S_W11
, S_END
};
184 unsigned char aG3_26
[] = { S_INV
, S_LNK
, 0x66, S_END
};
185 unsigned char aG3_27
[] = { S_INV
, S_LNK
, 0x67, S_END
};
186 unsigned char aG3_28
[] = { S_INV
, S_LNK
, 0x68, S_END
};
187 unsigned char aG3_29
[] = { S_INV
, S_LNK
, 0x69, S_END
};
188 unsigned char aG3_2a
[] = { S_INV
, S_LNK
, 0x6a, S_END
};
189 unsigned char aG3_2b
[] = { S_INV
, S_LNK
, 0x6b, S_END
};
190 unsigned char aG3_2c
[] = { S_INV
, S_LNK
, 0x6c, S_END
};
191 unsigned char aG3_2d
[] = { S_INV
, S_LNK
, 0x6d, S_END
};
192 unsigned char aG3_2e
[] = { S_BOX
, 2, 0, 3, S_H11
, S_END
};
193 unsigned char aG3_2f
[] = { S_ADT
};
194 unsigned char aG3_30
[] = { S_LNK
, 0x20, S_FLH
, S_END
};
195 unsigned char aG3_31
[] = { S_LNK
, 0x21, S_FLH
, S_END
};
196 unsigned char aG3_32
[] = { S_LNK
, 0x22, S_FLH
, S_END
};
197 unsigned char aG3_33
[] = { S_LNK
, 0x23, S_FLH
, S_END
};
198 unsigned char aG3_34
[] = { S_LNK
, 0x24, S_FLH
, S_END
};
199 unsigned char aG3_35
[] = { S_LNK
, 0x25, S_FLH
, S_END
};
200 unsigned char aG3_36
[] = { S_INV
, S_LNK
, 0x76, S_END
};
201 unsigned char aG3_37
[] = { S_INV
, S_LNK
, 0x77, S_END
};
202 unsigned char aG3_38
[] = { S_INV
, S_LNK
, 0x78, S_END
};
203 unsigned char aG3_39
[] = { S_INV
, S_LNK
, 0x79, S_END
};
204 unsigned char aG3_3a
[] = { S_INV
, S_LNK
, 0x7a, S_END
};
205 unsigned char aG3_3b
[] = { S_INV
, S_LNK
, 0x7b, S_END
};
206 unsigned char aG3_3c
[] = { S_INV
, S_LNK
, 0x7c, S_END
};
207 unsigned char aG3_3d
[] = { S_INV
, S_LNK
, 0x7d, S_END
};
208 unsigned char aG3_3e
[] = { S_LNK
, 0x2e, S_FLH
, S_END
};
209 unsigned char aG3_3f
[] = { S_BOX
, 0, 0, S_W11
, S_H11
, S_END
};
210 unsigned char aG3_40
[] = { S_BOX
, 0, S_H13
, S_W11
, S_H13
, S_LNK
, 0x7e, S_END
};
211 unsigned char aG3_41
[] = { S_BOX
, 0, S_H13
, S_W11
, S_H13
, S_LNK
, 0x7e, S_FLV
, S_END
};
212 unsigned char aG3_42
[] = { S_LNK
, 0x50, S_BOX
, S_W12
, S_H13
, S_W12
, S_H13
, S_END
};
213 unsigned char aG3_43
[] = { S_LNK
, 0x50, S_BOX
, 0, S_H13
, S_W12
, S_H13
, S_END
};
214 unsigned char aG3_44
[] = { S_LNK
, 0x48, S_FLV
, S_LNK
, 0x48, S_END
};
215 unsigned char aG3_45
[] = { S_LNK
, 0x44, S_FLH
, S_END
};
216 unsigned char aG3_46
[] = { S_LNK
, 0x47, S_FLV
, S_END
};
217 unsigned char aG3_47
[] = { S_LNK
, 0x48, S_FLH
, S_LNK
, 0x48, S_END
};
218 unsigned char aG3_48
[] = { S_TRA
, 0, 0, S_W23
, 0, S_H23
, 0, S_BTR
, 0, 0, S_W13
, 0, S_H13
, 0, S_END
};
219 unsigned char aG3_49
[] = { S_LNK
, 0x48, S_FLH
, S_END
};
220 unsigned char aG3_4a
[] = { S_LNK
, 0x48, S_FLV
, S_END
};
221 unsigned char aG3_4b
[] = { S_LNK
, 0x48, S_FLH
, S_FLV
, S_END
};
222 unsigned char aG3_4c
[] = { S_LNK
, 0x50, S_BOX
, 0, S_H13
, S_W11
, S_H13
, S_END
};
223 unsigned char aG3_4d
[] = { S_CHR
, 0x25, 0xE6 };
224 unsigned char aG3_4e
[] = { S_CHR
, 0x25, 0xCF };
225 unsigned char aG3_4f
[] = { S_CHR
, 0x25, 0xCB };
226 unsigned char aG3_50
[] = { S_BOX
, S_W12
, 0, 2, S_H11
, S_FLH
, S_BOX
, S_W12
, 0, 2, S_H11
,S_END
};
227 unsigned char aG3_51
[] = { S_BOX
, 0, S_H12
, S_W11
, 2, S_FLV
, S_BOX
, 0, S_H12
, S_W11
, 2,S_END
};
228 unsigned char aG3_52
[] = { S_LNK
, 0x55, S_FLH
, S_FLV
, S_END
};
229 unsigned char aG3_53
[] = { S_LNK
, 0x55, S_FLV
, S_END
};
230 unsigned char aG3_54
[] = { S_LNK
, 0x55, S_FLH
, S_END
};
231 unsigned char aG3_55
[] = { S_LNK
, 0x7e, S_FLV
, S_BOX
, 0, S_H12
, S_W12
, 2, S_FLV
, S_BOX
, 0, S_H12
, S_W12
, 2, S_END
};
232 unsigned char aG3_56
[] = { S_LNK
, 0x57, S_FLH
, S_END
};
233 unsigned char aG3_57
[] = { S_LNK
, 0x55, S_LNK
, 0x50 , S_END
};
234 unsigned char aG3_58
[] = { S_LNK
, 0x59, S_FLV
, S_END
};
235 unsigned char aG3_59
[] = { S_LNK
, 0x7e, S_LNK
, 0x51 , S_END
};
236 unsigned char aG3_5a
[] = { S_LNK
, 0x50, S_LNK
, 0x51 , S_END
};
237 unsigned char aG3_5b
[] = { S_CHR
, 0x21, 0x92};
238 unsigned char aG3_5c
[] = { S_CHR
, 0x21, 0x90};
239 unsigned char aG3_5d
[] = { S_CHR
, 0x21, 0x91};
240 unsigned char aG3_5e
[] = { S_CHR
, 0x21, 0x93};
241 unsigned char aG3_5f
[] = { S_CHR
, 0x00, 0x20};
242 unsigned char aG3_60
[] = { S_INV
, S_LNK
, 0x20, S_END
};
243 unsigned char aG3_61
[] = { S_INV
, S_LNK
, 0x21, S_END
};
244 unsigned char aG3_62
[] = { S_INV
, S_LNK
, 0x22, S_END
};
245 unsigned char aG3_63
[] = { S_INV
, S_LNK
, 0x23, S_END
};
246 unsigned char aG3_64
[] = { S_INV
, S_LNK
, 0x24, S_END
};
247 unsigned char aG3_65
[] = { S_INV
, S_LNK
, 0x25, S_END
};
248 unsigned char aG3_66
[] = { S_LNK
, 0x20, S_FLV
, S_END
};
249 unsigned char aG3_67
[] = { S_LNK
, 0x21, S_FLV
, S_END
};
250 unsigned char aG3_68
[] = { S_LNK
, 0x22, S_FLV
, S_END
};
251 unsigned char aG3_69
[] = { S_LNK
, 0x23, S_FLV
, S_END
};
252 unsigned char aG3_6a
[] = { S_LNK
, 0x24, S_FLV
, S_END
};
253 unsigned char aG3_6b
[] = { S_BOX
, 0, 0, S_W11
, S_H13
, S_TRA
, 0, S_H13
, S_W11
, 0, S_H23
, 1, S_END
};
254 unsigned char aG3_6c
[] = { S_TRA
, 0, 0, 1, 0, S_H12
, S_W12
, S_FLV
, S_TRA
, 0, 0, 1, 0, S_H12
, S_W12
, S_BOX
, 0, S_H12
, S_W12
,1, S_END
};
255 unsigned char aG3_6d
[] = { S_TRA
, 0, 0, S_W12
, S_W12
, S_H12
, 0, S_FLH
, S_TRA
, 0, 0, S_W12
, S_W12
, S_H12
, 0, S_END
};
256 unsigned char aG3_6e
[] = { S_CHR
, 0x00, 0x20};
257 unsigned char aG3_6f
[] = { S_CHR
, 0x00, 0x20};
258 unsigned char aG3_70
[] = { S_INV
, S_LNK
, 0x30, S_END
};
259 unsigned char aG3_71
[] = { S_INV
, S_LNK
, 0x31, S_END
};
260 unsigned char aG3_72
[] = { S_INV
, S_LNK
, 0x32, S_END
};
261 unsigned char aG3_73
[] = { S_INV
, S_LNK
, 0x33, S_END
};
262 unsigned char aG3_74
[] = { S_INV
, S_LNK
, 0x34, S_END
};
263 unsigned char aG3_75
[] = { S_INV
, S_LNK
, 0x35, S_END
};
264 unsigned char aG3_76
[] = { S_LNK
, 0x66, S_FLH
, S_END
};
265 unsigned char aG3_77
[] = { S_LNK
, 0x67, S_FLH
, S_END
};
266 unsigned char aG3_78
[] = { S_LNK
, 0x68, S_FLH
, S_END
};
267 unsigned char aG3_79
[] = { S_LNK
, 0x69, S_FLH
, S_END
};
268 unsigned char aG3_7a
[] = { S_LNK
, 0x6a, S_FLH
, S_END
};
269 unsigned char aG3_7b
[] = { S_LNK
, 0x6b, S_FLH
, S_END
};
270 unsigned char aG3_7c
[] = { S_LNK
, 0x6c, S_FLH
, S_END
};
271 unsigned char aG3_7d
[] = { S_LNK
, 0x6d, S_FLV
, S_END
};
272 unsigned char aG3_7e
[] = { S_BOX
, S_W12
, 0, 2, S_H12
, S_FLH
, S_BOX
, S_W12
, 0, 2, S_H12
, S_END
};// help char, not printed directly (only by S_LNK)
274 unsigned char *aShapes
[] =
276 aG3_20
, aG3_21
, aG3_22
, aG3_23
, aG3_24
, aG3_25
, aG3_26
, aG3_27
, aG3_28
, aG3_29
, aG3_2a
, aG3_2b
, aG3_2c
, aG3_2d
, aG3_2e
, aG3_2f
,
277 aG3_30
, aG3_31
, aG3_32
, aG3_33
, aG3_34
, aG3_35
, aG3_36
, aG3_37
, aG3_38
, aG3_39
, aG3_3a
, aG3_3b
, aG3_3c
, aG3_3d
, aG3_3e
, aG3_3f
,
278 aG3_40
, aG3_41
, aG3_42
, aG3_43
, aG3_44
, aG3_45
, aG3_46
, aG3_47
, aG3_48
, aG3_49
, aG3_4a
, aG3_4b
, aG3_4c
, aG3_4d
, aG3_4e
, aG3_4f
,
279 aG3_50
, aG3_51
, aG3_52
, aG3_53
, aG3_54
, aG3_55
, aG3_56
, aG3_57
, aG3_58
, aG3_59
, aG3_5a
, aG3_5b
, aG3_5c
, aG3_5d
, aG3_5e
, aG3_5f
,
280 aG3_60
, aG3_61
, aG3_62
, aG3_63
, aG3_64
, aG3_65
, aG3_66
, aG3_67
, aG3_68
, aG3_69
, aG3_6a
, aG3_6b
, aG3_6c
, aG3_6d
, aG3_6e
, aG3_6f
,
281 aG3_70
, aG3_71
, aG3_72
, aG3_73
, aG3_74
, aG3_75
, aG3_76
, aG3_77
, aG3_78
, aG3_79
, aG3_7a
, aG3_7b
, aG3_7c
, aG3_7d
, aG3_7e
284 // G0 Table as defined in ETS 300 706
285 // cyrillic G0 Charset (0 = Serbian/Croatian, 1 = Russian/Bulgarian, 2 = Ukrainian)
286 const unsigned short int G0table
[6][6*16] =
288 // Cyrillic G0 Set - Option 1 - Serbian/Croatian
289 { ' ', '!', '\"', '#', '$', '%', '&', '\'', '(' , ')' , '*', '+', ',', '-', '.', '/',
290 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
291 0x0427, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, 0x0425, 0x0418, 0x0408, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E,
292 0x041F, 0x040C, 0x0420, 0x0421, 0x0422, 0x0423, 0x0412, 0x0403, 0x0409, 0x040A, 0x0417, 0x040B, 0x0416, 0x0402, 0x0428, 0x040F,
293 0x0447, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, 0x0445, 0x0438, 0x0458, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E,
294 0x043F, 0x045C, 0x0440, 0x0441, 0x0442, 0x0443, 0x0432, 0x0453, 0x0459, 0x045A, 0x0437, 0x045B, 0x0436, 0x0452, 0x0448, 0x25A0},
295 // Cyrillic G0 Set - Option 2 - Russian/Bulgarian
296 { ' ', '!', '\"', '#', '$', '%', 0x044B, '\'', '(' , ')' , '*', '+', ',', '-', '.', '/',
297 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
298 0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, 0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E,
299 0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, 0x042C, 0x042A, 0x0417, 0x0428, 0x042D, 0x0429, 0x0427, 0x042B,
300 0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, 0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E,
301 0x043F, 0x044F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, 0x044C, 0x044A, 0x0437, 0x0448, 0x044D, 0x0449, 0x0447, 0x25A0},
302 // Cyrillic G0 Set - Option 3 - Ukrainian
303 { ' ', '!', '\"', '#', '$', '%', 0x0457, '\'', '(' , ')' , '*', '+', ',', '-', '.', '/',
304 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
305 0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, 0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E,
306 0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, 0x042C, 0x0406, 0x0417, 0x0428, 0x0404, 0x0429, 0x0427, 0x0407,
307 0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, 0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E,
308 0x043F, 0x044F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, 0x044C, 0x0456, 0x0437, 0x0448, 0x0454, 0x0449, 0x0447, 0x25A0},
310 { ' ', '!', '\"', '#', '$', '%', '&', '\'', '(' , ')' , '*', '+', ',', '-', '.', '/',
311 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', 0x00AB, '=', 0x00BB, '?',
312 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F,
313 0x03A0, 0x03A1, 0x0384, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF,
314 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
315 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0x25A0},
317 { ' ', '!', 0x05F2, 0x00A3, '$', '%', '&', '\'', '(' , ')' , '*', '+', ',', '-', '.', '/',
318 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
319 '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
320 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 0x2190, 0x00BD, 0x2192, 0x2191, '#',
321 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
322 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x20AA, 0x2551, 0x00BE, 0x00F7, 0x25A0},
323 // Arabic G0 Set - Thanks to Habib2006(fannansat)
324 { ' ', '!', 0x05F2, 0x00A3, '$', 0x066A, 0xFEF0, 0xFEF2, 0xFD3F, 0xFD3E, '*', '+', ',', '-', '.', '/',
325 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', 0x061B, '>', '=', '<', 0x061F,
326 0xFE94, 0x0621, 0xFE92, 0x0628, 0xFE98, 0x062A, 0xFE8E, 0xFE8D, 0xFE91, 0xFE93, 0xFE97, 0xFE9B, 0xFE9F, 0xFEA3, 0xFEA7, 0xFEA9,
327 0x0630, 0xFEAD, 0xFEAF, 0xFEB3, 0xFEB7, 0xFEBB, 0xFEBF, 0xFEC1, 0xFEC5, 0xFECB, 0xFECF, 0xFE9C, 0xFEA0, 0xFEA4, 0xFEA8, 0x0023,
328 0x0640, 0xFED3, 0xFED7, 0xFEDB, 0xFEDF, 0xFEE3, 0xFEE7, 0xFEEB, 0xFEED, 0xFEEF, 0xFEF3, 0xFE99, 0xFE9D, 0xFEA1, 0xFEA5, 0xFEF4,
329 0xFEF0, 0xFECC, 0xFED0, 0xFED4, 0xFED1, 0xFED8, 0xFED5, 0xFED9, 0xFEE0, 0xFEDD, 0xFEE4, 0xFEE1, 0xFEE8, 0xFEE5, 0xFEFB, 0x25A0}
332 const unsigned short int nationaltable23
[14][2] =
334 { '#', 0x00A4 }, /* 0 */
335 { '#', 0x016F }, /* 1 CS/SK */
336 { 0x00A3, '$' }, /* 2 EN */
337 { '#', 0x00F5 }, /* 3 ET */
338 { 0x00E9, 0x0457 }, /* 4 FR */
339 { '#', '$' }, /* 5 DE */
340 { 0x00A3, '$' }, /* 6 IT */
341 { '#', '$' }, /* 7 LV/LT */
342 { '#', 0x0144 }, /* 8 PL */
343 { 0x00E7, '$' }, /* 9 PT/ES */
344 { '#', 0x00A4 }, /* A RO */
345 { '#', 0x00CB }, /* B SR/HR/SL */
346 { '#', 0x00A4 }, /* C SV/FI/HU */
347 { 0x20A4, 0x011F }, /* D TR */
349 const unsigned short int nationaltable40
[14] =
352 0x010D, /* 1 CS/SK */
358 0x0161, /* 7 LV/LT */
360 0x00A1, /* 9 PT/ES */
362 0x010C, /* B SR/HR/SL */
363 0x00C9, /* C SV/FI/HU */
366 const unsigned short int nationaltable5b
[14][6] =
368 { '[', '\\', ']', '^', '_', '`' }, /* 0 */
369 { 0x0165, 0x017E, 0x00FD, 0x00ED, 0x0159, 0x00E9 }, /* 1 CS/SK */
370 { 0x2190, 0x00BD, 0x2192, 0x2191, '#', 0x00AD }, /* 2 EN */
371 { 0x00C4, 0x00D6, 0x017D, 0x00DC, 0x00D5, 0x0161 }, /* 3 ET */
372 { 0x0451, 0x00EA, 0x00F9, 0x00EE, '#', 0x00E8 }, /* 4 FR */
373 { 0x00C4, 0x00D6, 0x00DC, '^', '_', 0x00B0 }, /* 5 DE */
374 { 0x00B0, 0x00E7, 0x2192, 0x2191, '#', 0x00F9 }, /* 6 IT */
375 { 0x0117, 0x0119, 0x017D, 0x010D, 0x016B, 0x0161 }, /* 7 LV/LT */
376 { 0x017B, 0x015A, 0x0141, 0x0107, 0x00F3, 0x0119 }, /* 8 PL */
377 { 0x00E1, 0x00E9, 0x00ED, 0x00F3, 0x00FA, 0x00BF }, /* 9 PT/ES */
378 { 0x00C2, 0x015E, 0x01CD, 0x01CF, 0x0131, 0x0163 }, /* A RO */
379 { 0x0106, 0x017D, 0x00D0, 0x0160, 0x0451, 0x010D }, /* B SR/HR/SL */
380 { 0x00C4, 0x00D6, 0x00C5, 0x00DC, '_', 0x00E9 }, /* C SV/FI/HU */
381 { 0x015E, 0x00D6, 0x00C7, 0x00DC, 0x011E, 0x0131 }, /* D TR */
383 const unsigned short int nationaltable7b
[14][4] =
385 { '{', '|', '}', '~' }, /* 0 */
386 { 0x00E1, 0x011B, 0x00FA, 0x0161 }, /* 1 CS/SK */
387 { 0x00BC, 0x2551, 0x00BE, 0x00F7 }, /* 2 EN */
388 { 0x00E4, 0x00F6, 0x017E, 0x00FC }, /* 3 ET */
389 { 0x00E2, 0x00F4, 0x00FB, 0x00E7 }, /* 4 FR */
390 { 0x00E4, 0x00F6, 0x00FC, 0x00DF }, /* 5 DE */
391 { 0x00E0, 0x00F3, 0x00E8, 0x00EC }, /* 6 IT */
392 { 0x0105, 0x0173, 0x017E, 0x012F }, /* 7 LV/LT */
393 { 0x017C, 0x015B, 0x0142, 0x017A }, /* 8 PL */
394 { 0x00FC, 0x00F1, 0x00E8, 0x00E0 }, /* 9 PT/ES */
395 { 0x00E2, 0x015F, 0x01CE, 0x00EE }, /* A RO */
396 { 0x0107, 0x017E, 0x0111, 0x0161 }, /* B SR/HR/SL */
397 { 0x00E4, 0x00F6, 0x00E5, 0x00FC }, /* C SV/FI/HU */
398 { 0x015F, 0x00F6, 0x00E7, 0x00FC }, /* D TR */
400 const unsigned short int arrowtable
[] =
402 8592, 8594, 8593, 8595, 'O', 'K', 8592, 8592
405 CTeletextDecoder::CTeletextDecoder()
407 memset(&m_RenderInfo
, 0, sizeof(TextRenderInfo_t
));
409 m_teletextFont
= CSpecialProtocol::TranslatePath(TeletextFont
);
410 m_TextureBuffer
= NULL
;
414 m_RenderInfo
.ShowFlof
= true;
415 m_RenderInfo
.Show39
= false;
416 m_RenderInfo
.Showl25
= true;
417 m_RenderInfo
.Prev_100
= 0x100;
418 m_RenderInfo
.Prev_10
= 0x100;
419 m_RenderInfo
.Next_100
= 0x100;
420 m_RenderInfo
.Next_10
= 0x100;
421 m_RenderInfo
.InputCounter
= 2;
423 unsigned short rd0
[] = {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0x00<<8, 0x00<<8, 0x00<<8, 0, 0 };
424 unsigned short gn0
[] = {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0x20<<8, 0x10<<8, 0x20<<8, 0, 0 };
425 unsigned short bl0
[] = {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0x40<<8, 0x20<<8, 0x40<<8, 0, 0 };
426 unsigned short tr0
[] = {0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
427 0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
428 0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
429 0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
430 0x0000 , 0x0000 , 0x0A0A , 0xFFFF, 0x3030 };
432 memcpy(m_RenderInfo
.rd0
,rd0
,TXT_Color_SIZECOLTABLE
*sizeof(unsigned short));
433 memcpy(m_RenderInfo
.gn0
,gn0
,TXT_Color_SIZECOLTABLE
*sizeof(unsigned short));
434 memcpy(m_RenderInfo
.bl0
,bl0
,TXT_Color_SIZECOLTABLE
*sizeof(unsigned short));
435 memcpy(m_RenderInfo
.tr0
,tr0
,TXT_Color_SIZECOLTABLE
*sizeof(unsigned short));
447 m_updateTexture
= false;
451 CTeletextDecoder::~CTeletextDecoder() = default;
453 bool CTeletextDecoder::Changed()
455 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
456 if (IsSubtitlePage(m_txtCache
->Page
))
458 m_updateTexture
= true;
462 /* Update on every changed second */
463 if (m_txtCache
->TimeString
[7] != prevTimeSec
)
465 prevTimeSec
= m_txtCache
->TimeString
[7];
466 m_updateTexture
= true;
472 bool CTeletextDecoder::HandleAction(const CAction
&action
)
474 if (m_txtCache
== NULL
)
476 CLog::Log(LOGERROR
, "CTeletextDecoder::HandleAction called without teletext cache");
480 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
482 if (action
.GetID() == ACTION_MOVE_UP
)
484 if (m_RenderInfo
.PageCatching
)
485 CatchNextPage(-1, -1);
487 GetNextPageOne(true);
490 else if (action
.GetID() == ACTION_MOVE_DOWN
)
492 if (m_RenderInfo
.PageCatching
)
495 GetNextPageOne(false);
498 else if (action
.GetID() == ACTION_MOVE_RIGHT
)
500 if (m_RenderInfo
.PageCatching
)
502 else if (m_RenderInfo
.Boxed
)
504 m_RenderInfo
.SubtitleDelay
++;
505 // display SubtitleDelay
506 m_RenderInfo
.PosY
= 0;
509 snprintf(ns
, sizeof(ns
), "+%d ", m_RenderInfo
.SubtitleDelay
);
510 RenderCharFB(ns
[0], &Text_AtrTable
[ATR_WB
]);
511 RenderCharFB(ns
[1], &Text_AtrTable
[ATR_WB
]);
512 RenderCharFB(ns
[2], &Text_AtrTable
[ATR_WB
]);
513 RenderCharFB(ns
[4], &Text_AtrTable
[ATR_WB
]);
521 else if (action
.GetID() == ACTION_MOVE_LEFT
)
523 if (m_RenderInfo
.PageCatching
)
524 CatchNextPage(0, -1);
525 else if (m_RenderInfo
.Boxed
)
527 m_RenderInfo
.SubtitleDelay
--;
529 // display subtitledelay
530 m_RenderInfo
.PosY
= 0;
533 snprintf(ns
, sizeof(ns
), "+%d ", m_RenderInfo
.SubtitleDelay
);
534 RenderCharFB(ns
[0], &Text_AtrTable
[ATR_WB
]);
535 RenderCharFB(ns
[1], &Text_AtrTable
[ATR_WB
]);
536 RenderCharFB(ns
[2], &Text_AtrTable
[ATR_WB
]);
537 RenderCharFB(ns
[4], &Text_AtrTable
[ATR_WB
]);
545 else if (action
.GetID() >= REMOTE_0
&& action
.GetID() <= REMOTE_9
)
547 PageInput(action
.GetID() - REMOTE_0
);
550 else if (action
.GetID() == KEY_UNICODE
)
551 { // input from the keyboard
552 if (action
.GetUnicode() >= 48 && action
.GetUnicode() < 58)
554 PageInput(action
.GetUnicode() - 48);
559 else if (action
.GetID() == ACTION_PAGE_UP
)
564 else if (action
.GetID() == ACTION_PAGE_DOWN
)
569 else if (action
.GetID() == ACTION_SELECT_ITEM
)
571 if (m_txtCache
->SubPageTable
[m_txtCache
->Page
] == 0xFF)
574 if (!m_RenderInfo
.PageCatching
)
582 if (m_RenderInfo
.PageCatching
)
584 m_txtCache
->PageUpdate
= true;
585 m_RenderInfo
.PageCatching
= false;
589 if (action
.GetID() == ACTION_SHOW_INFO
)
594 else if (action
.GetID() == ACTION_TELETEXT_RED
)
596 ColorKey(m_RenderInfo
.Prev_100
);
599 else if (action
.GetID() == ACTION_TELETEXT_GREEN
)
601 ColorKey(m_RenderInfo
.Prev_10
);
604 else if (action
.GetID() == ACTION_TELETEXT_YELLOW
)
606 ColorKey(m_RenderInfo
.Next_10
);
609 else if (action
.GetID() == ACTION_TELETEXT_BLUE
)
611 ColorKey(m_RenderInfo
.Next_100
);
618 bool CTeletextDecoder::InitDecoder()
622 auto& components
= CServiceBroker::GetAppComponents();
623 const auto appPlayer
= components
.GetComponent
<CApplicationPlayer
>();
624 m_txtCache
= appPlayer
->GetTeletextCache();
625 if (m_txtCache
== nullptr)
627 CLog::Log(LOGERROR
, "{}: called without teletext cache", __FUNCTION__
);
631 /* init fontlibrary */
632 if ((error
= FT_Init_FreeType(&m_Library
)))
634 CLog::Log(LOGERROR
, "{}: <FT_Init_FreeType: {:#2X}>", __FUNCTION__
, error
);
639 if ((error
= FTC_Manager_New(m_Library
, 7, 2, 0, &MyFaceRequester
, NULL
, &m_Manager
)))
641 FT_Done_FreeType(m_Library
);
644 CLog::Log(LOGERROR
, "{}: <FTC_Manager_New: {:#2X}>", __FUNCTION__
, error
);
648 if ((error
= FTC_SBitCache_New(m_Manager
, &m_Cache
)))
650 FTC_Manager_Done(m_Manager
);
651 FT_Done_FreeType(m_Library
);
654 CLog::Log(LOGERROR
, "{}: <FTC_SBit_Cache_New: {:#2X}>", __FUNCTION__
, error
);
658 /* calculate font dimensions */
659 m_RenderInfo
.Width
= (int)(CServiceBroker::GetWinSystem()->GetGfxContext().GetWidth()*CServiceBroker::GetWinSystem()->GetGfxContext().GetGUIScaleX());
660 m_RenderInfo
.Height
= (int)(CServiceBroker::GetWinSystem()->GetGfxContext().GetHeight()*CServiceBroker::GetWinSystem()->GetGfxContext().GetGUIScaleY());
661 m_RenderInfo
.FontHeight
= m_RenderInfo
.Height
/ 25;
662 m_RenderInfo
.FontWidth_Normal
= m_RenderInfo
.Width
/ (m_RenderInfo
.Show39
? 39 : 40);
663 SetFontWidth(m_RenderInfo
.FontWidth_Normal
);
664 for (int i
= 0; i
<= 10; i
++)
665 m_RenderInfo
.axdrcs
[i
+12+1] = (m_RenderInfo
.FontHeight
* i
+ 6) / 10;
668 m_TypeTTF
.face_id
= (FTC_FaceID
) const_cast<char*>(m_teletextFont
.c_str());
669 m_TypeTTF
.height
= (FT_UShort
) m_RenderInfo
.FontHeight
;
670 m_TypeTTF
.flags
= FT_LOAD_MONOCHROME
;
671 if (FTC_Manager_LookupFace(m_Manager
, m_TypeTTF
.face_id
, &m_Face
))
673 m_TypeTTF
.face_id
= (FTC_FaceID
) const_cast<char*>(m_teletextFont
.c_str());
674 if ((error
= FTC_Manager_LookupFace(m_Manager
, m_TypeTTF
.face_id
, &m_Face
)))
676 CLog::Log(LOGERROR
, "{}: <FTC_Manager_Lookup_Face failed with Errorcode {:#2X}>",
677 __FUNCTION__
, error
);
678 FTC_Manager_Done(m_Manager
);
679 FT_Done_FreeType(m_Library
);
685 m_Ascender
= m_RenderInfo
.FontHeight
* m_Face
->ascender
/ m_Face
->units_per_EM
;
687 /* set variable screeninfo for double buffering */
689 m_TextureBuffer
= new Color
[4 * m_RenderInfo
.Height
* m_RenderInfo
.Width
];
691 ClearFB(GetColorRGB(TXT_ColorTransp
));
692 ClearBB(GetColorRGB(TXT_ColorTransp
)); /* initialize backbuffer */
693 /* set new colormap */
694 SetColors(DefaultColors
, 0, TXT_Color_SIZECOLTABLE
);
696 for (int i
= 0; i
< 40 * 25; i
++)
698 m_RenderInfo
.PageChar
[i
] = ' ';
699 m_RenderInfo
.PageAtrb
[i
].fg
= TXT_ColorTransp
;
700 m_RenderInfo
.PageAtrb
[i
].bg
= TXT_ColorTransp
;
701 m_RenderInfo
.PageAtrb
[i
].charset
= C_G0P
;
702 m_RenderInfo
.PageAtrb
[i
].doubleh
= 0;
703 m_RenderInfo
.PageAtrb
[i
].doublew
= 0;
704 m_RenderInfo
.PageAtrb
[i
].IgnoreAtBlackBgSubst
= 0;
707 m_RenderInfo
.TranspMode
= false;
713 void CTeletextDecoder::EndDecoder()
715 /* clear SubtitleCache */
716 for (TextSubtitleCache_t
*& subtitleCache
: m_RenderInfo
.SubtitleCache
)
718 if (subtitleCache
!= NULL
)
720 delete subtitleCache
;
721 subtitleCache
= NULL
;
727 delete[] m_TextureBuffer
;
728 m_TextureBuffer
= NULL
;
734 FTC_Node_Unref(m_anode
, m_Manager
);
735 FTC_Manager_Done(m_Manager
);
739 FT_Done_FreeType(m_Library
);
747 CLog::Log(LOGINFO
, "{}: called without cache", __FUNCTION__
);
751 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
752 m_txtCache
->PageUpdate
= true;
753 CLog::Log(LOGDEBUG
, "Teletext: Rendering ended");
757 void CTeletextDecoder::PageInput(int Number
)
759 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
761 m_updateTexture
= true;
763 /* clear m_TempPage */
764 if (m_RenderInfo
.InputCounter
== 2)
767 /* check for 0 & 9 on first position */
768 if (Number
== 0 && m_RenderInfo
.InputCounter
== 2)
771 m_TempPage
= m_LastPage
; /* 0 toggles to last page as in program switching */
772 m_RenderInfo
.InputCounter
= -1;
774 else if (Number
== 9 && m_RenderInfo
.InputCounter
== 2)
780 if (m_RenderInfo
.ZoomMode
== 2)
782 m_RenderInfo
.ZoomMode
= 1;
786 m_RenderInfo
.PosY
= 0;
788 switch (m_RenderInfo
.InputCounter
)
792 RenderCharFB(Number
| '0', &Text_AtrTable
[ATR_WB
]);
793 RenderCharFB('-', &Text_AtrTable
[ATR_WB
]);
794 RenderCharFB('-', &Text_AtrTable
[ATR_WB
]);
799 RenderCharFB(Number
| '0', &Text_AtrTable
[ATR_WB
]);
804 RenderCharFB(Number
| '0', &Text_AtrTable
[ATR_WB
]);
808 /* generate pagenumber */
809 m_TempPage
|= Number
<< (m_RenderInfo
.InputCounter
*4);
811 m_RenderInfo
.InputCounter
--;
813 if (m_RenderInfo
.InputCounter
< 0)
815 /* disable SubPage zapping */
816 m_txtCache
->ZapSubpageManual
= false;
819 m_RenderInfo
.InputCounter
= 2;
822 m_LastPage
= m_txtCache
->Page
;
824 m_txtCache
->Page
= m_TempPage
;
825 m_RenderInfo
.HintMode
= false;
828 int subp
= m_txtCache
->SubPageTable
[m_txtCache
->Page
];
831 m_txtCache
->SubPage
= subp
;
832 m_txtCache
->PageUpdate
= true;
836 m_txtCache
->SubPage
= 0;
837 // RenderMessage(PageNotFound);
842 void CTeletextDecoder::GetNextPageOne(bool up
)
844 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
846 /* disable subpage zapping */
847 m_txtCache
->ZapSubpageManual
= false;
849 /* abort pageinput */
850 m_RenderInfo
.InputCounter
= 2;
852 /* find next cached page */
853 m_LastPage
= m_txtCache
->Page
;
858 CDVDTeletextTools::NextDec(&m_txtCache
->Page
);
860 CDVDTeletextTools::PrevDec(&m_txtCache
->Page
);
861 subp
= m_txtCache
->SubPageTable
[m_txtCache
->Page
];
862 } while (subp
== 0xFF && m_txtCache
->Page
!= m_LastPage
);
865 if (m_txtCache
->Page
!= m_LastPage
)
867 if (m_RenderInfo
.ZoomMode
== 2)
868 m_RenderInfo
.ZoomMode
= 1;
870 m_txtCache
->SubPage
= subp
;
871 m_RenderInfo
.HintMode
= false;
872 m_txtCache
->PageUpdate
= true;
876 void CTeletextDecoder::GetNextSubPage(int offset
)
878 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
880 /* abort pageinput */
881 m_RenderInfo
.InputCounter
= 2;
883 for (int loop
= m_txtCache
->SubPage
+ offset
; loop
!= m_txtCache
->SubPage
; loop
+= offset
)
887 else if (loop
> 0x79)
889 if (loop
== m_txtCache
->SubPage
)
892 if (m_txtCache
->astCachetable
[m_txtCache
->Page
][loop
])
894 /* enable manual SubPage zapping */
895 m_txtCache
->ZapSubpageManual
= true;
898 if (m_RenderInfo
.ZoomMode
== 2) /* if zoomed to lower half */
899 m_RenderInfo
.ZoomMode
= 1; /* activate upper half */
901 m_txtCache
->SubPage
= loop
;
902 m_RenderInfo
.HintMode
= false;
903 m_txtCache
->PageUpdate
= true;
910 void CTeletextDecoder::SwitchZoomMode()
912 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
914 if (m_txtCache
->SubPageTable
[m_txtCache
->Page
] != 0xFF)
917 m_RenderInfo
.ZoomMode
++;
919 if (m_RenderInfo
.ZoomMode
== 3)
920 m_RenderInfo
.ZoomMode
= 0;
923 m_txtCache
->PageUpdate
= true;
927 void CTeletextDecoder::SwitchTranspMode()
929 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
932 if (!m_RenderInfo
.TranspMode
)
933 m_RenderInfo
.TranspMode
= true;
935 m_RenderInfo
.TranspMode
= false; /* backward to immediately switch to TV-screen */
938 if (!m_RenderInfo
.TranspMode
) /* normal text-only */
940 ClearBB(m_txtCache
->FullScrColor
);
941 m_txtCache
->PageUpdate
= true;
943 else /* semi-transparent BG with FG text */
945 ClearBB(TXT_ColorTransp
);
946 m_txtCache
->PageUpdate
= true;
950 void CTeletextDecoder::SwitchHintMode()
952 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
955 m_RenderInfo
.HintMode
^= true;
957 if (!m_RenderInfo
.HintMode
) /* toggle evaluation of level 2.5 information by explicitly switching off HintMode */
959 m_RenderInfo
.Showl25
^= true;
962 m_txtCache
->PageUpdate
= true;
965 void CTeletextDecoder::ColorKey(int target
)
967 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
972 if (m_RenderInfo
.ZoomMode
== 2)
973 m_RenderInfo
.ZoomMode
= 1;
975 m_LastPage
= m_txtCache
->Page
;
976 m_txtCache
->Page
= target
;
977 m_txtCache
->SubPage
= m_txtCache
->SubPageTable
[m_txtCache
->Page
];
978 m_RenderInfo
.InputCounter
= 2;
979 m_RenderInfo
.HintMode
= false;
980 m_txtCache
->PageUpdate
= true;
983 void CTeletextDecoder::StartPageCatching()
985 m_RenderInfo
.PageCatching
= true;
987 /* abort pageinput */
988 m_RenderInfo
.InputCounter
= 2;
991 m_RenderInfo
.ZoomMode
= 0;
992 m_RenderInfo
.PosX
= 0;
993 m_RenderInfo
.PosY
= 24*m_RenderInfo
.FontHeight
;
995 /* check for pagenumber(s) */
1000 m_PCOldCol
= 0; /* no inverted page number to restore yet */
1001 CatchNextPage(0, 1);
1005 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
1007 m_RenderInfo
.PageCatching
= false;
1008 m_txtCache
->PageUpdate
= true;
1013 void CTeletextDecoder::StopPageCatching()
1015 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
1018 if (m_RenderInfo
.ZoomMode
== 2)
1019 m_RenderInfo
.ZoomMode
= 1;
1021 m_LastPage
= m_txtCache
->Page
;
1022 m_txtCache
->Page
= m_CatchedPage
;
1023 m_RenderInfo
.HintMode
= false;
1024 m_txtCache
->PageUpdate
= true;
1025 m_RenderInfo
.PageCatching
= false;
1027 int subp
= m_txtCache
->SubPageTable
[m_txtCache
->Page
];
1029 m_txtCache
->SubPage
= subp
;
1031 m_txtCache
->SubPage
= 0;
1034 void CTeletextDecoder::CatchNextPage(int firstlineinc
, int inc
)
1036 int tmp_page
, allowwrap
= 1; /* allow first wrap around */
1038 /* catch next page */
1041 unsigned char *p
= &(m_RenderInfo
.PageChar
[m_CatchRow
*40 + m_CatchCol
]);
1042 TextPageAttr_t a
= m_RenderInfo
.PageAtrb
[m_CatchRow
*40 + m_CatchCol
];
1044 if (!(a
.charset
== C_G1C
|| a
.charset
== C_G1S
) && /* no mosaic */
1045 (a
.fg
!= a
.bg
) && /* not hidden */
1046 (*p
>= '1' && *p
<= '8' && /* valid page number */
1047 *(p
+1) >= '0' && *(p
+1) <= '9' &&
1048 *(p
+2) >= '0' && *(p
+2) <= '9') &&
1049 (m_CatchRow
== 0 || (*(p
-1) < '0' || *(p
-1) > '9')) && /* non-numeric char before and behind */
1050 (m_CatchRow
== 37 || (*(p
+3) < '0' || *(p
+3) > '9')))
1052 tmp_page
= ((*p
- '0')<<8) | ((*(p
+1) - '0')<<4) | (*(p
+2) - '0');
1055 if (tmp_page
!= m_CatchedPage
) /* confusing to skip identical page numbers - I want to reach what I aim to */
1058 m_CatchedPage
= tmp_page
;
1059 RenderCatchedPage();
1060 m_CatchCol
+= inc
; /* FIXME: limit */
1065 if (firstlineinc
> 0)
1071 else if (firstlineinc
< 0)
1080 if (m_CatchCol
> 37)
1085 else if (m_CatchCol
< 0)
1091 if (m_CatchRow
> 23)
1104 else if (m_CatchRow
< 1)
1120 void CTeletextDecoder::RenderCatchedPage()
1123 m_updateTexture
= true;
1126 if (m_RenderInfo
.ZoomMode
)
1129 if (m_PCOldRow
|| m_PCOldCol
) /* not at first call */
1131 /* restore pagenumber */
1132 SetPosX(m_PCOldCol
);
1134 if (m_RenderInfo
.ZoomMode
== 2)
1135 m_RenderInfo
.PosY
= (m_PCOldRow
-12)*m_RenderInfo
.FontHeight
*((zoom
>>10)+1);
1137 m_RenderInfo
.PosY
= m_PCOldRow
*m_RenderInfo
.FontHeight
*((zoom
>>10)+1);
1139 RenderCharFB(m_RenderInfo
.PageChar
[m_PCOldRow
*40 + m_PCOldCol
], &m_RenderInfo
.PageAtrb
[m_PCOldRow
*40 + m_PCOldCol
]);
1140 RenderCharFB(m_RenderInfo
.PageChar
[m_PCOldRow
*40 + m_PCOldCol
+ 1], &m_RenderInfo
.PageAtrb
[m_PCOldRow
*40 + m_PCOldCol
+ 1]);
1141 RenderCharFB(m_RenderInfo
.PageChar
[m_PCOldRow
*40 + m_PCOldCol
+ 2], &m_RenderInfo
.PageAtrb
[m_PCOldRow
*40 + m_PCOldCol
+ 2]);
1144 m_PCOldRow
= m_CatchRow
;
1145 m_PCOldCol
= m_CatchCol
;
1147 /* mark pagenumber */
1148 if (m_RenderInfo
.ZoomMode
== 1 && m_CatchRow
> 11)
1150 m_RenderInfo
.ZoomMode
= 2;
1153 else if (m_RenderInfo
.ZoomMode
== 2 && m_CatchRow
< 12)
1155 m_RenderInfo
.ZoomMode
= 1;
1158 SetPosX(m_CatchCol
);
1160 if (m_RenderInfo
.ZoomMode
== 2)
1161 m_RenderInfo
.PosY
= (m_CatchRow
-12)*m_RenderInfo
.FontHeight
*((zoom
>>10)+1);
1163 m_RenderInfo
.PosY
= m_CatchRow
*m_RenderInfo
.FontHeight
*((zoom
>>10)+1);
1165 TextPageAttr_t a0
= m_RenderInfo
.PageAtrb
[m_CatchRow
*40 + m_CatchCol
];
1166 TextPageAttr_t a1
= m_RenderInfo
.PageAtrb
[m_CatchRow
*40 + m_CatchCol
+ 1];
1167 TextPageAttr_t a2
= m_RenderInfo
.PageAtrb
[m_CatchRow
*40 + m_CatchCol
+ 2];
1170 /* exchange colors */
1171 t
= a0
.fg
; a0
.fg
= a0
.bg
; a0
.bg
= t
;
1172 t
= a1
.fg
; a1
.fg
= a1
.bg
; a1
.bg
= t
;
1173 t
= a2
.fg
; a2
.fg
= a2
.bg
; a2
.bg
= t
;
1175 RenderCharFB(m_RenderInfo
.PageChar
[m_CatchRow
*40 + m_CatchCol
], &a0
);
1176 RenderCharFB(m_RenderInfo
.PageChar
[m_CatchRow
*40 + m_CatchCol
+ 1], &a1
);
1177 RenderCharFB(m_RenderInfo
.PageChar
[m_CatchRow
*40 + m_CatchCol
+ 2], &a2
);
1180 void CTeletextDecoder::RenderPage()
1182 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
1185 int national_subset_bak
= m_txtCache
->NationalSubset
;
1187 if (m_txtCache
->PageUpdate
)
1188 m_updateTexture
= true;
1190 /* update page or timestring */
1191 if (m_txtCache
->PageUpdate
&& m_txtCache
->PageReceiving
!= m_txtCache
->Page
&& m_RenderInfo
.InputCounter
== 2)
1193 /* reset update flag */
1194 m_txtCache
->PageUpdate
= false;
1195 if (m_RenderInfo
.Boxed
&& m_RenderInfo
.SubtitleDelay
)
1197 TextSubtitleCache_t
* c
= NULL
;
1199 for (int i
= 0; i
< SUBTITLE_CACHESIZE
; i
++)
1201 if (j
== -1 && !m_RenderInfo
.SubtitleCache
[i
])
1203 if (m_RenderInfo
.SubtitleCache
[i
] && !m_RenderInfo
.SubtitleCache
[i
]->Valid
)
1205 c
= m_RenderInfo
.SubtitleCache
[i
];
1211 if (j
== -1) // no more space in SubtitleCache
1214 c
= new TextSubtitleCache_t
;
1219 m_RenderInfo
.SubtitleCache
[j
] = c
;
1222 c
->Timestamp
= std::chrono::steady_clock::now();
1224 if (m_txtCache
->SubPageTable
[m_txtCache
->Page
] != 0xFF)
1226 TextPageinfo_t
* p
= DecodePage(m_RenderInfo
.Showl25
, c
->PageChar
, c
->PageAtrb
, m_RenderInfo
.HintMode
, m_RenderInfo
.ShowFlof
);
1229 m_RenderInfo
.Boxed
= p
->boxed
;
1232 m_RenderInfo
.DelayStarted
= true;
1235 m_RenderInfo
.DelayStarted
= false;
1237 if (m_txtCache
->SubPageTable
[m_txtCache
->Page
] != 0xFF)
1239 TextPageinfo_t
* p
= DecodePage(m_RenderInfo
.Showl25
, m_RenderInfo
.PageChar
, m_RenderInfo
.PageAtrb
, m_RenderInfo
.HintMode
, m_RenderInfo
.ShowFlof
);
1242 m_RenderInfo
.PageInfo
= p
;
1243 m_RenderInfo
.Boxed
= p
->boxed
;
1245 if (m_RenderInfo
.Boxed
|| m_RenderInfo
.TranspMode
)
1246 FillBorder(GetColorRGB(TXT_ColorTransp
));
1248 FillBorder(GetColorRGB((enumTeletextColor
)m_txtCache
->FullScrColor
));
1250 if (m_txtCache
->ColorTable
) /* as late as possible to shorten the time the old page is displayed with the new colors */
1251 SetColors(m_txtCache
->ColorTable
, 16, 16); /* set colors for CLUTs 2+3 */
1256 DoRenderPage(StartRow
, national_subset_bak
);
1260 if (m_RenderInfo
.DelayStarted
)
1262 auto now
= std::chrono::steady_clock::now();
1263 for (TextSubtitleCache_t
* const subtitleCache
: m_RenderInfo
.SubtitleCache
)
1265 if (subtitleCache
&& subtitleCache
->Valid
&&
1266 std::chrono::duration_cast
<std::chrono::seconds
>(now
- subtitleCache
->Timestamp
)
1267 .count() >= m_RenderInfo
.SubtitleDelay
)
1269 memcpy(m_RenderInfo
.PageChar
, subtitleCache
->PageChar
, 40 * 25);
1270 memcpy(m_RenderInfo
.PageAtrb
, subtitleCache
->PageAtrb
, 40 * 25 * sizeof(TextPageAttr_t
));
1271 DoRenderPage(StartRow
, national_subset_bak
);
1272 subtitleCache
->Valid
= false;
1277 if (m_RenderInfo
.ZoomMode
!= 2)
1279 m_RenderInfo
.PosY
= 0;
1280 if (m_txtCache
->SubPageTable
[m_txtCache
->Page
] == 0xff)
1282 m_RenderInfo
.PageAtrb
[32].fg
= TXT_ColorYellow
;
1283 m_RenderInfo
.PageAtrb
[32].bg
= TXT_ColorMenu1
;
1284 int showpage
= m_txtCache
->PageReceiving
;
1287 // Verify that showpage is positive before any access to the array
1288 if (showpage
>= 0 && (showsubpage
= m_txtCache
->SubPageTable
[showpage
]) != 0xff)
1290 TextCachedPage_t
*pCachedPage
;
1291 pCachedPage
= m_txtCache
->astCachetable
[showpage
][showsubpage
];
1292 if (pCachedPage
&& IsDec(showpage
))
1294 m_RenderInfo
.PosX
= 0;
1295 if (m_RenderInfo
.InputCounter
== 2)
1297 if (m_txtCache
->BTTok
&& !m_txtCache
->BasicTop
[m_txtCache
->Page
]) /* page non-existent according to TOP (continue search anyway) */
1299 m_RenderInfo
.PageAtrb
[0].fg
= TXT_ColorWhite
;
1300 m_RenderInfo
.PageAtrb
[0].bg
= TXT_ColorRed
;
1304 m_RenderInfo
.PageAtrb
[0].fg
= TXT_ColorYellow
;
1305 m_RenderInfo
.PageAtrb
[0].bg
= TXT_ColorMenu1
;
1307 CDVDTeletextTools::Hex2Str((char*)m_RenderInfo
.PageChar
+3, m_txtCache
->Page
);
1310 for (col
= m_RenderInfo
.nofirst
; col
< 7; col
++) // selected page
1312 RenderCharFB(m_RenderInfo
.PageChar
[col
], &m_RenderInfo
.PageAtrb
[0]);
1314 RenderCharFB(m_RenderInfo
.PageChar
[col
], &m_RenderInfo
.PageAtrb
[32]);
1319 memcpy(&m_RenderInfo
.PageChar
[8], pCachedPage
->p0
, 24); /* header line without timestring */
1320 for (unsigned char i
: pCachedPage
->p0
)
1322 RenderCharFB(i
, &m_RenderInfo
.PageAtrb
[32]);
1325 /* Update on every Header number change */
1326 if (pCachedPage
->p0
[2] != prevHeaderPage
)
1328 prevHeaderPage
= pCachedPage
->p0
[2];
1329 m_updateTexture
= true;
1335 /* update timestring */
1337 for (int i
= 0; i
< 8; i
++)
1339 if (!m_RenderInfo
.PageAtrb
[32+i
].flashing
)
1340 RenderCharFB(m_txtCache
->TimeString
[i
], &m_RenderInfo
.PageAtrb
[32]);
1347 DoFlashing(StartRow
);
1348 m_txtCache
->NationalSubset
= national_subset_bak
;
1352 bool CTeletextDecoder::IsSubtitlePage(int pageNumber
) const
1357 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
1359 for (const auto subPage
: m_txtCache
->SubtitlePages
)
1361 if (subPage
.page
== pageNumber
)
1368 void CTeletextDecoder::DoFlashing(int startrow
)
1370 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
1372 TextCachedPage_t
* textCachepage
=
1373 m_txtCache
->astCachetable
[m_txtCache
->Page
][m_txtCache
->SubPage
];
1375 // Verify that the page is not deleted by the other thread: CDVDTeletextData::ResetTeletextCache()
1376 if (!textCachepage
|| m_RenderInfo
.PageInfo
!= &textCachepage
->pageinfo
)
1377 m_RenderInfo
.PageInfo
= nullptr;
1379 /* get national subset */
1380 if (m_txtCache
->NationalSubset
<= NAT_MAX_FROM_HEADER
&& /* not for GR/RU as long as line28 is not evaluated */
1381 m_RenderInfo
.PageInfo
&& m_RenderInfo
.PageInfo
->nationalvalid
) /* individual subset according to page header */
1383 m_txtCache
->NationalSubset
= CountryConversionTable
[m_RenderInfo
.PageInfo
->national
];
1387 TextPageAttr_t flashattr
;
1389 std::chrono::milliseconds flashphase
= std::chrono::duration_cast
<std::chrono::milliseconds
>(
1390 std::chrono::steady_clock::now().time_since_epoch()) %
1393 int srow
= startrow
;
1397 switch (m_RenderInfo
.ZoomMode
)
1399 case 1: erow
= 12; factor
=2;break;
1400 case 2: srow
= 12; factor
=2;break;
1403 m_RenderInfo
.PosY
= startrow
*m_RenderInfo
.FontHeight
*factor
;
1404 for (int row
= srow
; row
< erow
; row
++)
1406 int index
= row
* 40;
1411 m_RenderInfo
.PosX
= 0;
1412 for (int col
= m_RenderInfo
.nofirst
; col
< 40; col
++)
1414 if (m_RenderInfo
.PageAtrb
[index
+ col
].flashing
&& m_RenderInfo
.PageChar
[index
+ col
] > 0x20 && m_RenderInfo
.PageChar
[index
+ col
] != 0xff )
1417 flashchar
= m_RenderInfo
.PageChar
[index
+ col
];
1418 bool doflash
= false;
1419 memcpy(&flashattr
, &m_RenderInfo
.PageAtrb
[index
+ col
], sizeof(TextPageAttr_t
));
1420 switch (flashattr
.flashing
&0x1c) // Flash Rate
1423 if (flashphase
> 500ms
)
1426 case 0x04 : // 2 Hz Phase 1
1427 if (flashphase
< 250ms
)
1430 case 0x08 : // 2 Hz Phase 2
1431 if (flashphase
>= 250ms
&& flashphase
< 500ms
)
1434 case 0x0c : // 2 Hz Phase 3
1435 if (flashphase
>= 500ms
&& flashphase
< 750ms
)
1438 case 0x10 : // incremental flash
1440 if (incflash
>3) incflash
= 1;
1444 if (flashphase
< 250ms
)
1448 if (flashphase
>= 250ms
&& flashphase
< 500ms
)
1452 if (flashphase
>= 500ms
&& flashphase
< 750ms
)
1457 case 0x14 : // decremental flash
1459 if (decflash
<1) decflash
= 3;
1463 if (flashphase
< 250ms
)
1467 if (flashphase
>= 250ms
&& flashphase
< 500ms
)
1471 if (flashphase
>= 500ms
&& flashphase
< 750ms
)
1479 switch (flashattr
.flashing
&0x03) // Flash Mode
1481 case 0x01 : // normal Flashing
1482 if (doflash
) flashattr
.fg
= flashattr
.bg
;
1484 case 0x02 : // inverted Flashing
1486 if (doflash
) flashattr
.fg
= flashattr
.bg
;
1488 case 0x03 : // color Flashing
1489 if (doflash
) flashattr
.fg
= flashattr
.fg
+ (flashattr
.fg
> 7 ? (-8) : 8);
1493 RenderCharFB(flashchar
, &flashattr
);
1494 if (flashattr
.doublew
) col
++;
1495 if (flashattr
.doubleh
) dhset
= 1;
1497 m_updateTexture
= true;
1503 m_RenderInfo
.PosY
+= m_RenderInfo
.FontHeight
*factor
;
1505 m_RenderInfo
.PosY
+= m_RenderInfo
.FontHeight
*factor
;
1509 void CTeletextDecoder::DoRenderPage(int startrow
, int national_subset_bak
)
1511 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
1513 /* display first column? */
1514 m_RenderInfo
.nofirst
= m_RenderInfo
.Show39
;
1515 for (int row
= 1; row
< 24; row
++)
1517 int Byte
= m_RenderInfo
.PageChar
[row
*40];
1518 if (Byte
!= ' ' && Byte
!= 0x00 && Byte
!= 0xFF && m_RenderInfo
.PageAtrb
[row
*40].fg
!= m_RenderInfo
.PageAtrb
[row
*40].bg
)
1520 m_RenderInfo
.nofirst
= 0;
1524 m_RenderInfo
.FontWidth_Normal
= m_RenderInfo
.Width
/ (m_RenderInfo
.nofirst
? 39 : 40);
1525 SetFontWidth(m_RenderInfo
.FontWidth_Normal
);
1527 if (m_RenderInfo
.TranspMode
|| m_RenderInfo
.Boxed
)
1529 FillBorder(GetColorRGB(TXT_ColorTransp
));//ClearBB(transp);
1530 m_RenderInfo
.ClearBBColor
= TXT_ColorTransp
;
1533 /* get national subset */
1534 if (m_txtCache
->NationalSubset
<= NAT_MAX_FROM_HEADER
&& /* not for GR/RU as long as line28 is not evaluated */
1535 m_RenderInfo
.PageInfo
&& m_RenderInfo
.PageInfo
->nationalvalid
) /* individual subset according to page header */
1537 m_txtCache
->NationalSubset
= CountryConversionTable
[m_RenderInfo
.PageInfo
->national
];
1540 if (m_RenderInfo
.PageInfo
&& (m_RenderInfo
.PageInfo
->function
== FUNC_GDRCS
|| m_RenderInfo
.PageInfo
->function
== FUNC_DRCS
)) /* character definitions */
1543 #define DRCSCOLS (48/DRCSROWS)
1546 #define DRCSXSPC (12*DRCSZOOMX + 2)
1547 #define DRCSYSPC (10*DRCSZOOMY + 2)
1549 unsigned char ax
[] = { /* array[0..12] of x-offsets, array[0..10] of y-offsets for each pixel */
1576 ClearBB(TXT_ColorBlack
);
1577 for (int col
= 0; col
< 24*40; col
++)
1578 m_RenderInfo
.PageAtrb
[col
] = Text_AtrTable
[ATR_WB
];
1580 for (int row
= 0; row
< DRCSROWS
; row
++)
1582 for (int col
= 0; col
< DRCSCOLS
; col
++)
1584 RenderDRCS(m_RenderInfo
.Width
,
1585 m_RenderInfo
.PageChar
+ 20 * (DRCSCOLS
* row
+ col
+ 2),
1587 + (m_RenderInfo
.FontHeight
+ DRCSYSPC
* row
+ m_RenderInfo
.Height
) * m_RenderInfo
.Width
1589 ax
, GetColorRGB(TXT_ColorWhite
), GetColorRGB(TXT_ColorBlack
));
1592 memset(m_RenderInfo
.PageChar
+ 40, 0xff, 24*40); /* don't render any char below row 0 */
1594 m_RenderInfo
.PosY
= startrow
*m_RenderInfo
.FontHeight
;
1595 for (int row
= startrow
; row
< 24; row
++)
1597 int index
= row
* 40;
1599 m_RenderInfo
.PosX
= 0;
1600 for (int col
= m_RenderInfo
.nofirst
; col
< 40; col
++)
1602 RenderCharBB(m_RenderInfo
.PageChar
[index
+ col
], &m_RenderInfo
.PageAtrb
[index
+ col
]);
1604 if (m_RenderInfo
.PageAtrb
[index
+ col
].doubleh
&& m_RenderInfo
.PageChar
[index
+ col
] != 0xff && row
< 24-1) /* disable lower char in case of doubleh setting in l25 objects */
1605 m_RenderInfo
.PageChar
[index
+ col
+ 40] = 0xff;
1606 if (m_RenderInfo
.PageAtrb
[index
+ col
].doublew
&& col
< 40-1) /* skip next column if double width */
1609 if (m_RenderInfo
.PageAtrb
[index
+ col
- 1].doubleh
&& m_RenderInfo
.PageChar
[index
+ col
] != 0xff && row
< 24-1) /* disable lower char in case of doubleh setting in l25 objects */
1610 m_RenderInfo
.PageChar
[index
+ col
+ 40] = 0xff;
1613 m_RenderInfo
.PosY
+= m_RenderInfo
.FontHeight
;
1615 DoFlashing(startrow
);
1617 /* update framebuffer */
1619 m_txtCache
->NationalSubset
= national_subset_bak
;
1622 void CTeletextDecoder::Decode_BTT()
1624 /* basic top table */
1625 int current
, b1
, b2
, b3
, b4
;
1626 unsigned char btt
[23*40];
1628 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
1630 if (m_txtCache
->SubPageTable
[0x1f0] == 0xff || 0 == m_txtCache
->astCachetable
[0x1f0][m_txtCache
->SubPageTable
[0x1f0]]) /* not yet received */
1633 auto& components
= CServiceBroker::GetAppComponents();
1634 const auto appPlayer
= components
.GetComponent
<CApplicationPlayer
>();
1636 appPlayer
->LoadPage(0x1f0, m_txtCache
->SubPageTable
[0x1f0], btt
);
1637 if (btt
[799] == ' ') /* not completely received or error */
1641 for (int i
= 0; i
< 800; i
++)
1649 if (b1
== 0xFF) /* hamming error in btt */
1651 btt
[799] = ' '; /* mark btt as not received */
1655 m_txtCache
->BasicTop
[current
] = b1
;
1656 CDVDTeletextTools::NextDec(¤t
);
1658 /* page linking table */
1659 m_txtCache
->ADIP_PgMax
= -1; /* rebuild table of adip pages */
1660 for (int i
= 0; i
< 10; i
++)
1662 b1
= dehamming
[btt
[800 + 8*i
+0]];
1665 continue; /* unused */
1669 b4
= dehamming
[btt
[800 + 8*i
+7]];
1671 if (b4
!= 2) /* only adip, ignore multipage (1) */
1674 b2
= dehamming
[btt
[800 + 8*i
+1]];
1675 b3
= dehamming
[btt
[800 + 8*i
+2]];
1677 if (b1
== 0xFF || b2
== 0xFF || b3
== 0xFF)
1679 CLog::Log(LOGERROR
, "CTeletextDecoder::Decode_BTT <Biterror in btt/plt index {}>", i
);
1680 btt
[799] = ' '; /* mark btt as not received */
1684 b1
= b1
<<8 | b2
<<4 | b3
; /* page number */
1685 m_txtCache
->ADIP_Pg
[++m_txtCache
->ADIP_PgMax
] = b1
;
1688 m_txtCache
->BTTok
= true;
1691 void CTeletextDecoder::Decode_ADIP() /* additional information table */
1693 int i
, p
, j
, b1
, b2
, b3
, charfound
;
1694 unsigned char padip
[23*40];
1696 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
1698 auto& components
= CServiceBroker::GetAppComponents();
1699 const auto appPlayer
= components
.GetComponent
<CApplicationPlayer
>();
1701 for (i
= 0; i
<= m_txtCache
->ADIP_PgMax
; i
++)
1703 p
= m_txtCache
->ADIP_Pg
[i
];
1704 if (!p
|| m_txtCache
->SubPageTable
[p
] == 0xff || 0 == m_txtCache
->astCachetable
[p
][m_txtCache
->SubPageTable
[p
]]) /* not cached (avoid segfault) */
1707 appPlayer
->LoadPage(p
, m_txtCache
->SubPageTable
[p
], padip
);
1708 for (j
= 0; j
< 44; j
++)
1710 b1
= dehamming
[padip
[20*j
+0]];
1712 continue; /* unused */
1717 b2
= dehamming
[padip
[20*j
+1]];
1718 b3
= dehamming
[padip
[20*j
+2]];
1720 if (b1
== 0xFF || b2
== 0xFF || b3
== 0xFF)
1723 "CTeletextDecoder::Decode_BTT <Biterror in ait {:03x} {} {:02x} {:02x} {:02x} "
1724 "{:02x} {:02x} {:02x}>",
1725 p
, j
, padip
[20 * j
+ 0], padip
[20 * j
+ 1], padip
[20 * j
+ 2], b1
, b2
, b3
);
1729 if (b1
>8 || b2
>9 || b3
>9) /* ignore entries with invalid or hex page numbers */
1734 b1
= b1
<<8 | b2
<<4 | b3
; /* page number */
1735 charfound
= 0; /* flag: no printable char found */
1737 for (b2
= 11; b2
>= 0; b2
--)
1739 b3
= deparity
[padip
[20*j
+ 8 + b2
]];
1743 if (b3
== ' ' && !charfound
)
1744 m_txtCache
->ADIPTable
[b1
][b2
] = '\0';
1747 m_txtCache
->ADIPTable
[b1
][b2
] = b3
;
1753 m_txtCache
->ADIP_Pg
[i
] = 0; /* completely decoded: clear entry */
1754 } /* next adip page i */
1756 while ((m_txtCache
->ADIP_PgMax
>= 0) && !m_txtCache
->ADIP_Pg
[m_txtCache
->ADIP_PgMax
]) /* and shrink table */
1757 m_txtCache
->ADIP_PgMax
--;
1760 int CTeletextDecoder::TopText_GetNext(int startpage
, int up
, int findgroup
)
1762 int current
, nextgrp
, nextblk
;
1764 int stoppage
= (IsDec(startpage
) ? startpage
: startpage
& 0xF00); // avoid endless loop in hexmode
1765 nextgrp
= nextblk
= 0;
1766 current
= startpage
;
1768 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
1772 CDVDTeletextTools::NextDec(¤t
);
1774 CDVDTeletextTools::PrevDec(¤t
);
1776 if (!m_txtCache
->BTTok
|| m_txtCache
->BasicTop
[current
]) /* only if existent */
1780 if (m_txtCache
->BasicTop
[current
] >= 6 && m_txtCache
->BasicTop
[current
] <= 7)
1782 if (!nextgrp
&& (current
&0x00F) == 0)
1785 if (m_txtCache
->BasicTop
[current
] >= 2 && m_txtCache
->BasicTop
[current
] <= 5) /* always find block */
1788 if (!nextblk
&& (current
&0x0FF) == 0)
1791 } while (current
!= stoppage
);
1801 void CTeletextDecoder::Showlink(int column
, int linkpage
)
1803 unsigned char line
[] = " >??? ";
1804 int oldfontwidth
= m_RenderInfo
.FontWidth
;
1810 yoffset
= m_RenderInfo
.Height
;
1812 int abx
= ((m_RenderInfo
.Width
)%(40-m_RenderInfo
.nofirst
) == 0 ? m_RenderInfo
.Width
+1 : (m_RenderInfo
.Width
)/(((m_RenderInfo
.Width
)%(40-m_RenderInfo
.nofirst
)))+1);// distance between 'inserted' pixels
1813 int width
= m_RenderInfo
.Width
/4;
1815 m_RenderInfo
.PosY
= 24*m_RenderInfo
.FontHeight
;
1817 if (m_RenderInfo
.Boxed
)
1819 m_RenderInfo
.PosX
= column
*width
;
1820 FillRect(m_TextureBuffer
, m_RenderInfo
.Width
, m_RenderInfo
.PosX
, m_RenderInfo
.PosY
+yoffset
, m_RenderInfo
.Width
, m_RenderInfo
.FontHeight
, GetColorRGB(TXT_ColorTransp
));
1824 if (m_txtCache
->ADIPTable
[linkpage
][0])
1826 m_RenderInfo
.PosX
= column
*width
;
1827 int l
= strlen(m_txtCache
->ADIPTable
[linkpage
]);
1829 if (l
> 9) /* smaller font, if no space for one half space at front and end */
1830 SetFontWidth(oldfontwidth
* 10 / (l
+1));
1832 FillRect(m_TextureBuffer
, m_RenderInfo
.Width
, m_RenderInfo
.PosX
, m_RenderInfo
.PosY
+yoffset
, width
+(m_RenderInfo
.Width
%4), m_RenderInfo
.FontHeight
, GetColorRGB((enumTeletextColor
)Text_AtrTable
[ATR_L250
+ column
].bg
));
1833 m_RenderInfo
.PosX
+= ((width
) - (l
*m_RenderInfo
.FontWidth
+l
*m_RenderInfo
.FontWidth
/abx
))/2; /* center */
1835 for (char *p
= m_txtCache
->ADIPTable
[linkpage
]; *p
; p
++)
1836 RenderCharBB(*p
, &Text_AtrTable
[ATR_L250
+ column
]);
1838 SetFontWidth(oldfontwidth
);
1840 else /* display number */
1842 m_RenderInfo
.PosX
= column
*width
;
1843 FillRect(m_TextureBuffer
, m_RenderInfo
.Width
, m_RenderInfo
.PosX
, m_RenderInfo
.PosY
+yoffset
, m_RenderInfo
.Width
-m_RenderInfo
.PosX
, m_RenderInfo
.FontHeight
, GetColorRGB((enumTeletextColor
)Text_AtrTable
[ATR_L250
+ column
].bg
));
1844 if (linkpage
< m_txtCache
->Page
)
1847 CDVDTeletextTools::Hex2Str((char*)line
+ 5, linkpage
);
1850 CDVDTeletextTools::Hex2Str((char*)line
+ 6, linkpage
);
1852 for (unsigned char *p
= line
; p
< line
+9; p
++)
1853 RenderCharBB(*p
, &Text_AtrTable
[ATR_L250
+ column
]);
1857 void CTeletextDecoder::CreateLine25()
1859 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
1861 /* btt completely received and not yet decoded */
1862 if (!m_txtCache
->BTTok
)
1865 if (m_txtCache
->ADIP_PgMax
>= 0)
1868 if (!m_RenderInfo
.ShowHex
&& m_RenderInfo
.ShowFlof
&&
1869 (m_txtCache
->FlofPages
[m_txtCache
->Page
][0] || m_txtCache
->FlofPages
[m_txtCache
->Page
][1] || m_txtCache
->FlofPages
[m_txtCache
->Page
][2] || m_txtCache
->FlofPages
[m_txtCache
->Page
][3])) // FLOF-Navigation present
1871 m_RenderInfo
.Prev_100
= m_txtCache
->FlofPages
[m_txtCache
->Page
][0];
1872 m_RenderInfo
.Prev_10
= m_txtCache
->FlofPages
[m_txtCache
->Page
][1];
1873 m_RenderInfo
.Next_10
= m_txtCache
->FlofPages
[m_txtCache
->Page
][2];
1874 m_RenderInfo
.Next_100
= m_txtCache
->FlofPages
[m_txtCache
->Page
][3];
1876 m_RenderInfo
.PosY
= 24*m_RenderInfo
.FontHeight
;
1877 m_RenderInfo
.PosX
= 0;
1878 for (int i
=m_RenderInfo
.nofirst
; i
<40; i
++)
1879 RenderCharBB(m_RenderInfo
.PageChar
[24*40 + i
], &m_RenderInfo
.PageAtrb
[24*40 + i
]);
1883 /* normal: blk-1, grp+1, grp+2, blk+1 */
1884 /* hex: hex+1, blk-1, grp+1, blk+1 */
1885 if (m_RenderInfo
.ShowHex
)
1887 /* arguments: startpage, up, findgroup */
1888 m_RenderInfo
.Prev_100
= NextHex(m_txtCache
->Page
);
1889 m_RenderInfo
.Prev_10
= TopText_GetNext(m_txtCache
->Page
, 0, 0);
1890 m_RenderInfo
.Next_10
= TopText_GetNext(m_txtCache
->Page
, 1, 1);
1894 m_RenderInfo
.Prev_100
= TopText_GetNext(m_txtCache
->Page
, 0, 0);
1895 m_RenderInfo
.Prev_10
= TopText_GetNext(m_txtCache
->Page
, 1, 1);
1896 m_RenderInfo
.Next_10
= TopText_GetNext(m_RenderInfo
.Prev_10
, 1, 1);
1898 m_RenderInfo
.Next_100
= TopText_GetNext(m_RenderInfo
.Next_10
, 1, 0);
1899 Showlink(0, m_RenderInfo
.Prev_100
);
1900 Showlink(1, m_RenderInfo
.Prev_10
);
1901 Showlink(2, m_RenderInfo
.Next_10
);
1902 Showlink(3, m_RenderInfo
.Next_100
);
1906 void CTeletextDecoder::RenderCharFB(int Char
, TextPageAttr_t
*Attribute
)
1908 RenderCharIntern(&m_RenderInfo
, Char
, Attribute
, m_RenderInfo
.ZoomMode
, m_YOffset
);
1911 void CTeletextDecoder::RenderCharBB(int Char
, TextPageAttr_t
*Attribute
)
1913 RenderCharIntern(&m_RenderInfo
, Char
, Attribute
, 0, m_RenderInfo
.Height
-m_YOffset
);
1916 void CTeletextDecoder::CopyBB2FB()
1918 Color
*src
, *dst
, *topsrc
;
1922 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
1925 if (!m_RenderInfo
.PageCatching
)
1928 /* copy backbuffer to framebuffer */
1929 if (!m_RenderInfo
.ZoomMode
)
1934 m_YOffset
= m_RenderInfo
.Height
;
1936 if (m_RenderInfo
.ClearBBColor
>= 0)
1938 m_RenderInfo
.ClearBBColor
= -1;
1943 src
= dst
= topsrc
= m_TextureBuffer
+ m_RenderInfo
.Width
;
1947 dst
+= m_RenderInfo
.Width
* m_RenderInfo
.Height
;
1951 src
+= m_RenderInfo
.Width
* m_RenderInfo
.Height
;
1952 topsrc
+= m_RenderInfo
.Width
* m_RenderInfo
.Height
;
1955 if (!m_RenderInfo
.PageCatching
)
1956 SDL_memcpy4(dst
+(24*m_RenderInfo
.FontHeight
)*m_RenderInfo
.Width
, src
+ (24*m_RenderInfo
.FontHeight
)*m_RenderInfo
.Width
, m_RenderInfo
.Width
*m_RenderInfo
.FontHeight
); /* copy line25 in normal height */
1958 if (m_RenderInfo
.TranspMode
)
1959 fillcolor
= GetColorRGB(TXT_ColorTransp
);
1961 fillcolor
= GetColorRGB((enumTeletextColor
)m_txtCache
->FullScrColor
);
1963 if (m_RenderInfo
.ZoomMode
== 2)
1964 src
+= 12*m_RenderInfo
.FontHeight
*m_RenderInfo
.Width
;
1966 screenwidth
= m_RenderInfo
.Width
;
1968 for (int i
= 12*m_RenderInfo
.FontHeight
; i
; i
--)
1970 SDL_memcpy4(dst
, src
, screenwidth
);
1971 dst
+= m_RenderInfo
.Width
;
1972 SDL_memcpy4(dst
, src
, screenwidth
);
1973 dst
+= m_RenderInfo
.Width
;
1974 src
+= m_RenderInfo
.Width
;
1977 for (int i
= m_RenderInfo
.Height
- 25*m_RenderInfo
.FontHeight
; i
>= 0;i
--)
1979 SDL_memset4(dst
+ m_RenderInfo
.Width
*(m_RenderInfo
.FontHeight
+i
), fillcolor
, screenwidth
);
1983 FT_Error
CTeletextDecoder::MyFaceRequester(FTC_FaceID face_id
, FT_Library library
, FT_Pointer request_data
, FT_Face
*aface
)
1985 FT_Error result
= FT_New_Face(library
, (const char*)face_id
, 0, aface
);
1988 CLog::Log(LOGINFO
, "Teletext font {} loaded", (char*)face_id
);
1990 CLog::Log(LOGERROR
, "Opening of Teletext font {} failed", (char*)face_id
);
1995 void CTeletextDecoder::SetFontWidth(int newWidth
)
1997 if (m_RenderInfo
.FontWidth
!= newWidth
)
1999 m_RenderInfo
.FontWidth
= newWidth
;
2000 m_TypeTTF
.width
= (FT_UShort
) m_RenderInfo
.FontWidth
;
2002 for (int i
= 0; i
<= 12; i
++)
2003 m_RenderInfo
.axdrcs
[i
] = (m_RenderInfo
.FontWidth
* i
+ 6) / 12;
2007 int CTeletextDecoder::GetCurFontWidth()
2009 int mx
= (m_RenderInfo
.Width
)%(40-m_RenderInfo
.nofirst
); // # of unused pixels
2010 int abx
= (mx
== 0 ? m_RenderInfo
.Width
+1 : (m_RenderInfo
.Width
)/(mx
+1)); // distance between 'inserted' pixels
2011 int nx
= abx
+1-(m_RenderInfo
.PosX
% (abx
+1)); // # of pixels to next insert
2012 return m_RenderInfo
.FontWidth
+(((m_RenderInfo
.PosX
+m_RenderInfo
.FontWidth
+1) <= m_RenderInfo
.Width
&& nx
<= m_RenderInfo
.FontWidth
+1) ? 1 : 0);
2015 void CTeletextDecoder::SetPosX(int column
)
2017 m_RenderInfo
.PosX
= 0;
2019 for (int i
= 0; i
< column
-m_RenderInfo
.nofirst
; i
++)
2020 m_RenderInfo
.PosX
+= GetCurFontWidth();
2023 void CTeletextDecoder::ClearBB(Color Color
)
2025 SDL_memset4(m_TextureBuffer
+ (m_RenderInfo
.Height
-m_YOffset
)*m_RenderInfo
.Width
, Color
, m_RenderInfo
.Width
*m_RenderInfo
.Height
);
2028 void CTeletextDecoder::ClearFB(Color Color
)
2030 SDL_memset4(m_TextureBuffer
+ m_RenderInfo
.Width
*m_YOffset
, Color
, m_RenderInfo
.Width
*m_RenderInfo
.Height
);
2033 void CTeletextDecoder::FillBorder(Color Color
)
2035 FillRect(m_TextureBuffer
+ (m_RenderInfo
.Height
-m_YOffset
)*m_RenderInfo
.Width
, m_RenderInfo
.Width
, 0, 25*m_RenderInfo
.FontHeight
, m_RenderInfo
.Width
, m_RenderInfo
.Height
-(25*m_RenderInfo
.FontHeight
), Color
);
2036 FillRect(m_TextureBuffer
+ m_RenderInfo
.Width
*m_YOffset
, m_RenderInfo
.Width
, 0, 25*m_RenderInfo
.FontHeight
, m_RenderInfo
.Width
, m_RenderInfo
.Height
-(25*m_RenderInfo
.FontHeight
), Color
);
2039 void CTeletextDecoder::FillRect(Color
* buffer
, int xres
, int x
, int y
, int w
, int h
, Color color
)
2041 if (!buffer
) return;
2043 Color
* p
= buffer
+ x
+ y
* xres
;
2047 for ( ; h
> 0 ; h
--)
2049 SDL_memset4(p
, color
, w
);
2055 void CTeletextDecoder::DrawVLine(Color
* lfb
, int xres
, int x
, int y
, int l
, Color color
)
2058 Color
* p
= lfb
+ x
+ y
* xres
;
2060 for ( ; l
> 0 ; l
--)
2067 void CTeletextDecoder::DrawHLine(Color
* lfb
, int xres
, int x
, int y
, int l
, Color color
)
2071 SDL_memset4(lfb
+ x
+ y
* xres
, color
, l
);
2074 void CTeletextDecoder::RenderDRCS(
2076 unsigned char* s
, /* pointer to char data, parity undecoded */
2077 Color
* d
, /* pointer to frame buffer of top left pixel */
2078 unsigned char* ax
, /* array[0..12] of x-offsets, array[0..10] of y-offsets for each pixel */
2082 if (d
== NULL
) return;
2084 unsigned char *ay
= ax
+ 13; /* array[0..10] of y-offsets for each pixel */
2086 for (int y
= 0; y
< 10; y
++) /* 10*2 bytes a 6 pixels per char definition */
2088 unsigned char c1
= deparity
[*s
++];
2089 unsigned char c2
= deparity
[*s
++];
2090 int h
= ay
[y
+1] - ay
[y
];
2094 if (((c1
== ' ') && (*(s
-2) != ' ')) || ((c2
== ' ') && (*(s
-1) != ' '))) /* parity error: stop decoding FIXME */
2096 for (int bit
= 0x20, x
= 0;
2098 bit
>>= 1, x
++) /* bit mask (MSB left), column counter */
2100 Color f1
= (c1
& bit
) ? fgcolor
: bgcolor
;
2101 Color f2
= (c2
& bit
) ? fgcolor
: bgcolor
;
2102 for (int i
= 0; i
< h
; i
++)
2104 if (ax
[x
+1] > ax
[x
])
2105 SDL_memset4(d
+ ax
[x
], f1
, ax
[x
+1] - ax
[x
]);
2106 if (ax
[x
+7] > ax
[x
+6])
2107 SDL_memset4(d
+ ax
[x
+6], f2
, ax
[x
+7] - ax
[x
+6]); /* 2nd byte 6 pixels to the right */
2116 void CTeletextDecoder::FillRectMosaicSeparated(
2117 Color
* lfb
, int xres
, int x
, int y
, int w
, int h
, Color fgcolor
, Color bgcolor
, int set
)
2120 FillRect(lfb
,xres
,x
, y
, w
, h
, bgcolor
);
2123 FillRect(lfb
,xres
,x
+1, y
+1, w
-2, h
-2, fgcolor
);
2127 void CTeletextDecoder::FillTrapez(
2128 Color
* lfb
, int xres
, int x0
, int y0
, int l0
, int xoffset1
, int h
, int l1
, Color color
)
2130 Color
* p
= lfb
+ x0
+ y0
* xres
;
2133 for (int yoffset
= 0; yoffset
< h
; yoffset
++)
2135 l
= l0
+ ((l1
-l0
) * yoffset
+ h
/2) / h
;
2136 xoffset
= (xoffset1
* yoffset
+ h
/2) / h
;
2138 SDL_memset4(p
+ xoffset
, color
, l
);
2143 void CTeletextDecoder::FlipHorz(Color
* lfb
, int xres
, int x
, int y
, int w
, int h
)
2146 Color
* p
= lfb
+ x
+ y
* xres
;
2149 for (h1
= 0 ; h1
< h
; h1
++)
2151 SDL_memcpy4(buf
,p
,w
);
2152 for (w1
= 0 ; w1
< w
; w1
++)
2154 *(p
+w1
) = buf
[w
-(w1
+1)];
2160 void CTeletextDecoder::FlipVert(Color
* lfb
, int xres
, int x
, int y
, int w
, int h
)
2163 Color
*p
= lfb
+ x
+ y
* xres
, *p1
, *p2
;
2166 for (h1
= 0 ; h1
< h
/2 ; h1
++)
2169 p2
= (p
+(h
-(h1
+1))*xres
);
2170 SDL_memcpy4(buf
, p1
, w
);
2171 SDL_memcpy4(p1
, p2
, w
);
2172 SDL_memcpy4(p2
, buf
, w
);
2176 int CTeletextDecoder::ShapeCoord(int param
, int curfontwidth
, int curFontHeight
)
2181 return curfontwidth
/3;
2183 return curfontwidth
/2;
2185 return curfontwidth
*2/3;
2187 return curfontwidth
;
2189 return curfontwidth
-3;
2191 return curFontHeight
/3;
2193 return curFontHeight
/2;
2195 return curFontHeight
*2/3;
2197 return curFontHeight
;
2203 void CTeletextDecoder::DrawShape(Color
* lfb
,
2215 if (!lfb
|| shapenumber
< 0x20 || shapenumber
> 0x7e || (shapenumber
== 0x7e && clear
))
2218 unsigned char *p
= aShapes
[shapenumber
- 0x20];
2229 FillRect(lfb
, xres
, x
, y
, curfontwidth
, FontHeight
, bgcolor
);
2237 int offset
= ShapeCoord(*p
++, curfontwidth
, curFontHeight
);
2238 DrawHLine(lfb
, xres
, x
, y
+ offset
, curfontwidth
, fgcolor
);
2243 int offset
= ShapeCoord(*p
++, curfontwidth
, curFontHeight
);
2244 DrawVLine(lfb
,xres
,x
+ offset
, y
, FontHeight
, fgcolor
);
2248 FlipHorz(lfb
,xres
,x
,y
,curfontwidth
, FontHeight
);
2251 FlipVert(lfb
,xres
,x
,y
,curfontwidth
, FontHeight
);
2255 int xo
= ShapeCoord(*p
++, curfontwidth
, curFontHeight
);
2256 int yo
= ShapeCoord(*p
++, curfontwidth
, curFontHeight
);
2257 int w
= ShapeCoord(*p
++, curfontwidth
, curFontHeight
);
2258 int h
= ShapeCoord(*p
++, curfontwidth
, curFontHeight
);
2259 FillRect(lfb
,xres
,x
+ xo
, y
+ yo
, w
, h
, fgcolor
);
2264 int x0
= ShapeCoord(*p
++, curfontwidth
, curFontHeight
);
2265 int y0
= ShapeCoord(*p
++, curfontwidth
, curFontHeight
);
2266 int l0
= ShapeCoord(*p
++, curfontwidth
, curFontHeight
);
2267 int x1
= ShapeCoord(*p
++, curfontwidth
, curFontHeight
);
2268 int y1
= ShapeCoord(*p
++, curfontwidth
, curFontHeight
);
2269 int l1
= ShapeCoord(*p
++, curfontwidth
, curFontHeight
);
2270 FillTrapez(lfb
, xres
,x
+ x0
, y
+ y0
, l0
, x1
-x0
, y1
-y0
, l1
, fgcolor
);
2275 int x0
= ShapeCoord(*p
++, curfontwidth
, curFontHeight
);
2276 int y0
= ShapeCoord(*p
++, curfontwidth
, curFontHeight
);
2277 int l0
= ShapeCoord(*p
++, curfontwidth
, curFontHeight
);
2278 int x1
= ShapeCoord(*p
++, curfontwidth
, curFontHeight
);
2279 int y1
= ShapeCoord(*p
++, curfontwidth
, curFontHeight
);
2280 int l1
= ShapeCoord(*p
++, curfontwidth
, curFontHeight
);
2281 FillTrapez(lfb
, xres
, x
+ x0
, y
+ y0
, l0
, x1
-x0
, y1
-y0
, l1
, bgcolor
);
2286 DrawShape(lfb
,xres
,x
, y
, ShapeCoord(*p
, curfontwidth
, curFontHeight
), curfontwidth
, FontHeight
, curFontHeight
, fgcolor
, bgcolor
, false);
2295 void CTeletextDecoder::RenderCharIntern(TextRenderInfo_t
* RenderInfo
, int Char
, TextPageAttr_t
*Attribute
, int zoom
, int yoffset
)
2299 Color bgcolor
, fgcolor
;
2300 int factor
, xfactor
;
2301 unsigned char *sbitbuffer
;
2303 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
2305 int national_subset_local
= m_txtCache
->NationalSubset
;
2306 int curfontwidth
= GetCurFontWidth();
2307 int t
= curfontwidth
;
2308 m_RenderInfo
.PosX
+= t
;
2309 int curfontwidth2
= GetCurFontWidth();
2310 m_RenderInfo
.PosX
-= t
;
2311 int alphachar
= RenderChar(m_TextureBuffer
+(yoffset
)*m_RenderInfo
.Width
, m_RenderInfo
.Width
, Char
, &m_RenderInfo
.PosX
, m_RenderInfo
.PosY
, Attribute
, zoom
> 0, curfontwidth
, curfontwidth2
, m_RenderInfo
.FontHeight
, m_RenderInfo
.TranspMode
, m_RenderInfo
.axdrcs
, m_Ascender
);
2312 if (alphachar
<= 0) return;
2314 if (zoom
&& Attribute
->doubleh
)
2316 else if (zoom
|| Attribute
->doubleh
)
2321 fgcolor
= GetColorRGB((enumTeletextColor
)Attribute
->fg
);
2322 if (m_RenderInfo
.TranspMode
&& m_RenderInfo
.PosY
< 24*m_RenderInfo
.FontHeight
)
2324 bgcolor
= GetColorRGB(TXT_ColorTransp
);
2328 bgcolor
= GetColorRGB((enumTeletextColor
)Attribute
->bg
);
2331 if (Attribute
->doublew
)
2333 curfontwidth
+= curfontwidth2
;
2339 // Check if the alphanumeric char has diacritical marks (or results from composing chars) or
2340 // on the other hand it is just a simple alphanumeric char
2341 if (!Attribute
->diacrit
)
2347 if ((national_subset_local
== NAT_SC
) || (national_subset_local
== NAT_RB
) ||
2348 (national_subset_local
== NAT_UA
))
2349 Char
= G2table
[1][0x20 + Attribute
->diacrit
];
2350 else if (national_subset_local
== NAT_GR
)
2351 Char
= G2table
[2][0x20 + Attribute
->diacrit
];
2352 else if (national_subset_local
== NAT_HB
)
2353 Char
= G2table
[3][0x20 + Attribute
->diacrit
];
2354 else if (national_subset_local
== NAT_AR
)
2355 Char
= G2table
[4][0x20 + Attribute
->diacrit
];
2357 Char
= G2table
[0][0x20 + Attribute
->diacrit
];
2359 // use harfbuzz to combine the diacritical mark with the alphanumeric char
2360 // fallback to the alphanumeric char if composition fails
2361 hb_unicode_funcs_t
* ufuncs
= hb_unicode_funcs_get_default();
2362 hb_codepoint_t composedChar
;
2363 const hb_bool_t isComposed
= hb_unicode_compose(ufuncs
, alphachar
, Char
, &composedChar
);
2364 Char
= isComposed
? composedChar
: alphachar
;
2368 if (!(glyph
= FT_Get_Char_Index(m_Face
, Char
)))
2370 CLog::Log(LOGERROR
, "{}: <FT_Get_Char_Index for Char {:x} \"{}\" failed", __FUNCTION__
,
2371 alphachar
, alphachar
);
2373 FillRect(m_TextureBuffer
, m_RenderInfo
.Width
, m_RenderInfo
.PosX
, m_RenderInfo
.PosY
+ yoffset
, curfontwidth
, factor
*m_RenderInfo
.FontHeight
, bgcolor
);
2374 m_RenderInfo
.PosX
+= curfontwidth
;
2378 if (FTC_SBitCache_Lookup(m_Cache
, &m_TypeTTF
, glyph
, &m_sBit
, &m_anode
) != 0)
2380 FillRect(m_TextureBuffer
, m_RenderInfo
.Width
, m_RenderInfo
.PosX
, m_RenderInfo
.PosY
+ yoffset
, curfontwidth
, m_RenderInfo
.FontHeight
, bgcolor
);
2381 m_RenderInfo
.PosX
+= curfontwidth
;
2385 sbitbuffer
= m_sBit
->buffer
;
2387 int backupTTFshiftY
= m_RenderInfo
.TTFShiftY
;
2388 if (national_subset_local
== NAT_AR
)
2389 m_RenderInfo
.TTFShiftY
= backupTTFshiftY
- 2; // for arabic TTF font should be shifted up slightly
2392 int f
; /* running counter for zoom factor */
2393 int he
= m_sBit
->height
; // sbit->height should not be altered, I guess
2394 Row
= factor
* (m_Ascender
- m_sBit
->top
+ m_RenderInfo
.TTFShiftY
);
2397 sbitbuffer
-= m_sBit
->pitch
*Row
;
2403 FillRect(m_TextureBuffer
, m_RenderInfo
.Width
, m_RenderInfo
.PosX
, m_RenderInfo
.PosY
+ yoffset
, curfontwidth
, Row
, bgcolor
); /* fill upper margin */
2406 if (m_Ascender
- m_sBit
->top
+ m_RenderInfo
.TTFShiftY
+ he
> m_RenderInfo
.FontHeight
)
2407 he
= m_RenderInfo
.FontHeight
- m_Ascender
+ m_sBit
->top
- m_RenderInfo
.TTFShiftY
; /* limit char height to defined/calculated FontHeight */
2408 if (he
< 0) he
= m_RenderInfo
.FontHeight
;
2410 p
= m_TextureBuffer
+ m_RenderInfo
.PosX
+ (yoffset
+ m_RenderInfo
.PosY
+ Row
) * m_RenderInfo
.Width
; /* running pointer into framebuffer */
2411 for (Row
= he
; Row
; Row
--) /* row counts up, but down may be a little faster :) */
2413 int pixtodo
= m_sBit
->width
;
2416 for (int Bit
= xfactor
* (m_sBit
->left
+ m_RenderInfo
.TTFShiftX
); Bit
> 0; Bit
--) /* fill left margin */
2418 for (f
= factor
-1; f
>= 0; f
--)
2419 *(p
+ f
*m_RenderInfo
.Width
) = bgcolor
;
2423 for (Pitch
= m_sBit
->pitch
; Pitch
; Pitch
--)
2425 for (int Bit
= 0x80; Bit
; Bit
>>= 1)
2432 if (*sbitbuffer
& Bit
) /* bit set -> foreground */
2434 else /* bit not set -> background */
2437 for (f
= factor
-1; f
>= 0; f
--)
2438 *(p
+ f
*m_RenderInfo
.Width
) = color
;
2441 if (xfactor
> 1) /* double width */
2443 for (f
= factor
-1; f
>= 0; f
--)
2444 *(p
+ f
*m_RenderInfo
.Width
) = color
;
2450 for (int Bit
= (curfontwidth
- xfactor
*(m_sBit
->width
+ m_sBit
->left
+ m_RenderInfo
.TTFShiftX
));
2451 Bit
> 0; Bit
--) /* fill rest of char width */
2453 for (f
= factor
-1; f
>= 0; f
--)
2454 *(p
+ f
*m_RenderInfo
.Width
) = bgcolor
;
2458 p
= pstart
+ factor
*m_RenderInfo
.Width
;
2461 Row
= m_Ascender
- m_sBit
->top
+ he
+ m_RenderInfo
.TTFShiftY
;
2462 FillRect(m_TextureBuffer
,
2465 m_RenderInfo
.PosY
+ yoffset
+ Row
* factor
,
2467 (m_RenderInfo
.FontHeight
- Row
) * factor
,
2468 bgcolor
); /* fill lower margin */
2470 if (Attribute
->underline
)
2471 FillRect(m_TextureBuffer
,
2474 m_RenderInfo
.PosY
+ yoffset
+ (m_RenderInfo
.FontHeight
-2)* factor
,
2477 fgcolor
); /* underline char */
2479 m_RenderInfo
.PosX
+= curfontwidth
;
2480 m_RenderInfo
.TTFShiftY
= backupTTFshiftY
; // restore TTFShiftY
2483 int CTeletextDecoder::RenderChar(
2484 Color
* buffer
, // pointer to render buffer, min. FontHeight*2*xres
2485 int xres
, // length of 1 line in render buffer
2486 int Char
, // character to render
2488 pPosX
, // left border for rendering relative to *buffer, will be set to right border after rendering
2489 int PosY
, // vertical position of char in *buffer
2490 TextPageAttr_t
* Attribute
, // Attributes of Char
2491 bool zoom
, // 1= character will be rendered in double height
2492 int curfontwidth
, // rendering width of character
2493 int curfontwidth2
, // rendering width of next character (needed for doublewidth)
2494 int FontHeight
, // height of character
2495 bool transpmode
, // 1= transparent display
2496 unsigned char* axdrcs
, // width and height of DRCS-chars
2497 int Ascender
) // Ascender of font
2499 Color bgcolor
, fgcolor
;
2500 int factor
, xfactor
;
2502 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
2504 int national_subset_local
= m_txtCache
->NationalSubset
;
2506 ymosaic
[0] = 0; /* y-offsets for 2*3 mosaic */
2507 ymosaic
[1] = (FontHeight
+ 1) / 3;
2508 ymosaic
[2] = (FontHeight
* 2 + 1) / 3;
2509 ymosaic
[3] = FontHeight
;
2511 if (Attribute
->setX26
)
2513 national_subset_local
= 0; // no national subset
2516 // G0+G2 set designation
2517 if (Attribute
->setG0G2
!= 0x3f)
2519 switch (Attribute
->setG0G2
)
2522 national_subset_local
= NAT_SC
;
2525 national_subset_local
= NAT_RB
;
2528 national_subset_local
= NAT_UA
;
2531 national_subset_local
= NAT_GR
;
2534 national_subset_local
= NAT_HB
;
2538 national_subset_local
= NAT_AR
;
2541 national_subset_local
= CountryConversionTable
[Attribute
->setG0G2
& 0x07];
2546 if (Attribute
->charset
== C_G0S
) // use secondary charset
2547 national_subset_local
= m_txtCache
->NationalSubsetSecondary
;
2548 if (zoom
&& Attribute
->doubleh
)
2550 else if (zoom
|| Attribute
->doubleh
)
2555 if (Attribute
->doublew
)
2557 curfontwidth
+= curfontwidth2
;
2563 if (Char
== 0xFF) /* skip doubleheight chars in lower line */
2565 *pPosX
+= curfontwidth
;
2570 if (Attribute
->inverted
)
2572 int t
= Attribute
->fg
;
2573 Attribute
->fg
= Attribute
->bg
;
2576 fgcolor
= GetColorRGB((enumTeletextColor
)Attribute
->fg
);
2577 if (transpmode
== true && PosY
< 24*FontHeight
)
2579 bgcolor
= GetColorRGB(TXT_ColorTransp
);
2583 bgcolor
= GetColorRGB((enumTeletextColor
)Attribute
->bg
);
2587 if ((Attribute
->charset
== C_G1C
|| Attribute
->charset
== C_G1S
) &&
2588 ((Char
&0xA0) == 0x20))
2590 int w1
= (curfontwidth
/ 2 ) *xfactor
;
2591 int w2
= (curfontwidth
- w1
) *xfactor
;
2593 Char
= (Char
& 0x1f) | ((Char
& 0x40) >> 1);
2594 if (Attribute
->charset
== C_G1S
) /* separated mosaic */
2596 for (int y
= 0; y
< 3; y
++)
2598 FillRectMosaicSeparated(buffer
, xres
,*pPosX
, PosY
+ ymosaic
[y
]*factor
, w1
, (ymosaic
[y
+1] - ymosaic
[y
])*factor
, fgcolor
, bgcolor
, Char
& 0x01);
2599 FillRectMosaicSeparated(buffer
, xres
,*pPosX
+ w1
, PosY
+ ymosaic
[y
]*factor
, w2
, (ymosaic
[y
+1] - ymosaic
[y
])*factor
, fgcolor
, bgcolor
, Char
& 0x02);
2605 for (int y
= 0; y
< 3; y
++)
2607 FillRect(buffer
, xres
, *pPosX
, PosY
+ ymosaic
[y
]*factor
, w1
, (ymosaic
[y
+1] - ymosaic
[y
])*factor
, (Char
& 0x01) ? fgcolor
: bgcolor
);
2608 FillRect(buffer
, xres
, *pPosX
+ w1
, PosY
+ ymosaic
[y
]*factor
, w2
, (ymosaic
[y
+1] - ymosaic
[y
])*factor
, (Char
& 0x02) ? fgcolor
: bgcolor
);
2613 *pPosX
+= curfontwidth
;
2617 if (Attribute
->charset
== C_G3
)
2619 if (Char
< 0x20 || Char
> 0x7d)
2625 if (*aShapes
[Char
- 0x20] == S_CHR
)
2627 unsigned char *p
= aShapes
[Char
- 0x20];
2628 Char
= (*(p
+1) <<8) + (*(p
+2));
2630 else if (*aShapes
[Char
- 0x20] == S_ADT
)
2635 Color
* p
= buffer
+ *pPosX
+ PosY
* xres
;
2636 for (y
=0; y
<FontHeight
;y
++)
2638 for (f
=0; f
<factor
; f
++)
2640 for (x
=0; x
<curfontwidth
*xfactor
;x
++)
2642 c
= (y
&4 ? (x
/3)&1 :((x
+3)/3)&1);
2643 *(p
+x
) = (c
? fgcolor
: bgcolor
);
2649 *pPosX
+= curfontwidth
;
2654 DrawShape(buffer
, xres
,*pPosX
, PosY
, Char
, curfontwidth
, FontHeight
, factor
*FontHeight
, fgcolor
, bgcolor
, true);
2655 *pPosX
+= curfontwidth
;
2660 else if (Attribute
->charset
>= C_OFFSET_DRCS
)
2662 TextCachedPage_t
*pcache
= m_txtCache
->astCachetable
[(Attribute
->charset
& 0x10) ? m_txtCache
->drcs
: m_txtCache
->gdrcs
][Attribute
->charset
& 0x0f];
2665 unsigned char drcs_data
[23*40];
2666 auto& components
= CServiceBroker::GetAppComponents();
2667 const auto appPlayer
= components
.GetComponent
<CApplicationPlayer
>();
2668 appPlayer
->LoadPage((Attribute
->charset
& 0x10) ? m_txtCache
->drcs
: m_txtCache
->gdrcs
,
2669 Attribute
->charset
& 0x0f, drcs_data
);
2672 p
= drcs_data
+ 20*Char
;
2673 else if (pcache
->pageinfo
.p24
)
2674 p
= pcache
->pageinfo
.p24
+ 20*(Char
- 23*2);
2677 FillRect(buffer
, xres
,*pPosX
, PosY
, curfontwidth
, factor
*FontHeight
, bgcolor
);
2678 *pPosX
+= curfontwidth
;
2681 axdrcs
[12] = curfontwidth
; /* adjust last x-offset according to position, FIXME: double width */
2682 RenderDRCS(xres
, p
, buffer
+ *pPosX
+ PosY
* xres
, axdrcs
, fgcolor
, bgcolor
);
2686 FillRect(buffer
,xres
,*pPosX
, PosY
, curfontwidth
, factor
*FontHeight
, bgcolor
);
2688 *pPosX
+= curfontwidth
;
2691 else if (Attribute
->charset
== C_G2
&& Char
>= 0x20 && Char
<= 0x7F)
2693 if ((national_subset_local
== NAT_SC
) || (national_subset_local
== NAT_RB
) || (national_subset_local
== NAT_UA
))
2694 Char
= G2table
[1][Char
-0x20];
2695 else if (national_subset_local
== NAT_GR
)
2696 Char
= G2table
[2][Char
-0x20];
2697 else if (national_subset_local
== NAT_AR
)
2698 Char
= G2table
[3][Char
-0x20];
2700 Char
= G2table
[0][Char
-0x20];
2704 // FillRect(buffer,xres,*pPosX, PosY, curfontwidth, factor*Ascender, fgcolor);
2705 // FillRect(buffer,xres,*pPosX, PosY + factor*Ascender, curfontwidth, factor*(FontHeight-Ascender), bgcolor);
2706 // *pPosX += curfontwidth;
2710 else if (national_subset_local
== NAT_SC
&& Char
>= 0x20 && Char
<= 0x7F) /* remap complete areas for serbian/croatian */
2711 Char
= G0table
[0][Char
-0x20];
2712 else if (national_subset_local
== NAT_RB
&& Char
>= 0x20 && Char
<= 0x7F) /* remap complete areas for russian/bulgarian */
2713 Char
= G0table
[1][Char
-0x20];
2714 else if (national_subset_local
== NAT_UA
&& Char
>= 0x20 && Char
<= 0x7F) /* remap complete areas for ukrainian */
2715 Char
= G0table
[2][Char
-0x20];
2716 else if (national_subset_local
== NAT_GR
&& Char
>= 0x20 && Char
<= 0x7F) /* remap complete areas for greek */
2717 Char
= G0table
[3][Char
-0x20];
2718 else if (national_subset_local
== NAT_HB
&& Char
>= 0x20 && Char
<= 0x7F) /* remap complete areas for hebrew */
2719 Char
= G0table
[4][Char
-0x20];
2720 else if (national_subset_local
== NAT_AR
&& Char
>= 0x20 && Char
<= 0x7F) /* remap complete areas for arabic */
2721 Char
= G0table
[5][Char
-0x20];
2729 FillRect(buffer
, xres
, *pPosX
, PosY
, curfontwidth
, factor
*FontHeight
, bgcolor
);
2730 *pPosX
+= curfontwidth
;
2734 Char
= nationaltable23
[national_subset_local
][Char
-0x23];
2737 Char
= nationaltable40
[national_subset_local
];
2745 Char
= nationaltable5b
[national_subset_local
][Char
-0x5B];
2751 Char
= nationaltable7b
[national_subset_local
][Char
-0x7B];
2754 FillRect(buffer
,xres
,*pPosX
, PosY
, curfontwidth
, factor
*Ascender
, fgcolor
);
2755 FillRect(buffer
,xres
,*pPosX
, PosY
+ factor
*Ascender
, curfontwidth
, factor
*(FontHeight
-Ascender
), bgcolor
);
2756 *pPosX
+= curfontwidth
;
2759 DrawHLine(buffer
,xres
,*pPosX
, PosY
, curfontwidth
, fgcolor
);
2760 DrawVLine(buffer
,xres
,*pPosX
, PosY
+1, FontHeight
-1, fgcolor
);
2761 FillRect(buffer
,xres
,*pPosX
+1, PosY
+1, curfontwidth
-1, FontHeight
-1, bgcolor
);
2762 *pPosX
+= curfontwidth
;
2765 DrawHLine(buffer
,xres
,*pPosX
, PosY
, curfontwidth
, fgcolor
);
2766 FillRect(buffer
,xres
,*pPosX
, PosY
+1, curfontwidth
, FontHeight
-1, bgcolor
);
2767 *pPosX
+= curfontwidth
;
2770 DrawHLine(buffer
,xres
,*pPosX
, PosY
, curfontwidth
, fgcolor
);
2771 DrawVLine(buffer
,xres
,*pPosX
+ curfontwidth
-1, PosY
+1, FontHeight
-1, fgcolor
);
2772 FillRect(buffer
,xres
,*pPosX
, PosY
+1, curfontwidth
-1, FontHeight
-1, bgcolor
);
2773 *pPosX
+= curfontwidth
;
2776 DrawVLine(buffer
,xres
,*pPosX
, PosY
, FontHeight
, fgcolor
);
2777 FillRect(buffer
,xres
,*pPosX
+1, PosY
, curfontwidth
-1, FontHeight
, bgcolor
);
2778 *pPosX
+= curfontwidth
;
2781 DrawVLine(buffer
,xres
,*pPosX
+ curfontwidth
-1, PosY
, FontHeight
, fgcolor
);
2782 FillRect(buffer
,xres
,*pPosX
, PosY
, curfontwidth
-1, FontHeight
, bgcolor
);
2783 *pPosX
+= curfontwidth
;
2786 DrawHLine(buffer
,xres
,*pPosX
, PosY
+ FontHeight
-1, curfontwidth
, fgcolor
);
2787 DrawVLine(buffer
,xres
,*pPosX
, PosY
, FontHeight
-1, fgcolor
);
2788 FillRect(buffer
,xres
,*pPosX
+1, PosY
, curfontwidth
-1, FontHeight
-1, bgcolor
);
2789 *pPosX
+= curfontwidth
;
2792 DrawHLine(buffer
,xres
,*pPosX
, PosY
+ FontHeight
-1, curfontwidth
, fgcolor
);
2793 FillRect(buffer
,xres
,*pPosX
, PosY
, curfontwidth
, FontHeight
-1, bgcolor
);
2794 *pPosX
+= curfontwidth
;
2797 DrawHLine(buffer
,xres
,*pPosX
, PosY
+ FontHeight
-1, curfontwidth
, fgcolor
);
2798 DrawVLine(buffer
,xres
,*pPosX
+ curfontwidth
-1, PosY
, FontHeight
-1, fgcolor
);
2799 FillRect(buffer
,xres
,*pPosX
, PosY
, curfontwidth
-1, FontHeight
-1, bgcolor
);
2800 *pPosX
+= curfontwidth
;
2803 FillRect(buffer
,xres
,*pPosX
+1, PosY
, curfontwidth
-1, FontHeight
, bgcolor
);
2804 for (int Row
=0; Row
< curfontwidth
/2; Row
++)
2805 DrawVLine(buffer
,xres
,*pPosX
+ Row
, PosY
+ Row
, FontHeight
- Row
, fgcolor
);
2806 *pPosX
+= curfontwidth
;
2809 FillRect(buffer
,xres
,*pPosX
, PosY
, curfontwidth
/2, FontHeight
, fgcolor
);
2810 FillRect(buffer
,xres
,*pPosX
+ curfontwidth
/2, PosY
, (curfontwidth
+1)/2, FontHeight
, bgcolor
);
2811 *pPosX
+= curfontwidth
;
2813 case 0xEA: /* ∞ */
2814 FillRect(buffer
,xres
,*pPosX
, PosY
, curfontwidth
, FontHeight
, bgcolor
);
2815 FillRect(buffer
,xres
,*pPosX
, PosY
, curfontwidth
/2, curfontwidth
/2, fgcolor
);
2816 *pPosX
+= curfontwidth
;
2819 FillRect(buffer
,xres
,*pPosX
, PosY
+1, curfontwidth
, FontHeight
-1, bgcolor
);
2820 for (int Row
=0; Row
< curfontwidth
/2; Row
++)
2821 DrawHLine(buffer
,xres
,*pPosX
+ Row
, PosY
+ Row
, curfontwidth
- Row
, fgcolor
);
2822 *pPosX
+= curfontwidth
;
2825 FillRect(buffer
, xres
,*pPosX
, PosY
, curfontwidth
, curfontwidth
/2, fgcolor
);
2826 FillRect(buffer
, xres
,*pPosX
, PosY
+ curfontwidth
/2, curfontwidth
, FontHeight
- curfontwidth
/2, bgcolor
);
2827 *pPosX
+= curfontwidth
;
2837 Char
= arrowtable
[Char
- 0xED];
2845 FillRect(buffer
, xres
, *pPosX
, PosY
, curfontwidth
, factor
*FontHeight
, bgcolor
);
2846 *pPosX
+= curfontwidth
;
2849 return Char
; // Char is an alphanumeric unicode character
2852 TextPageinfo_t
* CTeletextDecoder::DecodePage(bool showl25
, // 1=decode Level2.5-graphics
2853 unsigned char* PageChar
, // page buffer, min. 25*40
2854 TextPageAttr_t
*PageAtrb
, // attribute buffer, min 25*40
2855 bool HintMode
, // 1=show hidden information
2856 bool showflof
) // 1=decode FLOF-line
2860 int foreground
, background
, doubleheight
, doublewidth
, charset
, previous_charset
, mosaictype
, IgnoreAtBlackBgSubst
, concealed
, flashmode
, boxwin
;
2861 unsigned char held_mosaic
, *p
;
2862 TextCachedPage_t
*pCachedPage
;
2864 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
2866 /* copy page to decode buffer */
2867 if (m_txtCache
->SubPageTable
[m_txtCache
->Page
] == 0xff) /* not cached: do nothing */
2870 if (m_txtCache
->ZapSubpageManual
)
2871 pCachedPage
= m_txtCache
->astCachetable
[m_txtCache
->Page
][m_txtCache
->SubPage
];
2873 pCachedPage
= m_txtCache
->astCachetable
[m_txtCache
->Page
][m_txtCache
->SubPageTable
[m_txtCache
->Page
]];
2874 if (!pCachedPage
) /* not cached: do nothing */
2877 auto& components
= CServiceBroker::GetAppComponents();
2878 const auto appPlayer
= components
.GetComponent
<CApplicationPlayer
>();
2879 appPlayer
->LoadPage(m_txtCache
->Page
, m_txtCache
->SubPage
, &PageChar
[40]);
2881 memcpy(&PageChar
[8], pCachedPage
->p0
, 24); /* header line without TimeString */
2883 TextPageinfo_t
* PageInfo
= &(pCachedPage
->pageinfo
);
2885 memcpy(&PageChar
[24*40], PageInfo
->p24
, 40); /* line 25 for FLOF */
2887 /* copy TimeString */
2888 memcpy(&PageChar
[32], &m_txtCache
->TimeString
, 8);
2891 /* check for newsflash & subtitle */
2892 if (PageInfo
->boxed
&& IsDec(m_txtCache
->Page
))
2901 memset(PageChar
, ' ', 40);
2905 memset(PageChar
, ' ', 8);
2906 CDVDTeletextTools::Hex2Str((char*)PageChar
+3, m_txtCache
->Page
);
2907 if (m_txtCache
->SubPage
)
2911 CDVDTeletextTools::Hex2Str((char*)PageChar
+6, m_txtCache
->SubPage
);
2915 if (!IsDec(m_txtCache
->Page
))
2917 TextPageAttr_t atr
= { TXT_ColorWhite
, TXT_ColorBlack
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f};
2918 if (PageInfo
->function
== FUNC_MOT
) /* magazine organization table */
2920 for (col
= 0; col
< 24*40; col
++)
2921 PageAtrb
[col
] = atr
;
2922 for (col
= 40; col
< 24*40; col
++)
2923 PageChar
[col
] = number2char(PageChar
[col
]);
2924 return PageInfo
; /* don't interpret irregular pages */
2926 else if (PageInfo
->function
== FUNC_GPOP
|| PageInfo
->function
== FUNC_POP
) /* object definitions */
2928 for (int col
= 0; col
< 24*40; col
++)
2929 PageAtrb
[col
] = atr
;
2932 for (int row
= 1; row
< 12; row
++)
2934 *p
++ = number2char(row
); /* first column: number (0-9, A-..) */
2935 for (int col
= 1; col
< 40; col
+= 3)
2937 int d
= CDVDTeletextTools::deh24(p
);
2940 memcpy(p
, "???", 3);
2945 *p
++ = number2char((d
>> 6) & 0x1f); /* mode */
2946 *p
++ = number2char(d
& 0x3f); /* address */
2947 *p
++ = number2char((d
>> 11) & 0x7f); /* data */
2951 return PageInfo
; /* don't interpret irregular pages */
2953 else if (PageInfo
->function
== FUNC_GDRCS
|| PageInfo
->function
== FUNC_DRCS
) /* character definitions */
2955 return PageInfo
; /* don't interpret irregular pages */
2959 int h
, parityerror
= 0;
2961 for (int i
= 0; i
< 8; i
++)
2964 /* decode parity/hamming */
2965 for (unsigned int i
= 40; i
< TELETEXT_PAGE_SIZE
; i
++)
2970 if (parityerror
&& h
!= 0xFF) /* if no regular page (after any parity error) */
2971 CDVDTeletextTools::Hex2Str((char*)p
, h
); /* first try dehamming */
2974 if (*p
== ' ' || deparity
[*p
] != ' ') /* correct parity */
2979 if (h
!= 0xFF) /* first parity error: try dehamming */
2980 CDVDTeletextTools::Hex2Str((char*)p
, h
);
2988 return PageInfo
; /* don't interpret irregular pages */
2992 int mosaic_pending
,esc_pending
;
2994 for (int row
= 0; row
< ((showflof
&& PageInfo
->p24
) ? 25 : 24); row
++)
2996 /* start-of-row default conditions */
2997 foreground
= TXT_ColorWhite
;
2998 background
= TXT_ColorBlack
;
3001 charset
= previous_charset
= C_G0P
; // remember charset for switching back after mosaic charset was used
3009 IgnoreAtBlackBgSubst
= 0;
3010 mosaic_pending
= esc_pending
= 0; // we need to render at least one mosaic char if 'esc' is received immediately after mosaic charset switch on
3012 if (boxed
&& memchr(&PageChar
[row
*40], start_box
, 40) == 0)
3014 foreground
= TXT_ColorTransp
;
3015 background
= TXT_ColorTransp
;
3018 for (int col
= 0; col
< 40; col
++)
3020 int index
= row
*40 + col
;
3022 PageAtrb
[index
].fg
= foreground
;
3023 PageAtrb
[index
].bg
= background
;
3024 PageAtrb
[index
].charset
= charset
;
3025 PageAtrb
[index
].doubleh
= doubleheight
;
3026 PageAtrb
[index
].doublew
= (col
< 39 ? doublewidth
: 0);
3027 PageAtrb
[index
].IgnoreAtBlackBgSubst
= IgnoreAtBlackBgSubst
;
3028 PageAtrb
[index
].concealed
= concealed
;
3029 PageAtrb
[index
].flashing
= flashmode
;
3030 PageAtrb
[index
].boxwin
= boxwin
;
3031 PageAtrb
[index
].inverted
= 0; // only relevant for Level 2.5
3032 PageAtrb
[index
].underline
= 0; // only relevant for Level 2.5
3033 PageAtrb
[index
].diacrit
= 0; // only relevant for Level 2.5
3034 PageAtrb
[index
].setX26
= 0; // only relevant for Level 2.5
3035 PageAtrb
[index
].setG0G2
= 0x3f; // only relevant for Level 2.5
3037 if (PageChar
[index
] < ' ')
3039 if (esc_pending
) { // mosaic char has been rendered and we can switch charsets
3040 charset
= previous_charset
;
3041 if (charset
== C_G0P
)
3042 charset
= previous_charset
= C_G0S
;
3043 else if (charset
== C_G0S
)
3044 charset
= previous_charset
= C_G0P
;
3047 switch (PageChar
[index
])
3058 foreground
= PageChar
[index
] - alpha_black
+ TXT_ColorBlack
;
3059 if (col
== 0 && PageChar
[index
] == alpha_white
)
3060 PageAtrb
[index
].fg
= TXT_ColorBlack
; // indicate level 1 color change on column 0; (hack)
3061 if ((charset
!=C_G0P
) && (charset
!=C_G0S
)) // we need to change charset to state it was before mosaic
3062 charset
= previous_charset
;
3071 PageAtrb
[index
].flashing
= 0;
3076 IgnoreAtBlackBgSubst
= 0;
3087 PageAtrb
[index
].doubleh
= doubleheight
;
3088 PageAtrb
[index
].doublew
= doublewidth
;
3122 case mosaic_magenta
:
3126 foreground
= PageChar
[index
] - mosaic_black
+ TXT_ColorBlack
;
3127 if ((charset
==C_G0P
) || (charset
==C_G0S
))
3128 previous_charset
=charset
;
3129 charset
= mosaictype
? C_G1S
: C_G1C
;
3134 PageAtrb
[index
].concealed
= 1;
3138 foreground
= background
;
3139 PageAtrb
[index
].fg
= foreground
;
3143 case contiguous_mosaic
:
3145 if (charset
== C_G1S
)
3148 PageAtrb
[index
].charset
= charset
;
3152 case separated_mosaic
:
3154 if (charset
== C_G1C
)
3157 PageAtrb
[index
].charset
= charset
;
3162 if (!mosaic_pending
) { // if mosaic is pending we need to wait before mosaic arrives
3163 if ((charset
!= C_G0P
) && (charset
!= C_G0S
)) // we need to switch to charset which was active before mosaic
3164 charset
= previous_charset
;
3165 if (charset
== C_G0P
)
3166 charset
= previous_charset
= C_G0S
;
3167 else if (charset
== C_G0S
)
3168 charset
= previous_charset
= C_G0P
;
3169 } else esc_pending
= 1;
3172 case black_background
:
3173 background
= TXT_ColorBlack
;
3174 IgnoreAtBlackBgSubst
= 0;
3175 PageAtrb
[index
].bg
= background
;
3176 PageAtrb
[index
].IgnoreAtBlackBgSubst
= IgnoreAtBlackBgSubst
;
3179 case new_background
:
3180 background
= foreground
;
3181 if (background
== TXT_ColorBlack
)
3182 IgnoreAtBlackBgSubst
= 1;
3184 IgnoreAtBlackBgSubst
= 0;
3185 PageAtrb
[index
].bg
= background
;
3186 PageAtrb
[index
].IgnoreAtBlackBgSubst
= IgnoreAtBlackBgSubst
;
3193 case release_mosaic
:
3198 /* handle spacing attributes */
3199 if (hold
&& (PageAtrb
[index
].charset
== C_G1C
|| PageAtrb
[index
].charset
== C_G1S
))
3200 PageChar
[index
] = held_mosaic
;
3202 PageChar
[index
] = ' ';
3207 else /* char >= ' ' */
3209 mosaic_pending
= 0; // charset will be switched next if esc_pending
3210 /* set new held-mosaic char */
3211 if ((charset
== C_G1C
|| charset
== C_G1S
) &&
3212 ((PageChar
[index
]&0xA0) == 0x20))
3213 held_mosaic
= PageChar
[index
];
3214 if (PageAtrb
[index
].doubleh
)
3215 PageChar
[index
+ 40] = 0xFF;
3218 if (!(charset
== C_G1C
|| charset
== C_G1S
))
3219 held_mosaic
= ' '; /* forget if outside mosaic */
3223 /* skip row if doubleheight */
3224 if (row
< 23 && dhset
)
3226 for (int col
= 0; col
< 40; col
++)
3228 int index
= row
*40 + col
;
3229 PageAtrb
[index
+40].bg
= PageAtrb
[index
].bg
;
3230 PageAtrb
[index
+40].fg
= TXT_ColorWhite
;
3231 if (!PageAtrb
[index
].doubleh
)
3232 PageChar
[index
+40] = ' ';
3233 PageAtrb
[index
+40].flashing
= 0;
3234 PageAtrb
[index
+40].charset
= C_G0P
;
3235 PageAtrb
[index
+40].doubleh
= 0;
3236 PageAtrb
[index
+40].doublew
= 0;
3237 PageAtrb
[index
+40].IgnoreAtBlackBgSubst
= 0;
3238 PageAtrb
[index
+40].concealed
= 0;
3239 PageAtrb
[index
+40].flashing
= 0;
3240 PageAtrb
[index
+40].boxwin
= PageAtrb
[index
].boxwin
;
3245 m_txtCache
->FullScrColor
= TXT_ColorBlack
;
3248 Eval_l25(PageChar
, PageAtrb
, HintMode
);
3250 /* handle Black Background Color Substitution and transparency (CLUT1#0) */
3255 for (unsigned char row
: m_txtCache
->FullRowColor
)
3257 for (int c
= 0; c
< 40; c
++)
3259 bitmask
= (PageAtrb
[o
].bg
== 0x08 ? 0x08 : 0x00) | (row
== 0x08 ? 0x04 : 0x00) | (PageAtrb
[o
].boxwin
<<1) | (int)boxed
;
3265 PageAtrb
[o
].bg
= m_txtCache
->FullScrColor
;
3267 PageAtrb
[o
].bg
= row
;
3277 PageAtrb
[o
].bg
= TXT_ColorTransp
;
3280 bitmask
= (PageAtrb
[o
].fg
== 0x08 ? 0x08 : 0x00) | (row
== 0x08 ? 0x04 : 0x00) | (PageAtrb
[o
].boxwin
<<1) | (int)boxed
;
3286 PageAtrb
[o
].fg
= m_txtCache
->FullScrColor
;
3288 PageAtrb
[o
].fg
= row
;
3298 PageAtrb
[o
].fg
= TXT_ColorTransp
;
3308 void CTeletextDecoder::Eval_l25(unsigned char* PageChar
, TextPageAttr_t
*PageAtrb
, bool HintMode
)
3310 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
3312 memset(m_txtCache
->FullRowColor
, 0, sizeof(m_txtCache
->FullRowColor
));
3313 m_txtCache
->FullScrColor
= TXT_ColorBlack
;
3314 m_txtCache
->ColorTable
= NULL
;
3316 if (!m_txtCache
->astCachetable
[m_txtCache
->Page
][m_txtCache
->SubPage
])
3320 if (IsDec(m_txtCache
->Page
))
3322 unsigned char APx0
, APy0
, APx
, APy
;
3323 TextPageinfo_t
*pi
= &(m_txtCache
->astCachetable
[m_txtCache
->Page
][m_txtCache
->SubPage
]->pageinfo
);
3324 TextCachedPage_t
*pmot
= m_txtCache
->astCachetable
[(m_txtCache
->Page
& 0xf00) | 0xfe][0];
3325 int p26Received
= 0;
3326 int BlackBgSubst
= 0;
3327 int ColorTableRemapping
= 0;
3329 m_txtCache
->pop
= m_txtCache
->gpop
= m_txtCache
->drcs
= m_txtCache
->gdrcs
= 0;
3333 TextExtData_t
*e
= pi
->ext
;
3340 Textp27_t
*p27
= e
->p27
;
3342 m_txtCache
->gpop
= p27
[0].page
;
3344 m_txtCache
->pop
= p27
[1].page
;
3346 m_txtCache
->gdrcs
= p27
[2].page
;
3348 m_txtCache
->drcs
= p27
[3].page
;
3353 m_txtCache
->ColorTable
= e
->bgr
;
3354 BlackBgSubst
= e
->BlackBgSubst
;
3355 ColorTableRemapping
= e
->ColorTableRemapping
;
3356 memset(m_txtCache
->FullRowColor
, e
->DefRowColor
, sizeof(m_txtCache
->FullRowColor
));
3357 m_txtCache
->FullScrColor
= e
->DefScreenColor
;
3358 m_txtCache
->NationalSubset
= SetNational(e
->DefaultCharset
);
3359 m_txtCache
->NationalSubsetSecondary
= SetNational(e
->SecondCharset
);
3360 } /* e->p28Received */
3363 if (!m_txtCache
->ColorTable
&& m_txtCache
->astP29
[m_txtCache
->Page
>> 8])
3365 TextExtData_t
*e
= m_txtCache
->astP29
[m_txtCache
->Page
>> 8];
3366 m_txtCache
->ColorTable
= e
->bgr
;
3367 BlackBgSubst
= e
->BlackBgSubst
;
3368 ColorTableRemapping
= e
->ColorTableRemapping
;
3369 memset(m_txtCache
->FullRowColor
, e
->DefRowColor
, sizeof(m_txtCache
->FullRowColor
));
3370 m_txtCache
->FullScrColor
= e
->DefScreenColor
;
3371 m_txtCache
->NationalSubset
= SetNational(e
->DefaultCharset
);
3372 m_txtCache
->NationalSubsetSecondary
= SetNational(e
->SecondCharset
);
3375 if (ColorTableRemapping
)
3377 for (int i
= 0; i
< 25*40; i
++)
3379 PageAtrb
[i
].fg
+= MapTblFG
[ColorTableRemapping
- 1];
3380 if (!BlackBgSubst
|| PageAtrb
[i
].bg
!= TXT_ColorBlack
|| PageAtrb
[i
].IgnoreAtBlackBgSubst
)
3381 PageAtrb
[i
].bg
+= MapTblBG
[ColorTableRemapping
- 1];
3385 /* determine ?pop/?drcs from MOT */
3388 unsigned char pmot_data
[23*40];
3389 auto& components
= CServiceBroker::GetAppComponents();
3390 const auto appPlayer
= components
.GetComponent
<CApplicationPlayer
>();
3391 appPlayer
->LoadPage((m_txtCache
->Page
& 0xf00) | 0xfe, 0, pmot_data
);
3393 unsigned char *p
= pmot_data
; /* start of link data */
3394 int o
= 2 * (((m_txtCache
->Page
& 0xf0) >> 4) * 10 + (m_txtCache
->Page
& 0x0f)); /* offset of links for current page */
3395 int opop
= p
[o
] & 0x07; /* index of POP link */
3396 int odrcs
= p
[o
+1] & 0x07; /* index of DRCS link */
3397 unsigned char obj
[3*4*4]; /* types* objects * (triplet,packet,subp,high) */
3398 unsigned char type
,ct
, tstart
= 4*4;
3399 memset(obj
,0,sizeof(obj
));
3401 if (p
[o
] & 0x08) /* GPOP data used */
3403 if (!m_txtCache
->gpop
|| !(p
[18*40] & 0x08)) /* no p27 data or higher prio of MOT link */
3405 m_txtCache
->gpop
= ((p
[18*40] << 8) | (p
[18*40+1] << 4) | p
[18*40+2]) & 0x7ff;
3406 if ((m_txtCache
->gpop
& 0xff) == 0xff)
3407 m_txtCache
->gpop
= 0;
3410 if (m_txtCache
->gpop
< 0x100)
3411 m_txtCache
->gpop
+= 0x800;
3418 type
= (p
[18*40+5] >> 2*ct
) & 0x03;
3420 if (type
== 0) continue;
3421 obj
[(type
-1)*(tstart
)+ct
*4 ] = 3 * ((p
[18*40+7+ct
*2] >> 1) & 0x03) + type
; //triplet
3422 obj
[(type
-1)*(tstart
)+ct
*4+1] = ((p
[18*40+7+ct
*2] & 0x08) >> 3) + 1 ; //packet
3423 obj
[(type
-1)*(tstart
)+ct
*4+2] = p
[18*40+6+ct
*2] & 0x0f ; //subp
3424 obj
[(type
-1)*(tstart
)+ct
*4+3] = p
[18*40+7+ct
*2] & 0x01 ; //high
3430 if (opop
) /* POP data used */
3432 opop
= 18*40 + 10*opop
; /* offset to POP link */
3433 if (!m_txtCache
->pop
|| !(p
[opop
] & 0x08)) /* no p27 data or higher prio of MOT link */
3435 m_txtCache
->pop
= ((p
[opop
] << 8) | (p
[opop
+1] << 4) | p
[opop
+2]) & 0x7ff;
3436 if ((m_txtCache
->pop
& 0xff) == 0xff)
3437 m_txtCache
->pop
= 0;
3440 if (m_txtCache
->pop
< 0x100)
3441 m_txtCache
->pop
+= 0x800;
3448 type
= (p
[opop
+5] >> 2*ct
) & 0x03;
3450 if (type
== 0) continue;
3451 obj
[(type
-1)*(tstart
)+(ct
+2)*4 ] = 3 * ((p
[opop
+7+ct
*2] >> 1) & 0x03) + type
; //triplet
3452 obj
[(type
-1)*(tstart
)+(ct
+2)*4+1] = ((p
[opop
+7+ct
*2] & 0x08) >> 3) + 1 ; //packet
3453 obj
[(type
-1)*(tstart
)+(ct
+2)*4+2] = p
[opop
+6+ct
*2] ; //subp
3454 obj
[(type
-1)*(tstart
)+(ct
+2)*4+3] = p
[opop
+7+ct
*2] & 0x01 ; //high
3460 // eval default objects in correct order
3461 for (int i
= 0; i
< 12; i
++)
3465 APx0
= APy0
= APx
= APy
= m_txtCache
->tAPx
= m_txtCache
->tAPy
= 0;
3466 Eval_NumberedObject(i
% 4 > 1 ? m_txtCache
->pop
: m_txtCache
->gpop
, obj
[i
*4+2], obj
[i
*4+1], obj
[i
*4], obj
[i
*4+3], &APx
, &APy
, &APx0
, &APy0
, PageChar
, PageAtrb
);
3470 if (p
[o
+1] & 0x08) /* GDRCS data used */
3472 if (!m_txtCache
->gdrcs
|| !(p
[20*40] & 0x08)) /* no p27 data or higher prio of MOT link */
3474 m_txtCache
->gdrcs
= ((p
[20*40] << 8) | (p
[20*40+1] << 4) | p
[20*40+2]) & 0x7ff;
3475 if ((m_txtCache
->gdrcs
& 0xff) == 0xff)
3476 m_txtCache
->gdrcs
= 0;
3477 else if (m_txtCache
->gdrcs
< 0x100)
3478 m_txtCache
->gdrcs
+= 0x800;
3481 if (odrcs
) /* DRCS data used */
3483 odrcs
= 20*40 + 4*odrcs
; /* offset to DRCS link */
3484 if (!m_txtCache
->drcs
|| !(p
[odrcs
] & 0x08)) /* no p27 data or higher prio of MOT link */
3486 m_txtCache
->drcs
= ((p
[odrcs
] << 8) | (p
[odrcs
+1] << 4) | p
[odrcs
+2]) & 0x7ff;
3487 if ((m_txtCache
->drcs
& 0xff) == 0xff)
3488 m_txtCache
->drcs
= 0;
3489 else if (m_txtCache
->drcs
< 0x100)
3490 m_txtCache
->drcs
+= 0x800;
3493 if (m_txtCache
->astCachetable
[m_txtCache
->gpop
][0])
3494 m_txtCache
->astCachetable
[m_txtCache
->gpop
][0]->pageinfo
.function
= FUNC_GPOP
;
3495 if (m_txtCache
->astCachetable
[m_txtCache
->pop
][0])
3496 m_txtCache
->astCachetable
[m_txtCache
->pop
][0]->pageinfo
.function
= FUNC_POP
;
3497 if (m_txtCache
->astCachetable
[m_txtCache
->gdrcs
][0])
3498 m_txtCache
->astCachetable
[m_txtCache
->gdrcs
][0]->pageinfo
.function
= FUNC_GDRCS
;
3499 if (m_txtCache
->astCachetable
[m_txtCache
->drcs
][0])
3500 m_txtCache
->astCachetable
[m_txtCache
->drcs
][0]->pageinfo
.function
= FUNC_DRCS
;
3503 /* evaluate local extension data from p26 */
3506 APx0
= APy0
= APx
= APy
= m_txtCache
->tAPx
= m_txtCache
->tAPy
= 0;
3507 Eval_Object(13 * (23-2 + 2), m_txtCache
->astCachetable
[m_txtCache
->Page
][m_txtCache
->SubPage
], &APx
, &APy
, &APx0
, &APy0
, OBJ_ACTIVE
, &PageChar
[40], PageChar
, PageAtrb
); /* 1st triplet p26/0 */
3512 for (unsigned char row
: m_txtCache
->FullRowColor
)
3514 for (int c
= 0; c
< 40; c
++)
3516 if (BlackBgSubst
&& PageAtrb
[o
].bg
== TXT_ColorBlack
&& !(PageAtrb
[o
].IgnoreAtBlackBgSubst
))
3519 PageAtrb
[o
].bg
= m_txtCache
->FullScrColor
;
3521 PageAtrb
[o
].bg
= row
;
3530 for (int i
= 0; i
< 25*40; i
++)
3532 if (PageAtrb
[i
].concealed
) PageAtrb
[i
].fg
= PageAtrb
[i
].bg
;
3535 } /* is_dec(page) */
3538 /* dump interpreted object data to stdout */
3539 /* in: 18 bit object data */
3540 /* out: termination info, >0 if end of object */
3541 void CTeletextDecoder::Eval_Object(int iONr
, TextCachedPage_t
*pstCachedPage
,
3542 unsigned char *pAPx
, unsigned char *pAPy
,
3543 unsigned char *pAPx0
, unsigned char *pAPy0
,
3544 tObjType ObjType
, unsigned char* pagedata
, unsigned char* PageChar
, TextPageAttr_t
* PageAtrb
)
3547 int iONr1
= iONr
+ 1; /* don't terminate after first triplet */
3548 unsigned char drcssubp
=0, gdrcssubp
=0;
3549 signed char endcol
= -1; /* last column to which to extend attribute changes */
3550 TextPageAttr_t attrPassive
= { TXT_ColorWhite
, TXT_ColorBlack
, C_G0P
, 0, 0, 1 ,0, 0, 0, 0, 0, 0, 0, 0x3f}; /* current attribute for passive objects */
3554 iOData
= iTripletNumber2Data(iONr
, pstCachedPage
, pagedata
); /* get triplet data, next triplet */
3555 if (iOData
< 0) /* invalid number, not cached, or hamming error: terminate */
3560 if (ObjType
== OBJ_ACTIVE
)
3564 else if (ObjType
== OBJ_ADAPTIVE
) /* search end of line */
3566 for (int i
= iONr
; i
<= 506; i
++)
3568 int iTempOData
= iTripletNumber2Data(i
, pstCachedPage
, pagedata
); /* get triplet data, next triplet */
3569 int iAddress
= (iTempOData
) & 0x3f;
3570 int iMode
= (iTempOData
>> 6) & 0x1f;
3571 //int iData = (iTempOData >> 11) & 0x7f;
3572 if (iTempOData
< 0 || /* invalid number, not cached, or hamming error: terminate */
3573 (iAddress
>= 40 /* new row: row address and */
3574 && (iMode
== 0x01 || /* Full Row Color or */
3575 iMode
== 0x04 || /* Set Active Position */
3576 (iMode
>= 0x15 && iMode
<= 0x17) || /* Object Definition */
3577 iMode
== 0x17))) /* Object Termination */
3579 if (iAddress
< 40 && iMode
!= 0x06)
3586 while (0 == Eval_Triplet(iOData
, pstCachedPage
, pAPx
, pAPy
, pAPx0
, pAPy0
, &drcssubp
, &gdrcssubp
, &endcol
, &attrPassive
, pagedata
, PageChar
, PageAtrb
) || iONr1
== iONr
); /* repeat until termination reached */
3589 void CTeletextDecoder::Eval_NumberedObject(int p
, int s
, int packet
, int triplet
, int high
,
3590 unsigned char *pAPx
, unsigned char *pAPy
,
3591 unsigned char *pAPx0
, unsigned char *pAPy0
, unsigned char* PageChar
, TextPageAttr_t
* PageAtrb
)
3593 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
3595 if (!packet
|| 0 == m_txtCache
->astCachetable
[p
][s
])
3598 unsigned char pagedata
[23*40];
3599 auto& components
= CServiceBroker::GetAppComponents();
3600 const auto appPlayer
= components
.GetComponent
<CApplicationPlayer
>();
3601 appPlayer
->LoadPage(p
, s
, pagedata
);
3603 int idata
= CDVDTeletextTools::deh24(pagedata
+ 40*(packet
-1) + 1 + 3*triplet
);
3606 if (idata
< 0) /* hamming error: ignore triplet */
3609 iONr
= idata
>> 9; /* triplet number of odd object data */
3611 iONr
= idata
& 0x1ff; /* triplet number of even object data */
3614 Eval_Object(iONr
, m_txtCache
->astCachetable
[p
][s
], pAPx
, pAPy
, pAPx0
, pAPy0
, (tObjType
)(triplet
% 3),pagedata
, PageChar
, PageAtrb
);
3618 int CTeletextDecoder::Eval_Triplet(int iOData
, TextCachedPage_t
*pstCachedPage
,
3619 unsigned char *pAPx
, unsigned char *pAPy
,
3620 unsigned char *pAPx0
, unsigned char *pAPy0
,
3621 unsigned char *drcssubp
, unsigned char *gdrcssubp
,
3622 signed char *endcol
, TextPageAttr_t
*attrPassive
, unsigned char* pagedata
, unsigned char* PageChar
, TextPageAttr_t
* PageAtrb
)
3624 int iAddress
= (iOData
) & 0x3f;
3625 int iMode
= (iOData
>> 6) & 0x1f;
3626 int iData
= (iOData
>> 11) & 0x7f;
3628 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
3630 if (iAddress
< 40) /* column addresses */
3632 int offset
; /* offset to PageChar and PageAtrb */
3635 *pAPx
= iAddress
; /* new Active Column */
3636 offset
= (*pAPy0
+ *pAPy
) * 40 + *pAPx0
+ *pAPx
; /* offset to PageChar and PageAtrb */
3641 if (0 == (iData
>>5))
3643 int newcolor
= iData
& 0x1f;
3644 if (*endcol
< 0) /* passive object */
3645 attrPassive
->fg
= newcolor
;
3646 else if (*endcol
== 40) /* active object */
3648 TextPageAttr_t
*p
= &PageAtrb
[offset
];
3649 int oldcolor
= (p
)->fg
; /* current color (set-after) */
3650 int c
= *pAPx0
+ *pAPx
; /* current column absolute */
3656 } while (c
< 40 && p
->fg
== oldcolor
); /* stop at change by level 1 page */
3658 else /* adaptive object */
3660 TextPageAttr_t
*p
= &PageAtrb
[offset
];
3661 int c
= *pAPx
; /* current column relative to object origin */
3667 } while (c
<= *endcol
);
3674 PageChar
[offset
] = iData
;
3675 if (*endcol
< 0) /* passive object */
3677 attrPassive
->charset
= C_G1C
; /* FIXME: separated? */
3678 PageAtrb
[offset
] = *attrPassive
;
3680 else if (PageAtrb
[offset
].charset
!= C_G1S
)
3681 PageAtrb
[offset
].charset
= C_G1C
; /* FIXME: separated? */
3686 PageChar
[offset
] = iData
;
3687 if (*endcol
< 0) /* passive object */
3689 attrPassive
->charset
= C_G3
;
3690 PageAtrb
[offset
] = *attrPassive
;
3693 PageAtrb
[offset
].charset
= C_G3
;
3696 if (0 == (iData
>>5))
3698 int newcolor
= iData
& 0x1f;
3699 if (*endcol
< 0) /* passive object */
3700 attrPassive
->bg
= newcolor
;
3701 else if (*endcol
== 40) /* active object */
3703 TextPageAttr_t
*p
= &PageAtrb
[offset
];
3704 int oldcolor
= (p
)->bg
; /* current color (set-after) */
3705 int c
= *pAPx0
+ *pAPx
; /* current column absolute */
3709 if (newcolor
== TXT_ColorBlack
)
3710 p
->IgnoreAtBlackBgSubst
= 1;
3713 } while (c
< 40 && p
->bg
== oldcolor
); /* stop at change by level 1 page */
3715 else /* adaptive object */
3717 TextPageAttr_t
*p
= &PageAtrb
[offset
];
3718 int c
= *pAPx
; /* current column relative to object origin */
3722 if (newcolor
== TXT_ColorBlack
)
3723 p
->IgnoreAtBlackBgSubst
= 1;
3726 } while (c
<= *endcol
);
3734 if ((iData
& 0x60) != 0) break; // reserved data field
3735 if (*endcol
< 0) /* passive object */
3737 attrPassive
->flashing
=iData
& 0x1f;
3738 PageAtrb
[offset
] = *attrPassive
;
3741 PageAtrb
[offset
].flashing
=iData
& 0x1f;
3744 if (*endcol
< 0) /* passive object */
3746 attrPassive
->setG0G2
=iData
& 0x3f;
3747 PageAtrb
[offset
] = *attrPassive
;
3750 PageAtrb
[offset
].setG0G2
=iData
& 0x3f;
3753 PageChar
[offset
] = iData
;
3754 if (*endcol
< 0) /* passive object */
3756 attrPassive
->charset
= C_G0P
; /* FIXME: secondary? */
3757 attrPassive
->setX26
= 1;
3758 PageAtrb
[offset
] = *attrPassive
;
3762 PageAtrb
[offset
].charset
= C_G0P
; /* FIXME: secondary? */
3763 PageAtrb
[offset
].setX26
= 1;
3766 // case 0x0b: (see 0x02)
3769 int conc
= (iData
& 0x04);
3770 int inv
= (iData
& 0x10);
3771 int dw
= (iData
& 0x40 ?1:0);
3772 int dh
= (iData
& 0x01 ?1:0);
3773 int sep
= (iData
& 0x20);
3774 int bw
= (iData
& 0x02 ?1:0);
3775 if (*endcol
< 0) /* passive object */
3779 attrPassive
->concealed
= 1;
3780 attrPassive
->fg
= attrPassive
->bg
;
3782 attrPassive
->inverted
= (inv
? 1- attrPassive
->inverted
: 0);
3783 attrPassive
->doubleh
= dh
;
3784 attrPassive
->doublew
= dw
;
3785 attrPassive
->boxwin
= bw
;
3786 if (bw
) attrPassive
->IgnoreAtBlackBgSubst
= 0;
3789 if (attrPassive
->charset
== C_G1C
)
3790 attrPassive
->charset
= C_G1S
;
3792 attrPassive
->underline
= 1;
3796 if (attrPassive
->charset
== C_G1S
)
3797 attrPassive
->charset
= C_G1C
;
3799 attrPassive
->underline
= 0;
3805 int c
= *pAPx0
+ (*endcol
== 40 ? *pAPx
: 0); /* current column */
3806 TextPageAttr_t
*p
= &PageAtrb
[offset
];
3809 p
->inverted
= (inv
? 1- p
->inverted
: 0);
3817 if (p
->charset
== C_G1C
)
3824 if (p
->charset
== C_G1S
)
3832 if (bw
) p
->IgnoreAtBlackBgSubst
= 0;
3835 } while (c
< *endcol
);
3840 PageChar
[offset
] = iData
& 0x3f;
3841 if (*endcol
< 0) /* passive object */
3843 attrPassive
->charset
= C_OFFSET_DRCS
+ ((iData
& 0x40) ? (0x10 + *drcssubp
) : *gdrcssubp
);
3844 PageAtrb
[offset
] = *attrPassive
;
3847 PageAtrb
[offset
].charset
= C_OFFSET_DRCS
+ ((iData
& 0x40) ? (0x10 + *drcssubp
) : *gdrcssubp
);
3850 PageChar
[offset
] = iData
;
3851 if (*endcol
< 0) /* passive object */
3853 attrPassive
->charset
= C_G2
;
3854 PageAtrb
[offset
] = *attrPassive
;
3857 PageAtrb
[offset
].charset
= C_G2
;
3860 if (iMode
== 0x10 && iData
== 0x2a)
3864 PageChar
[offset
] = iData
;
3865 if (*endcol
< 0) /* passive object */
3867 attrPassive
->charset
= C_G0P
;
3868 attrPassive
->diacrit
= iMode
& 0x0f;
3869 attrPassive
->setX26
= 1;
3870 PageAtrb
[offset
] = *attrPassive
;
3874 PageAtrb
[offset
].charset
= C_G0P
;
3875 PageAtrb
[offset
].diacrit
= iMode
& 0x0f;
3876 PageAtrb
[offset
].setX26
= 1;
3879 break; /* unsupported or not yet implemented mode: ignore */
3880 } /* switch (iMode) */
3882 else /* ================= (iAddress >= 40): row addresses ====================== */
3887 if (0 == (iData
>>5))
3889 m_txtCache
->FullScrColor
= iData
& 0x1f;
3893 if (*endcol
== 40) /* active object */
3895 *pAPy
= RowAddress2Row(iAddress
); /* new Active Row */
3897 int color
= iData
& 0x1f;
3898 int row
= *pAPy0
+ *pAPy
;
3901 if (row
<= 24 && 0 == (iData
>>5))
3903 else if (3 == (iData
>>5))
3907 for (; row
<= maxrow
; row
++)
3908 m_txtCache
->FullRowColor
[row
] = color
;
3913 *pAPy
= RowAddress2Row(iAddress
); /* new Active Row */
3915 *pAPx
= iData
; /* new Active Column */
3916 *endcol
= -1; /* FIXME: check if row changed? */
3919 if (iAddress
== 0x3f)
3921 *pAPx
= *pAPy
= 0; /* new Active Position 0,0 */
3922 if (*endcol
== 40) /* active object */
3924 int color
= iData
& 0x1f;
3925 int row
= *pAPy0
; // + *pAPy;
3928 if (row
<= 24 && 0 == (iData
>>5))
3930 else if (3 == (iData
>>5))
3934 for (; row
<= maxrow
; row
++)
3935 m_txtCache
->FullRowColor
[row
] = color
;
3951 m_txtCache
->tAPy
= iAddress
- 40;
3952 m_txtCache
->tAPx
= iData
;
3957 if (iAddress
& 0x10) /* POP or GPOP */
3959 unsigned char APx
= 0, APy
= 0;
3960 unsigned char APx0
= *pAPx0
+ *pAPx
+ m_txtCache
->tAPx
, APy0
= *pAPy0
+ *pAPy
+ m_txtCache
->tAPy
;
3961 int triplet
= 3 * ((iData
>> 5) & 0x03) + (iMode
& 0x03);
3962 int packet
= (iAddress
& 0x03) + 1;
3963 int subp
= iData
& 0x0f;
3964 int high
= (iData
>> 4) & 0x01;
3967 if (APx0
< 40) /* not in side panel */
3969 Eval_NumberedObject((iAddress
& 0x08) ? m_txtCache
->gpop
: m_txtCache
->pop
, subp
, packet
, triplet
, high
, &APx
, &APy
, &APx0
, &APy0
, PageChar
,PageAtrb
);
3972 else if (iAddress
& 0x08) /* local: eval invoked object */
3974 unsigned char APx
= 0, APy
= 0;
3975 unsigned char APx0
= *pAPx0
+ *pAPx
+ m_txtCache
->tAPx
, APy0
= *pAPy0
+ *pAPy
+ m_txtCache
->tAPy
;
3976 int descode
= ((iAddress
& 0x01) << 3) | (iData
>> 4);
3977 int triplet
= iData
& 0x0f;
3979 if (APx0
< 40) /* not in side panel */
3981 Eval_Object(13 * 23 + 13 * descode
+ triplet
, pstCachedPage
, &APx
, &APy
, &APx0
, &APy0
, (tObjType
)(triplet
% 3), pagedata
, PageChar
, PageAtrb
);
3988 if (0 == (iAddress
& 0x08)) /* Object Definition illegal or only level 3.5 */
3991 m_txtCache
->tAPx
= m_txtCache
->tAPy
= 0;
3993 return 0xFF; /* termination by object definition */
3996 if (0 == (iData
& 0x10)) /* DRCS Mode reserved or only level 3.5 */
4000 *drcssubp
= iData
& 0x0f;
4002 *gdrcssubp
= iData
& 0x0f;
4005 m_txtCache
->tAPx
= m_txtCache
->tAPy
= 0;
4007 return 0x80 | iData
; /* explicit termination */
4010 break; /* unsupported or not yet implemented mode: ignore */
4011 } /* switch (iMode) */
4012 } /* (iAddress >= 40): row addresses */
4014 if (iAddress
< 40 || iMode
!= 0x10) /* leave temp. AP-Offset unchanged only immediately after definition */
4015 m_txtCache
->tAPx
= m_txtCache
->tAPy
= 0;
4017 return 0; /* normal exit, no termination */
4020 /* get object data */
4021 /* in: absolute triplet number (0..506, start at packet 3 byte 1) */
4022 /* in: pointer to cache struct of page data */
4023 /* out: 18 bit triplet data, <0 if invalid number, not cached, or hamming error */
4024 int CTeletextDecoder::iTripletNumber2Data(int iONr
, TextCachedPage_t
*pstCachedPage
, unsigned char* pagedata
)
4026 if (iONr
> 506 || 0 == pstCachedPage
)
4030 int packet
= (iONr
/ 13) + 3;
4031 int packetoffset
= 3 * (iONr
% 13);
4034 p
= pagedata
+ 40*(packet
-1) + packetoffset
+ 1;
4035 else if (packet
<= 25)
4037 if (0 == pstCachedPage
->pageinfo
.p24
)
4039 p
= pstCachedPage
->pageinfo
.p24
+ 40*(packet
-24) + packetoffset
+ 1;
4043 int descode
= packet
- 26;
4044 if (0 == pstCachedPage
->pageinfo
.ext
)
4046 if (0 == pstCachedPage
->pageinfo
.ext
->p26
[descode
])
4048 p
= pstCachedPage
->pageinfo
.ext
->p26
[descode
] + packetoffset
; /* first byte (=designation code) is not cached */
4050 return CDVDTeletextTools::deh24(p
);
4053 int CTeletextDecoder::SetNational(unsigned char sec
)
4055 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
4060 return NAT_PL
; //polish
4063 return NAT_TR
; //turkish
4065 return NAT_SR
; //serbian, croatian, slovenian
4067 return NAT_SC
; // serbian, croatian
4069 return NAT_RB
; // russian, bulgarian
4071 return NAT_UA
; // ukrainian
4073 return NAT_ET
; // estonian
4075 return NAT_LV
; // latvian, lithuanian
4077 return NAT_GR
; // greek
4079 return NAT_HB
; // hebrew
4082 return NAT_AR
; // arabic
4084 return CountryConversionTable
[sec
& 0x07];
4087 int CTeletextDecoder::NextHex(int i
) /* return next existing non-decimal page number */
4090 if (startpage
< 0x100)
4100 } while ((m_txtCache
->SubPageTable
[i
] == 0xFF) || IsDec(i
));
4104 void CTeletextDecoder::SetColors(const unsigned short *pcolormap
, int offset
, int number
)
4106 int j
= offset
; /* index in global color table */
4108 for (int i
= 0; i
< number
; i
++)
4110 int r
= ((pcolormap
[i
] >> 8) & 0xf) << 4;
4111 int g
= ((pcolormap
[i
] >> 4) & 0xf) << 4;
4112 int b
= ((pcolormap
[i
]) & 0xf) << 4;
4114 if (m_RenderInfo
.rd0
[j
] != r
)
4116 m_RenderInfo
.rd0
[j
] = r
;
4118 if (m_RenderInfo
.gn0
[j
] != g
)
4120 m_RenderInfo
.gn0
[j
] = g
;
4122 if (m_RenderInfo
.bl0
[j
] != b
)
4124 m_RenderInfo
.bl0
[j
] = b
;
4130 Color
CTeletextDecoder::GetColorRGB(enumTeletextColor ttc
)
4134 case TXT_ColorBlack
: return 0xFF000000;
4135 case TXT_ColorRed
: return 0xFFFC1414;
4136 case TXT_ColorGreen
: return 0xFF24FC24;
4137 case TXT_ColorYellow
: return 0xFFFCC024;
4138 case TXT_ColorBlue
: return 0xFF0000FC;
4139 case TXT_ColorMagenta
: return 0xFFB000FC;
4140 case TXT_ColorCyan
: return 0xFF00FCFC;
4141 case TXT_ColorWhite
: return 0xFFFCFCFC;
4142 case TXT_ColorTransp
: return 0x00000000;
4146 /* Get colors for CLUTs 2+3 */
4147 int index
= (int)ttc
;
4148 Color color
= (m_RenderInfo
.tr0
[index
] << 24) | (m_RenderInfo
.bl0
[index
] << 16) |
4149 (m_RenderInfo
.gn0
[index
] << 8) | m_RenderInfo
.rd0
[index
];