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/Key.h"
22 #include "utils/log.h"
23 #include "windowing/GraphicContext.h"
25 #include <harfbuzz/hb-ft.h>
27 using namespace std::chrono_literals
;
29 static inline void SDL_memset4(uint32_t* dst
, uint32_t val
, size_t len
)
31 for (; len
> 0; --len
)
34 #define SDL_memcpy4(dst, src, len) memcpy(dst, src, (len) << 2)
36 static const char *TeletextFont
= "special://xbmc/media/Fonts/teletext.ttf";
38 /* spacing attributes */
39 #define alpha_black 0x00
40 #define alpha_red 0x01
41 #define alpha_green 0x02
42 #define alpha_yellow 0x03
43 #define alpha_blue 0x04
44 #define alpha_magenta 0x05
45 #define alpha_cyan 0x06
46 #define alpha_white 0x07
50 #define start_box 0x0B
51 #define normal_size 0x0C
52 #define double_height 0x0D
53 #define double_width 0x0E
54 #define double_size 0x0F
55 #define mosaic_black 0x10
56 #define mosaic_red 0x11
57 #define mosaic_green 0x12
58 #define mosaic_yellow 0x13
59 #define mosaic_blue 0x14
60 #define mosaic_magenta 0x15
61 #define mosaic_cyan 0x16
62 #define mosaic_white 0x17
64 #define contiguous_mosaic 0x19
65 #define separated_mosaic 0x1A
67 #define black_background 0x1C
68 #define new_background 0x1D
69 #define hold_mosaic 0x1E
70 #define release_mosaic 0x1F
72 #define RowAddress2Row(row) ((row == 40) ? 24 : (row - 40))
74 // G2 Set as defined in ETS 300 706
75 const unsigned short int G2table
[5][6*16] =
77 // Latin G2 Supplementary Set
78 { 0x0020, 0x00A1, 0x00A2, 0x00A3, 0x0024, 0x00A5, 0x0023, 0x00A7, 0x00A4, 0x2018, 0x201C, 0x00AB, 0x2190, 0x2191, 0x2192, 0x2193,
79 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00D7, 0x00B5, 0x00B6, 0x00B7, 0x00F7, 0x2019, 0x201D, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
80 0x0020, 0x0300, 0x0301, 0x02C6, 0x0303, 0x02C9, 0x02D8, 0x02D9, 0x00A8, 0x002E, 0x02DA, 0x00B8, 0x005F, 0x02DD, 0x02DB, 0x02C7,
81 0x2014, 0x00B9, 0x00AE, 0x00A9, 0x2122, 0x266A, 0x20AC, 0x2030, 0x03B1, 0x0020, 0x0020, 0x0020, 0x215B, 0x215C, 0x215D, 0x215E,
82 0x2126, 0x00C6, 0x00D0, 0x00AA, 0x0126, 0x0020, 0x0132, 0x013F, 0x0141, 0x00D8, 0x0152, 0x00BA, 0x00DE, 0x0166, 0x014A, 0x0149,
83 0x0138, 0x00E6, 0x0111, 0x00F0, 0x0127, 0x0131, 0x0133, 0x0140, 0x0142, 0x00F8, 0x0153, 0x00DF, 0x00FE, 0x0167, 0x014B, 0x25A0},
84 // Cyrillic G2 Supplementary Set
85 { 0x0020, 0x00A1, 0x00A2, 0x00A3, 0x0024, 0x00A5, 0x0020, 0x00A7, 0x0020, 0x2018, 0x201C, 0x00AB, 0x2190, 0x2191, 0x2192, 0x2193,
86 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00D7, 0x00B5, 0x00B6, 0x00B7, 0x00F7, 0x2019, 0x201D, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
87 0x0020, 0x0300, 0x0301, 0x02C6, 0x02DC, 0x02C9, 0x02D8, 0x02D9, 0x00A8, 0x002E, 0x02DA, 0x00B8, 0x005F, 0x02DD, 0x02DB, 0x02C7,
88 0x2014, 0x00B9, 0x00AE, 0x00A9, 0x2122, 0x266A, 0x20AC, 0x2030, 0x03B1, 0x0141, 0x0142, 0x00DF, 0x215B, 0x215C, 0x215D, 0x215E,
89 0x0044, 0x0045, 0x0046, 0x0047, 0x0049, 0x004A, 0x004B, 0x004C, 0x004E, 0x0051, 0x0052, 0x0053, 0x0055, 0x0056, 0x0057, 0x005A,
90 0x0064, 0x0065, 0x0066, 0x0067, 0x0069, 0x006A, 0x006B, 0x006C, 0x006E, 0x0071, 0x0072, 0x0073, 0x0075, 0x0076, 0x0077, 0x007A},
91 // Greek G2 Supplementary Set
92 { 0x0020, 0x0061, 0x0062, 0x00A3, 0x0065, 0x0068, 0x0069, 0x00A7, 0x003A, 0x2018, 0x201C, 0x006B, 0x2190, 0x2191, 0x2192, 0x2193,
93 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00D7, 0x006D, 0x006E, 0x0070, 0x00F7, 0x2019, 0x201D, 0x0074, 0x00BC, 0x00BD, 0x00BE, 0x0078,
94 0x0020, 0x0300, 0x0301, 0x02C6, 0x02DC, 0x02C9, 0x02D8, 0x02D9, 0x00A8, 0x002E, 0x02DA, 0x00B8, 0x005F, 0x02DD, 0x02DB, 0x02C7,
95 0x003F, 0x00B9, 0x00AE, 0x00A9, 0x2122, 0x266A, 0x20AC, 0x2030, 0x03B1, 0x038A, 0x038E, 0x038F, 0x215B, 0x215C, 0x215D, 0x215E,
96 0x0043, 0x0044, 0x0046, 0x0047, 0x004A, 0x004C, 0x0051, 0x0052, 0x0053, 0x0055, 0x0056, 0x0057, 0x0059, 0x005A, 0x0386, 0x0389,
97 0x0063, 0x0064, 0x0066, 0x0067, 0x006A, 0x006C, 0x0071, 0x0072, 0x0073, 0x0075, 0x0076, 0x0077, 0x0079, 0x007A, 0x0388, 0x25A0},
99 { 0x0020, 0x0639, 0xFEC9, 0xFE83, 0xFE85, 0xFE87, 0xFE8B, 0xFE89, 0xFB7C, 0xFB7D, 0xFB7A, 0xFB58, 0xFB59, 0xFB56, 0xFB6D, 0xFB8E,
100 0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667, 0x0668, 0x0669, 0xFECE, 0xFECD, 0xFEFC, 0xFEEC, 0xFEEA, 0xFEE9,
101 0x00E0, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
102 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005A, 0x00EB, 0x00EA, 0x00F9, 0x00EE, 0xFECA,
103 0x00E9, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
104 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x00E2, 0x00F4, 0x00FB, 0x00E7, 0x25A0}
107 //const (avoid warnings :<)
108 TextPageAttr_t Text_AtrTable
[] =
110 { TXT_ColorWhite
, TXT_ColorBlack
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_WB */
111 { TXT_ColorWhite
, TXT_ColorBlack
, C_G0P
, 0, 0, 1 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_PassiveDefault */
112 { TXT_ColorWhite
, TXT_ColorRed
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_L250 */
113 { TXT_ColorBlack
, TXT_ColorGreen
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_L251 */
114 { TXT_ColorBlack
, TXT_ColorYellow
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_L252 */
115 { TXT_ColorWhite
, TXT_ColorBlue
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_L253 */
116 { TXT_ColorMagenta
, TXT_ColorBlack
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_TOPMENU0 */
117 { TXT_ColorGreen
, TXT_ColorBlack
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_TOPMENU1 */
118 { TXT_ColorYellow
, TXT_ColorBlack
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_TOPMENU2 */
119 { TXT_ColorCyan
, TXT_ColorBlack
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_TOPMENU3 */
120 { TXT_ColorMenu2
, TXT_ColorMenu3
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSG0 */
121 { TXT_ColorYellow
, TXT_ColorMenu3
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSG1 */
122 { TXT_ColorMenu2
, TXT_ColorTransp
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSG2 */
123 { TXT_ColorWhite
, TXT_ColorMenu3
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSG3 */
124 { TXT_ColorMenu2
, TXT_ColorMenu1
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSGDRM0 */
125 { TXT_ColorYellow
, TXT_ColorMenu1
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSGDRM1 */
126 { TXT_ColorMenu2
, TXT_ColorBlack
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSGDRM2 */
127 { TXT_ColorWhite
, TXT_ColorMenu1
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSGDRM3 */
128 { TXT_ColorMenu1
, TXT_ColorBlue
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENUHIL0 5a Z */
129 { TXT_ColorWhite
, TXT_ColorBlue
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENUHIL1 58 X */
130 { TXT_ColorMenu2
, TXT_ColorTransp
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENUHIL2 9b õ */
131 { TXT_ColorMenu2
, TXT_ColorMenu1
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENU0 ab ´ */
132 { TXT_ColorYellow
, TXT_ColorMenu1
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENU1 a4 § */
133 { TXT_ColorMenu2
, TXT_ColorTransp
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENU2 9b õ */
134 { TXT_ColorMenu2
, TXT_ColorMenu3
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENU3 cb À */
135 { TXT_ColorCyan
, TXT_ColorMenu3
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENU4 c7 « */
136 { TXT_ColorWhite
, TXT_ColorMenu3
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENU5 c8 » */
137 { TXT_ColorWhite
, TXT_ColorMenu1
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENU6 a8 ® */
138 { TXT_ColorYellow
, TXT_ColorMenu1
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_CATCHMENU0 a4 § */
139 { TXT_ColorWhite
, TXT_ColorMenu1
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f} /* ATR_CATCHMENU1 a8 ® */
146 S_FHL
, /* full horizontal line: y-offset */
147 S_FVL
, /* full vertical line: x-offset */
148 S_BOX
, /* rectangle: x-offset, y-offset, width, height */
149 S_TRA
, /* trapez: x0, y0, l0, x1, y1, l1 */
150 S_BTR
, /* trapez in bgcolor: x0, y0, l0, x1, y1, l1 */
152 S_LNK
, /* call other shape: shapenumber */
153 S_CHR
, /* Character from freetype hibyte, lowbyte */
154 S_ADT
, /* Character 2F alternating raster */
155 S_FLH
, /* flip horizontal */
156 S_FLV
/* flip vertical */
159 /* shape coordinates */
162 S_W13
= 5, /* width*1/3 */
163 S_W12
, /* width*1/2 */
164 S_W23
, /* width*2/3 */
167 S_H13
, /* height*1/3 */
168 S_H12
, /* height*1/2 */
169 S_H23
, /* height*2/3 */
175 unsigned char aG3_20
[] = { S_TRA
, 0, S_H23
, 1, 0, S_H11
, S_W12
, S_END
};
176 unsigned char aG3_21
[] = { S_TRA
, 0, S_H23
, 1, 0, S_H11
, S_W11
, S_END
};
177 unsigned char aG3_22
[] = { S_TRA
, 0, S_H12
, 1, 0, S_H11
, S_W12
, S_END
};
178 unsigned char aG3_23
[] = { S_TRA
, 0, S_H12
, 1, 0, S_H11
, S_W11
, S_END
};
179 unsigned char aG3_24
[] = { S_TRA
, 0, 0, 1, 0, S_H11
, S_W12
, S_END
};
180 unsigned char aG3_25
[] = { S_TRA
, 0, 0, 1, 0, S_H11
, S_W11
, S_END
};
181 unsigned char aG3_26
[] = { S_INV
, S_LNK
, 0x66, S_END
};
182 unsigned char aG3_27
[] = { S_INV
, S_LNK
, 0x67, S_END
};
183 unsigned char aG3_28
[] = { S_INV
, S_LNK
, 0x68, S_END
};
184 unsigned char aG3_29
[] = { S_INV
, S_LNK
, 0x69, S_END
};
185 unsigned char aG3_2a
[] = { S_INV
, S_LNK
, 0x6a, S_END
};
186 unsigned char aG3_2b
[] = { S_INV
, S_LNK
, 0x6b, S_END
};
187 unsigned char aG3_2c
[] = { S_INV
, S_LNK
, 0x6c, S_END
};
188 unsigned char aG3_2d
[] = { S_INV
, S_LNK
, 0x6d, S_END
};
189 unsigned char aG3_2e
[] = { S_BOX
, 2, 0, 3, S_H11
, S_END
};
190 unsigned char aG3_2f
[] = { S_ADT
};
191 unsigned char aG3_30
[] = { S_LNK
, 0x20, S_FLH
, S_END
};
192 unsigned char aG3_31
[] = { S_LNK
, 0x21, S_FLH
, S_END
};
193 unsigned char aG3_32
[] = { S_LNK
, 0x22, S_FLH
, S_END
};
194 unsigned char aG3_33
[] = { S_LNK
, 0x23, S_FLH
, S_END
};
195 unsigned char aG3_34
[] = { S_LNK
, 0x24, S_FLH
, S_END
};
196 unsigned char aG3_35
[] = { S_LNK
, 0x25, S_FLH
, S_END
};
197 unsigned char aG3_36
[] = { S_INV
, S_LNK
, 0x76, S_END
};
198 unsigned char aG3_37
[] = { S_INV
, S_LNK
, 0x77, S_END
};
199 unsigned char aG3_38
[] = { S_INV
, S_LNK
, 0x78, S_END
};
200 unsigned char aG3_39
[] = { S_INV
, S_LNK
, 0x79, S_END
};
201 unsigned char aG3_3a
[] = { S_INV
, S_LNK
, 0x7a, S_END
};
202 unsigned char aG3_3b
[] = { S_INV
, S_LNK
, 0x7b, S_END
};
203 unsigned char aG3_3c
[] = { S_INV
, S_LNK
, 0x7c, S_END
};
204 unsigned char aG3_3d
[] = { S_INV
, S_LNK
, 0x7d, S_END
};
205 unsigned char aG3_3e
[] = { S_LNK
, 0x2e, S_FLH
, S_END
};
206 unsigned char aG3_3f
[] = { S_BOX
, 0, 0, S_W11
, S_H11
, S_END
};
207 unsigned char aG3_40
[] = { S_BOX
, 0, S_H13
, S_W11
, S_H13
, S_LNK
, 0x7e, S_END
};
208 unsigned char aG3_41
[] = { S_BOX
, 0, S_H13
, S_W11
, S_H13
, S_LNK
, 0x7e, S_FLV
, S_END
};
209 unsigned char aG3_42
[] = { S_LNK
, 0x50, S_BOX
, S_W12
, S_H13
, S_W12
, S_H13
, S_END
};
210 unsigned char aG3_43
[] = { S_LNK
, 0x50, S_BOX
, 0, S_H13
, S_W12
, S_H13
, S_END
};
211 unsigned char aG3_44
[] = { S_LNK
, 0x48, S_FLV
, S_LNK
, 0x48, S_END
};
212 unsigned char aG3_45
[] = { S_LNK
, 0x44, S_FLH
, S_END
};
213 unsigned char aG3_46
[] = { S_LNK
, 0x47, S_FLV
, S_END
};
214 unsigned char aG3_47
[] = { S_LNK
, 0x48, S_FLH
, S_LNK
, 0x48, S_END
};
215 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
};
216 unsigned char aG3_49
[] = { S_LNK
, 0x48, S_FLH
, S_END
};
217 unsigned char aG3_4a
[] = { S_LNK
, 0x48, S_FLV
, S_END
};
218 unsigned char aG3_4b
[] = { S_LNK
, 0x48, S_FLH
, S_FLV
, S_END
};
219 unsigned char aG3_4c
[] = { S_LNK
, 0x50, S_BOX
, 0, S_H13
, S_W11
, S_H13
, S_END
};
220 unsigned char aG3_4d
[] = { S_CHR
, 0x25, 0xE6 };
221 unsigned char aG3_4e
[] = { S_CHR
, 0x25, 0xCF };
222 unsigned char aG3_4f
[] = { S_CHR
, 0x25, 0xCB };
223 unsigned char aG3_50
[] = { S_BOX
, S_W12
, 0, 2, S_H11
, S_FLH
, S_BOX
, S_W12
, 0, 2, S_H11
,S_END
};
224 unsigned char aG3_51
[] = { S_BOX
, 0, S_H12
, S_W11
, 2, S_FLV
, S_BOX
, 0, S_H12
, S_W11
, 2,S_END
};
225 unsigned char aG3_52
[] = { S_LNK
, 0x55, S_FLH
, S_FLV
, S_END
};
226 unsigned char aG3_53
[] = { S_LNK
, 0x55, S_FLV
, S_END
};
227 unsigned char aG3_54
[] = { S_LNK
, 0x55, S_FLH
, S_END
};
228 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
};
229 unsigned char aG3_56
[] = { S_LNK
, 0x57, S_FLH
, S_END
};
230 unsigned char aG3_57
[] = { S_LNK
, 0x55, S_LNK
, 0x50 , S_END
};
231 unsigned char aG3_58
[] = { S_LNK
, 0x59, S_FLV
, S_END
};
232 unsigned char aG3_59
[] = { S_LNK
, 0x7e, S_LNK
, 0x51 , S_END
};
233 unsigned char aG3_5a
[] = { S_LNK
, 0x50, S_LNK
, 0x51 , S_END
};
234 unsigned char aG3_5b
[] = { S_CHR
, 0x21, 0x92};
235 unsigned char aG3_5c
[] = { S_CHR
, 0x21, 0x90};
236 unsigned char aG3_5d
[] = { S_CHR
, 0x21, 0x91};
237 unsigned char aG3_5e
[] = { S_CHR
, 0x21, 0x93};
238 unsigned char aG3_5f
[] = { S_CHR
, 0x00, 0x20};
239 unsigned char aG3_60
[] = { S_INV
, S_LNK
, 0x20, S_END
};
240 unsigned char aG3_61
[] = { S_INV
, S_LNK
, 0x21, S_END
};
241 unsigned char aG3_62
[] = { S_INV
, S_LNK
, 0x22, S_END
};
242 unsigned char aG3_63
[] = { S_INV
, S_LNK
, 0x23, S_END
};
243 unsigned char aG3_64
[] = { S_INV
, S_LNK
, 0x24, S_END
};
244 unsigned char aG3_65
[] = { S_INV
, S_LNK
, 0x25, S_END
};
245 unsigned char aG3_66
[] = { S_LNK
, 0x20, S_FLV
, S_END
};
246 unsigned char aG3_67
[] = { S_LNK
, 0x21, S_FLV
, S_END
};
247 unsigned char aG3_68
[] = { S_LNK
, 0x22, S_FLV
, S_END
};
248 unsigned char aG3_69
[] = { S_LNK
, 0x23, S_FLV
, S_END
};
249 unsigned char aG3_6a
[] = { S_LNK
, 0x24, S_FLV
, S_END
};
250 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
};
251 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
};
252 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
};
253 unsigned char aG3_6e
[] = { S_CHR
, 0x00, 0x20};
254 unsigned char aG3_6f
[] = { S_CHR
, 0x00, 0x20};
255 unsigned char aG3_70
[] = { S_INV
, S_LNK
, 0x30, S_END
};
256 unsigned char aG3_71
[] = { S_INV
, S_LNK
, 0x31, S_END
};
257 unsigned char aG3_72
[] = { S_INV
, S_LNK
, 0x32, S_END
};
258 unsigned char aG3_73
[] = { S_INV
, S_LNK
, 0x33, S_END
};
259 unsigned char aG3_74
[] = { S_INV
, S_LNK
, 0x34, S_END
};
260 unsigned char aG3_75
[] = { S_INV
, S_LNK
, 0x35, S_END
};
261 unsigned char aG3_76
[] = { S_LNK
, 0x66, S_FLH
, S_END
};
262 unsigned char aG3_77
[] = { S_LNK
, 0x67, S_FLH
, S_END
};
263 unsigned char aG3_78
[] = { S_LNK
, 0x68, S_FLH
, S_END
};
264 unsigned char aG3_79
[] = { S_LNK
, 0x69, S_FLH
, S_END
};
265 unsigned char aG3_7a
[] = { S_LNK
, 0x6a, S_FLH
, S_END
};
266 unsigned char aG3_7b
[] = { S_LNK
, 0x6b, S_FLH
, S_END
};
267 unsigned char aG3_7c
[] = { S_LNK
, 0x6c, S_FLH
, S_END
};
268 unsigned char aG3_7d
[] = { S_LNK
, 0x6d, S_FLV
, S_END
};
269 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)
271 unsigned char *aShapes
[] =
273 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
,
274 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
,
275 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
,
276 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
,
277 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
,
278 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
281 // G0 Table as defined in ETS 300 706
282 // cyrillic G0 Charset (0 = Serbian/Croatian, 1 = Russian/Bulgarian, 2 = Ukrainian)
283 const unsigned short int G0table
[6][6*16] =
285 // Cyrillic G0 Set - Option 1 - Serbian/Croatian
286 { ' ', '!', '\"', '#', '$', '%', '&', '\'', '(' , ')' , '*', '+', ',', '-', '.', '/',
287 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
288 0x0427, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, 0x0425, 0x0418, 0x0408, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E,
289 0x041F, 0x040C, 0x0420, 0x0421, 0x0422, 0x0423, 0x0412, 0x0403, 0x0409, 0x040A, 0x0417, 0x040B, 0x0416, 0x0402, 0x0428, 0x040F,
290 0x0447, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, 0x0445, 0x0438, 0x0458, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E,
291 0x043F, 0x045C, 0x0440, 0x0441, 0x0442, 0x0443, 0x0432, 0x0453, 0x0459, 0x045A, 0x0437, 0x045B, 0x0436, 0x0452, 0x0448, 0x25A0},
292 // Cyrillic G0 Set - Option 2 - Russian/Bulgarian
293 { ' ', '!', '\"', '#', '$', '%', 0x044B, '\'', '(' , ')' , '*', '+', ',', '-', '.', '/',
294 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
295 0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, 0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E,
296 0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, 0x042C, 0x042A, 0x0417, 0x0428, 0x042D, 0x0429, 0x0427, 0x042B,
297 0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, 0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E,
298 0x043F, 0x044F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, 0x044C, 0x044A, 0x0437, 0x0448, 0x044D, 0x0449, 0x0447, 0x25A0},
299 // Cyrillic G0 Set - Option 3 - Ukrainian
300 { ' ', '!', '\"', '#', '$', '%', 0x0457, '\'', '(' , ')' , '*', '+', ',', '-', '.', '/',
301 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
302 0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, 0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E,
303 0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, 0x042C, 0x0406, 0x0417, 0x0428, 0x0404, 0x0429, 0x0427, 0x0407,
304 0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, 0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E,
305 0x043F, 0x044F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, 0x044C, 0x0456, 0x0437, 0x0448, 0x0454, 0x0449, 0x0447, 0x25A0},
307 { ' ', '!', '\"', '#', '$', '%', '&', '\'', '(' , ')' , '*', '+', ',', '-', '.', '/',
308 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', 0x00AB, '=', 0x00BB, '?',
309 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F,
310 0x03A0, 0x03A1, 0x0384, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF,
311 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
312 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0x25A0},
314 { ' ', '!', 0x05F2, 0x00A3, '$', '%', '&', '\'', '(' , ')' , '*', '+', ',', '-', '.', '/',
315 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
316 '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
317 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 0x2190, 0x00BD, 0x2192, 0x2191, '#',
318 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
319 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x20AA, 0x2551, 0x00BE, 0x00F7, 0x25A0},
320 // Arabic G0 Set - Thanks to Habib2006(fannansat)
321 { ' ', '!', 0x05F2, 0x00A3, '$', 0x066A, 0xFEF0, 0xFEF2, 0xFD3F, 0xFD3E, '*', '+', ',', '-', '.', '/',
322 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', 0x061B, '>', '=', '<', 0x061F,
323 0xFE94, 0x0621, 0xFE92, 0x0628, 0xFE98, 0x062A, 0xFE8E, 0xFE8D, 0xFE91, 0xFE93, 0xFE97, 0xFE9B, 0xFE9F, 0xFEA3, 0xFEA7, 0xFEA9,
324 0x0630, 0xFEAD, 0xFEAF, 0xFEB3, 0xFEB7, 0xFEBB, 0xFEBF, 0xFEC1, 0xFEC5, 0xFECB, 0xFECF, 0xFE9C, 0xFEA0, 0xFEA4, 0xFEA8, 0x0023,
325 0x0640, 0xFED3, 0xFED7, 0xFEDB, 0xFEDF, 0xFEE3, 0xFEE7, 0xFEEB, 0xFEED, 0xFEEF, 0xFEF3, 0xFE99, 0xFE9D, 0xFEA1, 0xFEA5, 0xFEF4,
326 0xFEF0, 0xFECC, 0xFED0, 0xFED4, 0xFED1, 0xFED8, 0xFED5, 0xFED9, 0xFEE0, 0xFEDD, 0xFEE4, 0xFEE1, 0xFEE8, 0xFEE5, 0xFEFB, 0x25A0}
329 const unsigned short int nationaltable23
[14][2] =
331 { '#', 0x00A4 }, /* 0 */
332 { '#', 0x016F }, /* 1 CS/SK */
333 { 0x00A3, '$' }, /* 2 EN */
334 { '#', 0x00F5 }, /* 3 ET */
335 { 0x00E9, 0x0457 }, /* 4 FR */
336 { '#', '$' }, /* 5 DE */
337 { 0x00A3, '$' }, /* 6 IT */
338 { '#', '$' }, /* 7 LV/LT */
339 { '#', 0x0144 }, /* 8 PL */
340 { 0x00E7, '$' }, /* 9 PT/ES */
341 { '#', 0x00A4 }, /* A RO */
342 { '#', 0x00CB }, /* B SR/HR/SL */
343 { '#', 0x00A4 }, /* C SV/FI/HU */
344 { 0x20A4, 0x011F }, /* D TR */
346 const unsigned short int nationaltable40
[14] =
349 0x010D, /* 1 CS/SK */
355 0x0161, /* 7 LV/LT */
357 0x00A1, /* 9 PT/ES */
359 0x010C, /* B SR/HR/SL */
360 0x00C9, /* C SV/FI/HU */
363 const unsigned short int nationaltable5b
[14][6] =
365 { '[', '\\', ']', '^', '_', '`' }, /* 0 */
366 { 0x0165, 0x017E, 0x00FD, 0x00ED, 0x0159, 0x00E9 }, /* 1 CS/SK */
367 { 0x2190, 0x00BD, 0x2192, 0x2191, '#', 0x00AD }, /* 2 EN */
368 { 0x00C4, 0x00D6, 0x017D, 0x00DC, 0x00D5, 0x0161 }, /* 3 ET */
369 { 0x0451, 0x00EA, 0x00F9, 0x00EE, '#', 0x00E8 }, /* 4 FR */
370 { 0x00C4, 0x00D6, 0x00DC, '^', '_', 0x00B0 }, /* 5 DE */
371 { 0x00B0, 0x00E7, 0x2192, 0x2191, '#', 0x00F9 }, /* 6 IT */
372 { 0x0117, 0x0119, 0x017D, 0x010D, 0x016B, 0x0161 }, /* 7 LV/LT */
373 { 0x017B, 0x015A, 0x0141, 0x0107, 0x00F3, 0x0119 }, /* 8 PL */
374 { 0x00E1, 0x00E9, 0x00ED, 0x00F3, 0x00FA, 0x00BF }, /* 9 PT/ES */
375 { 0x00C2, 0x015E, 0x01CD, 0x01CF, 0x0131, 0x0163 }, /* A RO */
376 { 0x0106, 0x017D, 0x00D0, 0x0160, 0x0451, 0x010D }, /* B SR/HR/SL */
377 { 0x00C4, 0x00D6, 0x00C5, 0x00DC, '_', 0x00E9 }, /* C SV/FI/HU */
378 { 0x015E, 0x00D6, 0x00C7, 0x00DC, 0x011E, 0x0131 }, /* D TR */
380 const unsigned short int nationaltable7b
[14][4] =
382 { '{', '|', '}', '~' }, /* 0 */
383 { 0x00E1, 0x011B, 0x00FA, 0x0161 }, /* 1 CS/SK */
384 { 0x00BC, 0x2551, 0x00BE, 0x00F7 }, /* 2 EN */
385 { 0x00E4, 0x00F6, 0x017E, 0x00FC }, /* 3 ET */
386 { 0x00E2, 0x00F4, 0x00FB, 0x00E7 }, /* 4 FR */
387 { 0x00E4, 0x00F6, 0x00FC, 0x00DF }, /* 5 DE */
388 { 0x00E0, 0x00F3, 0x00E8, 0x00EC }, /* 6 IT */
389 { 0x0105, 0x0173, 0x017E, 0x012F }, /* 7 LV/LT */
390 { 0x017C, 0x015B, 0x0142, 0x017A }, /* 8 PL */
391 { 0x00FC, 0x00F1, 0x00E8, 0x00E0 }, /* 9 PT/ES */
392 { 0x00E2, 0x015F, 0x01CE, 0x00EE }, /* A RO */
393 { 0x0107, 0x017E, 0x0111, 0x0161 }, /* B SR/HR/SL */
394 { 0x00E4, 0x00F6, 0x00E5, 0x00FC }, /* C SV/FI/HU */
395 { 0x015F, 0x00F6, 0x00E7, 0x00FC }, /* D TR */
397 const unsigned short int arrowtable
[] =
399 8592, 8594, 8593, 8595, 'O', 'K', 8592, 8592
402 CTeletextDecoder::CTeletextDecoder()
404 memset(&m_RenderInfo
, 0, sizeof(TextRenderInfo_t
));
406 m_teletextFont
= CSpecialProtocol::TranslatePath(TeletextFont
);
407 m_TextureBuffer
= NULL
;
411 m_RenderInfo
.ShowFlof
= true;
412 m_RenderInfo
.Show39
= false;
413 m_RenderInfo
.Showl25
= true;
414 m_RenderInfo
.Prev_100
= 0x100;
415 m_RenderInfo
.Prev_10
= 0x100;
416 m_RenderInfo
.Next_100
= 0x100;
417 m_RenderInfo
.Next_10
= 0x100;
418 m_RenderInfo
.InputCounter
= 2;
420 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 };
421 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 };
422 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 };
423 unsigned short tr0
[] = {0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
424 0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
425 0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
426 0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
427 0x0000 , 0x0000 , 0x0A0A , 0xFFFF, 0x3030 };
429 memcpy(m_RenderInfo
.rd0
,rd0
,TXT_Color_SIZECOLTABLE
*sizeof(unsigned short));
430 memcpy(m_RenderInfo
.gn0
,gn0
,TXT_Color_SIZECOLTABLE
*sizeof(unsigned short));
431 memcpy(m_RenderInfo
.bl0
,bl0
,TXT_Color_SIZECOLTABLE
*sizeof(unsigned short));
432 memcpy(m_RenderInfo
.tr0
,tr0
,TXT_Color_SIZECOLTABLE
*sizeof(unsigned short));
444 m_updateTexture
= false;
448 CTeletextDecoder::~CTeletextDecoder() = default;
450 bool CTeletextDecoder::Changed()
452 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
453 if (IsSubtitlePage(m_txtCache
->Page
))
455 m_updateTexture
= true;
459 /* Update on every changed second */
460 if (m_txtCache
->TimeString
[7] != prevTimeSec
)
462 prevTimeSec
= m_txtCache
->TimeString
[7];
463 m_updateTexture
= true;
469 bool CTeletextDecoder::HandleAction(const CAction
&action
)
471 if (m_txtCache
== NULL
)
473 CLog::Log(LOGERROR
, "CTeletextDecoder::HandleAction called without teletext cache");
477 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
479 if (action
.GetID() == ACTION_MOVE_UP
)
481 if (m_RenderInfo
.PageCatching
)
482 CatchNextPage(-1, -1);
484 GetNextPageOne(true);
487 else if (action
.GetID() == ACTION_MOVE_DOWN
)
489 if (m_RenderInfo
.PageCatching
)
492 GetNextPageOne(false);
495 else if (action
.GetID() == ACTION_MOVE_RIGHT
)
497 if (m_RenderInfo
.PageCatching
)
499 else if (m_RenderInfo
.Boxed
)
501 m_RenderInfo
.SubtitleDelay
++;
502 // display SubtitleDelay
503 m_RenderInfo
.PosY
= 0;
506 snprintf(ns
, sizeof(ns
), "+%d ", m_RenderInfo
.SubtitleDelay
);
507 RenderCharFB(ns
[0], &Text_AtrTable
[ATR_WB
]);
508 RenderCharFB(ns
[1], &Text_AtrTable
[ATR_WB
]);
509 RenderCharFB(ns
[2], &Text_AtrTable
[ATR_WB
]);
510 RenderCharFB(ns
[4], &Text_AtrTable
[ATR_WB
]);
518 else if (action
.GetID() == ACTION_MOVE_LEFT
)
520 if (m_RenderInfo
.PageCatching
)
521 CatchNextPage(0, -1);
522 else if (m_RenderInfo
.Boxed
)
524 m_RenderInfo
.SubtitleDelay
--;
526 // display subtitledelay
527 m_RenderInfo
.PosY
= 0;
530 snprintf(ns
, sizeof(ns
), "+%d ", m_RenderInfo
.SubtitleDelay
);
531 RenderCharFB(ns
[0], &Text_AtrTable
[ATR_WB
]);
532 RenderCharFB(ns
[1], &Text_AtrTable
[ATR_WB
]);
533 RenderCharFB(ns
[2], &Text_AtrTable
[ATR_WB
]);
534 RenderCharFB(ns
[4], &Text_AtrTable
[ATR_WB
]);
542 else if (action
.GetID() >= REMOTE_0
&& action
.GetID() <= REMOTE_9
)
544 PageInput(action
.GetID() - REMOTE_0
);
547 else if (action
.GetID() == KEY_UNICODE
)
548 { // input from the keyboard
549 if (action
.GetUnicode() >= 48 && action
.GetUnicode() < 58)
551 PageInput(action
.GetUnicode() - 48);
556 else if (action
.GetID() == ACTION_PAGE_UP
)
561 else if (action
.GetID() == ACTION_PAGE_DOWN
)
566 else if (action
.GetID() == ACTION_SELECT_ITEM
)
568 if (m_txtCache
->SubPageTable
[m_txtCache
->Page
] == 0xFF)
571 if (!m_RenderInfo
.PageCatching
)
579 if (m_RenderInfo
.PageCatching
)
581 m_txtCache
->PageUpdate
= true;
582 m_RenderInfo
.PageCatching
= false;
586 if (action
.GetID() == ACTION_SHOW_INFO
)
591 else if (action
.GetID() == ACTION_TELETEXT_RED
)
593 ColorKey(m_RenderInfo
.Prev_100
);
596 else if (action
.GetID() == ACTION_TELETEXT_GREEN
)
598 ColorKey(m_RenderInfo
.Prev_10
);
601 else if (action
.GetID() == ACTION_TELETEXT_YELLOW
)
603 ColorKey(m_RenderInfo
.Next_10
);
606 else if (action
.GetID() == ACTION_TELETEXT_BLUE
)
608 ColorKey(m_RenderInfo
.Next_100
);
615 bool CTeletextDecoder::InitDecoder()
619 auto& components
= CServiceBroker::GetAppComponents();
620 const auto appPlayer
= components
.GetComponent
<CApplicationPlayer
>();
621 m_txtCache
= appPlayer
->GetTeletextCache();
622 if (m_txtCache
== nullptr)
624 CLog::Log(LOGERROR
, "{}: called without teletext cache", __FUNCTION__
);
628 /* init fontlibrary */
629 if ((error
= FT_Init_FreeType(&m_Library
)))
631 CLog::Log(LOGERROR
, "{}: <FT_Init_FreeType: {:#2X}>", __FUNCTION__
, error
);
636 if ((error
= FTC_Manager_New(m_Library
, 7, 2, 0, &MyFaceRequester
, NULL
, &m_Manager
)))
638 FT_Done_FreeType(m_Library
);
641 CLog::Log(LOGERROR
, "{}: <FTC_Manager_New: {:#2X}>", __FUNCTION__
, error
);
645 if ((error
= FTC_SBitCache_New(m_Manager
, &m_Cache
)))
647 FTC_Manager_Done(m_Manager
);
648 FT_Done_FreeType(m_Library
);
651 CLog::Log(LOGERROR
, "{}: <FTC_SBit_Cache_New: {:#2X}>", __FUNCTION__
, error
);
655 /* calculate font dimensions */
656 m_RenderInfo
.Width
= (int)(CServiceBroker::GetWinSystem()->GetGfxContext().GetWidth()*CServiceBroker::GetWinSystem()->GetGfxContext().GetGUIScaleX());
657 m_RenderInfo
.Height
= (int)(CServiceBroker::GetWinSystem()->GetGfxContext().GetHeight()*CServiceBroker::GetWinSystem()->GetGfxContext().GetGUIScaleY());
658 m_RenderInfo
.FontHeight
= m_RenderInfo
.Height
/ 25;
659 m_RenderInfo
.FontWidth_Normal
= m_RenderInfo
.Width
/ (m_RenderInfo
.Show39
? 39 : 40);
660 SetFontWidth(m_RenderInfo
.FontWidth_Normal
);
661 for (int i
= 0; i
<= 10; i
++)
662 m_RenderInfo
.axdrcs
[i
+12+1] = (m_RenderInfo
.FontHeight
* i
+ 6) / 10;
665 m_TypeTTF
.face_id
= (FTC_FaceID
) const_cast<char*>(m_teletextFont
.c_str());
666 m_TypeTTF
.height
= (FT_UShort
) m_RenderInfo
.FontHeight
;
667 m_TypeTTF
.flags
= FT_LOAD_MONOCHROME
;
668 if (FTC_Manager_LookupFace(m_Manager
, m_TypeTTF
.face_id
, &m_Face
))
670 m_TypeTTF
.face_id
= (FTC_FaceID
) const_cast<char*>(m_teletextFont
.c_str());
671 if ((error
= FTC_Manager_LookupFace(m_Manager
, m_TypeTTF
.face_id
, &m_Face
)))
673 CLog::Log(LOGERROR
, "{}: <FTC_Manager_Lookup_Face failed with Errorcode {:#2X}>",
674 __FUNCTION__
, error
);
675 FTC_Manager_Done(m_Manager
);
676 FT_Done_FreeType(m_Library
);
682 m_Ascender
= m_RenderInfo
.FontHeight
* m_Face
->ascender
/ m_Face
->units_per_EM
;
684 /* set variable screeninfo for double buffering */
686 m_TextureBuffer
= new UTILS::COLOR::Color
[4 * m_RenderInfo
.Height
* m_RenderInfo
.Width
];
688 ClearFB(GetColorRGB(TXT_ColorTransp
));
689 ClearBB(GetColorRGB(TXT_ColorTransp
)); /* initialize backbuffer */
690 /* set new colormap */
691 SetColors(DefaultColors
, 0, TXT_Color_SIZECOLTABLE
);
693 for (int i
= 0; i
< 40 * 25; i
++)
695 m_RenderInfo
.PageChar
[i
] = ' ';
696 m_RenderInfo
.PageAtrb
[i
].fg
= TXT_ColorTransp
;
697 m_RenderInfo
.PageAtrb
[i
].bg
= TXT_ColorTransp
;
698 m_RenderInfo
.PageAtrb
[i
].charset
= C_G0P
;
699 m_RenderInfo
.PageAtrb
[i
].doubleh
= 0;
700 m_RenderInfo
.PageAtrb
[i
].doublew
= 0;
701 m_RenderInfo
.PageAtrb
[i
].IgnoreAtBlackBgSubst
= 0;
704 m_RenderInfo
.TranspMode
= false;
710 void CTeletextDecoder::EndDecoder()
712 /* clear SubtitleCache */
713 for (TextSubtitleCache_t
*& subtitleCache
: m_RenderInfo
.SubtitleCache
)
715 if (subtitleCache
!= NULL
)
717 delete subtitleCache
;
718 subtitleCache
= NULL
;
724 delete[] m_TextureBuffer
;
725 m_TextureBuffer
= NULL
;
731 FTC_Node_Unref(m_anode
, m_Manager
);
732 FTC_Manager_Done(m_Manager
);
736 FT_Done_FreeType(m_Library
);
744 CLog::Log(LOGINFO
, "{}: called without cache", __FUNCTION__
);
748 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
749 m_txtCache
->PageUpdate
= true;
750 CLog::Log(LOGDEBUG
, "Teletext: Rendering ended");
754 void CTeletextDecoder::PageInput(int Number
)
756 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
758 m_updateTexture
= true;
760 /* clear m_TempPage */
761 if (m_RenderInfo
.InputCounter
== 2)
764 /* check for 0 & 9 on first position */
765 if (Number
== 0 && m_RenderInfo
.InputCounter
== 2)
768 m_TempPage
= m_LastPage
; /* 0 toggles to last page as in program switching */
769 m_RenderInfo
.InputCounter
= -1;
771 else if (Number
== 9 && m_RenderInfo
.InputCounter
== 2)
777 if (m_RenderInfo
.ZoomMode
== 2)
779 m_RenderInfo
.ZoomMode
= 1;
783 m_RenderInfo
.PosY
= 0;
785 switch (m_RenderInfo
.InputCounter
)
789 RenderCharFB(Number
| '0', &Text_AtrTable
[ATR_WB
]);
790 RenderCharFB('-', &Text_AtrTable
[ATR_WB
]);
791 RenderCharFB('-', &Text_AtrTable
[ATR_WB
]);
796 RenderCharFB(Number
| '0', &Text_AtrTable
[ATR_WB
]);
801 RenderCharFB(Number
| '0', &Text_AtrTable
[ATR_WB
]);
805 /* generate pagenumber */
806 m_TempPage
|= Number
<< (m_RenderInfo
.InputCounter
*4);
808 m_RenderInfo
.InputCounter
--;
810 if (m_RenderInfo
.InputCounter
< 0)
812 /* disable SubPage zapping */
813 m_txtCache
->ZapSubpageManual
= false;
816 m_RenderInfo
.InputCounter
= 2;
819 m_LastPage
= m_txtCache
->Page
;
821 m_txtCache
->Page
= m_TempPage
;
822 m_RenderInfo
.HintMode
= false;
825 int subp
= m_txtCache
->SubPageTable
[m_txtCache
->Page
];
828 m_txtCache
->SubPage
= subp
;
829 m_txtCache
->PageUpdate
= true;
833 m_txtCache
->SubPage
= 0;
834 // RenderMessage(PageNotFound);
839 void CTeletextDecoder::GetNextPageOne(bool up
)
841 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
843 /* disable subpage zapping */
844 m_txtCache
->ZapSubpageManual
= false;
846 /* abort pageinput */
847 m_RenderInfo
.InputCounter
= 2;
849 /* find next cached page */
850 m_LastPage
= m_txtCache
->Page
;
855 CDVDTeletextTools::NextDec(&m_txtCache
->Page
);
857 CDVDTeletextTools::PrevDec(&m_txtCache
->Page
);
858 subp
= m_txtCache
->SubPageTable
[m_txtCache
->Page
];
859 } while (subp
== 0xFF && m_txtCache
->Page
!= m_LastPage
);
862 if (m_txtCache
->Page
!= m_LastPage
)
864 if (m_RenderInfo
.ZoomMode
== 2)
865 m_RenderInfo
.ZoomMode
= 1;
867 m_txtCache
->SubPage
= subp
;
868 m_RenderInfo
.HintMode
= false;
869 m_txtCache
->PageUpdate
= true;
873 void CTeletextDecoder::GetNextSubPage(int offset
)
875 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
877 /* abort pageinput */
878 m_RenderInfo
.InputCounter
= 2;
880 for (int loop
= m_txtCache
->SubPage
+ offset
; loop
!= m_txtCache
->SubPage
; loop
+= offset
)
884 else if (loop
> 0x79)
886 if (loop
== m_txtCache
->SubPage
)
889 if (m_txtCache
->astCachetable
[m_txtCache
->Page
][loop
])
891 /* enable manual SubPage zapping */
892 m_txtCache
->ZapSubpageManual
= true;
895 if (m_RenderInfo
.ZoomMode
== 2) /* if zoomed to lower half */
896 m_RenderInfo
.ZoomMode
= 1; /* activate upper half */
898 m_txtCache
->SubPage
= loop
;
899 m_RenderInfo
.HintMode
= false;
900 m_txtCache
->PageUpdate
= true;
907 void CTeletextDecoder::SwitchZoomMode()
909 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
911 if (m_txtCache
->SubPageTable
[m_txtCache
->Page
] != 0xFF)
914 m_RenderInfo
.ZoomMode
++;
916 if (m_RenderInfo
.ZoomMode
== 3)
917 m_RenderInfo
.ZoomMode
= 0;
920 m_txtCache
->PageUpdate
= true;
924 void CTeletextDecoder::SwitchTranspMode()
926 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
929 if (!m_RenderInfo
.TranspMode
)
930 m_RenderInfo
.TranspMode
= true;
932 m_RenderInfo
.TranspMode
= false; /* backward to immediately switch to TV-screen */
935 if (!m_RenderInfo
.TranspMode
) /* normal text-only */
937 ClearBB(m_txtCache
->FullScrColor
);
938 m_txtCache
->PageUpdate
= true;
940 else /* semi-transparent BG with FG text */
942 ClearBB(TXT_ColorTransp
);
943 m_txtCache
->PageUpdate
= true;
947 void CTeletextDecoder::SwitchHintMode()
949 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
952 m_RenderInfo
.HintMode
^= true;
954 if (!m_RenderInfo
.HintMode
) /* toggle evaluation of level 2.5 information by explicitly switching off HintMode */
956 m_RenderInfo
.Showl25
^= true;
959 m_txtCache
->PageUpdate
= true;
962 void CTeletextDecoder::ColorKey(int target
)
964 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
969 if (m_RenderInfo
.ZoomMode
== 2)
970 m_RenderInfo
.ZoomMode
= 1;
972 m_LastPage
= m_txtCache
->Page
;
973 m_txtCache
->Page
= target
;
974 m_txtCache
->SubPage
= m_txtCache
->SubPageTable
[m_txtCache
->Page
];
975 m_RenderInfo
.InputCounter
= 2;
976 m_RenderInfo
.HintMode
= false;
977 m_txtCache
->PageUpdate
= true;
980 void CTeletextDecoder::StartPageCatching()
982 m_RenderInfo
.PageCatching
= true;
984 /* abort pageinput */
985 m_RenderInfo
.InputCounter
= 2;
988 m_RenderInfo
.ZoomMode
= 0;
989 m_RenderInfo
.PosX
= 0;
990 m_RenderInfo
.PosY
= 24*m_RenderInfo
.FontHeight
;
992 /* check for pagenumber(s) */
997 m_PCOldCol
= 0; /* no inverted page number to restore yet */
1002 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
1004 m_RenderInfo
.PageCatching
= false;
1005 m_txtCache
->PageUpdate
= true;
1010 void CTeletextDecoder::StopPageCatching()
1012 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
1015 if (m_RenderInfo
.ZoomMode
== 2)
1016 m_RenderInfo
.ZoomMode
= 1;
1018 m_LastPage
= m_txtCache
->Page
;
1019 m_txtCache
->Page
= m_CatchedPage
;
1020 m_RenderInfo
.HintMode
= false;
1021 m_txtCache
->PageUpdate
= true;
1022 m_RenderInfo
.PageCatching
= false;
1024 int subp
= m_txtCache
->SubPageTable
[m_txtCache
->Page
];
1026 m_txtCache
->SubPage
= subp
;
1028 m_txtCache
->SubPage
= 0;
1031 void CTeletextDecoder::CatchNextPage(int firstlineinc
, int inc
)
1033 int tmp_page
, allowwrap
= 1; /* allow first wrap around */
1035 /* catch next page */
1038 unsigned char *p
= &(m_RenderInfo
.PageChar
[m_CatchRow
*40 + m_CatchCol
]);
1039 TextPageAttr_t a
= m_RenderInfo
.PageAtrb
[m_CatchRow
*40 + m_CatchCol
];
1041 if (!(a
.charset
== C_G1C
|| a
.charset
== C_G1S
) && /* no mosaic */
1042 (a
.fg
!= a
.bg
) && /* not hidden */
1043 (*p
>= '1' && *p
<= '8' && /* valid page number */
1044 *(p
+1) >= '0' && *(p
+1) <= '9' &&
1045 *(p
+2) >= '0' && *(p
+2) <= '9') &&
1046 (m_CatchRow
== 0 || (*(p
-1) < '0' || *(p
-1) > '9')) && /* non-numeric char before and behind */
1047 (m_CatchRow
== 37 || (*(p
+3) < '0' || *(p
+3) > '9')))
1049 tmp_page
= ((*p
- '0')<<8) | ((*(p
+1) - '0')<<4) | (*(p
+2) - '0');
1052 if (tmp_page
!= m_CatchedPage
) /* confusing to skip identical page numbers - I want to reach what I aim to */
1055 m_CatchedPage
= tmp_page
;
1056 RenderCatchedPage();
1057 m_CatchCol
+= inc
; /* FIXME: limit */
1062 if (firstlineinc
> 0)
1068 else if (firstlineinc
< 0)
1077 if (m_CatchCol
> 37)
1082 else if (m_CatchCol
< 0)
1088 if (m_CatchRow
> 23)
1101 else if (m_CatchRow
< 1)
1117 void CTeletextDecoder::RenderCatchedPage()
1120 m_updateTexture
= true;
1123 if (m_RenderInfo
.ZoomMode
)
1126 if (m_PCOldRow
|| m_PCOldCol
) /* not at first call */
1128 /* restore pagenumber */
1129 SetPosX(m_PCOldCol
);
1131 if (m_RenderInfo
.ZoomMode
== 2)
1132 m_RenderInfo
.PosY
= (m_PCOldRow
-12)*m_RenderInfo
.FontHeight
*((zoom
>>10)+1);
1134 m_RenderInfo
.PosY
= m_PCOldRow
*m_RenderInfo
.FontHeight
*((zoom
>>10)+1);
1136 RenderCharFB(m_RenderInfo
.PageChar
[m_PCOldRow
*40 + m_PCOldCol
], &m_RenderInfo
.PageAtrb
[m_PCOldRow
*40 + m_PCOldCol
]);
1137 RenderCharFB(m_RenderInfo
.PageChar
[m_PCOldRow
*40 + m_PCOldCol
+ 1], &m_RenderInfo
.PageAtrb
[m_PCOldRow
*40 + m_PCOldCol
+ 1]);
1138 RenderCharFB(m_RenderInfo
.PageChar
[m_PCOldRow
*40 + m_PCOldCol
+ 2], &m_RenderInfo
.PageAtrb
[m_PCOldRow
*40 + m_PCOldCol
+ 2]);
1141 m_PCOldRow
= m_CatchRow
;
1142 m_PCOldCol
= m_CatchCol
;
1144 /* mark pagenumber */
1145 if (m_RenderInfo
.ZoomMode
== 1 && m_CatchRow
> 11)
1147 m_RenderInfo
.ZoomMode
= 2;
1150 else if (m_RenderInfo
.ZoomMode
== 2 && m_CatchRow
< 12)
1152 m_RenderInfo
.ZoomMode
= 1;
1155 SetPosX(m_CatchCol
);
1157 if (m_RenderInfo
.ZoomMode
== 2)
1158 m_RenderInfo
.PosY
= (m_CatchRow
-12)*m_RenderInfo
.FontHeight
*((zoom
>>10)+1);
1160 m_RenderInfo
.PosY
= m_CatchRow
*m_RenderInfo
.FontHeight
*((zoom
>>10)+1);
1162 TextPageAttr_t a0
= m_RenderInfo
.PageAtrb
[m_CatchRow
*40 + m_CatchCol
];
1163 TextPageAttr_t a1
= m_RenderInfo
.PageAtrb
[m_CatchRow
*40 + m_CatchCol
+ 1];
1164 TextPageAttr_t a2
= m_RenderInfo
.PageAtrb
[m_CatchRow
*40 + m_CatchCol
+ 2];
1167 /* exchange colors */
1168 t
= a0
.fg
; a0
.fg
= a0
.bg
; a0
.bg
= t
;
1169 t
= a1
.fg
; a1
.fg
= a1
.bg
; a1
.bg
= t
;
1170 t
= a2
.fg
; a2
.fg
= a2
.bg
; a2
.bg
= t
;
1172 RenderCharFB(m_RenderInfo
.PageChar
[m_CatchRow
*40 + m_CatchCol
], &a0
);
1173 RenderCharFB(m_RenderInfo
.PageChar
[m_CatchRow
*40 + m_CatchCol
+ 1], &a1
);
1174 RenderCharFB(m_RenderInfo
.PageChar
[m_CatchRow
*40 + m_CatchCol
+ 2], &a2
);
1177 void CTeletextDecoder::RenderPage()
1179 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
1182 int national_subset_bak
= m_txtCache
->NationalSubset
;
1184 if (m_txtCache
->PageUpdate
)
1185 m_updateTexture
= true;
1187 /* update page or timestring */
1188 if (m_txtCache
->PageUpdate
&& m_txtCache
->PageReceiving
!= m_txtCache
->Page
&& m_RenderInfo
.InputCounter
== 2)
1190 /* reset update flag */
1191 m_txtCache
->PageUpdate
= false;
1192 if (m_RenderInfo
.Boxed
&& m_RenderInfo
.SubtitleDelay
)
1194 TextSubtitleCache_t
* c
= NULL
;
1196 for (int i
= 0; i
< SUBTITLE_CACHESIZE
; i
++)
1198 if (j
== -1 && !m_RenderInfo
.SubtitleCache
[i
])
1200 if (m_RenderInfo
.SubtitleCache
[i
] && !m_RenderInfo
.SubtitleCache
[i
]->Valid
)
1202 c
= m_RenderInfo
.SubtitleCache
[i
];
1208 if (j
== -1) // no more space in SubtitleCache
1211 c
= new TextSubtitleCache_t
;
1216 m_RenderInfo
.SubtitleCache
[j
] = c
;
1219 c
->Timestamp
= std::chrono::steady_clock::now();
1221 if (m_txtCache
->SubPageTable
[m_txtCache
->Page
] != 0xFF)
1223 TextPageinfo_t
* p
= DecodePage(m_RenderInfo
.Showl25
, c
->PageChar
, c
->PageAtrb
, m_RenderInfo
.HintMode
, m_RenderInfo
.ShowFlof
);
1226 m_RenderInfo
.Boxed
= p
->boxed
;
1229 m_RenderInfo
.DelayStarted
= true;
1232 m_RenderInfo
.DelayStarted
= false;
1234 if (m_txtCache
->SubPageTable
[m_txtCache
->Page
] != 0xFF)
1236 TextPageinfo_t
* p
= DecodePage(m_RenderInfo
.Showl25
, m_RenderInfo
.PageChar
, m_RenderInfo
.PageAtrb
, m_RenderInfo
.HintMode
, m_RenderInfo
.ShowFlof
);
1239 m_RenderInfo
.PageInfo
= p
;
1240 m_RenderInfo
.Boxed
= p
->boxed
;
1242 if (m_RenderInfo
.Boxed
|| m_RenderInfo
.TranspMode
)
1243 FillBorder(GetColorRGB(TXT_ColorTransp
));
1245 FillBorder(GetColorRGB((enumTeletextColor
)m_txtCache
->FullScrColor
));
1247 if (m_txtCache
->ColorTable
) /* as late as possible to shorten the time the old page is displayed with the new colors */
1248 SetColors(m_txtCache
->ColorTable
, 16, 16); /* set colors for CLUTs 2+3 */
1253 DoRenderPage(StartRow
, national_subset_bak
);
1257 if (m_RenderInfo
.DelayStarted
)
1259 auto now
= std::chrono::steady_clock::now();
1260 for (TextSubtitleCache_t
* const subtitleCache
: m_RenderInfo
.SubtitleCache
)
1262 if (subtitleCache
&& subtitleCache
->Valid
&&
1263 std::chrono::duration_cast
<std::chrono::seconds
>(now
- subtitleCache
->Timestamp
)
1264 .count() >= m_RenderInfo
.SubtitleDelay
)
1266 memcpy(m_RenderInfo
.PageChar
, subtitleCache
->PageChar
, 40 * 25);
1267 memcpy(m_RenderInfo
.PageAtrb
, subtitleCache
->PageAtrb
, 40 * 25 * sizeof(TextPageAttr_t
));
1268 DoRenderPage(StartRow
, national_subset_bak
);
1269 subtitleCache
->Valid
= false;
1274 if (m_RenderInfo
.ZoomMode
!= 2)
1276 m_RenderInfo
.PosY
= 0;
1277 if (m_txtCache
->SubPageTable
[m_txtCache
->Page
] == 0xff)
1279 m_RenderInfo
.PageAtrb
[32].fg
= TXT_ColorYellow
;
1280 m_RenderInfo
.PageAtrb
[32].bg
= TXT_ColorMenu1
;
1281 int showpage
= m_txtCache
->PageReceiving
;
1284 // Verify that showpage is positive before any access to the array
1285 if (showpage
>= 0 && (showsubpage
= m_txtCache
->SubPageTable
[showpage
]) != 0xff)
1287 TextCachedPage_t
*pCachedPage
;
1288 pCachedPage
= m_txtCache
->astCachetable
[showpage
][showsubpage
];
1289 if (pCachedPage
&& IsDec(showpage
))
1291 m_RenderInfo
.PosX
= 0;
1292 if (m_RenderInfo
.InputCounter
== 2)
1294 if (m_txtCache
->BTTok
&& !m_txtCache
->BasicTop
[m_txtCache
->Page
]) /* page non-existent according to TOP (continue search anyway) */
1296 m_RenderInfo
.PageAtrb
[0].fg
= TXT_ColorWhite
;
1297 m_RenderInfo
.PageAtrb
[0].bg
= TXT_ColorRed
;
1301 m_RenderInfo
.PageAtrb
[0].fg
= TXT_ColorYellow
;
1302 m_RenderInfo
.PageAtrb
[0].bg
= TXT_ColorMenu1
;
1304 CDVDTeletextTools::Hex2Str((char*)m_RenderInfo
.PageChar
+3, m_txtCache
->Page
);
1307 for (col
= m_RenderInfo
.nofirst
; col
< 7; col
++) // selected page
1309 RenderCharFB(m_RenderInfo
.PageChar
[col
], &m_RenderInfo
.PageAtrb
[0]);
1311 RenderCharFB(m_RenderInfo
.PageChar
[col
], &m_RenderInfo
.PageAtrb
[32]);
1316 memcpy(&m_RenderInfo
.PageChar
[8], pCachedPage
->p0
, 24); /* header line without timestring */
1317 for (unsigned char i
: pCachedPage
->p0
)
1319 RenderCharFB(i
, &m_RenderInfo
.PageAtrb
[32]);
1322 /* Update on every Header number change */
1323 if (pCachedPage
->p0
[2] != prevHeaderPage
)
1325 prevHeaderPage
= pCachedPage
->p0
[2];
1326 m_updateTexture
= true;
1332 /* update timestring */
1334 for (int i
= 0; i
< 8; i
++)
1336 if (!m_RenderInfo
.PageAtrb
[32+i
].flashing
)
1337 RenderCharFB(m_txtCache
->TimeString
[i
], &m_RenderInfo
.PageAtrb
[32]);
1344 DoFlashing(StartRow
);
1345 m_txtCache
->NationalSubset
= national_subset_bak
;
1349 bool CTeletextDecoder::IsSubtitlePage(int pageNumber
) const
1354 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
1356 for (const auto subPage
: m_txtCache
->SubtitlePages
)
1358 if (subPage
.page
== pageNumber
)
1365 void CTeletextDecoder::DoFlashing(int startrow
)
1367 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
1369 TextCachedPage_t
* textCachepage
=
1370 m_txtCache
->astCachetable
[m_txtCache
->Page
][m_txtCache
->SubPage
];
1372 // Verify that the page is not deleted by the other thread: CDVDTeletextData::ResetTeletextCache()
1373 if (!textCachepage
|| m_RenderInfo
.PageInfo
!= &textCachepage
->pageinfo
)
1374 m_RenderInfo
.PageInfo
= nullptr;
1376 /* get national subset */
1377 if (m_txtCache
->NationalSubset
<= NAT_MAX_FROM_HEADER
&& /* not for GR/RU as long as line28 is not evaluated */
1378 m_RenderInfo
.PageInfo
&& m_RenderInfo
.PageInfo
->nationalvalid
) /* individual subset according to page header */
1380 m_txtCache
->NationalSubset
= CountryConversionTable
[m_RenderInfo
.PageInfo
->national
];
1384 TextPageAttr_t flashattr
;
1386 std::chrono::milliseconds flashphase
= std::chrono::duration_cast
<std::chrono::milliseconds
>(
1387 std::chrono::steady_clock::now().time_since_epoch()) %
1390 int srow
= startrow
;
1394 switch (m_RenderInfo
.ZoomMode
)
1396 case 1: erow
= 12; factor
=2;break;
1397 case 2: srow
= 12; factor
=2;break;
1400 m_RenderInfo
.PosY
= startrow
*m_RenderInfo
.FontHeight
*factor
;
1401 for (int row
= srow
; row
< erow
; row
++)
1403 int index
= row
* 40;
1408 m_RenderInfo
.PosX
= 0;
1409 for (int col
= m_RenderInfo
.nofirst
; col
< 40; col
++)
1411 if (m_RenderInfo
.PageAtrb
[index
+ col
].flashing
&& m_RenderInfo
.PageChar
[index
+ col
] > 0x20 && m_RenderInfo
.PageChar
[index
+ col
] != 0xff )
1414 flashchar
= m_RenderInfo
.PageChar
[index
+ col
];
1415 bool doflash
= false;
1416 memcpy(&flashattr
, &m_RenderInfo
.PageAtrb
[index
+ col
], sizeof(TextPageAttr_t
));
1417 switch (flashattr
.flashing
&0x1c) // Flash Rate
1420 if (flashphase
> 500ms
)
1423 case 0x04 : // 2 Hz Phase 1
1424 if (flashphase
< 250ms
)
1427 case 0x08 : // 2 Hz Phase 2
1428 if (flashphase
>= 250ms
&& flashphase
< 500ms
)
1431 case 0x0c : // 2 Hz Phase 3
1432 if (flashphase
>= 500ms
&& flashphase
< 750ms
)
1435 case 0x10 : // incremental flash
1437 if (incflash
>3) incflash
= 1;
1441 if (flashphase
< 250ms
)
1445 if (flashphase
>= 250ms
&& flashphase
< 500ms
)
1449 if (flashphase
>= 500ms
&& flashphase
< 750ms
)
1454 case 0x14 : // decremental flash
1456 if (decflash
<1) decflash
= 3;
1460 if (flashphase
< 250ms
)
1464 if (flashphase
>= 250ms
&& flashphase
< 500ms
)
1468 if (flashphase
>= 500ms
&& flashphase
< 750ms
)
1476 switch (flashattr
.flashing
&0x03) // Flash Mode
1478 case 0x01 : // normal Flashing
1479 if (doflash
) flashattr
.fg
= flashattr
.bg
;
1481 case 0x02 : // inverted Flashing
1483 if (doflash
) flashattr
.fg
= flashattr
.bg
;
1485 case 0x03 : // color Flashing
1486 if (doflash
) flashattr
.fg
= flashattr
.fg
+ (flashattr
.fg
> 7 ? (-8) : 8);
1490 RenderCharFB(flashchar
, &flashattr
);
1491 if (flashattr
.doublew
) col
++;
1492 if (flashattr
.doubleh
) dhset
= 1;
1494 m_updateTexture
= true;
1500 m_RenderInfo
.PosY
+= m_RenderInfo
.FontHeight
*factor
;
1502 m_RenderInfo
.PosY
+= m_RenderInfo
.FontHeight
*factor
;
1506 void CTeletextDecoder::DoRenderPage(int startrow
, int national_subset_bak
)
1508 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
1510 /* display first column? */
1511 m_RenderInfo
.nofirst
= m_RenderInfo
.Show39
;
1512 for (int row
= 1; row
< 24; row
++)
1514 int Byte
= m_RenderInfo
.PageChar
[row
*40];
1515 if (Byte
!= ' ' && Byte
!= 0x00 && Byte
!= 0xFF && m_RenderInfo
.PageAtrb
[row
*40].fg
!= m_RenderInfo
.PageAtrb
[row
*40].bg
)
1517 m_RenderInfo
.nofirst
= 0;
1521 m_RenderInfo
.FontWidth_Normal
= m_RenderInfo
.Width
/ (m_RenderInfo
.nofirst
? 39 : 40);
1522 SetFontWidth(m_RenderInfo
.FontWidth_Normal
);
1524 if (m_RenderInfo
.TranspMode
|| m_RenderInfo
.Boxed
)
1526 FillBorder(GetColorRGB(TXT_ColorTransp
));//ClearBB(transp);
1527 m_RenderInfo
.ClearBBColor
= TXT_ColorTransp
;
1530 /* get national subset */
1531 if (m_txtCache
->NationalSubset
<= NAT_MAX_FROM_HEADER
&& /* not for GR/RU as long as line28 is not evaluated */
1532 m_RenderInfo
.PageInfo
&& m_RenderInfo
.PageInfo
->nationalvalid
) /* individual subset according to page header */
1534 m_txtCache
->NationalSubset
= CountryConversionTable
[m_RenderInfo
.PageInfo
->national
];
1537 if (m_RenderInfo
.PageInfo
&& (m_RenderInfo
.PageInfo
->function
== FUNC_GDRCS
|| m_RenderInfo
.PageInfo
->function
== FUNC_DRCS
)) /* character definitions */
1540 #define DRCSCOLS (48/DRCSROWS)
1543 #define DRCSXSPC (12*DRCSZOOMX + 2)
1544 #define DRCSYSPC (10*DRCSZOOMY + 2)
1546 unsigned char ax
[] = { /* array[0..12] of x-offsets, array[0..10] of y-offsets for each pixel */
1573 ClearBB(TXT_ColorBlack
);
1574 for (int col
= 0; col
< 24*40; col
++)
1575 m_RenderInfo
.PageAtrb
[col
] = Text_AtrTable
[ATR_WB
];
1577 for (int row
= 0; row
< DRCSROWS
; row
++)
1579 for (int col
= 0; col
< DRCSCOLS
; col
++)
1581 RenderDRCS(m_RenderInfo
.Width
,
1582 m_RenderInfo
.PageChar
+ 20 * (DRCSCOLS
* row
+ col
+ 2),
1584 + (m_RenderInfo
.FontHeight
+ DRCSYSPC
* row
+ m_RenderInfo
.Height
) * m_RenderInfo
.Width
1586 ax
, GetColorRGB(TXT_ColorWhite
), GetColorRGB(TXT_ColorBlack
));
1589 memset(m_RenderInfo
.PageChar
+ 40, 0xff, 24*40); /* don't render any char below row 0 */
1591 m_RenderInfo
.PosY
= startrow
*m_RenderInfo
.FontHeight
;
1592 for (int row
= startrow
; row
< 24; row
++)
1594 int index
= row
* 40;
1596 m_RenderInfo
.PosX
= 0;
1597 for (int col
= m_RenderInfo
.nofirst
; col
< 40; col
++)
1599 RenderCharBB(m_RenderInfo
.PageChar
[index
+ col
], &m_RenderInfo
.PageAtrb
[index
+ col
]);
1601 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 */
1602 m_RenderInfo
.PageChar
[index
+ col
+ 40] = 0xff;
1603 if (m_RenderInfo
.PageAtrb
[index
+ col
].doublew
&& col
< 40-1) /* skip next column if double width */
1606 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 */
1607 m_RenderInfo
.PageChar
[index
+ col
+ 40] = 0xff;
1610 m_RenderInfo
.PosY
+= m_RenderInfo
.FontHeight
;
1612 DoFlashing(startrow
);
1614 /* update framebuffer */
1616 m_txtCache
->NationalSubset
= national_subset_bak
;
1619 void CTeletextDecoder::Decode_BTT()
1621 /* basic top table */
1622 int current
, b1
, b2
, b3
, b4
;
1623 unsigned char btt
[23*40];
1625 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
1627 if (m_txtCache
->SubPageTable
[0x1f0] == 0xff || 0 == m_txtCache
->astCachetable
[0x1f0][m_txtCache
->SubPageTable
[0x1f0]]) /* not yet received */
1630 auto& components
= CServiceBroker::GetAppComponents();
1631 const auto appPlayer
= components
.GetComponent
<CApplicationPlayer
>();
1633 appPlayer
->LoadPage(0x1f0, m_txtCache
->SubPageTable
[0x1f0], btt
);
1634 if (btt
[799] == ' ') /* not completely received or error */
1638 for (int i
= 0; i
< 800; i
++)
1646 if (b1
== 0xFF) /* hamming error in btt */
1648 btt
[799] = ' '; /* mark btt as not received */
1652 m_txtCache
->BasicTop
[current
] = b1
;
1653 CDVDTeletextTools::NextDec(¤t
);
1655 /* page linking table */
1656 m_txtCache
->ADIP_PgMax
= -1; /* rebuild table of adip pages */
1657 for (int i
= 0; i
< 10; i
++)
1659 b1
= dehamming
[btt
[800 + 8*i
+0]];
1662 continue; /* unused */
1666 b4
= dehamming
[btt
[800 + 8*i
+7]];
1668 if (b4
!= 2) /* only adip, ignore multipage (1) */
1671 b2
= dehamming
[btt
[800 + 8*i
+1]];
1672 b3
= dehamming
[btt
[800 + 8*i
+2]];
1674 if (b1
== 0xFF || b2
== 0xFF || b3
== 0xFF)
1676 CLog::Log(LOGERROR
, "CTeletextDecoder::Decode_BTT <Biterror in btt/plt index {}>", i
);
1677 btt
[799] = ' '; /* mark btt as not received */
1681 b1
= b1
<<8 | b2
<<4 | b3
; /* page number */
1682 m_txtCache
->ADIP_Pg
[++m_txtCache
->ADIP_PgMax
] = b1
;
1685 m_txtCache
->BTTok
= true;
1688 void CTeletextDecoder::Decode_ADIP() /* additional information table */
1690 int i
, p
, j
, b1
, b2
, b3
, charfound
;
1691 unsigned char padip
[23*40];
1693 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
1695 auto& components
= CServiceBroker::GetAppComponents();
1696 const auto appPlayer
= components
.GetComponent
<CApplicationPlayer
>();
1698 for (i
= 0; i
<= m_txtCache
->ADIP_PgMax
; i
++)
1700 p
= m_txtCache
->ADIP_Pg
[i
];
1701 if (!p
|| m_txtCache
->SubPageTable
[p
] == 0xff || 0 == m_txtCache
->astCachetable
[p
][m_txtCache
->SubPageTable
[p
]]) /* not cached (avoid segfault) */
1704 appPlayer
->LoadPage(p
, m_txtCache
->SubPageTable
[p
], padip
);
1705 for (j
= 0; j
< 44; j
++)
1707 b1
= dehamming
[padip
[20*j
+0]];
1709 continue; /* unused */
1714 b2
= dehamming
[padip
[20*j
+1]];
1715 b3
= dehamming
[padip
[20*j
+2]];
1717 if (b1
== 0xFF || b2
== 0xFF || b3
== 0xFF)
1720 "CTeletextDecoder::Decode_BTT <Biterror in ait {:03x} {} {:02x} {:02x} {:02x} "
1721 "{:02x} {:02x} {:02x}>",
1722 p
, j
, padip
[20 * j
+ 0], padip
[20 * j
+ 1], padip
[20 * j
+ 2], b1
, b2
, b3
);
1726 if (b1
>8 || b2
>9 || b3
>9) /* ignore entries with invalid or hex page numbers */
1731 b1
= b1
<<8 | b2
<<4 | b3
; /* page number */
1732 charfound
= 0; /* flag: no printable char found */
1734 for (b2
= 11; b2
>= 0; b2
--)
1736 b3
= deparity
[padip
[20*j
+ 8 + b2
]];
1740 if (b3
== ' ' && !charfound
)
1741 m_txtCache
->ADIPTable
[b1
][b2
] = '\0';
1744 m_txtCache
->ADIPTable
[b1
][b2
] = b3
;
1750 m_txtCache
->ADIP_Pg
[i
] = 0; /* completely decoded: clear entry */
1751 } /* next adip page i */
1753 while ((m_txtCache
->ADIP_PgMax
>= 0) && !m_txtCache
->ADIP_Pg
[m_txtCache
->ADIP_PgMax
]) /* and shrink table */
1754 m_txtCache
->ADIP_PgMax
--;
1757 int CTeletextDecoder::TopText_GetNext(int startpage
, int up
, int findgroup
)
1759 int current
, nextgrp
, nextblk
;
1761 int stoppage
= (IsDec(startpage
) ? startpage
: startpage
& 0xF00); // avoid endless loop in hexmode
1762 nextgrp
= nextblk
= 0;
1763 current
= startpage
;
1765 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
1769 CDVDTeletextTools::NextDec(¤t
);
1771 CDVDTeletextTools::PrevDec(¤t
);
1773 if (!m_txtCache
->BTTok
|| m_txtCache
->BasicTop
[current
]) /* only if existent */
1777 if (m_txtCache
->BasicTop
[current
] >= 6 && m_txtCache
->BasicTop
[current
] <= 7)
1779 if (!nextgrp
&& (current
&0x00F) == 0)
1782 if (m_txtCache
->BasicTop
[current
] >= 2 && m_txtCache
->BasicTop
[current
] <= 5) /* always find block */
1785 if (!nextblk
&& (current
&0x0FF) == 0)
1788 } while (current
!= stoppage
);
1798 void CTeletextDecoder::Showlink(int column
, int linkpage
)
1800 unsigned char line
[] = " >??? ";
1801 int oldfontwidth
= m_RenderInfo
.FontWidth
;
1807 yoffset
= m_RenderInfo
.Height
;
1809 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
1810 int width
= m_RenderInfo
.Width
/4;
1812 m_RenderInfo
.PosY
= 24*m_RenderInfo
.FontHeight
;
1814 if (m_RenderInfo
.Boxed
)
1816 m_RenderInfo
.PosX
= column
*width
;
1817 FillRect(m_TextureBuffer
, m_RenderInfo
.Width
, m_RenderInfo
.PosX
, m_RenderInfo
.PosY
+yoffset
, m_RenderInfo
.Width
, m_RenderInfo
.FontHeight
, GetColorRGB(TXT_ColorTransp
));
1821 if (m_txtCache
->ADIPTable
[linkpage
][0])
1823 m_RenderInfo
.PosX
= column
*width
;
1824 int l
= strlen(m_txtCache
->ADIPTable
[linkpage
]);
1826 if (l
> 9) /* smaller font, if no space for one half space at front and end */
1827 SetFontWidth(oldfontwidth
* 10 / (l
+1));
1829 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
));
1830 m_RenderInfo
.PosX
+= ((width
) - (l
*m_RenderInfo
.FontWidth
+l
*m_RenderInfo
.FontWidth
/abx
))/2; /* center */
1832 for (char *p
= m_txtCache
->ADIPTable
[linkpage
]; *p
; p
++)
1833 RenderCharBB(*p
, &Text_AtrTable
[ATR_L250
+ column
]);
1835 SetFontWidth(oldfontwidth
);
1837 else /* display number */
1839 m_RenderInfo
.PosX
= column
*width
;
1840 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
));
1841 if (linkpage
< m_txtCache
->Page
)
1844 CDVDTeletextTools::Hex2Str((char*)line
+ 5, linkpage
);
1847 CDVDTeletextTools::Hex2Str((char*)line
+ 6, linkpage
);
1849 for (unsigned char *p
= line
; p
< line
+9; p
++)
1850 RenderCharBB(*p
, &Text_AtrTable
[ATR_L250
+ column
]);
1854 void CTeletextDecoder::CreateLine25()
1856 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
1858 /* btt completely received and not yet decoded */
1859 if (!m_txtCache
->BTTok
)
1862 if (m_txtCache
->ADIP_PgMax
>= 0)
1865 if (!m_RenderInfo
.ShowHex
&& m_RenderInfo
.ShowFlof
&&
1866 (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
1868 m_RenderInfo
.Prev_100
= m_txtCache
->FlofPages
[m_txtCache
->Page
][0];
1869 m_RenderInfo
.Prev_10
= m_txtCache
->FlofPages
[m_txtCache
->Page
][1];
1870 m_RenderInfo
.Next_10
= m_txtCache
->FlofPages
[m_txtCache
->Page
][2];
1871 m_RenderInfo
.Next_100
= m_txtCache
->FlofPages
[m_txtCache
->Page
][3];
1873 m_RenderInfo
.PosY
= 24*m_RenderInfo
.FontHeight
;
1874 m_RenderInfo
.PosX
= 0;
1875 for (int i
=m_RenderInfo
.nofirst
; i
<40; i
++)
1876 RenderCharBB(m_RenderInfo
.PageChar
[24*40 + i
], &m_RenderInfo
.PageAtrb
[24*40 + i
]);
1880 /* normal: blk-1, grp+1, grp+2, blk+1 */
1881 /* hex: hex+1, blk-1, grp+1, blk+1 */
1882 if (m_RenderInfo
.ShowHex
)
1884 /* arguments: startpage, up, findgroup */
1885 m_RenderInfo
.Prev_100
= NextHex(m_txtCache
->Page
);
1886 m_RenderInfo
.Prev_10
= TopText_GetNext(m_txtCache
->Page
, 0, 0);
1887 m_RenderInfo
.Next_10
= TopText_GetNext(m_txtCache
->Page
, 1, 1);
1891 m_RenderInfo
.Prev_100
= TopText_GetNext(m_txtCache
->Page
, 0, 0);
1892 m_RenderInfo
.Prev_10
= TopText_GetNext(m_txtCache
->Page
, 1, 1);
1893 m_RenderInfo
.Next_10
= TopText_GetNext(m_RenderInfo
.Prev_10
, 1, 1);
1895 m_RenderInfo
.Next_100
= TopText_GetNext(m_RenderInfo
.Next_10
, 1, 0);
1896 Showlink(0, m_RenderInfo
.Prev_100
);
1897 Showlink(1, m_RenderInfo
.Prev_10
);
1898 Showlink(2, m_RenderInfo
.Next_10
);
1899 Showlink(3, m_RenderInfo
.Next_100
);
1903 void CTeletextDecoder::RenderCharFB(int Char
, TextPageAttr_t
*Attribute
)
1905 RenderCharIntern(&m_RenderInfo
, Char
, Attribute
, m_RenderInfo
.ZoomMode
, m_YOffset
);
1908 void CTeletextDecoder::RenderCharBB(int Char
, TextPageAttr_t
*Attribute
)
1910 RenderCharIntern(&m_RenderInfo
, Char
, Attribute
, 0, m_RenderInfo
.Height
-m_YOffset
);
1913 void CTeletextDecoder::CopyBB2FB()
1915 UTILS::COLOR::Color
*src
, *dst
, *topsrc
;
1917 UTILS::COLOR::Color fillcolor
;
1919 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
1922 if (!m_RenderInfo
.PageCatching
)
1925 /* copy backbuffer to framebuffer */
1926 if (!m_RenderInfo
.ZoomMode
)
1931 m_YOffset
= m_RenderInfo
.Height
;
1933 if (m_RenderInfo
.ClearBBColor
>= 0)
1935 m_RenderInfo
.ClearBBColor
= -1;
1940 src
= dst
= topsrc
= m_TextureBuffer
+ m_RenderInfo
.Width
;
1944 dst
+= m_RenderInfo
.Width
* m_RenderInfo
.Height
;
1948 src
+= m_RenderInfo
.Width
* m_RenderInfo
.Height
;
1949 topsrc
+= m_RenderInfo
.Width
* m_RenderInfo
.Height
;
1952 if (!m_RenderInfo
.PageCatching
)
1953 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 */
1955 if (m_RenderInfo
.TranspMode
)
1956 fillcolor
= GetColorRGB(TXT_ColorTransp
);
1958 fillcolor
= GetColorRGB((enumTeletextColor
)m_txtCache
->FullScrColor
);
1960 if (m_RenderInfo
.ZoomMode
== 2)
1961 src
+= 12*m_RenderInfo
.FontHeight
*m_RenderInfo
.Width
;
1963 screenwidth
= m_RenderInfo
.Width
;
1965 for (int i
= 12*m_RenderInfo
.FontHeight
; i
; i
--)
1967 SDL_memcpy4(dst
, src
, screenwidth
);
1968 dst
+= m_RenderInfo
.Width
;
1969 SDL_memcpy4(dst
, src
, screenwidth
);
1970 dst
+= m_RenderInfo
.Width
;
1971 src
+= m_RenderInfo
.Width
;
1974 for (int i
= m_RenderInfo
.Height
- 25*m_RenderInfo
.FontHeight
; i
>= 0;i
--)
1976 SDL_memset4(dst
+ m_RenderInfo
.Width
*(m_RenderInfo
.FontHeight
+i
), fillcolor
, screenwidth
);
1980 FT_Error
CTeletextDecoder::MyFaceRequester(FTC_FaceID face_id
, FT_Library library
, FT_Pointer request_data
, FT_Face
*aface
)
1982 FT_Error result
= FT_New_Face(library
, (const char*)face_id
, 0, aface
);
1985 CLog::Log(LOGINFO
, "Teletext font {} loaded", (char*)face_id
);
1987 CLog::Log(LOGERROR
, "Opening of Teletext font {} failed", (char*)face_id
);
1992 void CTeletextDecoder::SetFontWidth(int newWidth
)
1994 if (m_RenderInfo
.FontWidth
!= newWidth
)
1996 m_RenderInfo
.FontWidth
= newWidth
;
1997 m_TypeTTF
.width
= (FT_UShort
) m_RenderInfo
.FontWidth
;
1999 for (int i
= 0; i
<= 12; i
++)
2000 m_RenderInfo
.axdrcs
[i
] = (m_RenderInfo
.FontWidth
* i
+ 6) / 12;
2004 int CTeletextDecoder::GetCurFontWidth()
2006 int mx
= (m_RenderInfo
.Width
)%(40-m_RenderInfo
.nofirst
); // # of unused pixels
2007 int abx
= (mx
== 0 ? m_RenderInfo
.Width
+1 : (m_RenderInfo
.Width
)/(mx
+1)); // distance between 'inserted' pixels
2008 int nx
= abx
+1-(m_RenderInfo
.PosX
% (abx
+1)); // # of pixels to next insert
2009 return m_RenderInfo
.FontWidth
+(((m_RenderInfo
.PosX
+m_RenderInfo
.FontWidth
+1) <= m_RenderInfo
.Width
&& nx
<= m_RenderInfo
.FontWidth
+1) ? 1 : 0);
2012 void CTeletextDecoder::SetPosX(int column
)
2014 m_RenderInfo
.PosX
= 0;
2016 for (int i
= 0; i
< column
-m_RenderInfo
.nofirst
; i
++)
2017 m_RenderInfo
.PosX
+= GetCurFontWidth();
2020 void CTeletextDecoder::ClearBB(UTILS::COLOR::Color Color
)
2022 SDL_memset4(m_TextureBuffer
+ (m_RenderInfo
.Height
-m_YOffset
)*m_RenderInfo
.Width
, Color
, m_RenderInfo
.Width
*m_RenderInfo
.Height
);
2025 void CTeletextDecoder::ClearFB(UTILS::COLOR::Color Color
)
2027 SDL_memset4(m_TextureBuffer
+ m_RenderInfo
.Width
*m_YOffset
, Color
, m_RenderInfo
.Width
*m_RenderInfo
.Height
);
2030 void CTeletextDecoder::FillBorder(UTILS::COLOR::Color Color
)
2032 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
);
2033 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
);
2036 void CTeletextDecoder::FillRect(
2037 UTILS::COLOR::Color
* buffer
, int xres
, int x
, int y
, int w
, int h
, UTILS::COLOR::Color Color
)
2039 if (!buffer
) return;
2041 UTILS::COLOR::Color
* p
= buffer
+ x
+ y
* xres
;
2045 for ( ; h
> 0 ; h
--)
2047 SDL_memset4(p
, Color
, w
);
2053 void CTeletextDecoder::DrawVLine(
2054 UTILS::COLOR::Color
* lfb
, int xres
, int x
, int y
, int l
, UTILS::COLOR::Color color
)
2057 UTILS::COLOR::Color
* p
= lfb
+ x
+ y
* xres
;
2059 for ( ; l
> 0 ; l
--)
2066 void CTeletextDecoder::DrawHLine(
2067 UTILS::COLOR::Color
* lfb
, int xres
, int x
, int y
, int l
, UTILS::COLOR::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 UTILS::COLOR::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 */
2079 UTILS::COLOR::Color fgcolor
,
2080 UTILS::COLOR::Color bgcolor
)
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 UTILS::COLOR::Color f1
= (c1
& bit
) ? fgcolor
: bgcolor
;
2101 UTILS::COLOR::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(UTILS::COLOR::Color
* lfb
,
2122 UTILS::COLOR::Color fgcolor
,
2123 UTILS::COLOR::Color bgcolor
,
2127 FillRect(lfb
,xres
,x
, y
, w
, h
, bgcolor
);
2130 FillRect(lfb
,xres
,x
+1, y
+1, w
-2, h
-2, fgcolor
);
2134 void CTeletextDecoder::FillTrapez(UTILS::COLOR::Color
* lfb
,
2142 UTILS::COLOR::Color color
)
2144 UTILS::COLOR::Color
* p
= lfb
+ x0
+ y0
* xres
;
2147 for (int yoffset
= 0; yoffset
< h
; yoffset
++)
2149 l
= l0
+ ((l1
-l0
) * yoffset
+ h
/2) / h
;
2150 xoffset
= (xoffset1
* yoffset
+ h
/2) / h
;
2152 SDL_memset4(p
+ xoffset
, color
, l
);
2157 void CTeletextDecoder::FlipHorz(UTILS::COLOR::Color
* lfb
, int xres
, int x
, int y
, int w
, int h
)
2159 UTILS::COLOR::Color buf
[2048];
2160 UTILS::COLOR::Color
* p
= lfb
+ x
+ y
* xres
;
2163 for (h1
= 0 ; h1
< h
; h1
++)
2165 SDL_memcpy4(buf
,p
,w
);
2166 for (w1
= 0 ; w1
< w
; w1
++)
2168 *(p
+w1
) = buf
[w
-(w1
+1)];
2174 void CTeletextDecoder::FlipVert(UTILS::COLOR::Color
* lfb
, int xres
, int x
, int y
, int w
, int h
)
2176 UTILS::COLOR::Color buf
[2048];
2177 UTILS::COLOR::Color
*p
= lfb
+ x
+ y
* xres
, *p1
, *p2
;
2180 for (h1
= 0 ; h1
< h
/2 ; h1
++)
2183 p2
= (p
+(h
-(h1
+1))*xres
);
2184 SDL_memcpy4(buf
, p1
, w
);
2185 SDL_memcpy4(p1
, p2
, w
);
2186 SDL_memcpy4(p2
, buf
, w
);
2190 int CTeletextDecoder::ShapeCoord(int param
, int curfontwidth
, int curFontHeight
)
2195 return curfontwidth
/3;
2197 return curfontwidth
/2;
2199 return curfontwidth
*2/3;
2201 return curfontwidth
;
2203 return curfontwidth
-3;
2205 return curFontHeight
/3;
2207 return curFontHeight
/2;
2209 return curFontHeight
*2/3;
2211 return curFontHeight
;
2217 void CTeletextDecoder::DrawShape(UTILS::COLOR::Color
* lfb
,
2225 UTILS::COLOR::Color fgcolor
,
2226 UTILS::COLOR::Color bgcolor
,
2229 if (!lfb
|| shapenumber
< 0x20 || shapenumber
> 0x7e || (shapenumber
== 0x7e && clear
))
2232 unsigned char *p
= aShapes
[shapenumber
- 0x20];
2243 FillRect(lfb
, xres
, x
, y
, curfontwidth
, FontHeight
, bgcolor
);
2251 int offset
= ShapeCoord(*p
++, curfontwidth
, curFontHeight
);
2252 DrawHLine(lfb
, xres
, x
, y
+ offset
, curfontwidth
, fgcolor
);
2257 int offset
= ShapeCoord(*p
++, curfontwidth
, curFontHeight
);
2258 DrawVLine(lfb
,xres
,x
+ offset
, y
, FontHeight
, fgcolor
);
2262 FlipHorz(lfb
,xres
,x
,y
,curfontwidth
, FontHeight
);
2265 FlipVert(lfb
,xres
,x
,y
,curfontwidth
, FontHeight
);
2269 int xo
= ShapeCoord(*p
++, curfontwidth
, curFontHeight
);
2270 int yo
= ShapeCoord(*p
++, curfontwidth
, curFontHeight
);
2271 int w
= ShapeCoord(*p
++, curfontwidth
, curFontHeight
);
2272 int h
= ShapeCoord(*p
++, curfontwidth
, curFontHeight
);
2273 FillRect(lfb
,xres
,x
+ xo
, y
+ yo
, w
, h
, fgcolor
);
2278 int x0
= ShapeCoord(*p
++, curfontwidth
, curFontHeight
);
2279 int y0
= ShapeCoord(*p
++, curfontwidth
, curFontHeight
);
2280 int l0
= ShapeCoord(*p
++, curfontwidth
, curFontHeight
);
2281 int x1
= ShapeCoord(*p
++, curfontwidth
, curFontHeight
);
2282 int y1
= ShapeCoord(*p
++, curfontwidth
, curFontHeight
);
2283 int l1
= ShapeCoord(*p
++, curfontwidth
, curFontHeight
);
2284 FillTrapez(lfb
, xres
,x
+ x0
, y
+ y0
, l0
, x1
-x0
, y1
-y0
, l1
, fgcolor
);
2289 int x0
= ShapeCoord(*p
++, curfontwidth
, curFontHeight
);
2290 int y0
= ShapeCoord(*p
++, curfontwidth
, curFontHeight
);
2291 int l0
= ShapeCoord(*p
++, curfontwidth
, curFontHeight
);
2292 int x1
= ShapeCoord(*p
++, curfontwidth
, curFontHeight
);
2293 int y1
= ShapeCoord(*p
++, curfontwidth
, curFontHeight
);
2294 int l1
= ShapeCoord(*p
++, curfontwidth
, curFontHeight
);
2295 FillTrapez(lfb
, xres
, x
+ x0
, y
+ y0
, l0
, x1
-x0
, y1
-y0
, l1
, bgcolor
);
2300 DrawShape(lfb
,xres
,x
, y
, ShapeCoord(*p
, curfontwidth
, curFontHeight
), curfontwidth
, FontHeight
, curFontHeight
, fgcolor
, bgcolor
, false);
2309 void CTeletextDecoder::RenderCharIntern(TextRenderInfo_t
* RenderInfo
, int Char
, TextPageAttr_t
*Attribute
, int zoom
, int yoffset
)
2313 UTILS::COLOR::Color bgcolor
, fgcolor
;
2314 int factor
, xfactor
;
2315 unsigned char *sbitbuffer
;
2317 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
2319 int national_subset_local
= m_txtCache
->NationalSubset
;
2320 int curfontwidth
= GetCurFontWidth();
2321 int t
= curfontwidth
;
2322 m_RenderInfo
.PosX
+= t
;
2323 int curfontwidth2
= GetCurFontWidth();
2324 m_RenderInfo
.PosX
-= t
;
2325 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
);
2326 if (alphachar
<= 0) return;
2328 if (zoom
&& Attribute
->doubleh
)
2330 else if (zoom
|| Attribute
->doubleh
)
2335 fgcolor
= GetColorRGB((enumTeletextColor
)Attribute
->fg
);
2336 if (m_RenderInfo
.TranspMode
&& m_RenderInfo
.PosY
< 24*m_RenderInfo
.FontHeight
)
2338 bgcolor
= GetColorRGB(TXT_ColorTransp
);
2342 bgcolor
= GetColorRGB((enumTeletextColor
)Attribute
->bg
);
2345 if (Attribute
->doublew
)
2347 curfontwidth
+= curfontwidth2
;
2353 // Check if the alphanumeric char has diacritical marks (or results from composing chars) or
2354 // on the other hand it is just a simple alphanumeric char
2355 if (!Attribute
->diacrit
)
2361 if ((national_subset_local
== NAT_SC
) || (national_subset_local
== NAT_RB
) ||
2362 (national_subset_local
== NAT_UA
))
2363 Char
= G2table
[1][0x20 + Attribute
->diacrit
];
2364 else if (national_subset_local
== NAT_GR
)
2365 Char
= G2table
[2][0x20 + Attribute
->diacrit
];
2366 else if (national_subset_local
== NAT_HB
)
2367 Char
= G2table
[3][0x20 + Attribute
->diacrit
];
2368 else if (national_subset_local
== NAT_AR
)
2369 Char
= G2table
[4][0x20 + Attribute
->diacrit
];
2371 Char
= G2table
[0][0x20 + Attribute
->diacrit
];
2373 // use harfbuzz to combine the diacritical mark with the alphanumeric char
2374 // fallback to the alphanumeric char if composition fails
2375 hb_unicode_funcs_t
* ufuncs
= hb_unicode_funcs_get_default();
2376 hb_codepoint_t composedChar
;
2377 const hb_bool_t isComposed
= hb_unicode_compose(ufuncs
, alphachar
, Char
, &composedChar
);
2378 Char
= isComposed
? composedChar
: alphachar
;
2382 if (!(glyph
= FT_Get_Char_Index(m_Face
, Char
)))
2384 CLog::Log(LOGERROR
, "{}: <FT_Get_Char_Index for Char {:x} \"{}\" failed", __FUNCTION__
,
2385 alphachar
, alphachar
);
2387 FillRect(m_TextureBuffer
, m_RenderInfo
.Width
, m_RenderInfo
.PosX
, m_RenderInfo
.PosY
+ yoffset
, curfontwidth
, factor
*m_RenderInfo
.FontHeight
, bgcolor
);
2388 m_RenderInfo
.PosX
+= curfontwidth
;
2392 if (FTC_SBitCache_Lookup(m_Cache
, &m_TypeTTF
, glyph
, &m_sBit
, &m_anode
) != 0)
2394 FillRect(m_TextureBuffer
, m_RenderInfo
.Width
, m_RenderInfo
.PosX
, m_RenderInfo
.PosY
+ yoffset
, curfontwidth
, m_RenderInfo
.FontHeight
, bgcolor
);
2395 m_RenderInfo
.PosX
+= curfontwidth
;
2399 sbitbuffer
= m_sBit
->buffer
;
2401 int backupTTFshiftY
= m_RenderInfo
.TTFShiftY
;
2402 if (national_subset_local
== NAT_AR
)
2403 m_RenderInfo
.TTFShiftY
= backupTTFshiftY
- 2; // for arabic TTF font should be shifted up slightly
2405 UTILS::COLOR::Color
* p
;
2406 int f
; /* running counter for zoom factor */
2407 int he
= m_sBit
->height
; // sbit->height should not be altered, I guess
2408 Row
= factor
* (m_Ascender
- m_sBit
->top
+ m_RenderInfo
.TTFShiftY
);
2411 sbitbuffer
-= m_sBit
->pitch
*Row
;
2417 FillRect(m_TextureBuffer
, m_RenderInfo
.Width
, m_RenderInfo
.PosX
, m_RenderInfo
.PosY
+ yoffset
, curfontwidth
, Row
, bgcolor
); /* fill upper margin */
2420 if (m_Ascender
- m_sBit
->top
+ m_RenderInfo
.TTFShiftY
+ he
> m_RenderInfo
.FontHeight
)
2421 he
= m_RenderInfo
.FontHeight
- m_Ascender
+ m_sBit
->top
- m_RenderInfo
.TTFShiftY
; /* limit char height to defined/calculated FontHeight */
2422 if (he
< 0) he
= m_RenderInfo
.FontHeight
;
2424 p
= m_TextureBuffer
+ m_RenderInfo
.PosX
+ (yoffset
+ m_RenderInfo
.PosY
+ Row
) * m_RenderInfo
.Width
; /* running pointer into framebuffer */
2425 for (Row
= he
; Row
; Row
--) /* row counts up, but down may be a little faster :) */
2427 int pixtodo
= m_sBit
->width
;
2428 UTILS::COLOR::Color
* pstart
= p
;
2430 for (int Bit
= xfactor
* (m_sBit
->left
+ m_RenderInfo
.TTFShiftX
); Bit
> 0; Bit
--) /* fill left margin */
2432 for (f
= factor
-1; f
>= 0; f
--)
2433 *(p
+ f
*m_RenderInfo
.Width
) = bgcolor
;
2437 for (Pitch
= m_sBit
->pitch
; Pitch
; Pitch
--)
2439 for (int Bit
= 0x80; Bit
; Bit
>>= 1)
2441 UTILS::COLOR::Color color
;
2446 if (*sbitbuffer
& Bit
) /* bit set -> foreground */
2448 else /* bit not set -> background */
2451 for (f
= factor
-1; f
>= 0; f
--)
2452 *(p
+ f
*m_RenderInfo
.Width
) = color
;
2455 if (xfactor
> 1) /* double width */
2457 for (f
= factor
-1; f
>= 0; f
--)
2458 *(p
+ f
*m_RenderInfo
.Width
) = color
;
2464 for (int Bit
= (curfontwidth
- xfactor
*(m_sBit
->width
+ m_sBit
->left
+ m_RenderInfo
.TTFShiftX
));
2465 Bit
> 0; Bit
--) /* fill rest of char width */
2467 for (f
= factor
-1; f
>= 0; f
--)
2468 *(p
+ f
*m_RenderInfo
.Width
) = bgcolor
;
2472 p
= pstart
+ factor
*m_RenderInfo
.Width
;
2475 Row
= m_Ascender
- m_sBit
->top
+ he
+ m_RenderInfo
.TTFShiftY
;
2476 FillRect(m_TextureBuffer
,
2479 m_RenderInfo
.PosY
+ yoffset
+ Row
* factor
,
2481 (m_RenderInfo
.FontHeight
- Row
) * factor
,
2482 bgcolor
); /* fill lower margin */
2484 if (Attribute
->underline
)
2485 FillRect(m_TextureBuffer
,
2488 m_RenderInfo
.PosY
+ yoffset
+ (m_RenderInfo
.FontHeight
-2)* factor
,
2491 fgcolor
); /* underline char */
2493 m_RenderInfo
.PosX
+= curfontwidth
;
2494 m_RenderInfo
.TTFShiftY
= backupTTFshiftY
; // restore TTFShiftY
2497 int CTeletextDecoder::RenderChar(
2498 UTILS::COLOR::Color
* buffer
, // pointer to render buffer, min. FontHeight*2*xres
2499 int xres
, // length of 1 line in render buffer
2500 int Char
, // character to render
2502 pPosX
, // left border for rendering relative to *buffer, will be set to right border after rendering
2503 int PosY
, // vertical position of char in *buffer
2504 TextPageAttr_t
* Attribute
, // Attributes of Char
2505 bool zoom
, // 1= character will be rendered in double height
2506 int curfontwidth
, // rendering width of character
2507 int curfontwidth2
, // rendering width of next character (needed for doublewidth)
2508 int FontHeight
, // height of character
2509 bool transpmode
, // 1= transparent display
2510 unsigned char* axdrcs
, // width and height of DRCS-chars
2511 int Ascender
) // Ascender of font
2513 UTILS::COLOR::Color bgcolor
, fgcolor
;
2514 int factor
, xfactor
;
2516 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
2518 int national_subset_local
= m_txtCache
->NationalSubset
;
2520 ymosaic
[0] = 0; /* y-offsets for 2*3 mosaic */
2521 ymosaic
[1] = (FontHeight
+ 1) / 3;
2522 ymosaic
[2] = (FontHeight
* 2 + 1) / 3;
2523 ymosaic
[3] = FontHeight
;
2525 if (Attribute
->setX26
)
2527 national_subset_local
= 0; // no national subset
2530 // G0+G2 set designation
2531 if (Attribute
->setG0G2
!= 0x3f)
2533 switch (Attribute
->setG0G2
)
2536 national_subset_local
= NAT_SC
;
2539 national_subset_local
= NAT_RB
;
2542 national_subset_local
= NAT_UA
;
2545 national_subset_local
= NAT_GR
;
2548 national_subset_local
= NAT_HB
;
2552 national_subset_local
= NAT_AR
;
2555 national_subset_local
= CountryConversionTable
[Attribute
->setG0G2
& 0x07];
2560 if (Attribute
->charset
== C_G0S
) // use secondary charset
2561 national_subset_local
= m_txtCache
->NationalSubsetSecondary
;
2562 if (zoom
&& Attribute
->doubleh
)
2564 else if (zoom
|| Attribute
->doubleh
)
2569 if (Attribute
->doublew
)
2571 curfontwidth
+= curfontwidth2
;
2577 if (Char
== 0xFF) /* skip doubleheight chars in lower line */
2579 *pPosX
+= curfontwidth
;
2584 if (Attribute
->inverted
)
2586 int t
= Attribute
->fg
;
2587 Attribute
->fg
= Attribute
->bg
;
2590 fgcolor
= GetColorRGB((enumTeletextColor
)Attribute
->fg
);
2591 if (transpmode
== true && PosY
< 24*FontHeight
)
2593 bgcolor
= GetColorRGB(TXT_ColorTransp
);
2597 bgcolor
= GetColorRGB((enumTeletextColor
)Attribute
->bg
);
2601 if ((Attribute
->charset
== C_G1C
|| Attribute
->charset
== C_G1S
) &&
2602 ((Char
&0xA0) == 0x20))
2604 int w1
= (curfontwidth
/ 2 ) *xfactor
;
2605 int w2
= (curfontwidth
- w1
) *xfactor
;
2607 Char
= (Char
& 0x1f) | ((Char
& 0x40) >> 1);
2608 if (Attribute
->charset
== C_G1S
) /* separated mosaic */
2610 for (int y
= 0; y
< 3; y
++)
2612 FillRectMosaicSeparated(buffer
, xres
,*pPosX
, PosY
+ ymosaic
[y
]*factor
, w1
, (ymosaic
[y
+1] - ymosaic
[y
])*factor
, fgcolor
, bgcolor
, Char
& 0x01);
2613 FillRectMosaicSeparated(buffer
, xres
,*pPosX
+ w1
, PosY
+ ymosaic
[y
]*factor
, w2
, (ymosaic
[y
+1] - ymosaic
[y
])*factor
, fgcolor
, bgcolor
, Char
& 0x02);
2619 for (int y
= 0; y
< 3; y
++)
2621 FillRect(buffer
, xres
, *pPosX
, PosY
+ ymosaic
[y
]*factor
, w1
, (ymosaic
[y
+1] - ymosaic
[y
])*factor
, (Char
& 0x01) ? fgcolor
: bgcolor
);
2622 FillRect(buffer
, xres
, *pPosX
+ w1
, PosY
+ ymosaic
[y
]*factor
, w2
, (ymosaic
[y
+1] - ymosaic
[y
])*factor
, (Char
& 0x02) ? fgcolor
: bgcolor
);
2627 *pPosX
+= curfontwidth
;
2631 if (Attribute
->charset
== C_G3
)
2633 if (Char
< 0x20 || Char
> 0x7d)
2639 if (*aShapes
[Char
- 0x20] == S_CHR
)
2641 unsigned char *p
= aShapes
[Char
- 0x20];
2642 Char
= (*(p
+1) <<8) + (*(p
+2));
2644 else if (*aShapes
[Char
- 0x20] == S_ADT
)
2649 UTILS::COLOR::Color
* p
= buffer
+ *pPosX
+ PosY
* xres
;
2650 for (y
=0; y
<FontHeight
;y
++)
2652 for (f
=0; f
<factor
; f
++)
2654 for (x
=0; x
<curfontwidth
*xfactor
;x
++)
2656 c
= (y
&4 ? (x
/3)&1 :((x
+3)/3)&1);
2657 *(p
+x
) = (c
? fgcolor
: bgcolor
);
2663 *pPosX
+= curfontwidth
;
2668 DrawShape(buffer
, xres
,*pPosX
, PosY
, Char
, curfontwidth
, FontHeight
, factor
*FontHeight
, fgcolor
, bgcolor
, true);
2669 *pPosX
+= curfontwidth
;
2674 else if (Attribute
->charset
>= C_OFFSET_DRCS
)
2676 TextCachedPage_t
*pcache
= m_txtCache
->astCachetable
[(Attribute
->charset
& 0x10) ? m_txtCache
->drcs
: m_txtCache
->gdrcs
][Attribute
->charset
& 0x0f];
2679 unsigned char drcs_data
[23*40];
2680 auto& components
= CServiceBroker::GetAppComponents();
2681 const auto appPlayer
= components
.GetComponent
<CApplicationPlayer
>();
2682 appPlayer
->LoadPage((Attribute
->charset
& 0x10) ? m_txtCache
->drcs
: m_txtCache
->gdrcs
,
2683 Attribute
->charset
& 0x0f, drcs_data
);
2686 p
= drcs_data
+ 20*Char
;
2687 else if (pcache
->pageinfo
.p24
)
2688 p
= pcache
->pageinfo
.p24
+ 20*(Char
- 23*2);
2691 FillRect(buffer
, xres
,*pPosX
, PosY
, curfontwidth
, factor
*FontHeight
, bgcolor
);
2692 *pPosX
+= curfontwidth
;
2695 axdrcs
[12] = curfontwidth
; /* adjust last x-offset according to position, FIXME: double width */
2696 RenderDRCS(xres
, p
, buffer
+ *pPosX
+ PosY
* xres
, axdrcs
, fgcolor
, bgcolor
);
2700 FillRect(buffer
,xres
,*pPosX
, PosY
, curfontwidth
, factor
*FontHeight
, bgcolor
);
2702 *pPosX
+= curfontwidth
;
2705 else if (Attribute
->charset
== C_G2
&& Char
>= 0x20 && Char
<= 0x7F)
2707 if ((national_subset_local
== NAT_SC
) || (national_subset_local
== NAT_RB
) || (national_subset_local
== NAT_UA
))
2708 Char
= G2table
[1][Char
-0x20];
2709 else if (national_subset_local
== NAT_GR
)
2710 Char
= G2table
[2][Char
-0x20];
2711 else if (national_subset_local
== NAT_AR
)
2712 Char
= G2table
[3][Char
-0x20];
2714 Char
= G2table
[0][Char
-0x20];
2718 // FillRect(buffer,xres,*pPosX, PosY, curfontwidth, factor*Ascender, fgcolor);
2719 // FillRect(buffer,xres,*pPosX, PosY + factor*Ascender, curfontwidth, factor*(FontHeight-Ascender), bgcolor);
2720 // *pPosX += curfontwidth;
2724 else if (national_subset_local
== NAT_SC
&& Char
>= 0x20 && Char
<= 0x7F) /* remap complete areas for serbian/croatian */
2725 Char
= G0table
[0][Char
-0x20];
2726 else if (national_subset_local
== NAT_RB
&& Char
>= 0x20 && Char
<= 0x7F) /* remap complete areas for russian/bulgarian */
2727 Char
= G0table
[1][Char
-0x20];
2728 else if (national_subset_local
== NAT_UA
&& Char
>= 0x20 && Char
<= 0x7F) /* remap complete areas for ukrainian */
2729 Char
= G0table
[2][Char
-0x20];
2730 else if (national_subset_local
== NAT_GR
&& Char
>= 0x20 && Char
<= 0x7F) /* remap complete areas for greek */
2731 Char
= G0table
[3][Char
-0x20];
2732 else if (national_subset_local
== NAT_HB
&& Char
>= 0x20 && Char
<= 0x7F) /* remap complete areas for hebrew */
2733 Char
= G0table
[4][Char
-0x20];
2734 else if (national_subset_local
== NAT_AR
&& Char
>= 0x20 && Char
<= 0x7F) /* remap complete areas for arabic */
2735 Char
= G0table
[5][Char
-0x20];
2743 FillRect(buffer
, xres
, *pPosX
, PosY
, curfontwidth
, factor
*FontHeight
, bgcolor
);
2744 *pPosX
+= curfontwidth
;
2748 Char
= nationaltable23
[national_subset_local
][Char
-0x23];
2751 Char
= nationaltable40
[national_subset_local
];
2759 Char
= nationaltable5b
[national_subset_local
][Char
-0x5B];
2765 Char
= nationaltable7b
[national_subset_local
][Char
-0x7B];
2768 FillRect(buffer
,xres
,*pPosX
, PosY
, curfontwidth
, factor
*Ascender
, fgcolor
);
2769 FillRect(buffer
,xres
,*pPosX
, PosY
+ factor
*Ascender
, curfontwidth
, factor
*(FontHeight
-Ascender
), bgcolor
);
2770 *pPosX
+= curfontwidth
;
2773 DrawHLine(buffer
,xres
,*pPosX
, PosY
, curfontwidth
, fgcolor
);
2774 DrawVLine(buffer
,xres
,*pPosX
, PosY
+1, FontHeight
-1, fgcolor
);
2775 FillRect(buffer
,xres
,*pPosX
+1, PosY
+1, curfontwidth
-1, FontHeight
-1, bgcolor
);
2776 *pPosX
+= curfontwidth
;
2779 DrawHLine(buffer
,xres
,*pPosX
, PosY
, curfontwidth
, fgcolor
);
2780 FillRect(buffer
,xres
,*pPosX
, PosY
+1, curfontwidth
, FontHeight
-1, bgcolor
);
2781 *pPosX
+= curfontwidth
;
2784 DrawHLine(buffer
,xres
,*pPosX
, PosY
, curfontwidth
, fgcolor
);
2785 DrawVLine(buffer
,xres
,*pPosX
+ curfontwidth
-1, PosY
+1, FontHeight
-1, fgcolor
);
2786 FillRect(buffer
,xres
,*pPosX
, PosY
+1, curfontwidth
-1, FontHeight
-1, bgcolor
);
2787 *pPosX
+= curfontwidth
;
2790 DrawVLine(buffer
,xres
,*pPosX
, PosY
, FontHeight
, fgcolor
);
2791 FillRect(buffer
,xres
,*pPosX
+1, PosY
, curfontwidth
-1, FontHeight
, bgcolor
);
2792 *pPosX
+= curfontwidth
;
2795 DrawVLine(buffer
,xres
,*pPosX
+ curfontwidth
-1, PosY
, FontHeight
, fgcolor
);
2796 FillRect(buffer
,xres
,*pPosX
, PosY
, curfontwidth
-1, FontHeight
, bgcolor
);
2797 *pPosX
+= curfontwidth
;
2800 DrawHLine(buffer
,xres
,*pPosX
, PosY
+ FontHeight
-1, curfontwidth
, fgcolor
);
2801 DrawVLine(buffer
,xres
,*pPosX
, PosY
, FontHeight
-1, fgcolor
);
2802 FillRect(buffer
,xres
,*pPosX
+1, PosY
, curfontwidth
-1, FontHeight
-1, bgcolor
);
2803 *pPosX
+= curfontwidth
;
2806 DrawHLine(buffer
,xres
,*pPosX
, PosY
+ FontHeight
-1, curfontwidth
, fgcolor
);
2807 FillRect(buffer
,xres
,*pPosX
, PosY
, curfontwidth
, FontHeight
-1, bgcolor
);
2808 *pPosX
+= curfontwidth
;
2811 DrawHLine(buffer
,xres
,*pPosX
, PosY
+ FontHeight
-1, curfontwidth
, fgcolor
);
2812 DrawVLine(buffer
,xres
,*pPosX
+ curfontwidth
-1, PosY
, FontHeight
-1, fgcolor
);
2813 FillRect(buffer
,xres
,*pPosX
, PosY
, curfontwidth
-1, FontHeight
-1, bgcolor
);
2814 *pPosX
+= curfontwidth
;
2817 FillRect(buffer
,xres
,*pPosX
+1, PosY
, curfontwidth
-1, FontHeight
, bgcolor
);
2818 for (int Row
=0; Row
< curfontwidth
/2; Row
++)
2819 DrawVLine(buffer
,xres
,*pPosX
+ Row
, PosY
+ Row
, FontHeight
- Row
, fgcolor
);
2820 *pPosX
+= curfontwidth
;
2823 FillRect(buffer
,xres
,*pPosX
, PosY
, curfontwidth
/2, FontHeight
, fgcolor
);
2824 FillRect(buffer
,xres
,*pPosX
+ curfontwidth
/2, PosY
, (curfontwidth
+1)/2, FontHeight
, bgcolor
);
2825 *pPosX
+= curfontwidth
;
2827 case 0xEA: /* ∞ */
2828 FillRect(buffer
,xres
,*pPosX
, PosY
, curfontwidth
, FontHeight
, bgcolor
);
2829 FillRect(buffer
,xres
,*pPosX
, PosY
, curfontwidth
/2, curfontwidth
/2, fgcolor
);
2830 *pPosX
+= curfontwidth
;
2833 FillRect(buffer
,xres
,*pPosX
, PosY
+1, curfontwidth
, FontHeight
-1, bgcolor
);
2834 for (int Row
=0; Row
< curfontwidth
/2; Row
++)
2835 DrawHLine(buffer
,xres
,*pPosX
+ Row
, PosY
+ Row
, curfontwidth
- Row
, fgcolor
);
2836 *pPosX
+= curfontwidth
;
2839 FillRect(buffer
, xres
,*pPosX
, PosY
, curfontwidth
, curfontwidth
/2, fgcolor
);
2840 FillRect(buffer
, xres
,*pPosX
, PosY
+ curfontwidth
/2, curfontwidth
, FontHeight
- curfontwidth
/2, bgcolor
);
2841 *pPosX
+= curfontwidth
;
2851 Char
= arrowtable
[Char
- 0xED];
2859 FillRect(buffer
, xres
, *pPosX
, PosY
, curfontwidth
, factor
*FontHeight
, bgcolor
);
2860 *pPosX
+= curfontwidth
;
2863 return Char
; // Char is an alphanumeric unicode character
2866 TextPageinfo_t
* CTeletextDecoder::DecodePage(bool showl25
, // 1=decode Level2.5-graphics
2867 unsigned char* PageChar
, // page buffer, min. 25*40
2868 TextPageAttr_t
*PageAtrb
, // attribute buffer, min 25*40
2869 bool HintMode
, // 1=show hidden information
2870 bool showflof
) // 1=decode FLOF-line
2874 int foreground
, background
, doubleheight
, doublewidth
, charset
, previous_charset
, mosaictype
, IgnoreAtBlackBgSubst
, concealed
, flashmode
, boxwin
;
2875 unsigned char held_mosaic
, *p
;
2876 TextCachedPage_t
*pCachedPage
;
2878 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
2880 /* copy page to decode buffer */
2881 if (m_txtCache
->SubPageTable
[m_txtCache
->Page
] == 0xff) /* not cached: do nothing */
2884 if (m_txtCache
->ZapSubpageManual
)
2885 pCachedPage
= m_txtCache
->astCachetable
[m_txtCache
->Page
][m_txtCache
->SubPage
];
2887 pCachedPage
= m_txtCache
->astCachetable
[m_txtCache
->Page
][m_txtCache
->SubPageTable
[m_txtCache
->Page
]];
2888 if (!pCachedPage
) /* not cached: do nothing */
2891 auto& components
= CServiceBroker::GetAppComponents();
2892 const auto appPlayer
= components
.GetComponent
<CApplicationPlayer
>();
2893 appPlayer
->LoadPage(m_txtCache
->Page
, m_txtCache
->SubPage
, &PageChar
[40]);
2895 memcpy(&PageChar
[8], pCachedPage
->p0
, 24); /* header line without TimeString */
2897 TextPageinfo_t
* PageInfo
= &(pCachedPage
->pageinfo
);
2899 memcpy(&PageChar
[24*40], PageInfo
->p24
, 40); /* line 25 for FLOF */
2901 /* copy TimeString */
2902 memcpy(&PageChar
[32], &m_txtCache
->TimeString
, 8);
2905 /* check for newsflash & subtitle */
2906 if (PageInfo
->boxed
&& IsDec(m_txtCache
->Page
))
2915 memset(PageChar
, ' ', 40);
2919 memset(PageChar
, ' ', 8);
2920 CDVDTeletextTools::Hex2Str((char*)PageChar
+3, m_txtCache
->Page
);
2921 if (m_txtCache
->SubPage
)
2925 CDVDTeletextTools::Hex2Str((char*)PageChar
+6, m_txtCache
->SubPage
);
2929 if (!IsDec(m_txtCache
->Page
))
2931 TextPageAttr_t atr
= { TXT_ColorWhite
, TXT_ColorBlack
, C_G0P
, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f};
2932 if (PageInfo
->function
== FUNC_MOT
) /* magazine organization table */
2934 for (col
= 0; col
< 24*40; col
++)
2935 PageAtrb
[col
] = atr
;
2936 for (col
= 40; col
< 24*40; col
++)
2937 PageChar
[col
] = number2char(PageChar
[col
]);
2938 return PageInfo
; /* don't interpret irregular pages */
2940 else if (PageInfo
->function
== FUNC_GPOP
|| PageInfo
->function
== FUNC_POP
) /* object definitions */
2942 for (int col
= 0; col
< 24*40; col
++)
2943 PageAtrb
[col
] = atr
;
2946 for (int row
= 1; row
< 12; row
++)
2948 *p
++ = number2char(row
); /* first column: number (0-9, A-..) */
2949 for (int col
= 1; col
< 40; col
+= 3)
2951 int d
= CDVDTeletextTools::deh24(p
);
2954 memcpy(p
, "???", 3);
2959 *p
++ = number2char((d
>> 6) & 0x1f); /* mode */
2960 *p
++ = number2char(d
& 0x3f); /* address */
2961 *p
++ = number2char((d
>> 11) & 0x7f); /* data */
2965 return PageInfo
; /* don't interpret irregular pages */
2967 else if (PageInfo
->function
== FUNC_GDRCS
|| PageInfo
->function
== FUNC_DRCS
) /* character definitions */
2969 return PageInfo
; /* don't interpret irregular pages */
2973 int h
, parityerror
= 0;
2975 for (int i
= 0; i
< 8; i
++)
2978 /* decode parity/hamming */
2979 for (unsigned int i
= 40; i
< TELETEXT_PAGE_SIZE
; i
++)
2984 if (parityerror
&& h
!= 0xFF) /* if no regular page (after any parity error) */
2985 CDVDTeletextTools::Hex2Str((char*)p
, h
); /* first try dehamming */
2988 if (*p
== ' ' || deparity
[*p
] != ' ') /* correct parity */
2993 if (h
!= 0xFF) /* first parity error: try dehamming */
2994 CDVDTeletextTools::Hex2Str((char*)p
, h
);
3002 return PageInfo
; /* don't interpret irregular pages */
3006 int mosaic_pending
,esc_pending
;
3008 for (int row
= 0; row
< ((showflof
&& PageInfo
->p24
) ? 25 : 24); row
++)
3010 /* start-of-row default conditions */
3011 foreground
= TXT_ColorWhite
;
3012 background
= TXT_ColorBlack
;
3015 charset
= previous_charset
= C_G0P
; // remember charset for switching back after mosaic charset was used
3023 IgnoreAtBlackBgSubst
= 0;
3024 mosaic_pending
= esc_pending
= 0; // we need to render at least one mosaic char if 'esc' is received immediately after mosaic charset switch on
3026 if (boxed
&& memchr(&PageChar
[row
*40], start_box
, 40) == 0)
3028 foreground
= TXT_ColorTransp
;
3029 background
= TXT_ColorTransp
;
3032 for (int col
= 0; col
< 40; col
++)
3034 int index
= row
*40 + col
;
3036 PageAtrb
[index
].fg
= foreground
;
3037 PageAtrb
[index
].bg
= background
;
3038 PageAtrb
[index
].charset
= charset
;
3039 PageAtrb
[index
].doubleh
= doubleheight
;
3040 PageAtrb
[index
].doublew
= (col
< 39 ? doublewidth
: 0);
3041 PageAtrb
[index
].IgnoreAtBlackBgSubst
= IgnoreAtBlackBgSubst
;
3042 PageAtrb
[index
].concealed
= concealed
;
3043 PageAtrb
[index
].flashing
= flashmode
;
3044 PageAtrb
[index
].boxwin
= boxwin
;
3045 PageAtrb
[index
].inverted
= 0; // only relevant for Level 2.5
3046 PageAtrb
[index
].underline
= 0; // only relevant for Level 2.5
3047 PageAtrb
[index
].diacrit
= 0; // only relevant for Level 2.5
3048 PageAtrb
[index
].setX26
= 0; // only relevant for Level 2.5
3049 PageAtrb
[index
].setG0G2
= 0x3f; // only relevant for Level 2.5
3051 if (PageChar
[index
] < ' ')
3053 if (esc_pending
) { // mosaic char has been rendered and we can switch charsets
3054 charset
= previous_charset
;
3055 if (charset
== C_G0P
)
3056 charset
= previous_charset
= C_G0S
;
3057 else if (charset
== C_G0S
)
3058 charset
= previous_charset
= C_G0P
;
3061 switch (PageChar
[index
])
3072 foreground
= PageChar
[index
] - alpha_black
+ TXT_ColorBlack
;
3073 if (col
== 0 && PageChar
[index
] == alpha_white
)
3074 PageAtrb
[index
].fg
= TXT_ColorBlack
; // indicate level 1 color change on column 0; (hack)
3075 if ((charset
!=C_G0P
) && (charset
!=C_G0S
)) // we need to change charset to state it was before mosaic
3076 charset
= previous_charset
;
3085 PageAtrb
[index
].flashing
= 0;
3090 IgnoreAtBlackBgSubst
= 0;
3101 PageAtrb
[index
].doubleh
= doubleheight
;
3102 PageAtrb
[index
].doublew
= doublewidth
;
3136 case mosaic_magenta
:
3140 foreground
= PageChar
[index
] - mosaic_black
+ TXT_ColorBlack
;
3141 if ((charset
==C_G0P
) || (charset
==C_G0S
))
3142 previous_charset
=charset
;
3143 charset
= mosaictype
? C_G1S
: C_G1C
;
3148 PageAtrb
[index
].concealed
= 1;
3152 foreground
= background
;
3153 PageAtrb
[index
].fg
= foreground
;
3157 case contiguous_mosaic
:
3159 if (charset
== C_G1S
)
3162 PageAtrb
[index
].charset
= charset
;
3166 case separated_mosaic
:
3168 if (charset
== C_G1C
)
3171 PageAtrb
[index
].charset
= charset
;
3176 if (!mosaic_pending
) { // if mosaic is pending we need to wait before mosaic arrives
3177 if ((charset
!= C_G0P
) && (charset
!= C_G0S
)) // we need to switch to charset which was active before mosaic
3178 charset
= previous_charset
;
3179 if (charset
== C_G0P
)
3180 charset
= previous_charset
= C_G0S
;
3181 else if (charset
== C_G0S
)
3182 charset
= previous_charset
= C_G0P
;
3183 } else esc_pending
= 1;
3186 case black_background
:
3187 background
= TXT_ColorBlack
;
3188 IgnoreAtBlackBgSubst
= 0;
3189 PageAtrb
[index
].bg
= background
;
3190 PageAtrb
[index
].IgnoreAtBlackBgSubst
= IgnoreAtBlackBgSubst
;
3193 case new_background
:
3194 background
= foreground
;
3195 if (background
== TXT_ColorBlack
)
3196 IgnoreAtBlackBgSubst
= 1;
3198 IgnoreAtBlackBgSubst
= 0;
3199 PageAtrb
[index
].bg
= background
;
3200 PageAtrb
[index
].IgnoreAtBlackBgSubst
= IgnoreAtBlackBgSubst
;
3207 case release_mosaic
:
3212 /* handle spacing attributes */
3213 if (hold
&& (PageAtrb
[index
].charset
== C_G1C
|| PageAtrb
[index
].charset
== C_G1S
))
3214 PageChar
[index
] = held_mosaic
;
3216 PageChar
[index
] = ' ';
3221 else /* char >= ' ' */
3223 mosaic_pending
= 0; // charset will be switched next if esc_pending
3224 /* set new held-mosaic char */
3225 if ((charset
== C_G1C
|| charset
== C_G1S
) &&
3226 ((PageChar
[index
]&0xA0) == 0x20))
3227 held_mosaic
= PageChar
[index
];
3228 if (PageAtrb
[index
].doubleh
)
3229 PageChar
[index
+ 40] = 0xFF;
3232 if (!(charset
== C_G1C
|| charset
== C_G1S
))
3233 held_mosaic
= ' '; /* forget if outside mosaic */
3237 /* skip row if doubleheight */
3238 if (row
< 23 && dhset
)
3240 for (int col
= 0; col
< 40; col
++)
3242 int index
= row
*40 + col
;
3243 PageAtrb
[index
+40].bg
= PageAtrb
[index
].bg
;
3244 PageAtrb
[index
+40].fg
= TXT_ColorWhite
;
3245 if (!PageAtrb
[index
].doubleh
)
3246 PageChar
[index
+40] = ' ';
3247 PageAtrb
[index
+40].flashing
= 0;
3248 PageAtrb
[index
+40].charset
= C_G0P
;
3249 PageAtrb
[index
+40].doubleh
= 0;
3250 PageAtrb
[index
+40].doublew
= 0;
3251 PageAtrb
[index
+40].IgnoreAtBlackBgSubst
= 0;
3252 PageAtrb
[index
+40].concealed
= 0;
3253 PageAtrb
[index
+40].flashing
= 0;
3254 PageAtrb
[index
+40].boxwin
= PageAtrb
[index
].boxwin
;
3259 m_txtCache
->FullScrColor
= TXT_ColorBlack
;
3262 Eval_l25(PageChar
, PageAtrb
, HintMode
);
3264 /* handle Black Background Color Substitution and transparency (CLUT1#0) */
3269 for (unsigned char row
: m_txtCache
->FullRowColor
)
3271 for (int c
= 0; c
< 40; c
++)
3273 bitmask
= (PageAtrb
[o
].bg
== 0x08 ? 0x08 : 0x00) | (row
== 0x08 ? 0x04 : 0x00) | (PageAtrb
[o
].boxwin
<<1) | (int)boxed
;
3279 PageAtrb
[o
].bg
= m_txtCache
->FullScrColor
;
3281 PageAtrb
[o
].bg
= row
;
3291 PageAtrb
[o
].bg
= TXT_ColorTransp
;
3294 bitmask
= (PageAtrb
[o
].fg
== 0x08 ? 0x08 : 0x00) | (row
== 0x08 ? 0x04 : 0x00) | (PageAtrb
[o
].boxwin
<<1) | (int)boxed
;
3300 PageAtrb
[o
].fg
= m_txtCache
->FullScrColor
;
3302 PageAtrb
[o
].fg
= row
;
3312 PageAtrb
[o
].fg
= TXT_ColorTransp
;
3322 void CTeletextDecoder::Eval_l25(unsigned char* PageChar
, TextPageAttr_t
*PageAtrb
, bool HintMode
)
3324 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
3326 memset(m_txtCache
->FullRowColor
, 0, sizeof(m_txtCache
->FullRowColor
));
3327 m_txtCache
->FullScrColor
= TXT_ColorBlack
;
3328 m_txtCache
->ColorTable
= NULL
;
3330 if (!m_txtCache
->astCachetable
[m_txtCache
->Page
][m_txtCache
->SubPage
])
3334 if (IsDec(m_txtCache
->Page
))
3336 unsigned char APx0
, APy0
, APx
, APy
;
3337 TextPageinfo_t
*pi
= &(m_txtCache
->astCachetable
[m_txtCache
->Page
][m_txtCache
->SubPage
]->pageinfo
);
3338 TextCachedPage_t
*pmot
= m_txtCache
->astCachetable
[(m_txtCache
->Page
& 0xf00) | 0xfe][0];
3339 int p26Received
= 0;
3340 int BlackBgSubst
= 0;
3341 int ColorTableRemapping
= 0;
3343 m_txtCache
->pop
= m_txtCache
->gpop
= m_txtCache
->drcs
= m_txtCache
->gdrcs
= 0;
3347 TextExtData_t
*e
= pi
->ext
;
3354 Textp27_t
*p27
= e
->p27
;
3356 m_txtCache
->gpop
= p27
[0].page
;
3358 m_txtCache
->pop
= p27
[1].page
;
3360 m_txtCache
->gdrcs
= p27
[2].page
;
3362 m_txtCache
->drcs
= p27
[3].page
;
3367 m_txtCache
->ColorTable
= e
->bgr
;
3368 BlackBgSubst
= e
->BlackBgSubst
;
3369 ColorTableRemapping
= e
->ColorTableRemapping
;
3370 memset(m_txtCache
->FullRowColor
, e
->DefRowColor
, sizeof(m_txtCache
->FullRowColor
));
3371 m_txtCache
->FullScrColor
= e
->DefScreenColor
;
3372 m_txtCache
->NationalSubset
= SetNational(e
->DefaultCharset
);
3373 m_txtCache
->NationalSubsetSecondary
= SetNational(e
->SecondCharset
);
3374 } /* e->p28Received */
3377 if (!m_txtCache
->ColorTable
&& m_txtCache
->astP29
[m_txtCache
->Page
>> 8])
3379 TextExtData_t
*e
= m_txtCache
->astP29
[m_txtCache
->Page
>> 8];
3380 m_txtCache
->ColorTable
= e
->bgr
;
3381 BlackBgSubst
= e
->BlackBgSubst
;
3382 ColorTableRemapping
= e
->ColorTableRemapping
;
3383 memset(m_txtCache
->FullRowColor
, e
->DefRowColor
, sizeof(m_txtCache
->FullRowColor
));
3384 m_txtCache
->FullScrColor
= e
->DefScreenColor
;
3385 m_txtCache
->NationalSubset
= SetNational(e
->DefaultCharset
);
3386 m_txtCache
->NationalSubsetSecondary
= SetNational(e
->SecondCharset
);
3389 if (ColorTableRemapping
)
3391 for (int i
= 0; i
< 25*40; i
++)
3393 PageAtrb
[i
].fg
+= MapTblFG
[ColorTableRemapping
- 1];
3394 if (!BlackBgSubst
|| PageAtrb
[i
].bg
!= TXT_ColorBlack
|| PageAtrb
[i
].IgnoreAtBlackBgSubst
)
3395 PageAtrb
[i
].bg
+= MapTblBG
[ColorTableRemapping
- 1];
3399 /* determine ?pop/?drcs from MOT */
3402 unsigned char pmot_data
[23*40];
3403 auto& components
= CServiceBroker::GetAppComponents();
3404 const auto appPlayer
= components
.GetComponent
<CApplicationPlayer
>();
3405 appPlayer
->LoadPage((m_txtCache
->Page
& 0xf00) | 0xfe, 0, pmot_data
);
3407 unsigned char *p
= pmot_data
; /* start of link data */
3408 int o
= 2 * (((m_txtCache
->Page
& 0xf0) >> 4) * 10 + (m_txtCache
->Page
& 0x0f)); /* offset of links for current page */
3409 int opop
= p
[o
] & 0x07; /* index of POP link */
3410 int odrcs
= p
[o
+1] & 0x07; /* index of DRCS link */
3411 unsigned char obj
[3*4*4]; /* types* objects * (triplet,packet,subp,high) */
3412 unsigned char type
,ct
, tstart
= 4*4;
3413 memset(obj
,0,sizeof(obj
));
3415 if (p
[o
] & 0x08) /* GPOP data used */
3417 if (!m_txtCache
->gpop
|| !(p
[18*40] & 0x08)) /* no p27 data or higher prio of MOT link */
3419 m_txtCache
->gpop
= ((p
[18*40] << 8) | (p
[18*40+1] << 4) | p
[18*40+2]) & 0x7ff;
3420 if ((m_txtCache
->gpop
& 0xff) == 0xff)
3421 m_txtCache
->gpop
= 0;
3424 if (m_txtCache
->gpop
< 0x100)
3425 m_txtCache
->gpop
+= 0x800;
3432 type
= (p
[18*40+5] >> 2*ct
) & 0x03;
3434 if (type
== 0) continue;
3435 obj
[(type
-1)*(tstart
)+ct
*4 ] = 3 * ((p
[18*40+7+ct
*2] >> 1) & 0x03) + type
; //triplet
3436 obj
[(type
-1)*(tstart
)+ct
*4+1] = ((p
[18*40+7+ct
*2] & 0x08) >> 3) + 1 ; //packet
3437 obj
[(type
-1)*(tstart
)+ct
*4+2] = p
[18*40+6+ct
*2] & 0x0f ; //subp
3438 obj
[(type
-1)*(tstart
)+ct
*4+3] = p
[18*40+7+ct
*2] & 0x01 ; //high
3444 if (opop
) /* POP data used */
3446 opop
= 18*40 + 10*opop
; /* offset to POP link */
3447 if (!m_txtCache
->pop
|| !(p
[opop
] & 0x08)) /* no p27 data or higher prio of MOT link */
3449 m_txtCache
->pop
= ((p
[opop
] << 8) | (p
[opop
+1] << 4) | p
[opop
+2]) & 0x7ff;
3450 if ((m_txtCache
->pop
& 0xff) == 0xff)
3451 m_txtCache
->pop
= 0;
3454 if (m_txtCache
->pop
< 0x100)
3455 m_txtCache
->pop
+= 0x800;
3462 type
= (p
[opop
+5] >> 2*ct
) & 0x03;
3464 if (type
== 0) continue;
3465 obj
[(type
-1)*(tstart
)+(ct
+2)*4 ] = 3 * ((p
[opop
+7+ct
*2] >> 1) & 0x03) + type
; //triplet
3466 obj
[(type
-1)*(tstart
)+(ct
+2)*4+1] = ((p
[opop
+7+ct
*2] & 0x08) >> 3) + 1 ; //packet
3467 obj
[(type
-1)*(tstart
)+(ct
+2)*4+2] = p
[opop
+6+ct
*2] ; //subp
3468 obj
[(type
-1)*(tstart
)+(ct
+2)*4+3] = p
[opop
+7+ct
*2] & 0x01 ; //high
3474 // eval default objects in correct order
3475 for (int i
= 0; i
< 12; i
++)
3479 APx0
= APy0
= APx
= APy
= m_txtCache
->tAPx
= m_txtCache
->tAPy
= 0;
3480 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
);
3484 if (p
[o
+1] & 0x08) /* GDRCS data used */
3486 if (!m_txtCache
->gdrcs
|| !(p
[20*40] & 0x08)) /* no p27 data or higher prio of MOT link */
3488 m_txtCache
->gdrcs
= ((p
[20*40] << 8) | (p
[20*40+1] << 4) | p
[20*40+2]) & 0x7ff;
3489 if ((m_txtCache
->gdrcs
& 0xff) == 0xff)
3490 m_txtCache
->gdrcs
= 0;
3491 else if (m_txtCache
->gdrcs
< 0x100)
3492 m_txtCache
->gdrcs
+= 0x800;
3495 if (odrcs
) /* DRCS data used */
3497 odrcs
= 20*40 + 4*odrcs
; /* offset to DRCS link */
3498 if (!m_txtCache
->drcs
|| !(p
[odrcs
] & 0x08)) /* no p27 data or higher prio of MOT link */
3500 m_txtCache
->drcs
= ((p
[odrcs
] << 8) | (p
[odrcs
+1] << 4) | p
[odrcs
+2]) & 0x7ff;
3501 if ((m_txtCache
->drcs
& 0xff) == 0xff)
3502 m_txtCache
->drcs
= 0;
3503 else if (m_txtCache
->drcs
< 0x100)
3504 m_txtCache
->drcs
+= 0x800;
3507 if (m_txtCache
->astCachetable
[m_txtCache
->gpop
][0])
3508 m_txtCache
->astCachetable
[m_txtCache
->gpop
][0]->pageinfo
.function
= FUNC_GPOP
;
3509 if (m_txtCache
->astCachetable
[m_txtCache
->pop
][0])
3510 m_txtCache
->astCachetable
[m_txtCache
->pop
][0]->pageinfo
.function
= FUNC_POP
;
3511 if (m_txtCache
->astCachetable
[m_txtCache
->gdrcs
][0])
3512 m_txtCache
->astCachetable
[m_txtCache
->gdrcs
][0]->pageinfo
.function
= FUNC_GDRCS
;
3513 if (m_txtCache
->astCachetable
[m_txtCache
->drcs
][0])
3514 m_txtCache
->astCachetable
[m_txtCache
->drcs
][0]->pageinfo
.function
= FUNC_DRCS
;
3517 /* evaluate local extension data from p26 */
3520 APx0
= APy0
= APx
= APy
= m_txtCache
->tAPx
= m_txtCache
->tAPy
= 0;
3521 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 */
3526 for (unsigned char row
: m_txtCache
->FullRowColor
)
3528 for (int c
= 0; c
< 40; c
++)
3530 if (BlackBgSubst
&& PageAtrb
[o
].bg
== TXT_ColorBlack
&& !(PageAtrb
[o
].IgnoreAtBlackBgSubst
))
3533 PageAtrb
[o
].bg
= m_txtCache
->FullScrColor
;
3535 PageAtrb
[o
].bg
= row
;
3544 for (int i
= 0; i
< 25*40; i
++)
3546 if (PageAtrb
[i
].concealed
) PageAtrb
[i
].fg
= PageAtrb
[i
].bg
;
3549 } /* is_dec(page) */
3552 /* dump interpreted object data to stdout */
3553 /* in: 18 bit object data */
3554 /* out: termination info, >0 if end of object */
3555 void CTeletextDecoder::Eval_Object(int iONr
, TextCachedPage_t
*pstCachedPage
,
3556 unsigned char *pAPx
, unsigned char *pAPy
,
3557 unsigned char *pAPx0
, unsigned char *pAPy0
,
3558 tObjType ObjType
, unsigned char* pagedata
, unsigned char* PageChar
, TextPageAttr_t
* PageAtrb
)
3561 int iONr1
= iONr
+ 1; /* don't terminate after first triplet */
3562 unsigned char drcssubp
=0, gdrcssubp
=0;
3563 signed char endcol
= -1; /* last column to which to extend attribute changes */
3564 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 */
3568 iOData
= iTripletNumber2Data(iONr
, pstCachedPage
, pagedata
); /* get triplet data, next triplet */
3569 if (iOData
< 0) /* invalid number, not cached, or hamming error: terminate */
3574 if (ObjType
== OBJ_ACTIVE
)
3578 else if (ObjType
== OBJ_ADAPTIVE
) /* search end of line */
3580 for (int i
= iONr
; i
<= 506; i
++)
3582 int iTempOData
= iTripletNumber2Data(i
, pstCachedPage
, pagedata
); /* get triplet data, next triplet */
3583 int iAddress
= (iTempOData
) & 0x3f;
3584 int iMode
= (iTempOData
>> 6) & 0x1f;
3585 //int iData = (iTempOData >> 11) & 0x7f;
3586 if (iTempOData
< 0 || /* invalid number, not cached, or hamming error: terminate */
3587 (iAddress
>= 40 /* new row: row address and */
3588 && (iMode
== 0x01 || /* Full Row Color or */
3589 iMode
== 0x04 || /* Set Active Position */
3590 (iMode
>= 0x15 && iMode
<= 0x17) || /* Object Definition */
3591 iMode
== 0x17))) /* Object Termination */
3593 if (iAddress
< 40 && iMode
!= 0x06)
3600 while (0 == Eval_Triplet(iOData
, pstCachedPage
, pAPx
, pAPy
, pAPx0
, pAPy0
, &drcssubp
, &gdrcssubp
, &endcol
, &attrPassive
, pagedata
, PageChar
, PageAtrb
) || iONr1
== iONr
); /* repeat until termination reached */
3603 void CTeletextDecoder::Eval_NumberedObject(int p
, int s
, int packet
, int triplet
, int high
,
3604 unsigned char *pAPx
, unsigned char *pAPy
,
3605 unsigned char *pAPx0
, unsigned char *pAPy0
, unsigned char* PageChar
, TextPageAttr_t
* PageAtrb
)
3607 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
3609 if (!packet
|| 0 == m_txtCache
->astCachetable
[p
][s
])
3612 unsigned char pagedata
[23*40];
3613 auto& components
= CServiceBroker::GetAppComponents();
3614 const auto appPlayer
= components
.GetComponent
<CApplicationPlayer
>();
3615 appPlayer
->LoadPage(p
, s
, pagedata
);
3617 int idata
= CDVDTeletextTools::deh24(pagedata
+ 40*(packet
-1) + 1 + 3*triplet
);
3620 if (idata
< 0) /* hamming error: ignore triplet */
3623 iONr
= idata
>> 9; /* triplet number of odd object data */
3625 iONr
= idata
& 0x1ff; /* triplet number of even object data */
3628 Eval_Object(iONr
, m_txtCache
->astCachetable
[p
][s
], pAPx
, pAPy
, pAPx0
, pAPy0
, (tObjType
)(triplet
% 3),pagedata
, PageChar
, PageAtrb
);
3632 int CTeletextDecoder::Eval_Triplet(int iOData
, TextCachedPage_t
*pstCachedPage
,
3633 unsigned char *pAPx
, unsigned char *pAPy
,
3634 unsigned char *pAPx0
, unsigned char *pAPy0
,
3635 unsigned char *drcssubp
, unsigned char *gdrcssubp
,
3636 signed char *endcol
, TextPageAttr_t
*attrPassive
, unsigned char* pagedata
, unsigned char* PageChar
, TextPageAttr_t
* PageAtrb
)
3638 int iAddress
= (iOData
) & 0x3f;
3639 int iMode
= (iOData
>> 6) & 0x1f;
3640 int iData
= (iOData
>> 11) & 0x7f;
3642 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
3644 if (iAddress
< 40) /* column addresses */
3646 int offset
; /* offset to PageChar and PageAtrb */
3649 *pAPx
= iAddress
; /* new Active Column */
3650 offset
= (*pAPy0
+ *pAPy
) * 40 + *pAPx0
+ *pAPx
; /* offset to PageChar and PageAtrb */
3655 if (0 == (iData
>>5))
3657 int newcolor
= iData
& 0x1f;
3658 if (*endcol
< 0) /* passive object */
3659 attrPassive
->fg
= newcolor
;
3660 else if (*endcol
== 40) /* active object */
3662 TextPageAttr_t
*p
= &PageAtrb
[offset
];
3663 int oldcolor
= (p
)->fg
; /* current color (set-after) */
3664 int c
= *pAPx0
+ *pAPx
; /* current column absolute */
3670 } while (c
< 40 && p
->fg
== oldcolor
); /* stop at change by level 1 page */
3672 else /* adaptive object */
3674 TextPageAttr_t
*p
= &PageAtrb
[offset
];
3675 int c
= *pAPx
; /* current column relative to object origin */
3681 } while (c
<= *endcol
);
3688 PageChar
[offset
] = iData
;
3689 if (*endcol
< 0) /* passive object */
3691 attrPassive
->charset
= C_G1C
; /* FIXME: separated? */
3692 PageAtrb
[offset
] = *attrPassive
;
3694 else if (PageAtrb
[offset
].charset
!= C_G1S
)
3695 PageAtrb
[offset
].charset
= C_G1C
; /* FIXME: separated? */
3700 PageChar
[offset
] = iData
;
3701 if (*endcol
< 0) /* passive object */
3703 attrPassive
->charset
= C_G3
;
3704 PageAtrb
[offset
] = *attrPassive
;
3707 PageAtrb
[offset
].charset
= C_G3
;
3710 if (0 == (iData
>>5))
3712 int newcolor
= iData
& 0x1f;
3713 if (*endcol
< 0) /* passive object */
3714 attrPassive
->bg
= newcolor
;
3715 else if (*endcol
== 40) /* active object */
3717 TextPageAttr_t
*p
= &PageAtrb
[offset
];
3718 int oldcolor
= (p
)->bg
; /* current color (set-after) */
3719 int c
= *pAPx0
+ *pAPx
; /* current column absolute */
3723 if (newcolor
== TXT_ColorBlack
)
3724 p
->IgnoreAtBlackBgSubst
= 1;
3727 } while (c
< 40 && p
->bg
== oldcolor
); /* stop at change by level 1 page */
3729 else /* adaptive object */
3731 TextPageAttr_t
*p
= &PageAtrb
[offset
];
3732 int c
= *pAPx
; /* current column relative to object origin */
3736 if (newcolor
== TXT_ColorBlack
)
3737 p
->IgnoreAtBlackBgSubst
= 1;
3740 } while (c
<= *endcol
);
3748 if ((iData
& 0x60) != 0) break; // reserved data field
3749 if (*endcol
< 0) /* passive object */
3751 attrPassive
->flashing
=iData
& 0x1f;
3752 PageAtrb
[offset
] = *attrPassive
;
3755 PageAtrb
[offset
].flashing
=iData
& 0x1f;
3758 if (*endcol
< 0) /* passive object */
3760 attrPassive
->setG0G2
=iData
& 0x3f;
3761 PageAtrb
[offset
] = *attrPassive
;
3764 PageAtrb
[offset
].setG0G2
=iData
& 0x3f;
3767 PageChar
[offset
] = iData
;
3768 if (*endcol
< 0) /* passive object */
3770 attrPassive
->charset
= C_G0P
; /* FIXME: secondary? */
3771 attrPassive
->setX26
= 1;
3772 PageAtrb
[offset
] = *attrPassive
;
3776 PageAtrb
[offset
].charset
= C_G0P
; /* FIXME: secondary? */
3777 PageAtrb
[offset
].setX26
= 1;
3780 // case 0x0b: (see 0x02)
3783 int conc
= (iData
& 0x04);
3784 int inv
= (iData
& 0x10);
3785 int dw
= (iData
& 0x40 ?1:0);
3786 int dh
= (iData
& 0x01 ?1:0);
3787 int sep
= (iData
& 0x20);
3788 int bw
= (iData
& 0x02 ?1:0);
3789 if (*endcol
< 0) /* passive object */
3793 attrPassive
->concealed
= 1;
3794 attrPassive
->fg
= attrPassive
->bg
;
3796 attrPassive
->inverted
= (inv
? 1- attrPassive
->inverted
: 0);
3797 attrPassive
->doubleh
= dh
;
3798 attrPassive
->doublew
= dw
;
3799 attrPassive
->boxwin
= bw
;
3800 if (bw
) attrPassive
->IgnoreAtBlackBgSubst
= 0;
3803 if (attrPassive
->charset
== C_G1C
)
3804 attrPassive
->charset
= C_G1S
;
3806 attrPassive
->underline
= 1;
3810 if (attrPassive
->charset
== C_G1S
)
3811 attrPassive
->charset
= C_G1C
;
3813 attrPassive
->underline
= 0;
3819 int c
= *pAPx0
+ (*endcol
== 40 ? *pAPx
: 0); /* current column */
3820 TextPageAttr_t
*p
= &PageAtrb
[offset
];
3823 p
->inverted
= (inv
? 1- p
->inverted
: 0);
3831 if (p
->charset
== C_G1C
)
3838 if (p
->charset
== C_G1S
)
3846 if (bw
) p
->IgnoreAtBlackBgSubst
= 0;
3849 } while (c
< *endcol
);
3854 PageChar
[offset
] = iData
& 0x3f;
3855 if (*endcol
< 0) /* passive object */
3857 attrPassive
->charset
= C_OFFSET_DRCS
+ ((iData
& 0x40) ? (0x10 + *drcssubp
) : *gdrcssubp
);
3858 PageAtrb
[offset
] = *attrPassive
;
3861 PageAtrb
[offset
].charset
= C_OFFSET_DRCS
+ ((iData
& 0x40) ? (0x10 + *drcssubp
) : *gdrcssubp
);
3864 PageChar
[offset
] = iData
;
3865 if (*endcol
< 0) /* passive object */
3867 attrPassive
->charset
= C_G2
;
3868 PageAtrb
[offset
] = *attrPassive
;
3871 PageAtrb
[offset
].charset
= C_G2
;
3874 if (iMode
== 0x10 && iData
== 0x2a)
3878 PageChar
[offset
] = iData
;
3879 if (*endcol
< 0) /* passive object */
3881 attrPassive
->charset
= C_G0P
;
3882 attrPassive
->diacrit
= iMode
& 0x0f;
3883 attrPassive
->setX26
= 1;
3884 PageAtrb
[offset
] = *attrPassive
;
3888 PageAtrb
[offset
].charset
= C_G0P
;
3889 PageAtrb
[offset
].diacrit
= iMode
& 0x0f;
3890 PageAtrb
[offset
].setX26
= 1;
3893 break; /* unsupported or not yet implemented mode: ignore */
3894 } /* switch (iMode) */
3896 else /* ================= (iAddress >= 40): row addresses ====================== */
3901 if (0 == (iData
>>5))
3903 m_txtCache
->FullScrColor
= iData
& 0x1f;
3907 if (*endcol
== 40) /* active object */
3909 *pAPy
= RowAddress2Row(iAddress
); /* new Active Row */
3911 int color
= iData
& 0x1f;
3912 int row
= *pAPy0
+ *pAPy
;
3915 if (row
<= 24 && 0 == (iData
>>5))
3917 else if (3 == (iData
>>5))
3921 for (; row
<= maxrow
; row
++)
3922 m_txtCache
->FullRowColor
[row
] = color
;
3927 *pAPy
= RowAddress2Row(iAddress
); /* new Active Row */
3929 *pAPx
= iData
; /* new Active Column */
3930 *endcol
= -1; /* FIXME: check if row changed? */
3933 if (iAddress
== 0x3f)
3935 *pAPx
= *pAPy
= 0; /* new Active Position 0,0 */
3936 if (*endcol
== 40) /* active object */
3938 int color
= iData
& 0x1f;
3939 int row
= *pAPy0
; // + *pAPy;
3942 if (row
<= 24 && 0 == (iData
>>5))
3944 else if (3 == (iData
>>5))
3948 for (; row
<= maxrow
; row
++)
3949 m_txtCache
->FullRowColor
[row
] = color
;
3965 m_txtCache
->tAPy
= iAddress
- 40;
3966 m_txtCache
->tAPx
= iData
;
3971 if (iAddress
& 0x10) /* POP or GPOP */
3973 unsigned char APx
= 0, APy
= 0;
3974 unsigned char APx0
= *pAPx0
+ *pAPx
+ m_txtCache
->tAPx
, APy0
= *pAPy0
+ *pAPy
+ m_txtCache
->tAPy
;
3975 int triplet
= 3 * ((iData
>> 5) & 0x03) + (iMode
& 0x03);
3976 int packet
= (iAddress
& 0x03) + 1;
3977 int subp
= iData
& 0x0f;
3978 int high
= (iData
>> 4) & 0x01;
3981 if (APx0
< 40) /* not in side panel */
3983 Eval_NumberedObject((iAddress
& 0x08) ? m_txtCache
->gpop
: m_txtCache
->pop
, subp
, packet
, triplet
, high
, &APx
, &APy
, &APx0
, &APy0
, PageChar
,PageAtrb
);
3986 else if (iAddress
& 0x08) /* local: eval invoked object */
3988 unsigned char APx
= 0, APy
= 0;
3989 unsigned char APx0
= *pAPx0
+ *pAPx
+ m_txtCache
->tAPx
, APy0
= *pAPy0
+ *pAPy
+ m_txtCache
->tAPy
;
3990 int descode
= ((iAddress
& 0x01) << 3) | (iData
>> 4);
3991 int triplet
= iData
& 0x0f;
3993 if (APx0
< 40) /* not in side panel */
3995 Eval_Object(13 * 23 + 13 * descode
+ triplet
, pstCachedPage
, &APx
, &APy
, &APx0
, &APy0
, (tObjType
)(triplet
% 3), pagedata
, PageChar
, PageAtrb
);
4002 if (0 == (iAddress
& 0x08)) /* Object Definition illegal or only level 3.5 */
4005 m_txtCache
->tAPx
= m_txtCache
->tAPy
= 0;
4007 return 0xFF; /* termination by object definition */
4010 if (0 == (iData
& 0x10)) /* DRCS Mode reserved or only level 3.5 */
4014 *drcssubp
= iData
& 0x0f;
4016 *gdrcssubp
= iData
& 0x0f;
4019 m_txtCache
->tAPx
= m_txtCache
->tAPy
= 0;
4021 return 0x80 | iData
; /* explicit termination */
4024 break; /* unsupported or not yet implemented mode: ignore */
4025 } /* switch (iMode) */
4026 } /* (iAddress >= 40): row addresses */
4028 if (iAddress
< 40 || iMode
!= 0x10) /* leave temp. AP-Offset unchanged only immediately after definition */
4029 m_txtCache
->tAPx
= m_txtCache
->tAPy
= 0;
4031 return 0; /* normal exit, no termination */
4034 /* get object data */
4035 /* in: absolute triplet number (0..506, start at packet 3 byte 1) */
4036 /* in: pointer to cache struct of page data */
4037 /* out: 18 bit triplet data, <0 if invalid number, not cached, or hamming error */
4038 int CTeletextDecoder::iTripletNumber2Data(int iONr
, TextCachedPage_t
*pstCachedPage
, unsigned char* pagedata
)
4040 if (iONr
> 506 || 0 == pstCachedPage
)
4044 int packet
= (iONr
/ 13) + 3;
4045 int packetoffset
= 3 * (iONr
% 13);
4048 p
= pagedata
+ 40*(packet
-1) + packetoffset
+ 1;
4049 else if (packet
<= 25)
4051 if (0 == pstCachedPage
->pageinfo
.p24
)
4053 p
= pstCachedPage
->pageinfo
.p24
+ 40*(packet
-24) + packetoffset
+ 1;
4057 int descode
= packet
- 26;
4058 if (0 == pstCachedPage
->pageinfo
.ext
)
4060 if (0 == pstCachedPage
->pageinfo
.ext
->p26
[descode
])
4062 p
= pstCachedPage
->pageinfo
.ext
->p26
[descode
] + packetoffset
; /* first byte (=designation code) is not cached */
4064 return CDVDTeletextTools::deh24(p
);
4067 int CTeletextDecoder::SetNational(unsigned char sec
)
4069 std::unique_lock
<CCriticalSection
> lock(m_txtCache
->m_critSection
);
4074 return NAT_PL
; //polish
4077 return NAT_TR
; //turkish
4079 return NAT_SR
; //serbian, croatian, slovenian
4081 return NAT_SC
; // serbian, croatian
4083 return NAT_RB
; // russian, bulgarian
4085 return NAT_UA
; // ukrainian
4087 return NAT_ET
; // estonian
4089 return NAT_LV
; // latvian, lithuanian
4091 return NAT_GR
; // greek
4093 return NAT_HB
; // hebrew
4096 return NAT_AR
; // arabic
4098 return CountryConversionTable
[sec
& 0x07];
4101 int CTeletextDecoder::NextHex(int i
) /* return next existing non-decimal page number */
4104 if (startpage
< 0x100)
4114 } while ((m_txtCache
->SubPageTable
[i
] == 0xFF) || IsDec(i
));
4118 void CTeletextDecoder::SetColors(const unsigned short *pcolormap
, int offset
, int number
)
4120 int j
= offset
; /* index in global color table */
4122 for (int i
= 0; i
< number
; i
++)
4124 int r
= ((pcolormap
[i
] >> 8) & 0xf) << 4;
4125 int g
= ((pcolormap
[i
] >> 4) & 0xf) << 4;
4126 int b
= ((pcolormap
[i
]) & 0xf) << 4;
4128 if (m_RenderInfo
.rd0
[j
] != r
)
4130 m_RenderInfo
.rd0
[j
] = r
;
4132 if (m_RenderInfo
.gn0
[j
] != g
)
4134 m_RenderInfo
.gn0
[j
] = g
;
4136 if (m_RenderInfo
.bl0
[j
] != b
)
4138 m_RenderInfo
.bl0
[j
] = b
;
4144 UTILS::COLOR::Color
CTeletextDecoder::GetColorRGB(enumTeletextColor ttc
)
4148 case TXT_ColorBlack
: return 0xFF000000;
4149 case TXT_ColorRed
: return 0xFFFC1414;
4150 case TXT_ColorGreen
: return 0xFF24FC24;
4151 case TXT_ColorYellow
: return 0xFFFCC024;
4152 case TXT_ColorBlue
: return 0xFF0000FC;
4153 case TXT_ColorMagenta
: return 0xFFB000FC;
4154 case TXT_ColorCyan
: return 0xFF00FCFC;
4155 case TXT_ColorWhite
: return 0xFFFCFCFC;
4156 case TXT_ColorTransp
: return 0x00000000;
4160 /* Get colors for CLUTs 2+3 */
4161 int index
= (int)ttc
;
4162 UTILS::COLOR::Color color
= (m_RenderInfo
.tr0
[index
] << 24) | (m_RenderInfo
.bl0
[index
] << 16) |
4163 (m_RenderInfo
.gn0
[index
] << 8) | m_RenderInfo
.rd0
[index
];