2 * Copyright (C) 2005-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
22 * Most Codeparts are taken from the TuxBox Teletext plugin which is based
23 * upon videotext-0.6.19991029 and written by Thomas Loewe (LazyT),
24 * Roland Meier and DBLuelle. See http://www.tuxtxt.net/ for more information.
25 * Many thanks to the TuxBox Teletext Team for this great work.
28 #include "threads/SystemClock.h"
30 #include "Application.h"
31 #include "utils/log.h"
32 #include "utils/TimeUtils.h"
33 #include "filesystem/SpecialProtocol.h"
34 #include "guilib/GraphicContext.h"
35 #include "cores/IPlayer.h"
38 #include <SDL/SDL_stdinc.h>
40 #define SDL_memset4(dst, val, len) \
42 uint32_t _count = (len); \
43 uint32_t _n = (_count + 3) / 4; \
44 uint32_t *_p = static_cast<uint32_t *>(dst); \
45 uint32_t _val = (val); \
46 if (len == 0) break; \
47 switch (_count % 4) { \
48 case 0: do { *_p++ = _val; \
49 case 3: *_p++ = _val; \
50 case 2: *_p++ = _val; \
51 case 1: *_p++ = _val; \
55 #define SDL_memcpy4(dst, src, len) memcpy(dst, src, (len) << 2)
60 static const char *TeletextFont = "special://xbmc/media/Fonts/teletext.ttf";
62 /* spacing attributes */
63 #define alpha_black 0x00
64 #define alpha_red 0x01
65 #define alpha_green 0x02
66 #define alpha_yellow 0x03
67 #define alpha_blue 0x04
68 #define alpha_magenta 0x05
69 #define alpha_cyan 0x06
70 #define alpha_white 0x07
74 #define start_box 0x0B
75 #define normal_size 0x0C
76 #define double_height 0x0D
77 #define double_width 0x0E
78 #define double_size 0x0F
79 #define mosaic_black 0x10
80 #define mosaic_red 0x11
81 #define mosaic_green 0x12
82 #define mosaic_yellow 0x13
83 #define mosaic_blue 0x14
84 #define mosaic_magenta 0x15
85 #define mosaic_cyan 0x16
86 #define mosaic_white 0x17
88 #define contiguous_mosaic 0x19
89 #define separated_mosaic 0x1A
91 #define black_background 0x1C
92 #define new_background 0x1D
93 #define hold_mosaic 0x1E
94 #define release_mosaic 0x1F
96 #define RowAddress2Row(row) ((row == 40) ? 24 : (row - 40))
98 // G2 Set as defined in ETS 300 706
99 const unsigned short int G2table[5][6*16] =
101 // Latin G2 Supplementary Set
102 { 0x0020, 0x00A1, 0x00A2, 0x00A3, 0x0024, 0x00A5, 0x0023, 0x00A7, 0x00A4, 0x2018, 0x201C, 0x00AB, 0x2190, 0x2191, 0x2192, 0x2193,
103 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00D7, 0x00B5, 0x00B6, 0x00B7, 0x00F7, 0x2019, 0x201D, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
104 0x0020, 0x0300, 0x0301, 0x02C6, 0x0303, 0x02C9, 0x02D8, 0x02D9, 0x00A8, 0x002E, 0x02DA, 0x00B8, 0x005F, 0x02DD, 0x02DB, 0x02C7,
105 0x2014, 0x00B9, 0x00AE, 0x00A9, 0x2122, 0x266A, 0x20AC, 0x2030, 0x03B1, 0x0020, 0x0020, 0x0020, 0x215B, 0x215C, 0x215D, 0x215E,
106 0x2126, 0x00C6, 0x00D0, 0x00AA, 0x0126, 0x0020, 0x0132, 0x013F, 0x0141, 0x00D8, 0x0152, 0x00BA, 0x00DE, 0x0166, 0x014A, 0x0149,
107 0x0138, 0x00E6, 0x0111, 0x00F0, 0x0127, 0x0131, 0x0133, 0x0140, 0x0142, 0x00F8, 0x0153, 0x00DF, 0x00FE, 0x0167, 0x014B, 0x25A0},
108 // Cyrillic G2 Supplementary Set
109 { 0x0020, 0x00A1, 0x00A2, 0x00A3, 0x0024, 0x00A5, 0x0020, 0x00A7, 0x0020, 0x2018, 0x201C, 0x00AB, 0x2190, 0x2191, 0x2192, 0x2193,
110 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00D7, 0x00B5, 0x00B6, 0x00B7, 0x00F7, 0x2019, 0x201D, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
111 0x0020, 0x0300, 0x0301, 0x02C6, 0x02DC, 0x02C9, 0x02D8, 0x02D9, 0x00A8, 0x002E, 0x02DA, 0x00B8, 0x005F, 0x02DD, 0x02DB, 0x02C7,
112 0x2014, 0x00B9, 0x00AE, 0x00A9, 0x2122, 0x266A, 0x20AC, 0x2030, 0x03B1, 0x0141, 0x0142, 0x00DF, 0x215B, 0x215C, 0x215D, 0x215E,
113 0x0044, 0x0045, 0x0046, 0x0047, 0x0049, 0x004A, 0x004B, 0x004C, 0x004E, 0x0051, 0x0052, 0x0053, 0x0055, 0x0056, 0x0057, 0x005A,
114 0x0064, 0x0065, 0x0066, 0x0067, 0x0069, 0x006A, 0x006B, 0x006C, 0x006E, 0x0071, 0x0072, 0x0073, 0x0075, 0x0076, 0x0077, 0x007A},
115 // Greek G2 Supplementary Set
116 { 0x0020, 0x0061, 0x0062, 0x00A3, 0x0065, 0x0068, 0x0069, 0x00A7, 0x003A, 0x2018, 0x201C, 0x006B, 0x2190, 0x2191, 0x2192, 0x2193,
117 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00D7, 0x006D, 0x006E, 0x0070, 0x00F7, 0x2019, 0x201D, 0x0074, 0x00BC, 0x00BD, 0x00BE, 0x0078,
118 0x0020, 0x0300, 0x0301, 0x02C6, 0x02DC, 0x02C9, 0x02D8, 0x02D9, 0x00A8, 0x002E, 0x02DA, 0x00B8, 0x005F, 0x02DD, 0x02DB, 0x02C7,
119 0x003F, 0x00B9, 0x00AE, 0x00A9, 0x2122, 0x266A, 0x20AC, 0x2030, 0x03B1, 0x038A, 0x038E, 0x038F, 0x215B, 0x215C, 0x215D, 0x215E,
120 0x0043, 0x0044, 0x0046, 0x0047, 0x004A, 0x004C, 0x0051, 0x0052, 0x0053, 0x0055, 0x0056, 0x0057, 0x0059, 0x005A, 0x0386, 0x0389,
121 0x0063, 0x0064, 0x0066, 0x0067, 0x006A, 0x006C, 0x0071, 0x0072, 0x0073, 0x0075, 0x0076, 0x0077, 0x0079, 0x007A, 0x0388, 0x25A0},
123 { 0x0020, 0x0639, 0xFEC9, 0xFE83, 0xFE85, 0xFE87, 0xFE8B, 0xFE89, 0xFB7C, 0xFB7D, 0xFB7A, 0xFB58, 0xFB59, 0xFB56, 0xFB6D, 0xFB8E,
124 0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667, 0x0668, 0x0669, 0xFECE, 0xFECD, 0xFEFC, 0xFEEC, 0xFEEA, 0xFEE9,
125 0x00E0, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
126 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005A, 0x00EB, 0x00EA, 0x00F9, 0x00EE, 0xFECA,
127 0x00E9, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
128 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x00E2, 0x00F4, 0x00FB, 0x00E7, 0x25A0}
131 //const (avoid warnings :<)
132 TextPageAttr_t Text_AtrTable[] =
134 { TXT_ColorWhite , TXT_ColorBlack , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_WB */
135 { TXT_ColorWhite , TXT_ColorBlack , C_G0P, 0, 0, 1 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_PassiveDefault */
136 { TXT_ColorWhite , TXT_ColorRed , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_L250 */
137 { TXT_ColorBlack , TXT_ColorYellow, C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_L252 */
138 { TXT_ColorBlack , TXT_ColorGreen , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_L251 */
139 { TXT_ColorWhite , TXT_ColorBlue , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_L253 */
140 { TXT_ColorMagenta, TXT_ColorBlack , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_TOPMENU0 */
141 { TXT_ColorGreen , TXT_ColorBlack , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_TOPMENU1 */
142 { TXT_ColorYellow , TXT_ColorBlack , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_TOPMENU2 */
143 { TXT_ColorCyan , TXT_ColorBlack , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_TOPMENU3 */
144 { TXT_ColorMenu2 , TXT_ColorMenu3 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSG0 */
145 { TXT_ColorYellow , TXT_ColorMenu3 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSG1 */
146 { TXT_ColorMenu2 , TXT_ColorTransp, C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSG2 */
147 { TXT_ColorWhite , TXT_ColorMenu3 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSG3 */
148 { TXT_ColorMenu2 , TXT_ColorMenu1 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSGDRM0 */
149 { TXT_ColorYellow , TXT_ColorMenu1 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSGDRM1 */
150 { TXT_ColorMenu2 , TXT_ColorBlack , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSGDRM2 */
151 { TXT_ColorWhite , TXT_ColorMenu1 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSGDRM3 */
152 { TXT_ColorMenu1 , TXT_ColorBlue , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENUHIL0 5a Z */
153 { TXT_ColorWhite , TXT_ColorBlue , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENUHIL1 58 X */
154 { TXT_ColorMenu2 , TXT_ColorTransp, C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENUHIL2 9b õ */
155 { TXT_ColorMenu2 , TXT_ColorMenu1 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENU0 ab ´ */
156 { TXT_ColorYellow , TXT_ColorMenu1 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENU1 a4 § */
157 { TXT_ColorMenu2 , TXT_ColorTransp, C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENU2 9b õ */
158 { TXT_ColorMenu2 , TXT_ColorMenu3 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENU3 cb À */
159 { TXT_ColorCyan , TXT_ColorMenu3 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENU4 c7 « */
160 { TXT_ColorWhite , TXT_ColorMenu3 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENU5 c8 » */
161 { TXT_ColorWhite , TXT_ColorMenu1 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENU6 a8 ® */
162 { TXT_ColorYellow , TXT_ColorMenu1 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_CATCHMENU0 a4 § */
163 { TXT_ColorWhite , TXT_ColorMenu1 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f} /* ATR_CATCHMENU1 a8 ® */
170 S_FHL, /* full horizontal line: y-offset */
171 S_FVL, /* full vertical line: x-offset */
172 S_BOX, /* rectangle: x-offset, y-offset, width, height */
173 S_TRA, /* trapez: x0, y0, l0, x1, y1, l1 */
174 S_BTR, /* trapez in bgcolor: x0, y0, l0, x1, y1, l1 */
176 S_LNK, /* call other shape: shapenumber */
177 S_CHR, /* Character from freetype hibyte, lowbyte */
178 S_ADT, /* Character 2F alternating raster */
179 S_FLH, /* flip horizontal */
180 S_FLV /* flip vertical */
183 /* shape coordinates */
186 S_W13 = 5, /* width*1/3 */
187 S_W12, /* width*1/2 */
188 S_W23, /* width*2/3 */
191 S_H13, /* height*1/3 */
192 S_H12, /* height*1/2 */
193 S_H23, /* height*2/3 */
199 unsigned char aG3_20[] = { S_TRA, 0, S_H23, 1, 0, S_H11, S_W12, S_END };
200 unsigned char aG3_21[] = { S_TRA, 0, S_H23, 1, 0, S_H11, S_W11, S_END };
201 unsigned char aG3_22[] = { S_TRA, 0, S_H12, 1, 0, S_H11, S_W12, S_END };
202 unsigned char aG3_23[] = { S_TRA, 0, S_H12, 1, 0, S_H11, S_W11, S_END };
203 unsigned char aG3_24[] = { S_TRA, 0, 0, 1, 0, S_H11, S_W12, S_END };
204 unsigned char aG3_25[] = { S_TRA, 0, 0, 1, 0, S_H11, S_W11, S_END };
205 unsigned char aG3_26[] = { S_INV, S_LNK, 0x66, S_END };
206 unsigned char aG3_27[] = { S_INV, S_LNK, 0x67, S_END };
207 unsigned char aG3_28[] = { S_INV, S_LNK, 0x68, S_END };
208 unsigned char aG3_29[] = { S_INV, S_LNK, 0x69, S_END };
209 unsigned char aG3_2a[] = { S_INV, S_LNK, 0x6a, S_END };
210 unsigned char aG3_2b[] = { S_INV, S_LNK, 0x6b, S_END };
211 unsigned char aG3_2c[] = { S_INV, S_LNK, 0x6c, S_END };
212 unsigned char aG3_2d[] = { S_INV, S_LNK, 0x6d, S_END };
213 unsigned char aG3_2e[] = { S_BOX, 2, 0, 3, S_H11, S_END };
214 unsigned char aG3_2f[] = { S_ADT };
215 unsigned char aG3_30[] = { S_LNK, 0x20, S_FLH, S_END };
216 unsigned char aG3_31[] = { S_LNK, 0x21, S_FLH, S_END };
217 unsigned char aG3_32[] = { S_LNK, 0x22, S_FLH, S_END };
218 unsigned char aG3_33[] = { S_LNK, 0x23, S_FLH, S_END };
219 unsigned char aG3_34[] = { S_LNK, 0x24, S_FLH, S_END };
220 unsigned char aG3_35[] = { S_LNK, 0x25, S_FLH, S_END };
221 unsigned char aG3_36[] = { S_INV, S_LNK, 0x76, S_END };
222 unsigned char aG3_37[] = { S_INV, S_LNK, 0x77, S_END };
223 unsigned char aG3_38[] = { S_INV, S_LNK, 0x78, S_END };
224 unsigned char aG3_39[] = { S_INV, S_LNK, 0x79, S_END };
225 unsigned char aG3_3a[] = { S_INV, S_LNK, 0x7a, S_END };
226 unsigned char aG3_3b[] = { S_INV, S_LNK, 0x7b, S_END };
227 unsigned char aG3_3c[] = { S_INV, S_LNK, 0x7c, S_END };
228 unsigned char aG3_3d[] = { S_INV, S_LNK, 0x7d, S_END };
229 unsigned char aG3_3e[] = { S_LNK, 0x2e, S_FLH, S_END };
230 unsigned char aG3_3f[] = { S_BOX, 0, 0, S_W11, S_H11, S_END };
231 unsigned char aG3_40[] = { S_BOX, 0, S_H13, S_W11, S_H13, S_LNK, 0x7e, S_END };
232 unsigned char aG3_41[] = { S_BOX, 0, S_H13, S_W11, S_H13, S_LNK, 0x7e, S_FLV, S_END };
233 unsigned char aG3_42[] = { S_LNK, 0x50, S_BOX, S_W12, S_H13, S_W12, S_H13, S_END };
234 unsigned char aG3_43[] = { S_LNK, 0x50, S_BOX, 0, S_H13, S_W12, S_H13, S_END };
235 unsigned char aG3_44[] = { S_LNK, 0x48, S_FLV, S_LNK, 0x48, S_END };
236 unsigned char aG3_45[] = { S_LNK, 0x44, S_FLH, S_END };
237 unsigned char aG3_46[] = { S_LNK, 0x47, S_FLV, S_END };
238 unsigned char aG3_47[] = { S_LNK, 0x48, S_FLH, S_LNK, 0x48, S_END };
239 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 };
240 unsigned char aG3_49[] = { S_LNK, 0x48, S_FLH, S_END };
241 unsigned char aG3_4a[] = { S_LNK, 0x48, S_FLV, S_END };
242 unsigned char aG3_4b[] = { S_LNK, 0x48, S_FLH, S_FLV, S_END };
243 unsigned char aG3_4c[] = { S_LNK, 0x50, S_BOX, 0, S_H13, S_W11, S_H13, S_END };
244 unsigned char aG3_4d[] = { S_CHR, 0x25, 0xE6 };
245 unsigned char aG3_4e[] = { S_CHR, 0x25, 0xCF };
246 unsigned char aG3_4f[] = { S_CHR, 0x25, 0xCB };
247 unsigned char aG3_50[] = { S_BOX, S_W12, 0, 2, S_H11, S_FLH, S_BOX, S_W12, 0, 2, S_H11,S_END };
248 unsigned char aG3_51[] = { S_BOX, 0, S_H12, S_W11, 2, S_FLV, S_BOX, 0, S_H12, S_W11, 2,S_END };
249 unsigned char aG3_52[] = { S_LNK, 0x55, S_FLH, S_FLV, S_END };
250 unsigned char aG3_53[] = { S_LNK, 0x55, S_FLV, S_END };
251 unsigned char aG3_54[] = { S_LNK, 0x55, S_FLH, S_END };
252 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 };
253 unsigned char aG3_56[] = { S_LNK, 0x57, S_FLH, S_END};
254 unsigned char aG3_57[] = { S_LNK, 0x55, S_LNK, 0x50 , S_END};
255 unsigned char aG3_58[] = { S_LNK, 0x59, S_FLV, S_END};
256 unsigned char aG3_59[] = { S_LNK, 0x7e, S_LNK, 0x51 , S_END};
257 unsigned char aG3_5a[] = { S_LNK, 0x50, S_LNK, 0x51 , S_END};
258 unsigned char aG3_5b[] = { S_CHR, 0x21, 0x92};
259 unsigned char aG3_5c[] = { S_CHR, 0x21, 0x90};
260 unsigned char aG3_5d[] = { S_CHR, 0x21, 0x91};
261 unsigned char aG3_5e[] = { S_CHR, 0x21, 0x93};
262 unsigned char aG3_5f[] = { S_CHR, 0x00, 0x20};
263 unsigned char aG3_60[] = { S_INV, S_LNK, 0x20, S_END };
264 unsigned char aG3_61[] = { S_INV, S_LNK, 0x21, S_END };
265 unsigned char aG3_62[] = { S_INV, S_LNK, 0x22, S_END };
266 unsigned char aG3_63[] = { S_INV, S_LNK, 0x23, S_END };
267 unsigned char aG3_64[] = { S_INV, S_LNK, 0x24, S_END };
268 unsigned char aG3_65[] = { S_INV, S_LNK, 0x25, S_END };
269 unsigned char aG3_66[] = { S_LNK, 0x20, S_FLV, S_END };
270 unsigned char aG3_67[] = { S_LNK, 0x21, S_FLV, S_END };
271 unsigned char aG3_68[] = { S_LNK, 0x22, S_FLV, S_END };
272 unsigned char aG3_69[] = { S_LNK, 0x23, S_FLV, S_END };
273 unsigned char aG3_6a[] = { S_LNK, 0x24, S_FLV, S_END };
274 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 };
275 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 };
276 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 };
277 unsigned char aG3_6e[] = { S_CHR, 0x00, 0x20};
278 unsigned char aG3_6f[] = { S_CHR, 0x00, 0x20};
279 unsigned char aG3_70[] = { S_INV, S_LNK, 0x30, S_END };
280 unsigned char aG3_71[] = { S_INV, S_LNK, 0x31, S_END };
281 unsigned char aG3_72[] = { S_INV, S_LNK, 0x32, S_END };
282 unsigned char aG3_73[] = { S_INV, S_LNK, 0x33, S_END };
283 unsigned char aG3_74[] = { S_INV, S_LNK, 0x34, S_END };
284 unsigned char aG3_75[] = { S_INV, S_LNK, 0x35, S_END };
285 unsigned char aG3_76[] = { S_LNK, 0x66, S_FLH, S_END };
286 unsigned char aG3_77[] = { S_LNK, 0x67, S_FLH, S_END };
287 unsigned char aG3_78[] = { S_LNK, 0x68, S_FLH, S_END };
288 unsigned char aG3_79[] = { S_LNK, 0x69, S_FLH, S_END };
289 unsigned char aG3_7a[] = { S_LNK, 0x6a, S_FLH, S_END };
290 unsigned char aG3_7b[] = { S_LNK, 0x6b, S_FLH, S_END };
291 unsigned char aG3_7c[] = { S_LNK, 0x6c, S_FLH, S_END };
292 unsigned char aG3_7d[] = { S_LNK, 0x6d, S_FLV, S_END };
293 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)
295 unsigned char *aShapes[] =
297 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,
298 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,
299 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,
300 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,
301 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,
302 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
305 // G0 Table as defined in ETS 300 706
306 // cyrillic G0 Charset (0 = Serbian/Croatian, 1 = Russian/Bulgarian, 2 = Ukrainian)
307 const unsigned short int G0table[6][6*16] =
309 // Cyrillic G0 Set - Option 1 - Serbian/Croatian
310 { ' ', '!', '\"', '#', '$', '%', '&', '\'', '(' , ')' , '*', '+', ',', '-', '.', '/',
311 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
312 0x0427, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, 0x0425, 0x0418, 0x0408, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E,
313 0x041F, 0x040C, 0x0420, 0x0421, 0x0422, 0x0423, 0x0412, 0x0403, 0x0409, 0x040A, 0x0417, 0x040B, 0x0416, 0x0402, 0x0428, 0x040F,
314 0x0447, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, 0x0445, 0x0438, 0x0458, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E,
315 0x043F, 0x045C, 0x0440, 0x0441, 0x0442, 0x0443, 0x0432, 0x0453, 0x0459, 0x045A, 0x0437, 0x045B, 0x0436, 0x0452, 0x0448, 0x25A0},
316 // Cyrillic G0 Set - Option 2 - Russian/Bulgarian
317 { ' ', '!', '\"', '#', '$', '%', 0x044B, '\'', '(' , ')' , '*', '+', ',', '-', '.', '/',
318 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
319 0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, 0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E,
320 0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, 0x042C, 0x042A, 0x0417, 0x0428, 0x042D, 0x0429, 0x0427, 0x042B,
321 0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, 0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E,
322 0x043F, 0x044F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, 0x044C, 0x044A, 0x0437, 0x0448, 0x044D, 0x0449, 0x0447, 0x25A0},
323 // Cyrillic G0 Set - Option 3 - Ukrainian
324 { ' ', '!', '\"', '#', '$', '%', 0x0457, '\'', '(' , ')' , '*', '+', ',', '-', '.', '/',
325 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
326 0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, 0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E,
327 0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, 0x042C, 0x0406, 0x0417, 0x0428, 0x0404, 0x0429, 0x0427, 0x0407,
328 0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, 0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E,
329 0x043F, 0x044F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, 0x044C, 0x0456, 0x0437, 0x0448, 0x0454, 0x0449, 0x0447, 0x25A0},
331 { ' ', '!', '\"', '#', '$', '%', '&', '\'', '(' , ')' , '*', '+', ',', '-', '.', '/',
332 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', 0x00AB, '=', 0x00BB, '?',
333 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F,
334 0x03A0, 0x03A1, 0x0384, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF,
335 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
336 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0x25A0},
338 { ' ', '!', 0x05F2, 0x00A3, '$', '%', '&', '\'', '(' , ')' , '*', '+', ',', '-', '.', '/',
339 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
340 '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
341 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 0x2190, 0x00BD, 0x2192, 0x2191, '#',
342 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
343 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x20AA, 0x2551, 0x00BE, 0x00F7, 0x25A0},
344 // Arabic G0 Set - Thanks to Habib2006(fannansat)
345 { ' ', '!', 0x05F2, 0x00A3, '$', 0x066A, 0xFEF0, 0xFEF2, 0xFD3F, 0xFD3E, '*', '+', ',', '-', '.', '/',
346 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', 0x061B, '>', '=', '<', 0x061F,
347 0xFE94, 0x0621, 0xFE92, 0x0628, 0xFE98, 0x062A, 0xFE8E, 0xFE8D, 0xFE91, 0xFE93, 0xFE97, 0xFE9B, 0xFE9F, 0xFEA3, 0xFEA7, 0xFEA9,
348 0x0630, 0xFEAD, 0xFEAF, 0xFEB3, 0xFEB7, 0xFEBB, 0xFEBF, 0xFEC1, 0xFEC5, 0xFECB, 0xFECF, 0xFE9C, 0xFEA0, 0xFEA4, 0xFEA8, 0x0023,
349 0x0640, 0xFED3, 0xFED7, 0xFEDB, 0xFEDF, 0xFEE3, 0xFEE7, 0xFEEB, 0xFEED, 0xFEEF, 0xFEF3, 0xFE99, 0xFE9D, 0xFEA1, 0xFEA5, 0xFEF4,
350 0xFEF0, 0xFECC, 0xFED0, 0xFED4, 0xFED1, 0xFED8, 0xFED5, 0xFED9, 0xFEE0, 0xFEDD, 0xFEE4, 0xFEE1, 0xFEE8, 0xFEE5, 0xFEFB, 0x25A0}
353 const unsigned short int nationaltable23[14][2] =
355 { '#', 0x00A4 }, /* 0 */
356 { '#', 0x016F }, /* 1 CS/SK */
357 { 0x00A3, '$' }, /* 2 EN */
358 { '#', 0x00F5 }, /* 3 ET */
359 { 0x00E9, 0x0457 }, /* 4 FR */
360 { '#', '$' }, /* 5 DE */
361 { 0x00A3, '$' }, /* 6 IT */
362 { '#', '$' }, /* 7 LV/LT */
363 { '#', 0x0144 }, /* 8 PL */
364 { 0x00E7, '$' }, /* 9 PT/ES */
365 { '#', 0x00A4 }, /* A RO */
366 { '#', 0x00CB }, /* B SR/HR/SL */
367 { '#', 0x00A4 }, /* C SV/FI/HU */
368 { 0x20A4, 0x011F }, /* D TR */
370 const unsigned short int nationaltable40[14] =
373 0x010D, /* 1 CS/SK */
379 0x0161, /* 7 LV/LT */
381 0x00A1, /* 9 PT/ES */
383 0x010C, /* B SR/HR/SL */
384 0x00C9, /* C SV/FI/HU */
387 const unsigned short int nationaltable5b[14][6] =
389 { '[', '\\', ']', '^', '_', '`' }, /* 0 */
390 { 0x0165, 0x017E, 0x00FD, 0x00ED, 0x0159, 0x00E9 }, /* 1 CS/SK */
391 { 0x2190, 0x00BD, 0x2192, 0x2191, '#', 0x00AD }, /* 2 EN */
392 { 0x00C4, 0x00D6, 0x017D, 0x00DC, 0x00D5, 0x0161 }, /* 3 ET */
393 { 0x0451, 0x00EA, 0x00F9, 0x00EE, '#', 0x00E8 }, /* 4 FR */
394 { 0x00C4, 0x00D6, 0x00DC, '^', '_', 0x00B0 }, /* 5 DE */
395 { 0x00B0, 0x00E7, 0x2192, 0x2191, '#', 0x00F9 }, /* 6 IT */
396 { 0x0117, 0x0119, 0x017D, 0x010D, 0x016B, 0x0161 }, /* 7 LV/LT */
397 { 0x017B, 0x015A, 0x0141, 0x0107, 0x00F3, 0x0119 }, /* 8 PL */
398 { 0x00E1, 0x00E9, 0x00ED, 0x00F3, 0x00FA, 0x00BF }, /* 9 PT/ES */
399 { 0x00C2, 0x015E, 0x01CD, 0x01CF, 0x0131, 0x0163 }, /* A RO */
400 { 0x0106, 0x017D, 0x00D0, 0x0160, 0x0451, 0x010D }, /* B SR/HR/SL */
401 { 0x00C4, 0x00D6, 0x00C5, 0x00DC, '_', 0x00E9 }, /* C SV/FI/HU */
402 { 0x015E, 0x00D6, 0x00C7, 0x00DC, 0x011E, 0x0131 }, /* D TR */
404 const unsigned short int nationaltable7b[14][4] =
406 { '{', '|', '}', '~' }, /* 0 */
407 { 0x00E1, 0x011B, 0x00FA, 0x0161 }, /* 1 CS/SK */
408 { 0x00BC, 0x2551, 0x00BE, 0x00F7 }, /* 2 EN */
409 { 0x00E4, 0x00F6, 0x017E, 0x00FC }, /* 3 ET */
410 { 0x00E2, 0x00F4, 0x00FB, 0x00E7 }, /* 4 FR */
411 { 0x00E4, 0x00F6, 0x00FC, 0x00DF }, /* 5 DE */
412 { 0x00E0, 0x00F3, 0x00E8, 0x00EC }, /* 6 IT */
413 { 0x0105, 0x0173, 0x017E, 0x012F }, /* 7 LV/LT */
414 { 0x017C, 0x015B, 0x0142, 0x017A }, /* 8 PL */
415 { 0x00FC, 0x00F1, 0x00E8, 0x00E0 }, /* 9 PT/ES */
416 { 0x00E2, 0x015F, 0x01CE, 0x00EE }, /* A RO */
417 { 0x0107, 0x017E, 0x0111, 0x0161 }, /* B SR/HR/SL */
418 { 0x00E4, 0x00F6, 0x00E5, 0x00FC }, /* C SV/FI/HU */
419 { 0x015F, 0x00F6, 0x00E7, 0x00FC }, /* D TR */
421 const unsigned short int arrowtable[] =
423 8592, 8594, 8593, 8595, 'O', 'K', 8592, 8592
426 CTeletextDecoder::CTeletextDecoder()
428 memset(&m_RenderInfo, 0, sizeof(TextRenderInfo_t));
430 m_teletextFont = CSpecialProtocol::TranslatePath(TeletextFont);
431 m_TextureBuffer = NULL;
435 m_RenderInfo.ShowFlof = true;
436 m_RenderInfo.Show39 = true;
437 m_RenderInfo.Showl25 = true;
438 m_RenderInfo.Prev_100 = 0x100;
439 m_RenderInfo.Prev_10 = 0x100;
440 m_RenderInfo.Next_100 = 0x100;
441 m_RenderInfo.Next_10 = 0x100;
442 m_RenderInfo.InputCounter = 2;
444 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 };
445 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 };
446 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 };
447 unsigned short tr0[] = {0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
448 0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
449 0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
450 0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
451 0x0000 , 0x0000 , 0x0A0A , 0xFFFF, 0x3030 };
453 memcpy(m_RenderInfo.rd0,rd0,TXT_Color_SIZECOLTABLE*sizeof(unsigned short));
454 memcpy(m_RenderInfo.gn0,gn0,TXT_Color_SIZECOLTABLE*sizeof(unsigned short));
455 memcpy(m_RenderInfo.bl0,bl0,TXT_Color_SIZECOLTABLE*sizeof(unsigned short));
456 memcpy(m_RenderInfo.tr0,tr0,TXT_Color_SIZECOLTABLE*sizeof(unsigned short));
468 m_updateTexture = false;
472 CTeletextDecoder::~CTeletextDecoder()
476 bool CTeletextDecoder::HandleAction(const CAction &action)
478 if (m_txtCache == NULL)
480 CLog::Log(LOGERROR, "CTeletextDecoder::HandleAction called without teletext cache");
484 if (action.GetID() == ACTION_MOVE_UP)
486 if (m_RenderInfo.PageCatching)
487 CatchNextPage(-1, -1);
489 GetNextPageOne(true);
492 else if (action.GetID() == ACTION_MOVE_DOWN)
494 if (m_RenderInfo.PageCatching)
497 GetNextPageOne(false);
500 else if (action.GetID() == ACTION_MOVE_RIGHT)
502 if (m_RenderInfo.PageCatching)
504 else if (m_RenderInfo.Boxed)
506 m_RenderInfo.SubtitleDelay++;
507 // display SubtitleDelay
508 m_RenderInfo.PosY = 0;
511 sprintf(ns,"+%d ", m_RenderInfo.SubtitleDelay);
512 RenderCharFB(ns[0], &Text_AtrTable[ATR_WB]);
513 RenderCharFB(ns[1], &Text_AtrTable[ATR_WB]);
514 RenderCharFB(ns[2], &Text_AtrTable[ATR_WB]);
515 RenderCharFB(ns[4], &Text_AtrTable[ATR_WB]);
523 else if (action.GetID() == ACTION_MOVE_LEFT)
525 if (m_RenderInfo.PageCatching)
526 CatchNextPage(0, -1);
527 else if (m_RenderInfo.Boxed)
529 m_RenderInfo.SubtitleDelay--;
531 // display subtitledelay
532 m_RenderInfo.PosY = 0;
535 sprintf(ns,"+%d ", m_RenderInfo.SubtitleDelay);
536 RenderCharFB(ns[0], &Text_AtrTable[ATR_WB]);
537 RenderCharFB(ns[1], &Text_AtrTable[ATR_WB]);
538 RenderCharFB(ns[2], &Text_AtrTable[ATR_WB]);
539 RenderCharFB(ns[4], &Text_AtrTable[ATR_WB]);
547 else if (action.GetID() >= REMOTE_0 && action.GetID() <= REMOTE_9)
549 PageInput(action.GetID() - REMOTE_0);
552 else if (action.GetID() >= KEY_ASCII) // FIXME make it KEY_UNICODE
553 { // input from the keyboard
554 if (action.GetUnicode() >= 48 && action.GetUnicode() < 58)
556 PageInput(action.GetUnicode() - 48);
561 else if (action.GetID() == ACTION_PAGE_UP)
566 else if (action.GetID() == ACTION_PAGE_DOWN)
571 else if (action.GetID() == ACTION_SELECT_ITEM)
573 if (m_txtCache->SubPageTable[m_txtCache->Page] == 0xFF)
576 if (!m_RenderInfo.PageCatching)
584 if (m_RenderInfo.PageCatching)
586 m_txtCache->PageUpdate = true;
587 m_RenderInfo.PageCatching = 0;
591 if (action.GetID() == ACTION_SHOW_INFO)
596 else if (action.GetID() == ACTION_TELETEXT_RED)
598 ColorKey(m_RenderInfo.Prev_100);
601 else if (action.GetID() == ACTION_TELETEXT_GREEN)
603 ColorKey(m_RenderInfo.Prev_10);
606 else if (action.GetID() == ACTION_TELETEXT_YELLOW)
608 ColorKey(m_RenderInfo.Next_10);
611 else if (action.GetID() == ACTION_TELETEXT_BLUE)
613 ColorKey(m_RenderInfo.Next_100);
620 bool CTeletextDecoder::InitDecoder()
624 m_txtCache = g_application.m_pPlayer->GetTeletextCache();
625 if (m_txtCache == NULL)
627 CLog::Log(LOGERROR, "%s: called without teletext cache", __FUNCTION__);
631 /* init fontlibrary */
632 if ((error = FT_Init_FreeType(&m_Library)))
634 CLog::Log(LOGERROR, "%s: <FT_Init_FreeType: 0x%.2X>", __FUNCTION__, error);
639 if ((error = FTC_Manager_New(m_Library, 7, 2, 0, &MyFaceRequester, NULL, &m_Manager)))
641 FT_Done_FreeType(m_Library);
644 CLog::Log(LOGERROR, "%s: <FTC_Manager_New: 0x%.2X>", __FUNCTION__, error);
648 if ((error = FTC_SBitCache_New(m_Manager, &m_Cache)))
650 FTC_Manager_Done(m_Manager);
651 FT_Done_FreeType(m_Library);
654 CLog::Log(LOGERROR, "%s: <FTC_SBit_Cache_New: 0x%.2X>", __FUNCTION__, error);
658 /* calculate font dimensions */
659 m_RenderInfo.Width = (int)(g_graphicsContext.GetWidth()*g_graphicsContext.GetGUIScaleX());
660 m_RenderInfo.Height = (int)(g_graphicsContext.GetHeight()*g_graphicsContext.GetGUIScaleY());
661 m_RenderInfo.FontHeight = m_RenderInfo.Height / 25;
662 m_RenderInfo.FontWidth_Normal = m_RenderInfo.Width / (m_RenderInfo.Show39 ? 39 : 40);
663 SetFontWidth(m_RenderInfo.FontWidth_Normal);
664 for (int i = 0; i <= 10; i++)
665 m_RenderInfo.axdrcs[i+12+1] = (m_RenderInfo.FontHeight * i + 6) / 10;
668 m_TypeTTF.face_id = (FTC_FaceID) m_teletextFont.c_str();
669 m_TypeTTF.height = (FT_UShort) m_RenderInfo.FontHeight;
670 m_TypeTTF.flags = FT_LOAD_MONOCHROME;
671 if (FTC_Manager_LookupFace(m_Manager, m_TypeTTF.face_id, &m_Face))
673 m_TypeTTF.face_id = (FTC_FaceID) m_teletextFont.c_str();
674 if ((error = FTC_Manager_LookupFace(m_Manager, m_TypeTTF.face_id, &m_Face)))
676 CLog::Log(LOGERROR, "%s: <FTC_Manager_Lookup_Face failed with Errorcode 0x%.2X>\n", __FUNCTION__, error);
677 FTC_Manager_Done(m_Manager);
678 FT_Done_FreeType(m_Library);
684 m_Ascender = m_RenderInfo.FontHeight * m_Face->ascender / m_Face->units_per_EM;
686 /* set variable screeninfo for double buffering */
688 m_TextureBuffer = new color_t [4*m_RenderInfo.Height*m_RenderInfo.Width];
690 ClearFB(GetColorRGB(TXT_ColorTransp));
691 ClearBB(GetColorRGB(TXT_ColorTransp)); /* initialize backbuffer */
692 /* set new colormap */
693 SetColors((unsigned short *)DefaultColors, 0, TXT_Color_SIZECOLTABLE);
695 for (int i = 0; i < 40 * 25; i++)
697 m_RenderInfo.PageChar[i] = ' ';
698 m_RenderInfo.PageAtrb[i].fg = TXT_ColorTransp;
699 m_RenderInfo.PageAtrb[i].bg = TXT_ColorTransp;
700 m_RenderInfo.PageAtrb[i].charset = C_G0P;
701 m_RenderInfo.PageAtrb[i].doubleh = 0;
702 m_RenderInfo.PageAtrb[i].doublew = 0;
703 m_RenderInfo.PageAtrb[i].IgnoreAtBlackBgSubst = 0;
706 m_RenderInfo.TranspMode = false;
712 void CTeletextDecoder::EndDecoder()
714 /* clear SubtitleCache */
715 for (int i = 0; i < SUBTITLE_CACHESIZE; i++)
717 if (m_RenderInfo.SubtitleCache[i] != NULL)
719 delete m_RenderInfo.SubtitleCache[i];
720 m_RenderInfo.SubtitleCache[i] = NULL;
726 delete[] m_TextureBuffer;
727 m_TextureBuffer = NULL;
733 FTC_Manager_Done(m_Manager);
737 FT_Done_FreeType(m_Library);
745 CLog::Log(LOGNOTICE, "%s: called without cache", __FUNCTION__);
749 m_txtCache->PageUpdate = true;
750 CLog::Log(LOGDEBUG, "Teletext: Rendering ended");
755 void CTeletextDecoder::PageInput(int Number)
757 m_updateTexture = true;
759 /* clear m_TempPage */
760 if (m_RenderInfo.InputCounter == 2)
763 /* check for 0 & 9 on first position */
764 if (Number == 0 && m_RenderInfo.InputCounter == 2)
767 m_TempPage = m_LastPage; /* 0 toggles to last page as in program switching */
768 m_RenderInfo.InputCounter = -1;
770 else if (Number == 9 && m_RenderInfo.InputCounter == 2)
776 if (m_RenderInfo.ZoomMode == 2)
778 m_RenderInfo.ZoomMode = 1;
782 m_RenderInfo.PosY = 0;
784 switch (m_RenderInfo.InputCounter)
788 RenderCharFB(Number | '0', &Text_AtrTable[ATR_WB]);
789 RenderCharFB('-', &Text_AtrTable[ATR_WB]);
790 RenderCharFB('-', &Text_AtrTable[ATR_WB]);
795 RenderCharFB(Number | '0', &Text_AtrTable[ATR_WB]);
800 RenderCharFB(Number | '0', &Text_AtrTable[ATR_WB]);
804 /* generate pagenumber */
805 m_TempPage |= Number << (m_RenderInfo.InputCounter*4);
807 m_RenderInfo.InputCounter--;
809 if (m_RenderInfo.InputCounter < 0)
811 /* disable SubPage zapping */
812 m_txtCache->ZapSubpageManual = false;
815 m_RenderInfo.InputCounter = 2;
818 m_LastPage = m_txtCache->Page;
820 m_txtCache->Page = m_TempPage;
821 m_RenderInfo.HintMode = false;
824 int subp = m_txtCache->SubPageTable[m_txtCache->Page];
827 m_txtCache->SubPage = subp;
828 m_txtCache->PageUpdate = true;
832 m_txtCache->SubPage = 0;
833 // RenderMessage(PageNotFound);
838 void CTeletextDecoder::GetNextPageOne(bool up)
840 /* disable subpage zapping */
841 m_txtCache->ZapSubpageManual = false;
843 /* abort pageinput */
844 m_RenderInfo.InputCounter = 2;
846 /* find next cached page */
847 m_LastPage = m_txtCache->Page;
852 CDVDTeletextTools::NextDec(&m_txtCache->Page);
854 CDVDTeletextTools::PrevDec(&m_txtCache->Page);
855 subp = m_txtCache->SubPageTable[m_txtCache->Page];
856 } while (subp == 0xFF && m_txtCache->Page != m_LastPage);
859 if (m_txtCache->Page != m_LastPage)
861 if (m_RenderInfo.ZoomMode == 2)
862 m_RenderInfo.ZoomMode = 1;
864 m_txtCache->SubPage = subp;
865 m_RenderInfo.HintMode = false;
866 m_txtCache->PageUpdate = true;
870 void CTeletextDecoder::GetNextSubPage(int offset)
872 /* abort pageinput */
873 m_RenderInfo.InputCounter = 2;
875 for (int loop = m_txtCache->SubPage + offset; loop != m_txtCache->SubPage; loop += offset)
879 else if (loop > 0x79)
881 if (loop == m_txtCache->SubPage)
884 if (m_txtCache->astCachetable[m_txtCache->Page][loop])
886 /* enable manual SubPage zapping */
887 m_txtCache->ZapSubpageManual = true;
890 if (m_RenderInfo.ZoomMode == 2) /* if zoomed to lower half */
891 m_RenderInfo.ZoomMode = 1; /* activate upper half */
893 m_txtCache->SubPage = loop;
894 m_RenderInfo.HintMode = false;
895 m_txtCache->PageUpdate = true;
902 void CTeletextDecoder::SwitchZoomMode()
904 if (m_txtCache->SubPageTable[m_txtCache->Page] != 0xFF)
907 m_RenderInfo.ZoomMode++;
909 if (m_RenderInfo.ZoomMode == 3)
910 m_RenderInfo.ZoomMode = 0;
913 m_txtCache->PageUpdate = true;
917 void CTeletextDecoder::SwitchTranspMode()
920 if (!m_RenderInfo.TranspMode)
921 m_RenderInfo.TranspMode = true;
923 m_RenderInfo.TranspMode = false; /* backward to immediately switch to TV-screen */
926 if (!m_RenderInfo.TranspMode) /* normal text-only */
928 ClearBB(m_txtCache->FullScrColor);
929 m_txtCache->PageUpdate = true;
931 else /* semi-transparent BG with FG text */
933 ClearBB(TXT_ColorTransp);
934 m_txtCache->PageUpdate = true;
938 void CTeletextDecoder::SwitchHintMode()
941 m_RenderInfo.HintMode ^= true;
943 if (!m_RenderInfo.HintMode) /* toggle evaluation of level 2.5 information by explicitly switching off HintMode */
945 m_RenderInfo.Showl25 ^= true;
948 m_txtCache->PageUpdate = true;
951 void CTeletextDecoder::ColorKey(int target)
956 if (m_RenderInfo.ZoomMode == 2)
957 m_RenderInfo.ZoomMode = 1;
959 m_LastPage = m_txtCache->Page;
960 m_txtCache->Page = target;
961 m_txtCache->SubPage = m_txtCache->SubPageTable[m_txtCache->Page];
962 m_RenderInfo.InputCounter = 2;
963 m_RenderInfo.HintMode = false;
964 m_txtCache->PageUpdate = true;
967 void CTeletextDecoder::StartPageCatching()
969 m_RenderInfo.PageCatching = true;
971 /* abort pageinput */
972 m_RenderInfo.InputCounter = 2;
975 m_RenderInfo.ZoomMode = 0;
976 m_RenderInfo.PosX = 0;
977 m_RenderInfo.PosY = 24*m_RenderInfo.FontHeight;
979 /* check for pagenumber(s) */
984 m_PCOldCol = 0; /* no inverted page number to restore yet */
989 m_RenderInfo.PageCatching = false;
990 m_txtCache->PageUpdate = true;
995 void CTeletextDecoder::StopPageCatching()
998 if (m_RenderInfo.ZoomMode == 2)
999 m_RenderInfo.ZoomMode = 1;
1001 m_LastPage = m_txtCache->Page;
1002 m_txtCache->Page = m_CatchedPage;
1003 m_RenderInfo.HintMode = false;
1004 m_txtCache->PageUpdate = true;
1005 m_RenderInfo.PageCatching = false;
1007 int subp = m_txtCache->SubPageTable[m_txtCache->Page];
1009 m_txtCache->SubPage = subp;
1011 m_txtCache->SubPage = 0;
1014 void CTeletextDecoder::CatchNextPage(int firstlineinc, int inc)
1016 int tmp_page, allowwrap = 1; /* allow first wrap around */
1018 /* catch next page */
1021 unsigned char *p = &(m_RenderInfo.PageChar[m_CatchRow*40 + m_CatchCol]);
1022 TextPageAttr_t a = m_RenderInfo.PageAtrb[m_CatchRow*40 + m_CatchCol];
1024 if (!(a.charset == C_G1C || a.charset == C_G1S) && /* no mosaic */
1025 (a.fg != a.bg) && /* not hidden */
1026 (*p >= '1' && *p <= '8' && /* valid page number */
1027 *(p+1) >= '0' && *(p+1) <= '9' &&
1028 *(p+2) >= '0' && *(p+2) <= '9') &&
1029 (m_CatchRow == 0 || (*(p-1) < '0' || *(p-1) > '9')) && /* non-numeric char before and behind */
1030 (m_CatchRow == 37 || (*(p+3) < '0' || *(p+3) > '9')))
1032 tmp_page = ((*p - '0')<<8) | ((*(p+1) - '0')<<4) | (*(p+2) - '0');
1035 if (tmp_page != m_CatchedPage) /* confusing to skip identical page numbers - I want to reach what I aim to */
1038 m_CatchedPage = tmp_page;
1039 RenderCatchedPage();
1040 m_CatchCol += inc; /* FIXME: limit */
1045 if (firstlineinc > 0)
1051 else if (firstlineinc < 0)
1060 if (m_CatchCol > 37)
1065 else if (m_CatchCol < 0)
1071 if (m_CatchRow > 23)
1084 else if (m_CatchRow < 1)
1100 void CTeletextDecoder::RenderCatchedPage()
1103 m_updateTexture = true;
1106 if (m_RenderInfo.ZoomMode)
1109 if (m_PCOldRow || m_PCOldCol) /* not at first call */
1111 /* restore pagenumber */
1112 SetPosX(m_PCOldCol);
1114 if (m_RenderInfo.ZoomMode == 2)
1115 m_RenderInfo.PosY = (m_PCOldRow-12)*m_RenderInfo.FontHeight*((zoom>>10)+1);
1117 m_RenderInfo.PosY = m_PCOldRow*m_RenderInfo.FontHeight*((zoom>>10)+1);
1119 RenderCharFB(m_RenderInfo.PageChar[m_PCOldRow*40 + m_PCOldCol ], &m_RenderInfo.PageAtrb[m_PCOldRow*40 + m_PCOldCol ]);
1120 RenderCharFB(m_RenderInfo.PageChar[m_PCOldRow*40 + m_PCOldCol + 1], &m_RenderInfo.PageAtrb[m_PCOldRow*40 + m_PCOldCol + 1]);
1121 RenderCharFB(m_RenderInfo.PageChar[m_PCOldRow*40 + m_PCOldCol + 2], &m_RenderInfo.PageAtrb[m_PCOldRow*40 + m_PCOldCol + 2]);
1124 m_PCOldRow = m_CatchRow;
1125 m_PCOldCol = m_CatchCol;
1127 /* mark pagenumber */
1128 if (m_RenderInfo.ZoomMode == 1 && m_CatchRow > 11)
1130 m_RenderInfo.ZoomMode = 2;
1133 else if (m_RenderInfo.ZoomMode == 2 && m_CatchRow < 12)
1135 m_RenderInfo.ZoomMode = 1;
1138 SetPosX(m_CatchCol);
1140 if (m_RenderInfo.ZoomMode == 2)
1141 m_RenderInfo.PosY = (m_CatchRow-12)*m_RenderInfo.FontHeight*((zoom>>10)+1);
1143 m_RenderInfo.PosY = m_CatchRow*m_RenderInfo.FontHeight*((zoom>>10)+1);
1145 TextPageAttr_t a0 = m_RenderInfo.PageAtrb[m_CatchRow*40 + m_CatchCol ];
1146 TextPageAttr_t a1 = m_RenderInfo.PageAtrb[m_CatchRow*40 + m_CatchCol + 1];
1147 TextPageAttr_t a2 = m_RenderInfo.PageAtrb[m_CatchRow*40 + m_CatchCol + 2];
1150 /* exchange colors */
1151 t = a0.fg; a0.fg = a0.bg; a0.bg = t;
1152 t = a1.fg; a1.fg = a1.bg; a1.bg = t;
1153 t = a2.fg; a2.fg = a2.bg; a2.bg = t;
1155 RenderCharFB(m_RenderInfo.PageChar[m_CatchRow*40 + m_CatchCol ], &a0);
1156 RenderCharFB(m_RenderInfo.PageChar[m_CatchRow*40 + m_CatchCol + 1], &a1);
1157 RenderCharFB(m_RenderInfo.PageChar[m_CatchRow*40 + m_CatchCol + 2], &a2);
1160 void CTeletextDecoder::RenderPage()
1163 int national_subset_bak = m_txtCache->NationalSubset;
1165 if (m_txtCache->PageUpdate)
1166 m_updateTexture = true;
1168 /* update page or timestring */
1169 if (m_txtCache->PageUpdate && m_txtCache->PageReceiving != m_txtCache->Page && m_RenderInfo.InputCounter == 2)
1171 /* reset update flag */
1172 m_txtCache->PageUpdate = false;
1173 if (m_RenderInfo.Boxed && m_RenderInfo.SubtitleDelay)
1175 TextSubtitleCache_t* c = NULL;
1177 for (int i = 0; i < SUBTITLE_CACHESIZE; i++)
1179 if (j == -1 && !m_RenderInfo.SubtitleCache[i])
1181 if (m_RenderInfo.SubtitleCache[i] && !m_RenderInfo.SubtitleCache[i]->Valid)
1183 c = m_RenderInfo.SubtitleCache[i];
1189 if (j == -1) // no more space in SubtitleCache
1192 c = new TextSubtitleCache_t;
1196 memset(c, 0x00, sizeof(TextSubtitleCache_t));
1197 m_RenderInfo.SubtitleCache[j] = c;
1200 c->Timestamp = XbmcThreads::SystemClockMillis()/1000;
1202 if (m_txtCache->SubPageTable[m_txtCache->Page] != 0xFF)
1204 TextPageinfo_t * p = DecodePage(m_RenderInfo.Showl25, c->PageChar, c->PageAtrb, m_RenderInfo.HintMode, m_RenderInfo.ShowFlof);
1207 m_RenderInfo.Boxed = p->boxed;
1210 m_RenderInfo.DelayStarted = true;
1213 m_RenderInfo.DelayStarted = false;
1215 if (m_txtCache->SubPageTable[m_txtCache->Page] != 0xFF)
1217 TextPageinfo_t * p = DecodePage(m_RenderInfo.Showl25, m_RenderInfo.PageChar, m_RenderInfo.PageAtrb, m_RenderInfo.HintMode, m_RenderInfo.ShowFlof);
1220 m_RenderInfo.PageInfo = p;
1221 m_RenderInfo.Boxed = p->boxed;
1223 if (m_RenderInfo.Boxed || m_RenderInfo.TranspMode)
1224 FillBorder(GetColorRGB(TXT_ColorTransp));
1226 FillBorder(GetColorRGB((enumTeletextColor)m_txtCache->FullScrColor));
1228 if (m_txtCache->ColorTable) /* as late as possible to shorten the time the old page is displayed with the new colors */
1229 SetColors(m_txtCache->ColorTable, 16, 16); /* set colors for CLUTs 2+3 */
1234 DoRenderPage(StartRow, national_subset_bak);
1238 if (m_RenderInfo.DelayStarted)
1240 long now = XbmcThreads::SystemClockMillis()/1000;
1241 for (int i = 0; i < SUBTITLE_CACHESIZE ; i++)
1243 if (m_RenderInfo.SubtitleCache[i] && m_RenderInfo.SubtitleCache[i]->Valid && now - m_RenderInfo.SubtitleCache[i]->Timestamp >= (long)m_RenderInfo.SubtitleDelay)
1245 memcpy(m_RenderInfo.PageChar, m_RenderInfo.SubtitleCache[i]->PageChar, 40 * 25);
1246 memcpy(m_RenderInfo.PageAtrb, m_RenderInfo.SubtitleCache[i]->PageAtrb, 40 * 25 * sizeof(TextPageAttr_t));
1247 DoRenderPage(StartRow, national_subset_bak);
1248 m_RenderInfo.SubtitleCache[i]->Valid = false;
1253 if (m_RenderInfo.ZoomMode != 2)
1255 m_RenderInfo.PosY = 0;
1256 if (m_txtCache->SubPageTable[m_txtCache->Page] == 0xff)
1258 m_RenderInfo.PageAtrb[32].fg = TXT_ColorYellow;
1259 m_RenderInfo.PageAtrb[32].bg = TXT_ColorMenu1;
1260 int showpage = m_txtCache->PageReceiving;
1261 int showsubpage = m_txtCache->SubPageTable[showpage];
1262 if (showsubpage!=0xff)
1264 TextCachedPage_t *pCachedPage;
1265 pCachedPage = m_txtCache->astCachetable[showpage][showsubpage];
1266 if (pCachedPage && IsDec(showpage))
1268 m_RenderInfo.PosX = 0;
1269 if (m_RenderInfo.InputCounter == 2)
1271 if (m_txtCache->BTTok && !m_txtCache->BasicTop[m_txtCache->Page]) /* page non-existent according to TOP (continue search anyway) */
1273 m_RenderInfo.PageAtrb[0].fg = TXT_ColorWhite;
1274 m_RenderInfo.PageAtrb[0].bg = TXT_ColorRed;
1278 m_RenderInfo.PageAtrb[0].fg = TXT_ColorYellow;
1279 m_RenderInfo.PageAtrb[0].bg = TXT_ColorMenu1;
1281 CDVDTeletextTools::Hex2Str((char*)m_RenderInfo.PageChar+3, m_txtCache->Page);
1284 for (col = m_RenderInfo.nofirst; col < 7; col++) // selected page
1286 RenderCharFB(m_RenderInfo.PageChar[col], &m_RenderInfo.PageAtrb[0]);
1288 RenderCharFB(m_RenderInfo.PageChar[col], &m_RenderInfo.PageAtrb[32]);
1293 memcpy(&m_RenderInfo.PageChar[8], pCachedPage->p0, 24); /* header line without timestring */
1294 for (int i = 0; i < 24; i++)
1296 RenderCharFB(pCachedPage->p0[i], &m_RenderInfo.PageAtrb[32]);
1299 /* Update on every Header number change */
1300 if (pCachedPage->p0[2] != prevHeaderPage)
1302 prevHeaderPage = pCachedPage->p0[2];
1303 m_updateTexture = true;
1309 /* update timestring */
1311 for (int i = 0; i < 8; i++)
1313 if (!m_RenderInfo.PageAtrb[32+i].flashing)
1314 RenderCharFB(m_txtCache->TimeString[i], &m_RenderInfo.PageAtrb[32]);
1318 m_RenderInfo.PageChar[32+i] = m_RenderInfo.PageChar[32+i];
1322 /* Update on every changed second */
1323 if (m_txtCache->TimeString[7] != prevTimeSec)
1325 prevTimeSec = m_txtCache->TimeString[7];
1326 m_updateTexture = true;
1329 DoFlashing(StartRow);
1330 m_txtCache->NationalSubset = national_subset_bak;
1334 void CTeletextDecoder::DoFlashing(int startrow)
1336 /* get national subset */
1337 if (m_txtCache->NationalSubset <= NAT_MAX_FROM_HEADER && /* not for GR/RU as long as line28 is not evaluated */
1338 m_RenderInfo.PageInfo && m_RenderInfo.PageInfo->nationalvalid) /* individual subset according to page header */
1340 m_txtCache->NationalSubset = CountryConversionTable[m_RenderInfo.PageInfo->national];
1344 TextPageAttr_t flashattr;
1346 long flashphase = XbmcThreads::SystemClockMillis() % 1000;
1348 int srow = startrow;
1352 switch (m_RenderInfo.ZoomMode)
1354 case 1: erow = 12; factor=2;break;
1355 case 2: srow = 12; factor=2;break;
1358 m_RenderInfo.PosY = startrow*m_RenderInfo.FontHeight*factor;
1359 for (int row = srow; row < erow; row++)
1361 int index = row * 40;
1366 m_RenderInfo.PosX = 0;
1367 for (int col = m_RenderInfo.nofirst; col < 40; col++)
1369 if (m_RenderInfo.PageAtrb[index + col].flashing && m_RenderInfo.PageChar[index + col] > 0x20 && m_RenderInfo.PageChar[index + col] != 0xff )
1372 flashchar = m_RenderInfo.PageChar[index + col];
1373 bool doflash = false;
1374 memcpy(&flashattr, &m_RenderInfo.PageAtrb[index + col], sizeof(TextPageAttr_t));
1375 switch (flashattr.flashing &0x1c) // Flash Rate
1378 if (flashphase>500) doflash = true;
1380 case 0x04 : // 2 Hz Phase 1
1381 if (flashphase<250) doflash = true;
1383 case 0x08 : // 2 Hz Phase 2
1384 if (flashphase>=250 && flashphase<500) doflash = true;
1386 case 0x0c : // 2 Hz Phase 3
1387 if (flashphase>=500 && flashphase<750) doflash = true;
1389 case 0x10 : // incremental flash
1391 if (incflash>3) incflash = 1;
1394 case 1: if (flashphase<250) doflash = true; break;
1395 case 2: if (flashphase>=250 && flashphase<500) doflash = true;break;
1396 case 3: if (flashphase>=500 && flashphase<750) doflash = true;
1399 case 0x14 : // decremental flash
1401 if (decflash<1) decflash = 3;
1404 case 1: if (flashphase<250) doflash = true; break;
1405 case 2: if (flashphase>=250 && flashphase<500) doflash = true;break;
1406 case 3: if (flashphase>=500 && flashphase<750) doflash = true;
1412 switch (flashattr.flashing &0x03) // Flash Mode
1414 case 0x01 : // normal Flashing
1415 if (doflash) flashattr.fg = flashattr.bg;
1417 case 0x02 : // inverted Flashing
1419 if (doflash) flashattr.fg = flashattr.bg;
1421 case 0x03 : // color Flashing
1422 if (doflash) flashattr.fg = flashattr.fg + (flashattr.fg > 7 ? (-8) : 8);
1426 RenderCharFB(flashchar, &flashattr);
1427 if (flashattr.doublew) col++;
1428 if (flashattr.doubleh) dhset = 1;
1430 m_updateTexture = true;
1436 m_RenderInfo.PosY += m_RenderInfo.FontHeight*factor;
1438 m_RenderInfo.PosY += m_RenderInfo.FontHeight*factor;
1442 void CTeletextDecoder::DoRenderPage(int startrow, int national_subset_bak)
1444 /* display first column? */
1445 m_RenderInfo.nofirst = m_RenderInfo.Show39;
1446 for (int row = 1; row < 24; row++)
1448 int Byte = m_RenderInfo.PageChar[row*40];
1449 if (Byte != ' ' && Byte != 0x00 && Byte != 0xFF && m_RenderInfo.PageAtrb[row*40].fg != m_RenderInfo.PageAtrb[row*40].bg)
1451 m_RenderInfo.nofirst = 0;
1456 if (m_RenderInfo.TranspMode || m_RenderInfo.Boxed)
1458 FillBorder(GetColorRGB(TXT_ColorTransp));//ClearBB(transp);
1459 m_RenderInfo.ClearBBColor = TXT_ColorTransp;
1462 /* get national subset */
1463 if (m_txtCache->NationalSubset <= NAT_MAX_FROM_HEADER && /* not for GR/RU as long as line28 is not evaluated */
1464 m_RenderInfo.PageInfo && m_RenderInfo.PageInfo->nationalvalid) /* individual subset according to page header */
1466 m_txtCache->NationalSubset = CountryConversionTable[m_RenderInfo.PageInfo->national];
1469 if (m_RenderInfo.PageInfo && (m_RenderInfo.PageInfo->function == FUNC_GDRCS || m_RenderInfo.PageInfo->function == FUNC_DRCS)) /* character definitions */
1472 #define DRCSCOLS (48/DRCSROWS)
1475 #define DRCSXSPC (12*DRCSZOOMX + 2)
1476 #define DRCSYSPC (10*DRCSZOOMY + 2)
1478 unsigned char ax[] = { /* array[0..12] of x-offsets, array[0..10] of y-offsets for each pixel */
1505 ClearBB(TXT_ColorBlack);
1506 for (int col = 0; col < 24*40; col++)
1507 m_RenderInfo.PageAtrb[col] = Text_AtrTable[ATR_WB];
1509 for (int row = 0; row < DRCSROWS; row++)
1511 for (int col = 0; col < DRCSCOLS; col++)
1513 RenderDRCS(m_RenderInfo.Width,
1514 m_RenderInfo.PageChar + 20 * (DRCSCOLS * row + col + 2),
1516 + (m_RenderInfo.FontHeight + DRCSYSPC * row + m_RenderInfo.Height) * m_RenderInfo.Width
1518 ax, GetColorRGB(TXT_ColorWhite), GetColorRGB(TXT_ColorBlack));
1521 memset(m_RenderInfo.PageChar + 40, 0xff, 24*40); /* don't render any char below row 0 */
1523 m_RenderInfo.PosY = startrow*m_RenderInfo.FontHeight;
1524 for (int row = startrow; row < 24; row++)
1526 int index = row * 40;
1528 m_RenderInfo.PosX = 0;
1529 for (int col = m_RenderInfo.nofirst; col < 40; col++)
1531 RenderCharBB(m_RenderInfo.PageChar[index + col], &m_RenderInfo.PageAtrb[index + col]);
1533 if (m_RenderInfo.PageAtrb[index + col].doubleh && m_RenderInfo.PageChar[index + col] != 0xff) /* disable lower char in case of doubleh setting in l25 objects */
1534 m_RenderInfo.PageChar[index + col + 40] = 0xff;
1535 if (m_RenderInfo.PageAtrb[index + col].doublew) /* skip next column if double width */
1538 if (m_RenderInfo.PageAtrb[index + col-1].doubleh && m_RenderInfo.PageChar[index + col] != 0xff) /* disable lower char in case of doubleh setting in l25 objects */
1539 m_RenderInfo.PageChar[index + col + 40] = 0xff;
1542 m_RenderInfo.PosY += m_RenderInfo.FontHeight;
1544 DoFlashing(startrow);
1546 /* update framebuffer */
1548 m_txtCache->NationalSubset = national_subset_bak;
1551 void CTeletextDecoder::Decode_BTT()
1553 /* basic top table */
1554 int current, b1, b2, b3, b4;
1555 unsigned char btt[23*40];
1557 if (m_txtCache->SubPageTable[0x1f0] == 0xff || 0 == m_txtCache->astCachetable[0x1f0][m_txtCache->SubPageTable[0x1f0]]) /* not yet received */
1560 g_application.m_pPlayer->LoadPage(0x1f0, m_txtCache->SubPageTable[0x1f0],btt);
1561 if (btt[799] == ' ') /* not completely received or error */
1565 for (int i = 0; i < 800; i++)
1573 if (b1 == 0xFF) /* hamming error in btt */
1575 btt[799] = ' '; /* mark btt as not received */
1579 m_txtCache->BasicTop[current] = b1;
1580 CDVDTeletextTools::NextDec(¤t);
1582 /* page linking table */
1583 m_txtCache->ADIP_PgMax = -1; /* rebuild table of adip pages */
1584 for (int i = 0; i < 10; i++)
1586 b1 = dehamming[btt[800 + 8*i +0]];
1589 continue; /* unused */
1593 b4 = dehamming[btt[800 + 8*i +7]];
1595 if (b4 != 2) /* only adip, ignore multipage (1) */
1598 b2 = dehamming[btt[800 + 8*i +1]];
1599 b3 = dehamming[btt[800 + 8*i +2]];
1601 if (b1 == 0xFF || b2 == 0xFF || b3 == 0xFF)
1603 CLog::Log(LOGERROR, "CTeletextDecoder::Decode_BTT <Biterror in btt/plt index %d>", i);
1604 btt[799] = ' '; /* mark btt as not received */
1608 b1 = b1<<8 | b2<<4 | b3; /* page number */
1609 m_txtCache->ADIP_Pg[++m_txtCache->ADIP_PgMax] = b1;
1612 m_txtCache->BTTok = true;
1615 void CTeletextDecoder::Decode_ADIP() /* additional information table */
1617 int i, p, j, b1, b2, b3, charfound;
1618 unsigned char padip[23*40];
1620 for (i = 0; i <= m_txtCache->ADIP_PgMax; i++)
1622 p = m_txtCache->ADIP_Pg[i];
1623 if (!p || m_txtCache->SubPageTable[p] == 0xff || 0 == m_txtCache->astCachetable[p][m_txtCache->SubPageTable[p]]) /* not cached (avoid segfault) */
1626 g_application.m_pPlayer->LoadPage(p,m_txtCache->SubPageTable[p],padip);
1627 for (j = 0; j < 44; j++)
1629 b1 = dehamming[padip[20*j+0]];
1631 continue; /* unused */
1636 b2 = dehamming[padip[20*j+1]];
1637 b3 = dehamming[padip[20*j+2]];
1639 if (b1 == 0xFF || b2 == 0xFF || b3 == 0xFF)
1641 CLog::Log(LOGERROR, "CTeletextDecoder::Decode_BTT <Biterror in ait %03x %d %02x %02x %02x %02x %02x %02x>", p, j,
1650 if (b1>8 || b2>9 || b3>9) /* ignore extries with invalid or hex page numbers */
1655 b1 = b1<<8 | b2<<4 | b3; /* page number */
1656 charfound = 0; /* flag: no printable char found */
1658 for (b2 = 11; b2 >= 0; b2--)
1660 b3 = deparity[padip[20*j + 8 + b2]];
1664 if (b3 == ' ' && !charfound)
1665 m_txtCache->ADIPTable[b1][b2] = '\0';
1668 m_txtCache->ADIPTable[b1][b2] = b3;
1674 m_txtCache->ADIP_Pg[i] = 0; /* completely decoded: clear entry */
1675 } /* next adip page i */
1677 while ((m_txtCache->ADIP_PgMax >= 0) && !m_txtCache->ADIP_Pg[m_txtCache->ADIP_PgMax]) /* and shrink table */
1678 m_txtCache->ADIP_PgMax--;
1681 int CTeletextDecoder::TopText_GetNext(int startpage, int up, int findgroup)
1683 int current, nextgrp, nextblk;
1685 int stoppage = (IsDec(startpage) ? startpage : startpage & 0xF00); // avoid endless loop in hexmode
1686 nextgrp = nextblk = 0;
1687 current = startpage;
1691 CDVDTeletextTools::NextDec(¤t);
1693 CDVDTeletextTools::PrevDec(¤t);
1695 if (!m_txtCache->BTTok || m_txtCache->BasicTop[current]) /* only if existent */
1699 if (m_txtCache->BasicTop[current] >= 6 && m_txtCache->BasicTop[current] <= 7)
1701 if (!nextgrp && (current&0x00F) == 0)
1704 if (m_txtCache->BasicTop[current] >= 2 && m_txtCache->BasicTop[current] <= 5) /* always find block */
1707 if (!nextblk && (current&0x0FF) == 0)
1710 } while (current != stoppage);
1720 void CTeletextDecoder::Showlink(int column, int linkpage)
1722 unsigned char line[] = " >??? ";
1723 int oldfontwidth = m_RenderInfo.FontWidth;
1729 yoffset = m_RenderInfo.Height;
1731 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
1732 int width = m_RenderInfo.Width /4;
1734 m_RenderInfo.PosY = 24*m_RenderInfo.FontHeight;
1736 if (m_RenderInfo.Boxed)
1738 m_RenderInfo.PosX = column*width;
1739 FillRect(m_TextureBuffer, m_RenderInfo.Width, m_RenderInfo.PosX, m_RenderInfo.PosY+yoffset, m_RenderInfo.Width, m_RenderInfo.FontHeight, GetColorRGB(TXT_ColorTransp));
1743 if (m_txtCache->ADIPTable[linkpage][0])
1745 m_RenderInfo.PosX = column*width;
1746 int l = strlen(m_txtCache->ADIPTable[linkpage]);
1748 if (l > 9) /* smaller font, if no space for one half space at front and end */
1749 SetFontWidth(oldfontwidth * 10 / (l+1));
1751 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));
1752 m_RenderInfo.PosX += ((width) - (l*m_RenderInfo.FontWidth+l*m_RenderInfo.FontWidth/abx))/2; /* center */
1754 for (char *p = m_txtCache->ADIPTable[linkpage]; *p; p++)
1755 RenderCharBB(*p, &Text_AtrTable[ATR_L250 + column]);
1757 SetFontWidth(oldfontwidth);
1759 else /* display number */
1761 m_RenderInfo.PosX = column*width;
1762 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));
1763 if (linkpage < m_txtCache->Page)
1766 CDVDTeletextTools::Hex2Str((char*)line + 5, linkpage);
1769 CDVDTeletextTools::Hex2Str((char*)line + 6, linkpage);
1771 for (unsigned char *p = line; p < line+9; p++)
1772 RenderCharBB(*p, &Text_AtrTable[ATR_L250 + column]);
1776 void CTeletextDecoder::CreateLine25()
1778 /* btt completely received and not yet decoded */
1779 if (!m_txtCache->BTTok)
1782 if (m_txtCache->ADIP_PgMax >= 0)
1785 if (!m_RenderInfo.ShowHex && m_RenderInfo.ShowFlof &&
1786 (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
1788 m_RenderInfo.Prev_100 = m_txtCache->FlofPages[m_txtCache->Page][0];
1789 m_RenderInfo.Prev_10 = m_txtCache->FlofPages[m_txtCache->Page][1];
1790 m_RenderInfo.Next_10 = m_txtCache->FlofPages[m_txtCache->Page][2];
1791 m_RenderInfo.Next_100 = m_txtCache->FlofPages[m_txtCache->Page][3];
1793 m_RenderInfo.PosY = 24*m_RenderInfo.FontHeight;
1794 m_RenderInfo.PosX = 0;
1795 for (int i=m_RenderInfo.nofirst; i<40; i++)
1796 RenderCharBB(m_RenderInfo.PageChar[24*40 + i], &m_RenderInfo.PageAtrb[24*40 + i]);
1800 /* normal: blk-1, grp+1, grp+2, blk+1 */
1801 /* hex: hex+1, blk-1, grp+1, blk+1 */
1802 if (m_RenderInfo.ShowHex)
1804 /* arguments: startpage, up, findgroup */
1805 m_RenderInfo.Prev_100 = NextHex(m_txtCache->Page);
1806 m_RenderInfo.Prev_10 = TopText_GetNext(m_txtCache->Page, 0, 0);
1807 m_RenderInfo.Next_10 = TopText_GetNext(m_txtCache->Page, 1, 1);
1811 m_RenderInfo.Prev_100 = TopText_GetNext(m_txtCache->Page, 0, 0);
1812 m_RenderInfo.Prev_10 = TopText_GetNext(m_txtCache->Page, 1, 1);
1813 m_RenderInfo.Next_10 = TopText_GetNext(m_RenderInfo.Prev_10, 1, 1);
1815 m_RenderInfo.Next_100 = TopText_GetNext(m_RenderInfo.Next_10, 1, 0);
1816 Showlink(0, m_RenderInfo.Prev_100);
1817 Showlink(1, m_RenderInfo.Prev_10);
1818 Showlink(2, m_RenderInfo.Next_10);
1819 Showlink(3, m_RenderInfo.Next_100);
1823 void CTeletextDecoder::RenderCharFB(int Char, TextPageAttr_t *Attribute)
1825 RenderCharIntern(&m_RenderInfo, Char, Attribute, m_RenderInfo.ZoomMode, m_YOffset);
1828 void CTeletextDecoder::RenderCharBB(int Char, TextPageAttr_t *Attribute)
1830 RenderCharIntern(&m_RenderInfo, Char, Attribute, 0, m_RenderInfo.Height-m_YOffset);
1833 void CTeletextDecoder::CopyBB2FB()
1835 color_t *src, *dst, *topsrc;
1840 if (!m_RenderInfo.PageCatching)
1843 /* copy backbuffer to framebuffer */
1844 if (!m_RenderInfo.ZoomMode)
1849 m_YOffset = m_RenderInfo.Height;
1851 if (m_RenderInfo.ClearBBColor >= 0)
1853 m_RenderInfo.ClearBBColor = -1;
1858 src = dst = topsrc = m_TextureBuffer + m_RenderInfo.Width;
1862 dst += m_RenderInfo.Width * m_RenderInfo.Height;
1866 src += m_RenderInfo.Width * m_RenderInfo.Height;
1867 topsrc += m_RenderInfo.Width * m_RenderInfo.Height;
1870 if (!m_RenderInfo.PageCatching)
1871 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 */
1873 if (m_RenderInfo.TranspMode)
1874 fillcolor = GetColorRGB(TXT_ColorTransp);
1876 fillcolor = GetColorRGB((enumTeletextColor)m_txtCache->FullScrColor);
1878 if (m_RenderInfo.ZoomMode == 2)
1879 src += 12*m_RenderInfo.FontHeight*m_RenderInfo.Width;
1881 screenwidth = m_RenderInfo.Width;
1883 for (int i = 12*m_RenderInfo.FontHeight; i; i--)
1885 SDL_memcpy4(dst, src, screenwidth);
1886 dst += m_RenderInfo.Width;
1887 SDL_memcpy4(dst, src, screenwidth);
1888 dst += m_RenderInfo.Width;
1889 src += m_RenderInfo.Width;
1892 for (int i = m_RenderInfo.Height - 25*m_RenderInfo.FontHeight; i >= 0;i--)
1894 SDL_memset4(dst + m_RenderInfo.Width*(m_RenderInfo.FontHeight+i), fillcolor, screenwidth);
1898 FT_Error CTeletextDecoder::MyFaceRequester(FTC_FaceID face_id, FT_Library library, FT_Pointer request_data, FT_Face *aface)
1900 FT_Error result = FT_New_Face(library, (const char*)face_id, 0, aface);
1903 CLog::Log(LOGNOTICE, "Teletext font %s loaded", (char*)face_id);
1905 CLog::Log(LOGERROR, "Opening of Teletext font %s failed", (char*)face_id);
1910 void CTeletextDecoder::SetFontWidth(int newWidth)
1912 if (m_RenderInfo.FontWidth != newWidth)
1914 m_RenderInfo.FontWidth = newWidth;
1915 m_TypeTTF.width = (FT_UShort) m_RenderInfo.FontWidth;
1917 for (int i = 0; i <= 12; i++)
1918 m_RenderInfo.axdrcs[i] = (m_RenderInfo.FontWidth * i + 6) / 12;
1922 int CTeletextDecoder::GetCurFontWidth()
1924 int mx = (m_RenderInfo.Width)%(40-m_RenderInfo.nofirst); // # of unused pixels
1925 int abx = (mx == 0 ? m_RenderInfo.Width+1 : (m_RenderInfo.Width)/(mx+1)); // distance between 'inserted' pixels
1926 int nx = abx+1-(m_RenderInfo.PosX % (abx+1)); // # of pixels to next insert
1927 return m_RenderInfo.FontWidth+(((m_RenderInfo.PosX+m_RenderInfo.FontWidth+1) <= m_RenderInfo.Width && nx <= m_RenderInfo.FontWidth+1) ? 1 : 0);
1930 void CTeletextDecoder::SetPosX(int column)
1932 m_RenderInfo.PosX = 0;
1934 for (int i = 0; i < column-m_RenderInfo.nofirst; i++)
1935 m_RenderInfo.PosX += GetCurFontWidth();
1938 void CTeletextDecoder::ClearBB(color_t Color)
1940 SDL_memset4(m_TextureBuffer + (m_RenderInfo.Height-m_YOffset)*m_RenderInfo.Width, Color, m_RenderInfo.Width*m_RenderInfo.Height);
1943 void CTeletextDecoder::ClearFB(color_t Color)
1945 SDL_memset4(m_TextureBuffer + m_RenderInfo.Width*m_YOffset, Color, m_RenderInfo.Width*m_RenderInfo.Height);
1948 void CTeletextDecoder::FillBorder(color_t Color)
1950 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);
1951 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);
1954 void CTeletextDecoder::FillRect(color_t *buffer, int xres, int x, int y, int w, int h, color_t Color)
1956 if (!buffer) return;
1958 color_t *p = buffer + x + y * xres;
1962 for ( ; h > 0 ; h--)
1964 SDL_memset4(p, Color, w);
1970 void CTeletextDecoder::DrawVLine(color_t *lfb, int xres, int x, int y, int l, color_t color)
1973 color_t *p = lfb + x + y * xres;
1975 for ( ; l > 0 ; l--)
1982 void CTeletextDecoder::DrawHLine(color_t *lfb, int xres,int x, int y, int l, color_t color)
1986 SDL_memset4(lfb + x + y * xres, color, l);
1989 void CTeletextDecoder::RenderDRCS(int xres,
1990 unsigned char *s, /* pointer to char data, parity undecoded */
1991 color_t *d, /* pointer to frame buffer of top left pixel */
1992 unsigned char *ax, /* array[0..12] of x-offsets, array[0..10] of y-offsets for each pixel */
1993 color_t fgcolor, color_t bgcolor)
1995 if (d == NULL) return;
1997 unsigned char *ay = ax + 13; /* array[0..10] of y-offsets for each pixel */
1999 for (int y = 0; y < 10; y++) /* 10*2 bytes a 6 pixels per char definition */
2001 unsigned char c1 = deparity[*s++];
2002 unsigned char c2 = deparity[*s++];
2003 int h = ay[y+1] - ay[y];
2007 if (((c1 == ' ') && (*(s-2) != ' ')) || ((c2 == ' ') && (*(s-1) != ' '))) /* parity error: stop decoding FIXME */
2009 for (int bit = 0x20, x = 0;
2011 bit >>= 1, x++) /* bit mask (MSB left), column counter */
2013 color_t f1 = (c1 & bit) ? fgcolor : bgcolor;
2014 color_t f2 = (c2 & bit) ? fgcolor : bgcolor;
2015 for (int i = 0; i < h; i++)
2017 if (ax[x+1] > ax[x])
2018 SDL_memset4(d + ax[x], f1, ax[x+1] - ax[x]);
2019 if (ax[x+7] > ax[x+6])
2020 SDL_memset4(d + ax[x+6], f2, ax[x+7] - ax[x+6]); /* 2nd byte 6 pixels to the right */
2029 void CTeletextDecoder::FillRectMosaicSeparated(color_t *lfb, int xres,int x, int y, int w, int h, color_t fgcolor, color_t bgcolor, int set)
2032 FillRect(lfb,xres,x, y, w, h, bgcolor);
2035 FillRect(lfb,xres,x+1, y+1, w-2, h-2, fgcolor);
2039 void CTeletextDecoder::FillTrapez(color_t *lfb, int xres,int x0, int y0, int l0, int xoffset1, int h, int l1, color_t color)
2041 color_t *p = lfb + x0 + y0 * xres;
2044 for (int yoffset = 0; yoffset < h; yoffset++)
2046 l = l0 + ((l1-l0) * yoffset + h/2) / h;
2047 xoffset = (xoffset1 * yoffset + h/2) / h;
2049 SDL_memset4(p + xoffset, color, l);
2054 void CTeletextDecoder::FlipHorz(color_t *lfb, int xres,int x, int y, int w, int h)
2057 color_t *p = lfb + x + y * xres;
2060 for (h1 = 0 ; h1 < h ; h1++)
2062 SDL_memcpy4(buf,p,w);
2063 for (w1 = 0 ; w1 < w ; w1++)
2065 *(p+w1) = buf[w-(w1+1)];
2071 void CTeletextDecoder::FlipVert(color_t *lfb, int xres,int x, int y, int w, int h)
2074 color_t *p = lfb + x + y * xres, *p1, *p2;
2077 for (h1 = 0 ; h1 < h/2 ; h1++)
2080 p2 = (p+(h-(h1+1))*xres);
2081 SDL_memcpy4(buf, p1, w);
2082 SDL_memcpy4(p1, p2, w);
2083 SDL_memcpy4(p2, buf, w);
2087 int CTeletextDecoder::ShapeCoord(int param, int curfontwidth, int curFontHeight)
2092 return curfontwidth/3;
2094 return curfontwidth/2;
2096 return curfontwidth*2/3;
2098 return curfontwidth;
2100 return curfontwidth-3;
2102 return curFontHeight/3;
2104 return curFontHeight/2;
2106 return curFontHeight*2/3;
2108 return curFontHeight;
2114 void CTeletextDecoder::DrawShape(color_t *lfb, int xres, int x, int y, int shapenumber, int curfontwidth, int FontHeight, int curFontHeight, color_t fgcolor, color_t bgcolor, bool clear)
2116 if (!lfb || shapenumber < 0x20 || shapenumber > 0x7e || (shapenumber == 0x7e && clear))
2119 unsigned char *p = aShapes[shapenumber - 0x20];
2130 FillRect(lfb, xres, x, y, curfontwidth, FontHeight, bgcolor);
2138 int offset = ShapeCoord(*p++, curfontwidth, curFontHeight);
2139 DrawHLine(lfb, xres, x, y + offset, curfontwidth, fgcolor);
2144 int offset = ShapeCoord(*p++, curfontwidth, curFontHeight);
2145 DrawVLine(lfb,xres,x + offset, y, FontHeight, fgcolor);
2149 FlipHorz(lfb,xres,x,y,curfontwidth, FontHeight);
2152 FlipVert(lfb,xres,x,y,curfontwidth, FontHeight);
2156 int xo = ShapeCoord(*p++, curfontwidth, curFontHeight);
2157 int yo = ShapeCoord(*p++, curfontwidth, curFontHeight);
2158 int w = ShapeCoord(*p++, curfontwidth, curFontHeight);
2159 int h = ShapeCoord(*p++, curfontwidth, curFontHeight);
2160 FillRect(lfb,xres,x + xo, y + yo, w, h, fgcolor);
2165 int x0 = ShapeCoord(*p++, curfontwidth, curFontHeight);
2166 int y0 = ShapeCoord(*p++, curfontwidth, curFontHeight);
2167 int l0 = ShapeCoord(*p++, curfontwidth, curFontHeight);
2168 int x1 = ShapeCoord(*p++, curfontwidth, curFontHeight);
2169 int y1 = ShapeCoord(*p++, curfontwidth, curFontHeight);
2170 int l1 = ShapeCoord(*p++, curfontwidth, curFontHeight);
2171 FillTrapez(lfb, xres,x + x0, y + y0, l0, x1-x0, y1-y0, l1, fgcolor);
2176 int x0 = ShapeCoord(*p++, curfontwidth, curFontHeight);
2177 int y0 = ShapeCoord(*p++, curfontwidth, curFontHeight);
2178 int l0 = ShapeCoord(*p++, curfontwidth, curFontHeight);
2179 int x1 = ShapeCoord(*p++, curfontwidth, curFontHeight);
2180 int y1 = ShapeCoord(*p++, curfontwidth, curFontHeight);
2181 int l1 = ShapeCoord(*p++, curfontwidth, curFontHeight);
2182 FillTrapez(lfb, xres, x + x0, y + y0, l0, x1-x0, y1-y0, l1, bgcolor);
2187 DrawShape(lfb,xres,x, y, ShapeCoord(*p, curfontwidth, curFontHeight), curfontwidth, FontHeight, curFontHeight, fgcolor, bgcolor, false);
2196 void CTeletextDecoder::RenderCharIntern(TextRenderInfo_t* RenderInfo, int Char, TextPageAttr_t *Attribute, int zoom, int yoffset)
2200 color_t bgcolor, fgcolor;
2201 int factor, xfactor;
2202 unsigned char *sbitbuffer;
2204 int national_subset_local = m_txtCache->NationalSubset;
2205 int curfontwidth = GetCurFontWidth();
2206 int t = curfontwidth;
2207 m_RenderInfo.PosX += t;
2208 int curfontwidth2 = GetCurFontWidth();
2209 m_RenderInfo.PosX -= t;
2210 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);
2211 if (alphachar <= 0) return;
2213 if (zoom && Attribute->doubleh)
2215 else if (zoom || Attribute->doubleh)
2220 fgcolor = GetColorRGB((enumTeletextColor)Attribute->fg);
2221 if (m_RenderInfo.TranspMode && m_RenderInfo.PosY < 24*m_RenderInfo.FontHeight)
2223 bgcolor = GetColorRGB(TXT_ColorTransp);
2227 bgcolor = GetColorRGB((enumTeletextColor)Attribute->bg);
2230 if (Attribute->doublew)
2232 curfontwidth += curfontwidth2;
2238 if (!(glyph = FT_Get_Char_Index(m_Face, alphachar)))
2240 CLog::Log(LOGERROR, "%s: <FT_Get_Char_Index for Char %x \"%c\" failed", __FUNCTION__, alphachar, alphachar);
2242 FillRect(m_TextureBuffer, m_RenderInfo.Width, m_RenderInfo.PosX, m_RenderInfo.PosY + yoffset, curfontwidth, factor*m_RenderInfo.FontHeight, bgcolor);
2243 m_RenderInfo.PosX += curfontwidth;
2247 if (FTC_SBitCache_Lookup(m_Cache, &m_TypeTTF, glyph, &m_sBit, NULL) != 0)
2249 FillRect(m_TextureBuffer, m_RenderInfo.Width, m_RenderInfo.PosX, m_RenderInfo.PosY + yoffset, curfontwidth, m_RenderInfo.FontHeight, bgcolor);
2250 m_RenderInfo.PosX += curfontwidth;
2255 sbitbuffer = m_sBit->buffer;
2256 unsigned char localbuffer[1000]; // should be enough to store one character-bitmap...
2257 // add diacritical marks
2258 if (Attribute->diacrit)
2260 FTC_SBit sbit_diacrit;
2262 if ((national_subset_local == NAT_SC) || (national_subset_local == NAT_RB) || (national_subset_local == NAT_UA))
2263 Char = G2table[1][0x20+ Attribute->diacrit];
2264 else if (national_subset_local == NAT_GR)
2265 Char = G2table[2][0x20+ Attribute->diacrit];
2266 else if (national_subset_local == NAT_HB)
2267 Char = G2table[3][0x20+ Attribute->diacrit];
2268 else if (national_subset_local == NAT_AR)
2269 Char = G2table[4][0x20+ Attribute->diacrit];
2271 Char = G2table[0][0x20+ Attribute->diacrit];
2272 if ((glyph = FT_Get_Char_Index(m_Face, Char)))
2274 if (FTC_SBitCache_Lookup(m_Cache, &m_TypeTTF, glyph, &sbit_diacrit, NULL) == 0)
2276 sbitbuffer = localbuffer;
2277 memcpy(sbitbuffer,m_sBit->buffer,m_sBit->pitch*m_sBit->height);
2279 for (Row = 0; Row < m_sBit->height; Row++)
2281 for (Pitch = 0; Pitch < m_sBit->pitch; Pitch++)
2283 if (sbit_diacrit->pitch > Pitch && sbit_diacrit->height > Row)
2284 sbitbuffer[Row*m_sBit->pitch+Pitch] |= sbit_diacrit->buffer[Row*m_sBit->pitch+Pitch];
2291 int backupTTFshiftY = m_RenderInfo.TTFShiftY;
2292 if (national_subset_local == NAT_AR)
2293 m_RenderInfo.TTFShiftY = backupTTFshiftY - 2; // for arabic TTF font should be shifted up slightly
2296 int f; /* running counter for zoom factor */
2297 int he = m_sBit->height; // sbit->height should not be altered, I guess
2298 Row = factor * (m_Ascender - m_sBit->top + m_RenderInfo.TTFShiftY);
2301 sbitbuffer -= m_sBit->pitch*Row;
2307 FillRect(m_TextureBuffer, m_RenderInfo.Width, m_RenderInfo.PosX, m_RenderInfo.PosY + yoffset, curfontwidth, Row, bgcolor); /* fill upper margin */
2310 if (m_Ascender - m_sBit->top + m_RenderInfo.TTFShiftY + he > m_RenderInfo.FontHeight)
2311 he = m_RenderInfo.FontHeight - m_Ascender + m_sBit->top - m_RenderInfo.TTFShiftY; /* limit char height to defined/calculated FontHeight */
2312 if (he < 0) he = m_RenderInfo.FontHeight;
2314 p = m_TextureBuffer + m_RenderInfo.PosX + (yoffset + m_RenderInfo.PosY + Row) * m_RenderInfo.Width; /* running pointer into framebuffer */
2315 for (Row = he; Row; Row--) /* row counts up, but down may be a little faster :) */
2317 int pixtodo = m_sBit->width;
2318 color_t *pstart = p;
2320 for (int Bit = xfactor * (m_sBit->left + m_RenderInfo.TTFShiftX); Bit > 0; Bit--) /* fill left margin */
2322 for (f = factor-1; f >= 0; f--)
2323 *(p + f*m_RenderInfo.Width) = bgcolor;
2327 for (Pitch = m_sBit->pitch; Pitch; Pitch--)
2329 for (int Bit = 0x80; Bit; Bit >>= 1)
2336 if (*sbitbuffer & Bit) /* bit set -> foreground */
2338 else /* bit not set -> background */
2341 for (f = factor-1; f >= 0; f--)
2342 *(p + f*m_RenderInfo.Width) = color;
2345 if (xfactor > 1) /* double width */
2347 for (f = factor-1; f >= 0; f--)
2348 *(p + f*m_RenderInfo.Width) = color;
2354 for (int Bit = (curfontwidth - xfactor*(m_sBit->width + m_sBit->left + m_RenderInfo.TTFShiftX));
2355 Bit > 0; Bit--) /* fill rest of char width */
2357 for (f = factor-1; f >= 0; f--)
2358 *(p + f*m_RenderInfo.Width) = bgcolor;
2362 p = pstart + factor*m_RenderInfo.Width;
2365 Row = m_Ascender - m_sBit->top + he + m_RenderInfo.TTFShiftY;
2366 FillRect(m_TextureBuffer,
2369 m_RenderInfo.PosY + yoffset + Row * factor,
2371 (m_RenderInfo.FontHeight - Row) * factor,
2372 bgcolor); /* fill lower margin */
2374 if (Attribute->underline)
2375 FillRect(m_TextureBuffer,
2378 m_RenderInfo.PosY + yoffset + (m_RenderInfo.FontHeight-2)* factor,
2381 fgcolor); /* underline char */
2383 m_RenderInfo.PosX += curfontwidth;
2384 m_RenderInfo.TTFShiftY = backupTTFshiftY; // restore TTFShiftY
2387 int CTeletextDecoder::RenderChar(color_t *buffer, // pointer to render buffer, min. FontHeight*2*xres
2388 int xres, // length of 1 line in render buffer
2389 int Char, // character to render
2390 int *pPosX, // left border for rendering relative to *buffer, will be set to right border after rendering
2391 int PosY, // vertical position of char in *buffer
2392 TextPageAttr_t *Attribute,// Attributes of Char
2393 bool zoom, // 1= character will be rendered in double height
2394 int curfontwidth, // rendering width of character
2395 int curfontwidth2, // rendering width of next character (needed for doublewidth)
2396 int FontHeight, // height of character
2397 bool transpmode, // 1= transparent display
2398 unsigned char *axdrcs, // width and height of DRCS-chars
2399 int Ascender) // Ascender of font
2401 color_t bgcolor, fgcolor;
2402 int factor, xfactor;
2403 int national_subset_local = m_txtCache->NationalSubset;
2405 ymosaic[0] = 0; /* y-offsets for 2*3 mosaic */
2406 ymosaic[1] = (FontHeight + 1) / 3;
2407 ymosaic[2] = (FontHeight * 2 + 1) / 3;
2408 ymosaic[3] = FontHeight;
2410 if (Attribute->setX26)
2412 national_subset_local = 0; // no national subset
2415 // G0+G2 set designation
2416 if (Attribute->setG0G2 != 0x3f)
2418 switch (Attribute->setG0G2)
2421 national_subset_local = NAT_SC;
2424 national_subset_local = NAT_RB;
2427 national_subset_local = NAT_UA;
2430 national_subset_local = NAT_GR;
2433 national_subset_local = NAT_HB;
2437 national_subset_local = NAT_AR;
2440 national_subset_local = CountryConversionTable[Attribute->setG0G2 & 0x07];
2445 if (Attribute->charset == C_G0S) // use secondary charset
2446 national_subset_local = m_txtCache->NationalSubsetSecondary;
2447 if (zoom && Attribute->doubleh)
2449 else if (zoom || Attribute->doubleh)
2454 if (Attribute->doublew)
2456 curfontwidth += curfontwidth2;
2462 if (Char == 0xFF) /* skip doubleheight chars in lower line */
2464 *pPosX += curfontwidth;
2469 if (Attribute->inverted)
2471 int t = Attribute->fg;
2472 Attribute->fg = Attribute->bg;
2475 fgcolor = GetColorRGB((enumTeletextColor)Attribute->fg);
2476 if (transpmode == true && PosY < 24*FontHeight)
2478 bgcolor = GetColorRGB(TXT_ColorTransp);
2482 bgcolor = GetColorRGB((enumTeletextColor)Attribute->bg);
2486 if ((Attribute->charset == C_G1C || Attribute->charset == C_G1S) &&
2487 ((Char&0xA0) == 0x20))
2489 int w1 = (curfontwidth / 2 ) *xfactor;
2490 int w2 = (curfontwidth - w1) *xfactor;
2492 Char = (Char & 0x1f) | ((Char & 0x40) >> 1);
2493 if (Attribute->charset == C_G1S) /* separated mosaic */
2495 for (int y = 0; y < 3; y++)
2497 FillRectMosaicSeparated(buffer, xres,*pPosX, PosY + ymosaic[y]*factor, w1, (ymosaic[y+1] - ymosaic[y])*factor, fgcolor, bgcolor, Char & 0x01);
2498 FillRectMosaicSeparated(buffer, xres,*pPosX + w1, PosY + ymosaic[y]*factor, w2, (ymosaic[y+1] - ymosaic[y])*factor, fgcolor, bgcolor, Char & 0x02);
2504 for (int y = 0; y < 3; y++)
2506 FillRect(buffer, xres, *pPosX, PosY + ymosaic[y]*factor, w1, (ymosaic[y+1] - ymosaic[y])*factor, (Char & 0x01) ? fgcolor : bgcolor);
2507 FillRect(buffer, xres, *pPosX + w1, PosY + ymosaic[y]*factor, w2, (ymosaic[y+1] - ymosaic[y])*factor, (Char & 0x02) ? fgcolor : bgcolor);
2512 *pPosX += curfontwidth;
2516 if (Attribute->charset == C_G3)
2518 if (Char < 0x20 || Char > 0x7d)
2524 if (*aShapes[Char - 0x20] == S_CHR)
2526 unsigned char *p = aShapes[Char - 0x20];
2527 Char = (*(p+1) <<8) + (*(p+2));
2529 else if (*aShapes[Char - 0x20] == S_ADT)
2534 color_t* p = buffer + *pPosX + PosY* xres;
2535 for (y=0; y<FontHeight;y++)
2537 for (f=0; f<factor; f++)
2539 for (x=0; x<curfontwidth*xfactor;x++)
2541 c = (y&4 ? (x/3)&1 :((x+3)/3)&1);
2542 *(p+x) = (c ? fgcolor : bgcolor);
2548 *pPosX += curfontwidth;
2553 DrawShape(buffer, xres,*pPosX, PosY, Char, curfontwidth, FontHeight, factor*FontHeight, fgcolor, bgcolor, true);
2554 *pPosX += curfontwidth;
2559 else if (Attribute->charset >= C_OFFSET_DRCS)
2561 TextCachedPage_t *pcache = m_txtCache->astCachetable[(Attribute->charset & 0x10) ? m_txtCache->drcs : m_txtCache->gdrcs][Attribute->charset & 0x0f];
2564 unsigned char drcs_data[23*40];
2565 g_application.m_pPlayer->LoadPage((Attribute->charset & 0x10) ? m_txtCache->drcs : m_txtCache->gdrcs, Attribute->charset & 0x0f, drcs_data);
2568 p = drcs_data + 20*Char;
2569 else if (pcache->pageinfo.p24)
2570 p = pcache->pageinfo.p24 + 20*(Char - 23*2);
2573 FillRect(buffer, xres,*pPosX, PosY, curfontwidth, factor*FontHeight, bgcolor);
2574 *pPosX += curfontwidth;
2577 axdrcs[12] = curfontwidth; /* adjust last x-offset according to position, FIXME: double width */
2578 RenderDRCS(xres, p, buffer + *pPosX + PosY * xres, axdrcs, fgcolor, bgcolor);
2582 FillRect(buffer,xres,*pPosX, PosY, curfontwidth, factor*FontHeight, bgcolor);
2584 *pPosX += curfontwidth;
2587 else if (Attribute->charset == C_G2 && Char >= 0x20 && Char <= 0x7F)
2589 if ((national_subset_local == NAT_SC) || (national_subset_local == NAT_RB) || (national_subset_local == NAT_UA))
2590 Char = G2table[1][Char-0x20];
2591 else if (national_subset_local == NAT_GR)
2592 Char = G2table[2][Char-0x20];
2593 else if (national_subset_local == NAT_AR)
2594 Char = G2table[3][Char-0x20];
2596 Char = G2table[0][Char-0x20];
2600 // FillRect(buffer,xres,*pPosX, PosY, curfontwidth, factor*Ascender, fgcolor);
2601 // FillRect(buffer,xres,*pPosX, PosY + factor*Ascender, curfontwidth, factor*(FontHeight-Ascender), bgcolor);
2602 // *pPosX += curfontwidth;
2606 else if (national_subset_local == NAT_SC && Char >= 0x20 && Char <= 0x7F) /* remap complete areas for serbian/croatian */
2607 Char = G0table[0][Char-0x20];
2608 else if (national_subset_local == NAT_RB && Char >= 0x20 && Char <= 0x7F) /* remap complete areas for russian/bulgarian */
2609 Char = G0table[1][Char-0x20];
2610 else if (national_subset_local == NAT_UA && Char >= 0x20 && Char <= 0x7F) /* remap complete areas for ukrainian */
2611 Char = G0table[2][Char-0x20];
2612 else if (national_subset_local == NAT_GR && Char >= 0x20 && Char <= 0x7F) /* remap complete areas for greek */
2613 Char = G0table[3][Char-0x20];
2614 else if (national_subset_local == NAT_HB && Char >= 0x20 && Char <= 0x7F) /* remap complete areas for hebrew */
2615 Char = G0table[4][Char-0x20];
2616 else if (national_subset_local == NAT_AR && Char >= 0x20 && Char <= 0x7F) /* remap complete areas for arabic */
2617 Char = G0table[5][Char-0x20];
2625 FillRect(buffer, xres, *pPosX, PosY, curfontwidth, factor*FontHeight, bgcolor);
2626 *pPosX += curfontwidth;
2630 Char = nationaltable23[national_subset_local][Char-0x23];
2633 Char = nationaltable40[national_subset_local];
2641 Char = nationaltable5b[national_subset_local][Char-0x5B];
2647 Char = nationaltable7b[national_subset_local][Char-0x7B];
2650 FillRect(buffer,xres,*pPosX, PosY , curfontwidth, factor*Ascender, fgcolor);
2651 FillRect(buffer,xres,*pPosX, PosY + factor*Ascender, curfontwidth, factor*(FontHeight-Ascender), bgcolor);
2652 *pPosX += curfontwidth;
2655 DrawHLine(buffer,xres,*pPosX, PosY, curfontwidth, fgcolor);
2656 DrawVLine(buffer,xres,*pPosX, PosY +1, FontHeight -1, fgcolor);
2657 FillRect(buffer,xres,*pPosX +1, PosY +1, curfontwidth-1, FontHeight-1, bgcolor);
2658 *pPosX += curfontwidth;
2661 DrawHLine(buffer,xres,*pPosX, PosY, curfontwidth, fgcolor);
2662 FillRect(buffer,xres,*pPosX, PosY +1, curfontwidth, FontHeight-1, bgcolor);
2663 *pPosX += curfontwidth;
2666 DrawHLine(buffer,xres,*pPosX, PosY, curfontwidth, fgcolor);
2667 DrawVLine(buffer,xres,*pPosX + curfontwidth -1, PosY +1, FontHeight -1, fgcolor);
2668 FillRect(buffer,xres,*pPosX, PosY +1, curfontwidth-1, FontHeight-1, bgcolor);
2669 *pPosX += curfontwidth;
2672 DrawVLine(buffer,xres,*pPosX, PosY, FontHeight, fgcolor);
2673 FillRect(buffer,xres,*pPosX +1, PosY, curfontwidth -1, FontHeight, bgcolor);
2674 *pPosX += curfontwidth;
2677 DrawVLine(buffer,xres,*pPosX + curfontwidth -1, PosY, FontHeight, fgcolor);
2678 FillRect(buffer,xres,*pPosX, PosY, curfontwidth -1, FontHeight, bgcolor);
2679 *pPosX += curfontwidth;
2682 DrawHLine(buffer,xres,*pPosX, PosY + FontHeight -1, curfontwidth, fgcolor);
2683 DrawVLine(buffer,xres,*pPosX, PosY, FontHeight -1, fgcolor);
2684 FillRect(buffer,xres,*pPosX +1, PosY, curfontwidth-1, FontHeight-1, bgcolor);
2685 *pPosX += curfontwidth;
2688 DrawHLine(buffer,xres,*pPosX, PosY + FontHeight -1, curfontwidth, fgcolor);
2689 FillRect(buffer,xres,*pPosX, PosY, curfontwidth, FontHeight-1, bgcolor);
2690 *pPosX += curfontwidth;
2693 DrawHLine(buffer,xres,*pPosX, PosY + FontHeight -1, curfontwidth, fgcolor);
2694 DrawVLine(buffer,xres,*pPosX + curfontwidth -1, PosY, FontHeight -1, fgcolor);
2695 FillRect(buffer,xres,*pPosX, PosY, curfontwidth-1, FontHeight-1, bgcolor);
2696 *pPosX += curfontwidth;
2699 FillRect(buffer,xres,*pPosX +1, PosY, curfontwidth -1, FontHeight, bgcolor);
2700 for (int Row=0; Row < curfontwidth/2; Row++)
2701 DrawVLine(buffer,xres,*pPosX + Row, PosY + Row, FontHeight - Row, fgcolor);
2702 *pPosX += curfontwidth;
2705 FillRect(buffer,xres,*pPosX, PosY, curfontwidth/2, FontHeight, fgcolor);
2706 FillRect(buffer,xres,*pPosX + curfontwidth/2, PosY, (curfontwidth+1)/2, FontHeight, bgcolor);
2707 *pPosX += curfontwidth;
2710 FillRect(buffer,xres,*pPosX, PosY, curfontwidth, FontHeight, bgcolor);
2711 FillRect(buffer,xres,*pPosX, PosY, curfontwidth/2, curfontwidth/2, fgcolor);
2712 *pPosX += curfontwidth;
2715 FillRect(buffer,xres,*pPosX, PosY +1, curfontwidth, FontHeight -1, bgcolor);
2716 for (int Row=0; Row < curfontwidth/2; Row++)
2717 DrawHLine(buffer,xres,*pPosX + Row, PosY + Row, curfontwidth - Row, fgcolor);
2718 *pPosX += curfontwidth;
2721 FillRect(buffer, xres,*pPosX, PosY, curfontwidth, curfontwidth/2, fgcolor);
2722 FillRect(buffer, xres,*pPosX, PosY + curfontwidth/2, curfontwidth, FontHeight - curfontwidth/2, bgcolor);
2723 *pPosX += curfontwidth;
2735 Char = arrowtable[Char - 0xED];
2743 FillRect(buffer, xres, *pPosX, PosY, curfontwidth, factor*FontHeight, bgcolor);
2744 *pPosX += curfontwidth;
2747 return Char; // Char is an alphanumeric unicode character
2750 TextPageinfo_t* CTeletextDecoder::DecodePage(bool showl25, // 1=decode Level2.5-graphics
2751 unsigned char* PageChar, // page buffer, min. 25*40
2752 TextPageAttr_t *PageAtrb, // attribut buffer, min 25*40
2753 bool HintMode, // 1=show hidden information
2754 bool showflof) // 1=decode FLOF-line
2758 int foreground, background, doubleheight, doublewidth, charset, previous_charset, mosaictype, IgnoreAtBlackBgSubst, concealed, flashmode, boxwin;
2759 unsigned char held_mosaic, *p;
2760 TextCachedPage_t *pCachedPage;
2762 /* copy page to decode buffer */
2763 if (m_txtCache->SubPageTable[m_txtCache->Page] == 0xff) /* not cached: do nothing */
2766 if (m_txtCache->ZapSubpageManual)
2767 pCachedPage = m_txtCache->astCachetable[m_txtCache->Page][m_txtCache->SubPage];
2769 pCachedPage = m_txtCache->astCachetable[m_txtCache->Page][m_txtCache->SubPageTable[m_txtCache->Page]];
2770 if (!pCachedPage) /* not cached: do nothing */
2773 g_application.m_pPlayer->LoadPage(m_txtCache->Page, m_txtCache->SubPage, &PageChar[40]);
2775 memcpy(&PageChar[8], pCachedPage->p0, 24); /* header line without TimeString */
2777 TextPageinfo_t* PageInfo = &(pCachedPage->pageinfo);
2779 memcpy(&PageChar[24*40], PageInfo->p24, 40); /* line 25 for FLOF */
2781 /* copy TimeString */
2782 memcpy(&PageChar[32], &m_txtCache->TimeString, 8);
2785 /* check for newsflash & subtitle */
2786 if (PageInfo->boxed && IsDec(m_txtCache->Page))
2795 memset(PageChar, ' ', 40);
2799 memset(PageChar, ' ', 8);
2800 CDVDTeletextTools::Hex2Str((char*)PageChar+3, m_txtCache->Page);
2801 if (m_txtCache->SubPage)
2805 CDVDTeletextTools::Hex2Str((char*)PageChar+6, m_txtCache->SubPage);
2809 if (!IsDec(m_txtCache->Page))
2811 TextPageAttr_t atr = { TXT_ColorWhite , TXT_ColorBlack , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f};
2812 if (PageInfo->function == FUNC_MOT) /* magazine organization table */
2814 for (col = 0; col < 24*40; col++)
2815 PageAtrb[col] = atr;
2816 for (col = 40; col < 24*40; col++)
2817 PageChar[col] = number2char(PageChar[col]);
2818 return PageInfo; /* don't interpret irregular pages */
2820 else if (PageInfo->function == FUNC_GPOP || PageInfo->function == FUNC_POP) /* object definitions */
2822 for (int col = 0; col < 24*40; col++)
2823 PageAtrb[col] = atr;
2826 for (int row = 1; row < 12; row++)
2828 *p++ = number2char(row); /* first column: number (0-9, A-..) */
2829 for (int col = 1; col < 40; col += 3)
2831 int d = CDVDTeletextTools::deh24(p);
2834 memcpy(p, "???", 3);
2839 *p++ = number2char((d >> 6) & 0x1f); /* mode */
2840 *p++ = number2char(d & 0x3f); /* address */
2841 *p++ = number2char((d >> 11) & 0x7f); /* data */
2845 return PageInfo; /* don't interpret irregular pages */
2847 else if (PageInfo->function == FUNC_GDRCS || PageInfo->function == FUNC_DRCS) /* character definitions */
2849 return PageInfo; /* don't interpret irregular pages */
2853 int h, parityerror = 0;
2855 for (int i = 0; i < 8; i++)
2858 /* decode parity/hamming */
2859 for (unsigned int i = 40; i < sizeof(PageChar); i++)
2864 if (parityerror && h != 0xFF) /* if no regular page (after any parity error) */
2865 CDVDTeletextTools::Hex2Str((char*)p, h); /* first try dehamming */
2868 if (*p == ' ' || deparity[*p] != ' ') /* correct parity */
2873 if (h != 0xFF) /* first parity error: try dehamming */
2874 CDVDTeletextTools::Hex2Str((char*)p, h);
2882 return PageInfo; /* don't interpret irregular pages */
2886 int mosaic_pending,esc_pending;
2888 for (int row = 0; row < ((showflof && PageInfo->p24) ? 25 : 24); row++)
2890 /* start-of-row default conditions */
2891 foreground = TXT_ColorWhite;
2892 background = TXT_ColorBlack;
2895 charset = previous_charset = C_G0P; // remember charset for switching back after mosaic charset was used
2903 IgnoreAtBlackBgSubst = 0;
2904 mosaic_pending = esc_pending = 0; // we need to render at least one mosaic char if 'esc' is received immediatly after mosac charset switch on
2906 if (boxed && memchr(&PageChar[row*40], start_box, 40) == 0)
2908 foreground = TXT_ColorTransp;
2909 background = TXT_ColorTransp;
2912 for (int col = 0; col < 40; col++)
2914 int index = row*40 + col;
2916 PageAtrb[index].fg = foreground;
2917 PageAtrb[index].bg = background;
2918 PageAtrb[index].charset = charset;
2919 PageAtrb[index].doubleh = doubleheight;
2920 PageAtrb[index].doublew = (col < 39 ? doublewidth : 0);
2921 PageAtrb[index].IgnoreAtBlackBgSubst = IgnoreAtBlackBgSubst;
2922 PageAtrb[index].concealed = concealed;
2923 PageAtrb[index].flashing = flashmode;
2924 PageAtrb[index].boxwin = boxwin;
2925 PageAtrb[index].inverted = 0; // only relevant for Level 2.5
2926 PageAtrb[index].underline = 0; // only relevant for Level 2.5
2927 PageAtrb[index].diacrit = 0; // only relevant for Level 2.5
2928 PageAtrb[index].setX26 = 0; // only relevant for Level 2.5
2929 PageAtrb[index].setG0G2 = 0x3f; // only relevant for Level 2.5
2931 if (PageChar[index] < ' ')
2933 if (esc_pending) { // mosaic char has been rendered and we can switch charsets
2934 charset = previous_charset;
2935 if (charset == C_G0P)
2936 charset = previous_charset = C_G0S;
2937 else if (charset == C_G0S)
2938 charset = previous_charset = C_G0P;
2941 switch (PageChar[index])
2952 foreground = PageChar[index] - alpha_black + TXT_ColorBlack;
2953 if (col == 0 && PageChar[index] == alpha_white)
2954 PageAtrb[index].fg = TXT_ColorBlack; // indicate level 1 color change on column 0; (hack)
2955 if ((charset!=C_G0P) && (charset!=C_G0S)) // we need to change charset to state it was before mosaic
2956 charset = previous_charset;
2965 PageAtrb[index].flashing = 0;
2970 IgnoreAtBlackBgSubst = 0;
2981 PageAtrb[index].doubleh = doubleheight;
2982 PageAtrb[index].doublew = doublewidth;
3016 case mosaic_magenta:
3020 foreground = PageChar[index] - mosaic_black + TXT_ColorBlack;
3021 if ((charset==C_G0P) || (charset==C_G0S))
3022 previous_charset=charset;
3023 charset = mosaictype ? C_G1S : C_G1C;
3028 PageAtrb[index].concealed = 1;
3032 foreground = background;
3033 PageAtrb[index].fg = foreground;
3037 case contiguous_mosaic:
3039 if (charset == C_G1S)
3042 PageAtrb[index].charset = charset;
3046 case separated_mosaic:
3048 if (charset == C_G1C)
3051 PageAtrb[index].charset = charset;
3056 if (!mosaic_pending) { // if mosaic is pending we need to wait before mosaic arrives
3057 if ((charset != C_G0P) && (charset != C_G0S)) // we need to switch to charset which was active before mosaic
3058 charset = previous_charset;
3059 if (charset == C_G0P)
3060 charset = previous_charset = C_G0S;
3061 else if (charset == C_G0S)
3062 charset = previous_charset = C_G0P;
3063 } else esc_pending = 1;
3066 case black_background:
3067 background = TXT_ColorBlack;
3068 IgnoreAtBlackBgSubst = 0;
3069 PageAtrb[index].bg = background;
3070 PageAtrb[index].IgnoreAtBlackBgSubst = IgnoreAtBlackBgSubst;
3073 case new_background:
3074 background = foreground;
3075 if (background == TXT_ColorBlack)
3076 IgnoreAtBlackBgSubst = 1;
3078 IgnoreAtBlackBgSubst = 0;
3079 PageAtrb[index].bg = background;
3080 PageAtrb[index].IgnoreAtBlackBgSubst = IgnoreAtBlackBgSubst;
3087 case release_mosaic:
3092 /* handle spacing attributes */
3093 if (hold && (PageAtrb[index].charset == C_G1C || PageAtrb[index].charset == C_G1S))
3094 PageChar[index] = held_mosaic;
3096 PageChar[index] = ' ';
3101 else /* char >= ' ' */
3103 mosaic_pending = 0; // charset will be switched next if esc_pending
3104 /* set new held-mosaic char */
3105 if ((charset == C_G1C || charset == C_G1S) &&
3106 ((PageChar[index]&0xA0) == 0x20))
3107 held_mosaic = PageChar[index];
3108 if (PageAtrb[index].doubleh)
3109 PageChar[index + 40] = 0xFF;
3112 if (!(charset == C_G1C || charset == C_G1S))
3113 held_mosaic = ' '; /* forget if outside mosaic */
3117 /* skip row if doubleheight */
3118 if (row < 23 && dhset)
3120 for (int col = 0; col < 40; col++)
3122 int index = row*40 + col;
3123 PageAtrb[index+40].bg = PageAtrb[index].bg;
3124 PageAtrb[index+40].fg = TXT_ColorWhite;
3125 if (!PageAtrb[index].doubleh)
3126 PageChar[index+40] = ' ';
3127 PageAtrb[index+40].flashing = 0;
3128 PageAtrb[index+40].charset = C_G0P;
3129 PageAtrb[index+40].doubleh = 0;
3130 PageAtrb[index+40].doublew = 0;
3131 PageAtrb[index+40].IgnoreAtBlackBgSubst = 0;
3132 PageAtrb[index+40].concealed = 0;
3133 PageAtrb[index+40].flashing = 0;
3134 PageAtrb[index+40].boxwin = PageAtrb[index].boxwin;
3139 m_txtCache->FullScrColor = TXT_ColorBlack;
3142 Eval_l25(PageChar, PageAtrb, HintMode);
3144 /* handle Black Background Color Substitution and transparency (CLUT1#0) */
3149 for (int r = 0; r < 25; r++)
3151 for (int c = 0; c < 40; c++)
3153 bitmask = (PageAtrb[o].bg == 0x08 ? 0x08 : 0x00) | (m_txtCache->FullRowColor[r] == 0x08 ? 0x04 : 0x00) | (PageAtrb[o].boxwin <<1) | (int)boxed;
3158 if (m_txtCache->FullRowColor[r] == 0x08)
3159 PageAtrb[o].bg = m_txtCache->FullScrColor;
3161 PageAtrb[o].bg = m_txtCache->FullRowColor[r];
3171 PageAtrb[o].bg = TXT_ColorTransp;
3174 bitmask = (PageAtrb[o].fg == 0x08 ? 0x08 : 0x00) | (m_txtCache->FullRowColor[r] == 0x08 ? 0x04 : 0x00) | (PageAtrb[o].boxwin <<1) | (int)boxed;
3179 if (m_txtCache->FullRowColor[r] == 0x08)
3180 PageAtrb[o].fg = m_txtCache->FullScrColor;
3182 PageAtrb[o].fg = m_txtCache->FullRowColor[r];
3192 PageAtrb[o].fg = TXT_ColorTransp;
3202 void CTeletextDecoder::Eval_l25(unsigned char* PageChar, TextPageAttr_t *PageAtrb, bool HintMode)
3204 memset(m_txtCache->FullRowColor, 0, sizeof(m_txtCache->FullRowColor));
3205 m_txtCache->FullScrColor = TXT_ColorBlack;
3206 m_txtCache->ColorTable = NULL;
3208 if (!m_txtCache->astCachetable[m_txtCache->Page][m_txtCache->SubPage])
3212 if (IsDec(m_txtCache->Page))
3214 unsigned char APx0, APy0, APx, APy;
3215 TextPageinfo_t *pi = &(m_txtCache->astCachetable[m_txtCache->Page][m_txtCache->SubPage]->pageinfo);
3216 TextCachedPage_t *pmot = m_txtCache->astCachetable[(m_txtCache->Page & 0xf00) | 0xfe][0];
3217 int p26Received = 0;
3218 int BlackBgSubst = 0;
3219 int ColorTableRemapping = 0;
3221 m_txtCache->pop = m_txtCache->gpop = m_txtCache->drcs = m_txtCache->gdrcs = 0;
3225 TextExtData_t *e = pi->ext;
3232 Textp27_t *p27 = e->p27;
3234 m_txtCache->gpop = p27[0].page;
3236 m_txtCache->pop = p27[1].page;
3238 m_txtCache->gdrcs = p27[2].page;
3240 m_txtCache->drcs = p27[3].page;
3245 m_txtCache->ColorTable = e->bgr;
3246 BlackBgSubst = e->BlackBgSubst;
3247 ColorTableRemapping = e->ColorTableRemapping;
3248 memset(m_txtCache->FullRowColor, e->DefRowColor, sizeof(m_txtCache->FullRowColor));
3249 m_txtCache->FullScrColor = e->DefScreenColor;
3250 m_txtCache->NationalSubset = SetNational(e->DefaultCharset);
3251 m_txtCache->NationalSubsetSecondary = SetNational(e->SecondCharset);
3252 } /* e->p28Received */
3255 if (!m_txtCache->ColorTable && m_txtCache->astP29[m_txtCache->Page >> 8])
3257 TextExtData_t *e = m_txtCache->astP29[m_txtCache->Page >> 8];
3258 m_txtCache->ColorTable = e->bgr;
3259 BlackBgSubst = e->BlackBgSubst;
3260 ColorTableRemapping = e->ColorTableRemapping;
3261 memset(m_txtCache->FullRowColor, e->DefRowColor, sizeof(m_txtCache->FullRowColor));
3262 m_txtCache->FullScrColor = e->DefScreenColor;
3263 m_txtCache->NationalSubset = SetNational(e->DefaultCharset);
3264 m_txtCache->NationalSubsetSecondary = SetNational(e->SecondCharset);
3267 if (ColorTableRemapping)
3269 for (int i = 0; i < 25*40; i++)
3271 PageAtrb[i].fg += MapTblFG[ColorTableRemapping - 1];
3272 if (!BlackBgSubst || PageAtrb[i].bg != TXT_ColorBlack || PageAtrb[i].IgnoreAtBlackBgSubst)
3273 PageAtrb[i].bg += MapTblBG[ColorTableRemapping - 1];
3277 /* determine ?pop/?drcs from MOT */
3280 unsigned char pmot_data[23*40];
3281 g_application.m_pPlayer->LoadPage((m_txtCache->Page & 0xf00) | 0xfe, 0, pmot_data);
3283 unsigned char *p = pmot_data; /* start of link data */
3284 int o = 2 * (((m_txtCache->Page & 0xf0) >> 4) * 10 + (m_txtCache->Page & 0x0f)); /* offset of links for current page */
3285 int opop = p[o] & 0x07; /* index of POP link */
3286 int odrcs = p[o+1] & 0x07; /* index of DRCS link */
3287 unsigned char obj[3*4*4]; /* types* objects * (triplet,packet,subp,high) */
3288 unsigned char type,ct, tstart = 4*4;
3289 memset(obj,0,sizeof(obj));
3291 if (p[o] & 0x08) /* GPOP data used */
3293 if (!m_txtCache->gpop || !(p[18*40] & 0x08)) /* no p27 data or higher prio of MOT link */
3295 m_txtCache->gpop = ((p[18*40] << 8) | (p[18*40+1] << 4) | p[18*40+2]) & 0x7ff;
3296 if ((m_txtCache->gpop & 0xff) == 0xff)
3297 m_txtCache->gpop = 0;
3300 if (m_txtCache->gpop < 0x100)
3301 m_txtCache->gpop += 0x800;
3308 type = (p[18*40+5] >> 2*ct) & 0x03;
3310 if (type == 0) continue;
3311 obj[(type-1)*(tstart)+ct*4 ] = 3 * ((p[18*40+7+ct*2] >> 1) & 0x03) + type; //triplet
3312 obj[(type-1)*(tstart)+ct*4+1] = ((p[18*40+7+ct*2] & 0x08) >> 3) + 1 ; //packet
3313 obj[(type-1)*(tstart)+ct*4+2] = p[18*40+6+ct*2] & 0x0f ; //subp
3314 obj[(type-1)*(tstart)+ct*4+3] = p[18*40+7+ct*2] & 0x01 ; //high
3320 if (opop) /* POP data used */
3322 opop = 18*40 + 10*opop; /* offset to POP link */
3323 if (!m_txtCache->pop || !(p[opop] & 0x08)) /* no p27 data or higher prio of MOT link */
3325 m_txtCache->pop = ((p[opop] << 8) | (p[opop+1] << 4) | p[opop+2]) & 0x7ff;
3326 if ((m_txtCache->pop & 0xff) == 0xff)
3327 m_txtCache->pop = 0;
3330 if (m_txtCache->pop < 0x100)
3331 m_txtCache->pop += 0x800;
3338 type = (p[opop+5] >> 2*ct) & 0x03;
3340 if (type == 0) continue;
3341 obj[(type-1)*(tstart)+(ct+2)*4 ] = 3 * ((p[opop+7+ct*2] >> 1) & 0x03) + type; //triplet
3342 obj[(type-1)*(tstart)+(ct+2)*4+1] = ((p[opop+7+ct*2] & 0x08) >> 3) + 1 ; //packet
3343 obj[(type-1)*(tstart)+(ct+2)*4+2] = p[opop+6+ct*2] ; //subp
3344 obj[(type-1)*(tstart)+(ct+2)*4+3] = p[opop+7+ct*2] & 0x01 ; //high
3350 // eval default objects in correct order
3351 for (int i = 0; i < 12; i++)
3355 APx0 = APy0 = APx = APy = m_txtCache->tAPx = m_txtCache->tAPy = 0;
3356 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);
3360 if (p[o+1] & 0x08) /* GDRCS data used */
3362 if (!m_txtCache->gdrcs || !(p[20*40] & 0x08)) /* no p27 data or higher prio of MOT link */
3364 m_txtCache->gdrcs = ((p[20*40] << 8) | (p[20*40+1] << 4) | p[20*40+2]) & 0x7ff;
3365 if ((m_txtCache->gdrcs & 0xff) == 0xff)
3366 m_txtCache->gdrcs = 0;
3367 else if (m_txtCache->gdrcs < 0x100)
3368 m_txtCache->gdrcs += 0x800;
3371 if (odrcs) /* DRCS data used */
3373 odrcs = 20*40 + 4*odrcs; /* offset to DRCS link */
3374 if (!m_txtCache->drcs || !(p[odrcs] & 0x08)) /* no p27 data or higher prio of MOT link */
3376 m_txtCache->drcs = ((p[odrcs] << 8) | (p[odrcs+1] << 4) | p[odrcs+2]) & 0x7ff;
3377 if ((m_txtCache->drcs & 0xff) == 0xff)
3378 m_txtCache->drcs = 0;
3379 else if (m_txtCache->drcs < 0x100)
3380 m_txtCache->drcs += 0x800;
3383 if (m_txtCache->astCachetable[m_txtCache->gpop][0])
3384 m_txtCache->astCachetable[m_txtCache->gpop][0]->pageinfo.function = FUNC_GPOP;
3385 if (m_txtCache->astCachetable[m_txtCache->pop][0])
3386 m_txtCache->astCachetable[m_txtCache->pop][0]->pageinfo.function = FUNC_POP;
3387 if (m_txtCache->astCachetable[m_txtCache->gdrcs][0])
3388 m_txtCache->astCachetable[m_txtCache->gdrcs][0]->pageinfo.function = FUNC_GDRCS;
3389 if (m_txtCache->astCachetable[m_txtCache->drcs][0])
3390 m_txtCache->astCachetable[m_txtCache->drcs][0]->pageinfo.function = FUNC_DRCS;
3393 /* evaluate local extension data from p26 */
3396 APx0 = APy0 = APx = APy = m_txtCache->tAPx = m_txtCache->tAPy = 0;
3397 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 */
3402 for (int r = 0; r < 25; r++)
3404 for (int c = 0; c < 40; c++)
3406 if (BlackBgSubst && PageAtrb[o].bg == TXT_ColorBlack && !(PageAtrb[o].IgnoreAtBlackBgSubst))
3408 if (m_txtCache->FullRowColor[r] == 0x08)
3409 PageAtrb[o].bg = m_txtCache->FullScrColor;
3411 PageAtrb[o].bg = m_txtCache->FullRowColor[r];
3420 for (int i = 0; i < 25*40; i++)
3422 if (PageAtrb[i].concealed) PageAtrb[i].fg = PageAtrb[i].bg;
3425 } /* is_dec(page) */
3428 /* dump interpreted object data to stdout */
3429 /* in: 18 bit object data */
3430 /* out: termination info, >0 if end of object */
3431 void CTeletextDecoder::Eval_Object(int iONr, TextCachedPage_t *pstCachedPage,
3432 unsigned char *pAPx, unsigned char *pAPy,
3433 unsigned char *pAPx0, unsigned char *pAPy0,
3434 tObjType ObjType, unsigned char* pagedata, unsigned char* PageChar, TextPageAttr_t* PageAtrb)
3437 int iONr1 = iONr + 1; /* don't terminate after first triplet */
3438 unsigned char drcssubp=0, gdrcssubp=0;
3439 signed char endcol = -1; /* last column to which to extend attribute changes */
3440 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 */
3444 iOData = iTripletNumber2Data(iONr, pstCachedPage, pagedata); /* get triplet data, next triplet */
3445 if (iOData < 0) /* invalid number, not cached, or hamming error: terminate */
3450 if (ObjType == OBJ_ACTIVE)
3454 else if (ObjType == OBJ_ADAPTIVE) /* search end of line */
3456 for (int i = iONr; i <= 506; i++)
3458 int iTempOData = iTripletNumber2Data(i, pstCachedPage, pagedata); /* get triplet data, next triplet */
3459 int iAddress = (iTempOData ) & 0x3f;
3460 int iMode = (iTempOData >> 6) & 0x1f;
3461 //int iData = (iTempOData >> 11) & 0x7f;
3462 if (iTempOData < 0 || /* invalid number, not cached, or hamming error: terminate */
3463 (iAddress >= 40 /* new row: row address and */
3464 && (iMode == 0x01 || /* Full Row Color or */
3465 iMode == 0x04 || /* Set Active Position */
3466 (iMode >= 0x15 && iMode <= 0x17) || /* Object Definition */
3467 iMode == 0x17))) /* Object Termination */
3469 if (iAddress < 40 && iMode != 0x06)
3476 while (0 == Eval_Triplet(iOData, pstCachedPage, pAPx, pAPy, pAPx0, pAPy0, &drcssubp, &gdrcssubp, &endcol, &attrPassive, pagedata, PageChar, PageAtrb) || iONr1 == iONr); /* repeat until termination reached */
3479 void CTeletextDecoder::Eval_NumberedObject(int p, int s, int packet, int triplet, int high,
3480 unsigned char *pAPx, unsigned char *pAPy,
3481 unsigned char *pAPx0, unsigned char *pAPy0, unsigned char* PageChar, TextPageAttr_t* PageAtrb)
3483 if (!packet || 0 == m_txtCache->astCachetable[p][s])
3486 unsigned char pagedata[23*40];
3487 g_application.m_pPlayer->LoadPage(p, s,pagedata);
3489 int idata = CDVDTeletextTools::deh24(pagedata + 40*(packet-1) + 1 + 3*triplet);
3492 if (idata < 0) /* hamming error: ignore triplet */
3495 iONr = idata >> 9; /* triplet number of odd object data */
3497 iONr = idata & 0x1ff; /* triplet number of even object data */
3500 Eval_Object(iONr, m_txtCache->astCachetable[p][s], pAPx, pAPy, pAPx0, pAPy0, (tObjType)(triplet % 3),pagedata, PageChar, PageAtrb);
3504 int CTeletextDecoder::Eval_Triplet(int iOData, TextCachedPage_t *pstCachedPage,
3505 unsigned char *pAPx, unsigned char *pAPy,
3506 unsigned char *pAPx0, unsigned char *pAPy0,
3507 unsigned char *drcssubp, unsigned char *gdrcssubp,
3508 signed char *endcol, TextPageAttr_t *attrPassive, unsigned char* pagedata, unsigned char* PageChar, TextPageAttr_t* PageAtrb)
3510 int iAddress = (iOData ) & 0x3f;
3511 int iMode = (iOData >> 6) & 0x1f;
3512 int iData = (iOData >> 11) & 0x7f;
3514 if (iAddress < 40) /* column addresses */
3516 int offset; /* offset to PageChar and PageAtrb */
3519 *pAPx = iAddress; /* new Active Column */
3520 offset = (*pAPy0 + *pAPy) * 40 + *pAPx0 + *pAPx; /* offset to PageChar and PageAtrb */
3525 if (0 == (iData>>5))
3527 int newcolor = iData & 0x1f;
3528 if (*endcol < 0) /* passive object */
3529 attrPassive->fg = newcolor;
3530 else if (*endcol == 40) /* active object */
3532 TextPageAttr_t *p = &PageAtrb[offset];
3533 int oldcolor = (p)->fg; /* current color (set-after) */
3534 int c = *pAPx0 + *pAPx; /* current column absolute */
3540 } while (c < 40 && p->fg == oldcolor); /* stop at change by level 1 page */
3542 else /* adaptive object */
3544 TextPageAttr_t *p = &PageAtrb[offset];
3545 int c = *pAPx; /* current column relative to object origin */
3551 } while (c <= *endcol);
3558 PageChar[offset] = iData;
3559 if (*endcol < 0) /* passive object */
3561 attrPassive->charset = C_G1C; /* FIXME: separated? */
3562 PageAtrb[offset] = *attrPassive;
3564 else if (PageAtrb[offset].charset != C_G1S)
3565 PageAtrb[offset].charset = C_G1C; /* FIXME: separated? */
3570 PageChar[offset] = iData;
3571 if (*endcol < 0) /* passive object */
3573 attrPassive->charset = C_G3;
3574 PageAtrb[offset] = *attrPassive;
3577 PageAtrb[offset].charset = C_G3;
3580 if (0 == (iData>>5))
3582 int newcolor = iData & 0x1f;
3583 if (*endcol < 0) /* passive object */
3584 attrPassive->bg = newcolor;
3585 else if (*endcol == 40) /* active object */
3587 TextPageAttr_t *p = &PageAtrb[offset];
3588 int oldcolor = (p)->bg; /* current color (set-after) */
3589 int c = *pAPx0 + *pAPx; /* current column absolute */
3593 if (newcolor == TXT_ColorBlack)
3594 p->IgnoreAtBlackBgSubst = 1;
3597 } while (c < 40 && p->bg == oldcolor); /* stop at change by level 1 page */
3599 else /* adaptive object */
3601 TextPageAttr_t *p = &PageAtrb[offset];
3602 int c = *pAPx; /* current column relative to object origin */
3606 if (newcolor == TXT_ColorBlack)
3607 p->IgnoreAtBlackBgSubst = 1;
3610 } while (c <= *endcol);
3618 if ((iData & 0x60) != 0) break; // reserved data field
3619 if (*endcol < 0) /* passive object */
3621 attrPassive->flashing=iData & 0x1f;
3622 PageAtrb[offset] = *attrPassive;
3625 PageAtrb[offset].flashing=iData & 0x1f;
3628 if (*endcol < 0) /* passive object */
3630 attrPassive->setG0G2=iData & 0x3f;
3631 PageAtrb[offset] = *attrPassive;
3634 PageAtrb[offset].setG0G2=iData & 0x3f;
3637 PageChar[offset] = iData;
3638 if (*endcol < 0) /* passive object */
3640 attrPassive->charset = C_G0P; /* FIXME: secondary? */
3641 attrPassive->setX26 = 1;
3642 PageAtrb[offset] = *attrPassive;
3646 PageAtrb[offset].charset = C_G0P; /* FIXME: secondary? */
3647 PageAtrb[offset].setX26 = 1;
3650 // case 0x0b: (see 0x02)
3653 int conc = (iData & 0x04);
3654 int inv = (iData & 0x10);
3655 int dw = (iData & 0x40 ?1:0);
3656 int dh = (iData & 0x01 ?1:0);
3657 int sep = (iData & 0x20);
3658 int bw = (iData & 0x02 ?1:0);
3659 if (*endcol < 0) /* passive object */
3663 attrPassive->concealed = 1;
3664 attrPassive->fg = attrPassive->bg;
3666 attrPassive->inverted = (inv ? 1- attrPassive->inverted : 0);
3667 attrPassive->doubleh = dh;
3668 attrPassive->doublew = dw;
3669 attrPassive->boxwin = bw;
3670 if (bw) attrPassive->IgnoreAtBlackBgSubst = 0;
3673 if (attrPassive->charset == C_G1C)
3674 attrPassive->charset = C_G1S;
3676 attrPassive->underline = 1;
3680 if (attrPassive->charset == C_G1S)
3681 attrPassive->charset = C_G1C;
3683 attrPassive->underline = 0;
3689 int c = *pAPx0 + (*endcol == 40 ? *pAPx : 0); /* current column */
3691 TextPageAttr_t *p = &PageAtrb[offset];
3694 p->inverted = (inv ? 1- p->inverted : 0);
3702 if (p->charset == C_G1C)
3709 if (p->charset == C_G1S)
3717 if (bw) p->IgnoreAtBlackBgSubst = 0;
3721 } while (c < *endcol);
3726 PageChar[offset] = iData & 0x3f;
3727 if (*endcol < 0) /* passive object */
3729 attrPassive->charset = C_OFFSET_DRCS + ((iData & 0x40) ? (0x10 + *drcssubp) : *gdrcssubp);
3730 PageAtrb[offset] = *attrPassive;
3733 PageAtrb[offset].charset = C_OFFSET_DRCS + ((iData & 0x40) ? (0x10 + *drcssubp) : *gdrcssubp);
3736 PageChar[offset] = iData;
3737 if (*endcol < 0) /* passive object */
3739 attrPassive->charset = C_G2;
3740 PageAtrb[offset] = *attrPassive;
3743 PageAtrb[offset].charset = C_G2;
3746 if (iMode == 0x10 && iData == 0x2a)
3750 PageChar[offset] = iData;
3751 if (*endcol < 0) /* passive object */
3753 attrPassive->charset = C_G0P;
3754 attrPassive->diacrit = iMode & 0x0f;
3755 attrPassive->setX26 = 1;
3756 PageAtrb[offset] = *attrPassive;
3760 PageAtrb[offset].charset = C_G0P;
3761 PageAtrb[offset].diacrit = iMode & 0x0f;
3762 PageAtrb[offset].setX26 = 1;
3765 break; /* unsupported or not yet implemented mode: ignore */
3766 } /* switch (iMode) */
3768 else /* ================= (iAddress >= 40): row addresses ====================== */
3773 if (0 == (iData>>5))
3775 m_txtCache->FullScrColor = iData & 0x1f;
3779 if (*endcol == 40) /* active object */
3781 *pAPy = RowAddress2Row(iAddress); /* new Active Row */
3783 int color = iData & 0x1f;
3784 int row = *pAPy0 + *pAPy;
3787 if (row <= 24 && 0 == (iData>>5))
3789 else if (3 == (iData>>5))
3793 for (; row <= maxrow; row++)
3794 m_txtCache->FullRowColor[row] = color;
3799 *pAPy = RowAddress2Row(iAddress); /* new Active Row */
3801 *pAPx = iData; /* new Active Column */
3802 *endcol = -1; /* FIXME: check if row changed? */
3805 if (iAddress == 0x3f)
3807 *pAPx = *pAPy = 0; /* new Active Position 0,0 */
3808 if (*endcol == 40) /* active object */
3810 int color = iData & 0x1f;
3811 int row = *pAPy0; // + *pAPy;
3814 if (row <= 24 && 0 == (iData>>5))
3816 else if (3 == (iData>>5))
3820 for (; row <= maxrow; row++)
3821 m_txtCache->FullRowColor[row] = color;
3837 m_txtCache->tAPy = iAddress - 40;
3838 m_txtCache->tAPx = iData;
3843 if (iAddress & 0x10) /* POP or GPOP */
3845 unsigned char APx = 0, APy = 0;
3846 unsigned char APx0 = *pAPx0 + *pAPx + m_txtCache->tAPx, APy0 = *pAPy0 + *pAPy + m_txtCache->tAPy;
3847 int triplet = 3 * ((iData >> 5) & 0x03) + (iMode & 0x03);
3848 int packet = (iAddress & 0x03) + 1;
3849 int subp = iData & 0x0f;
3850 int high = (iData >> 4) & 0x01;
3853 if (APx0 < 40) /* not in side panel */
3855 Eval_NumberedObject((iAddress & 0x08) ? m_txtCache->gpop : m_txtCache->pop, subp, packet, triplet, high, &APx, &APy, &APx0, &APy0, PageChar,PageAtrb);
3858 else if (iAddress & 0x08) /* local: eval invoked object */
3860 unsigned char APx = 0, APy = 0;
3861 unsigned char APx0 = *pAPx0 + *pAPx + m_txtCache->tAPx, APy0 = *pAPy0 + *pAPy + m_txtCache->tAPy;
3862 int descode = ((iAddress & 0x01) << 3) | (iData >> 4);
3863 int triplet = iData & 0x0f;
3865 if (APx0 < 40) /* not in side panel */
3867 Eval_Object(13 * 23 + 13 * descode + triplet, pstCachedPage, &APx, &APy, &APx0, &APy0, (tObjType)(triplet % 3), pagedata, PageChar, PageAtrb);
3874 if (0 == (iAddress & 0x08)) /* Object Definition illegal or only level 3.5 */
3877 m_txtCache->tAPx = m_txtCache->tAPy = 0;
3879 return 0xFF; /* termination by object definition */
3882 if (0 == (iData & 0x10)) /* DRCS Mode reserved or only level 3.5 */
3886 *drcssubp = iData & 0x0f;
3888 *gdrcssubp = iData & 0x0f;
3891 m_txtCache->tAPx = m_txtCache->tAPy = 0;
3893 return 0x80 | iData; /* explicit termination */
3896 break; /* unsupported or not yet implemented mode: ignore */
3897 } /* switch (iMode) */
3898 } /* (iAddress >= 40): row addresses */
3900 if (iAddress < 40 || iMode != 0x10) /* leave temp. AP-Offset unchanged only immediately after definition */
3901 m_txtCache->tAPx = m_txtCache->tAPy = 0;
3903 return 0; /* normal exit, no termination */
3906 /* get object data */
3907 /* in: absolute triplet number (0..506, start at packet 3 byte 1) */
3908 /* in: pointer to cache struct of page data */
3909 /* out: 18 bit triplet data, <0 if invalid number, not cached, or hamming error */
3910 int CTeletextDecoder::iTripletNumber2Data(int iONr, TextCachedPage_t *pstCachedPage, unsigned char* pagedata)
3912 if (iONr > 506 || 0 == pstCachedPage)
3916 int packet = (iONr / 13) + 3;
3917 int packetoffset = 3 * (iONr % 13);
3920 p = pagedata + 40*(packet-1) + packetoffset + 1;
3921 else if (packet <= 25)
3923 if (0 == pstCachedPage->pageinfo.p24)
3925 p = pstCachedPage->pageinfo.p24 + 40*(packet-24) + packetoffset + 1;
3929 int descode = packet - 26;
3930 if (0 == pstCachedPage->pageinfo.ext)
3932 if (0 == pstCachedPage->pageinfo.ext->p26[descode])
3934 p = pstCachedPage->pageinfo.ext->p26[descode] + packetoffset; /* first byte (=designation code) is not cached */
3936 return CDVDTeletextTools::deh24(p);
3939 int CTeletextDecoder::SetNational(unsigned char sec)
3944 return NAT_PL; //polish
3947 return NAT_TR; //turkish
3949 return NAT_SR; //serbian, croatian, slovenian
3951 return NAT_SC; // serbian, croatian
3953 return NAT_RB; // russian, bulgarian
3955 return NAT_UA; // ukrainian
3957 return NAT_ET; // estonian
3959 return NAT_LV; // latvian, lithuanian
3961 return NAT_GR; // greek
3963 return NAT_HB; // hebrew
3966 return NAT_AR; // arabic
3968 return CountryConversionTable[sec & 0x07];
3971 int CTeletextDecoder::NextHex(int i) /* return next existing non-decimal page number */
3974 if (startpage < 0x100)
3984 } while ((m_txtCache->SubPageTable[i] == 0xFF) || IsDec(i));
3988 void CTeletextDecoder::SetColors(unsigned short *pcolormap, int offset, int number)
3990 int j = offset; /* index in global color table */
3992 for (int i = 0; i < number; i++)
3994 int r = ((pcolormap[i] >> 8) & 0xf) << 4;
3995 int g = ((pcolormap[i] >> 4) & 0xf) << 4;
3996 int b = ((pcolormap[i]) & 0xf) << 4;
3998 if (m_RenderInfo.rd0[j] != r)
4000 m_RenderInfo.rd0[j] = r;
4002 if (m_RenderInfo.gn0[j] != g)
4004 m_RenderInfo.gn0[j] = g;
4006 if (m_RenderInfo.bl0[j] != b)
4008 m_RenderInfo.bl0[j] = b;
4014 color_t CTeletextDecoder::GetColorRGB(enumTeletextColor ttc)
4018 case TXT_ColorBlack: return 0xFF000000;
4019 case TXT_ColorRed: return 0xFFFC1414;
4020 case TXT_ColorGreen: return 0xFF24FC24;
4021 case TXT_ColorYellow: return 0xFFFCC024;
4022 case TXT_ColorBlue: return 0xFF0000FC;
4023 case TXT_ColorMagenta: return 0xFFB000FC;
4024 case TXT_ColorCyan: return 0xFF00FCFC;
4025 case TXT_ColorWhite: return 0xFFFCFCFC;
4026 case TXT_ColorTransp: return 0x00000000;
4030 /* Get colors for CLUTs 2+3 */
4031 int index = (int)ttc;
4032 color_t color = (m_RenderInfo.tr0[index] << 24) |
4033 (m_RenderInfo.bl0[index] << 16) |
4034 (m_RenderInfo.gn0[index] << 8) |
4035 m_RenderInfo.rd0[index];