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"
37 #include <SDL/SDL_stdinc.h>
39 #define SDL_memset4(dst, val, len) \
41 uint32_t _count = (len); \
42 uint32_t _n = (_count + 3) / 4; \
43 uint32_t *_p = static_cast<uint32_t *>(dst); \
44 uint32_t _val = (val); \
45 if (len == 0) break; \
46 switch (_count % 4) { \
47 case 0: do { *_p++ = _val; \
48 case 3: *_p++ = _val; \
49 case 2: *_p++ = _val; \
50 case 1: *_p++ = _val; \
54 #define SDL_memcpy4(dst, src, len) memcpy(dst, src, (len) << 2)
59 static const char *TeletextFont = "special://xbmc/media/Fonts/teletext.ttf";
61 /* spacing attributes */
62 #define alpha_black 0x00
63 #define alpha_red 0x01
64 #define alpha_green 0x02
65 #define alpha_yellow 0x03
66 #define alpha_blue 0x04
67 #define alpha_magenta 0x05
68 #define alpha_cyan 0x06
69 #define alpha_white 0x07
73 #define start_box 0x0B
74 #define normal_size 0x0C
75 #define double_height 0x0D
76 #define double_width 0x0E
77 #define double_size 0x0F
78 #define mosaic_black 0x10
79 #define mosaic_red 0x11
80 #define mosaic_green 0x12
81 #define mosaic_yellow 0x13
82 #define mosaic_blue 0x14
83 #define mosaic_magenta 0x15
84 #define mosaic_cyan 0x16
85 #define mosaic_white 0x17
87 #define contiguous_mosaic 0x19
88 #define separated_mosaic 0x1A
90 #define black_background 0x1C
91 #define new_background 0x1D
92 #define hold_mosaic 0x1E
93 #define release_mosaic 0x1F
95 #define RowAddress2Row(row) ((row == 40) ? 24 : (row - 40))
97 // G2 Set as defined in ETS 300 706
98 const unsigned short int G2table[5][6*16] =
100 // Latin G2 Supplementary Set
101 { 0x0020, 0x00A1, 0x00A2, 0x00A3, 0x0024, 0x00A5, 0x0023, 0x00A7, 0x00A4, 0x2018, 0x201C, 0x00AB, 0x2190, 0x2191, 0x2192, 0x2193,
102 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00D7, 0x00B5, 0x00B6, 0x00B7, 0x00F7, 0x2019, 0x201D, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
103 0x0020, 0x0300, 0x0301, 0x02C6, 0x0303, 0x02C9, 0x02D8, 0x02D9, 0x00A8, 0x002E, 0x02DA, 0x00B8, 0x005F, 0x02DD, 0x02DB, 0x02C7,
104 0x2014, 0x00B9, 0x00AE, 0x00A9, 0x2122, 0x266A, 0x20AC, 0x2030, 0x03B1, 0x0020, 0x0020, 0x0020, 0x215B, 0x215C, 0x215D, 0x215E,
105 0x2126, 0x00C6, 0x00D0, 0x00AA, 0x0126, 0x0020, 0x0132, 0x013F, 0x0141, 0x00D8, 0x0152, 0x00BA, 0x00DE, 0x0166, 0x014A, 0x0149,
106 0x0138, 0x00E6, 0x0111, 0x00F0, 0x0127, 0x0131, 0x0133, 0x0140, 0x0142, 0x00F8, 0x0153, 0x00DF, 0x00FE, 0x0167, 0x014B, 0x25A0},
107 // Cyrillic G2 Supplementary Set
108 { 0x0020, 0x00A1, 0x00A2, 0x00A3, 0x0024, 0x00A5, 0x0020, 0x00A7, 0x0020, 0x2018, 0x201C, 0x00AB, 0x2190, 0x2191, 0x2192, 0x2193,
109 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00D7, 0x00B5, 0x00B6, 0x00B7, 0x00F7, 0x2019, 0x201D, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
110 0x0020, 0x0300, 0x0301, 0x02C6, 0x02DC, 0x02C9, 0x02D8, 0x02D9, 0x00A8, 0x002E, 0x02DA, 0x00B8, 0x005F, 0x02DD, 0x02DB, 0x02C7,
111 0x2014, 0x00B9, 0x00AE, 0x00A9, 0x2122, 0x266A, 0x20AC, 0x2030, 0x03B1, 0x0141, 0x0142, 0x00DF, 0x215B, 0x215C, 0x215D, 0x215E,
112 0x0044, 0x0045, 0x0046, 0x0047, 0x0049, 0x004A, 0x004B, 0x004C, 0x004E, 0x0051, 0x0052, 0x0053, 0x0055, 0x0056, 0x0057, 0x005A,
113 0x0064, 0x0065, 0x0066, 0x0067, 0x0069, 0x006A, 0x006B, 0x006C, 0x006E, 0x0071, 0x0072, 0x0073, 0x0075, 0x0076, 0x0077, 0x007A},
114 // Greek G2 Supplementary Set
115 { 0x0020, 0x0061, 0x0062, 0x00A3, 0x0065, 0x0068, 0x0069, 0x00A7, 0x003A, 0x2018, 0x201C, 0x006B, 0x2190, 0x2191, 0x2192, 0x2193,
116 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00D7, 0x006D, 0x006E, 0x0070, 0x00F7, 0x2019, 0x201D, 0x0074, 0x00BC, 0x00BD, 0x00BE, 0x0078,
117 0x0020, 0x0300, 0x0301, 0x02C6, 0x02DC, 0x02C9, 0x02D8, 0x02D9, 0x00A8, 0x002E, 0x02DA, 0x00B8, 0x005F, 0x02DD, 0x02DB, 0x02C7,
118 0x003F, 0x00B9, 0x00AE, 0x00A9, 0x2122, 0x266A, 0x20AC, 0x2030, 0x03B1, 0x038A, 0x038E, 0x038F, 0x215B, 0x215C, 0x215D, 0x215E,
119 0x0043, 0x0044, 0x0046, 0x0047, 0x004A, 0x004C, 0x0051, 0x0052, 0x0053, 0x0055, 0x0056, 0x0057, 0x0059, 0x005A, 0x0386, 0x0389,
120 0x0063, 0x0064, 0x0066, 0x0067, 0x006A, 0x006C, 0x0071, 0x0072, 0x0073, 0x0075, 0x0076, 0x0077, 0x0079, 0x007A, 0x0388, 0x25A0},
122 { 0x0020, 0x0639, 0xFEC9, 0xFE83, 0xFE85, 0xFE87, 0xFE8B, 0xFE89, 0xFB7C, 0xFB7D, 0xFB7A, 0xFB58, 0xFB59, 0xFB56, 0xFB6D, 0xFB8E,
123 0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667, 0x0668, 0x0669, 0xFECE, 0xFECD, 0xFEFC, 0xFEEC, 0xFEEA, 0xFEE9,
124 0x00E0, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
125 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005A, 0x00EB, 0x00EA, 0x00F9, 0x00EE, 0xFECA,
126 0x00E9, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
127 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x00E2, 0x00F4, 0x00FB, 0x00E7, 0x25A0}
130 //const (avoid warnings :<)
131 TextPageAttr_t Text_AtrTable[] =
133 { TXT_ColorWhite , TXT_ColorBlack , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_WB */
134 { TXT_ColorWhite , TXT_ColorBlack , C_G0P, 0, 0, 1 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_PassiveDefault */
135 { TXT_ColorWhite , TXT_ColorRed , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_L250 */
136 { TXT_ColorBlack , TXT_ColorYellow, C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_L252 */
137 { TXT_ColorBlack , TXT_ColorGreen , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_L251 */
138 { TXT_ColorWhite , TXT_ColorBlue , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_L253 */
139 { TXT_ColorMagenta, TXT_ColorBlack , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_TOPMENU0 */
140 { TXT_ColorGreen , TXT_ColorBlack , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_TOPMENU1 */
141 { TXT_ColorYellow , TXT_ColorBlack , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_TOPMENU2 */
142 { TXT_ColorCyan , TXT_ColorBlack , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_TOPMENU3 */
143 { TXT_ColorMenu2 , TXT_ColorMenu3 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSG0 */
144 { TXT_ColorYellow , TXT_ColorMenu3 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSG1 */
145 { TXT_ColorMenu2 , TXT_ColorTransp, C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSG2 */
146 { TXT_ColorWhite , TXT_ColorMenu3 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSG3 */
147 { TXT_ColorMenu2 , TXT_ColorMenu1 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSGDRM0 */
148 { TXT_ColorYellow , TXT_ColorMenu1 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSGDRM1 */
149 { TXT_ColorMenu2 , TXT_ColorBlack , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSGDRM2 */
150 { TXT_ColorWhite , TXT_ColorMenu1 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MSGDRM3 */
151 { TXT_ColorMenu1 , TXT_ColorBlue , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENUHIL0 5a Z */
152 { TXT_ColorWhite , TXT_ColorBlue , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENUHIL1 58 X */
153 { TXT_ColorMenu2 , TXT_ColorTransp, C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENUHIL2 9b õ */
154 { TXT_ColorMenu2 , TXT_ColorMenu1 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENU0 ab ´ */
155 { TXT_ColorYellow , TXT_ColorMenu1 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENU1 a4 § */
156 { TXT_ColorMenu2 , TXT_ColorTransp, C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENU2 9b õ */
157 { TXT_ColorMenu2 , TXT_ColorMenu3 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENU3 cb À */
158 { TXT_ColorCyan , TXT_ColorMenu3 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENU4 c7 « */
159 { TXT_ColorWhite , TXT_ColorMenu3 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENU5 c8 » */
160 { TXT_ColorWhite , TXT_ColorMenu1 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_MENU6 a8 ® */
161 { TXT_ColorYellow , TXT_ColorMenu1 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f}, /* ATR_CATCHMENU0 a4 § */
162 { TXT_ColorWhite , TXT_ColorMenu1 , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f} /* ATR_CATCHMENU1 a8 ® */
169 S_FHL, /* full horizontal line: y-offset */
170 S_FVL, /* full vertical line: x-offset */
171 S_BOX, /* rectangle: x-offset, y-offset, width, height */
172 S_TRA, /* trapez: x0, y0, l0, x1, y1, l1 */
173 S_BTR, /* trapez in bgcolor: x0, y0, l0, x1, y1, l1 */
175 S_LNK, /* call other shape: shapenumber */
176 S_CHR, /* Character from freetype hibyte, lowbyte */
177 S_ADT, /* Character 2F alternating raster */
178 S_FLH, /* flip horizontal */
179 S_FLV /* flip vertical */
182 /* shape coordinates */
185 S_W13 = 5, /* width*1/3 */
186 S_W12, /* width*1/2 */
187 S_W23, /* width*2/3 */
190 S_H13, /* height*1/3 */
191 S_H12, /* height*1/2 */
192 S_H23, /* height*2/3 */
198 unsigned char aG3_20[] = { S_TRA, 0, S_H23, 1, 0, S_H11, S_W12, S_END };
199 unsigned char aG3_21[] = { S_TRA, 0, S_H23, 1, 0, S_H11, S_W11, S_END };
200 unsigned char aG3_22[] = { S_TRA, 0, S_H12, 1, 0, S_H11, S_W12, S_END };
201 unsigned char aG3_23[] = { S_TRA, 0, S_H12, 1, 0, S_H11, S_W11, S_END };
202 unsigned char aG3_24[] = { S_TRA, 0, 0, 1, 0, S_H11, S_W12, S_END };
203 unsigned char aG3_25[] = { S_TRA, 0, 0, 1, 0, S_H11, S_W11, S_END };
204 unsigned char aG3_26[] = { S_INV, S_LNK, 0x66, S_END };
205 unsigned char aG3_27[] = { S_INV, S_LNK, 0x67, S_END };
206 unsigned char aG3_28[] = { S_INV, S_LNK, 0x68, S_END };
207 unsigned char aG3_29[] = { S_INV, S_LNK, 0x69, S_END };
208 unsigned char aG3_2a[] = { S_INV, S_LNK, 0x6a, S_END };
209 unsigned char aG3_2b[] = { S_INV, S_LNK, 0x6b, S_END };
210 unsigned char aG3_2c[] = { S_INV, S_LNK, 0x6c, S_END };
211 unsigned char aG3_2d[] = { S_INV, S_LNK, 0x6d, S_END };
212 unsigned char aG3_2e[] = { S_BOX, 2, 0, 3, S_H11, S_END };
213 unsigned char aG3_2f[] = { S_ADT };
214 unsigned char aG3_30[] = { S_LNK, 0x20, S_FLH, S_END };
215 unsigned char aG3_31[] = { S_LNK, 0x21, S_FLH, S_END };
216 unsigned char aG3_32[] = { S_LNK, 0x22, S_FLH, S_END };
217 unsigned char aG3_33[] = { S_LNK, 0x23, S_FLH, S_END };
218 unsigned char aG3_34[] = { S_LNK, 0x24, S_FLH, S_END };
219 unsigned char aG3_35[] = { S_LNK, 0x25, S_FLH, S_END };
220 unsigned char aG3_36[] = { S_INV, S_LNK, 0x76, S_END };
221 unsigned char aG3_37[] = { S_INV, S_LNK, 0x77, S_END };
222 unsigned char aG3_38[] = { S_INV, S_LNK, 0x78, S_END };
223 unsigned char aG3_39[] = { S_INV, S_LNK, 0x79, S_END };
224 unsigned char aG3_3a[] = { S_INV, S_LNK, 0x7a, S_END };
225 unsigned char aG3_3b[] = { S_INV, S_LNK, 0x7b, S_END };
226 unsigned char aG3_3c[] = { S_INV, S_LNK, 0x7c, S_END };
227 unsigned char aG3_3d[] = { S_INV, S_LNK, 0x7d, S_END };
228 unsigned char aG3_3e[] = { S_LNK, 0x2e, S_FLH, S_END };
229 unsigned char aG3_3f[] = { S_BOX, 0, 0, S_W11, S_H11, S_END };
230 unsigned char aG3_40[] = { S_BOX, 0, S_H13, S_W11, S_H13, S_LNK, 0x7e, S_END };
231 unsigned char aG3_41[] = { S_BOX, 0, S_H13, S_W11, S_H13, S_LNK, 0x7e, S_FLV, S_END };
232 unsigned char aG3_42[] = { S_LNK, 0x50, S_BOX, S_W12, S_H13, S_W12, S_H13, S_END };
233 unsigned char aG3_43[] = { S_LNK, 0x50, S_BOX, 0, S_H13, S_W12, S_H13, S_END };
234 unsigned char aG3_44[] = { S_LNK, 0x48, S_FLV, S_LNK, 0x48, S_END };
235 unsigned char aG3_45[] = { S_LNK, 0x44, S_FLH, S_END };
236 unsigned char aG3_46[] = { S_LNK, 0x47, S_FLV, S_END };
237 unsigned char aG3_47[] = { S_LNK, 0x48, S_FLH, S_LNK, 0x48, S_END };
238 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 };
239 unsigned char aG3_49[] = { S_LNK, 0x48, S_FLH, S_END };
240 unsigned char aG3_4a[] = { S_LNK, 0x48, S_FLV, S_END };
241 unsigned char aG3_4b[] = { S_LNK, 0x48, S_FLH, S_FLV, S_END };
242 unsigned char aG3_4c[] = { S_LNK, 0x50, S_BOX, 0, S_H13, S_W11, S_H13, S_END };
243 unsigned char aG3_4d[] = { S_CHR, 0x25, 0xE6 };
244 unsigned char aG3_4e[] = { S_CHR, 0x25, 0xCF };
245 unsigned char aG3_4f[] = { S_CHR, 0x25, 0xCB };
246 unsigned char aG3_50[] = { S_BOX, S_W12, 0, 2, S_H11, S_FLH, S_BOX, S_W12, 0, 2, S_H11,S_END };
247 unsigned char aG3_51[] = { S_BOX, 0, S_H12, S_W11, 2, S_FLV, S_BOX, 0, S_H12, S_W11, 2,S_END };
248 unsigned char aG3_52[] = { S_LNK, 0x55, S_FLH, S_FLV, S_END };
249 unsigned char aG3_53[] = { S_LNK, 0x55, S_FLV, S_END };
250 unsigned char aG3_54[] = { S_LNK, 0x55, S_FLH, S_END };
251 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 };
252 unsigned char aG3_56[] = { S_LNK, 0x57, S_FLH, S_END};
253 unsigned char aG3_57[] = { S_LNK, 0x55, S_LNK, 0x50 , S_END};
254 unsigned char aG3_58[] = { S_LNK, 0x59, S_FLV, S_END};
255 unsigned char aG3_59[] = { S_LNK, 0x7e, S_LNK, 0x51 , S_END};
256 unsigned char aG3_5a[] = { S_LNK, 0x50, S_LNK, 0x51 , S_END};
257 unsigned char aG3_5b[] = { S_CHR, 0x21, 0x92};
258 unsigned char aG3_5c[] = { S_CHR, 0x21, 0x90};
259 unsigned char aG3_5d[] = { S_CHR, 0x21, 0x91};
260 unsigned char aG3_5e[] = { S_CHR, 0x21, 0x93};
261 unsigned char aG3_5f[] = { S_CHR, 0x00, 0x20};
262 unsigned char aG3_60[] = { S_INV, S_LNK, 0x20, S_END };
263 unsigned char aG3_61[] = { S_INV, S_LNK, 0x21, S_END };
264 unsigned char aG3_62[] = { S_INV, S_LNK, 0x22, S_END };
265 unsigned char aG3_63[] = { S_INV, S_LNK, 0x23, S_END };
266 unsigned char aG3_64[] = { S_INV, S_LNK, 0x24, S_END };
267 unsigned char aG3_65[] = { S_INV, S_LNK, 0x25, S_END };
268 unsigned char aG3_66[] = { S_LNK, 0x20, S_FLV, S_END };
269 unsigned char aG3_67[] = { S_LNK, 0x21, S_FLV, S_END };
270 unsigned char aG3_68[] = { S_LNK, 0x22, S_FLV, S_END };
271 unsigned char aG3_69[] = { S_LNK, 0x23, S_FLV, S_END };
272 unsigned char aG3_6a[] = { S_LNK, 0x24, S_FLV, S_END };
273 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 };
274 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 };
275 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 };
276 unsigned char aG3_6e[] = { S_CHR, 0x00, 0x20};
277 unsigned char aG3_6f[] = { S_CHR, 0x00, 0x20};
278 unsigned char aG3_70[] = { S_INV, S_LNK, 0x30, S_END };
279 unsigned char aG3_71[] = { S_INV, S_LNK, 0x31, S_END };
280 unsigned char aG3_72[] = { S_INV, S_LNK, 0x32, S_END };
281 unsigned char aG3_73[] = { S_INV, S_LNK, 0x33, S_END };
282 unsigned char aG3_74[] = { S_INV, S_LNK, 0x34, S_END };
283 unsigned char aG3_75[] = { S_INV, S_LNK, 0x35, S_END };
284 unsigned char aG3_76[] = { S_LNK, 0x66, S_FLH, S_END };
285 unsigned char aG3_77[] = { S_LNK, 0x67, S_FLH, S_END };
286 unsigned char aG3_78[] = { S_LNK, 0x68, S_FLH, S_END };
287 unsigned char aG3_79[] = { S_LNK, 0x69, S_FLH, S_END };
288 unsigned char aG3_7a[] = { S_LNK, 0x6a, S_FLH, S_END };
289 unsigned char aG3_7b[] = { S_LNK, 0x6b, S_FLH, S_END };
290 unsigned char aG3_7c[] = { S_LNK, 0x6c, S_FLH, S_END };
291 unsigned char aG3_7d[] = { S_LNK, 0x6d, S_FLV, S_END };
292 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)
294 unsigned char *aShapes[] =
296 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,
297 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,
298 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,
299 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,
300 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,
301 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
304 // G0 Table as defined in ETS 300 706
305 // cyrillic G0 Charset (0 = Serbian/Croatian, 1 = Russian/Bulgarian, 2 = Ukrainian)
306 const unsigned short int G0table[6][6*16] =
308 // Cyrillic G0 Set - Option 1 - Serbian/Croatian
309 { ' ', '!', '\"', '#', '$', '%', '&', '\'', '(' , ')' , '*', '+', ',', '-', '.', '/',
310 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
311 0x0427, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, 0x0425, 0x0418, 0x0408, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E,
312 0x041F, 0x040C, 0x0420, 0x0421, 0x0422, 0x0423, 0x0412, 0x0403, 0x0409, 0x040A, 0x0417, 0x040B, 0x0416, 0x0402, 0x0428, 0x040F,
313 0x0447, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, 0x0445, 0x0438, 0x0458, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E,
314 0x043F, 0x045C, 0x0440, 0x0441, 0x0442, 0x0443, 0x0432, 0x0453, 0x0459, 0x045A, 0x0437, 0x045B, 0x0436, 0x0452, 0x0448, 0x25A0},
315 // Cyrillic G0 Set - Option 2 - Russian/Bulgarian
316 { ' ', '!', '\"', '#', '$', '%', 0x044B, '\'', '(' , ')' , '*', '+', ',', '-', '.', '/',
317 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
318 0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, 0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E,
319 0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, 0x042C, 0x042A, 0x0417, 0x0428, 0x042D, 0x0429, 0x0427, 0x042B,
320 0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, 0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E,
321 0x043F, 0x044F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, 0x044C, 0x044A, 0x0437, 0x0448, 0x044D, 0x0449, 0x0447, 0x25A0},
322 // Cyrillic G0 Set - Option 3 - Ukrainian
323 { ' ', '!', '\"', '#', '$', '%', 0x0457, '\'', '(' , ')' , '*', '+', ',', '-', '.', '/',
324 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
325 0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, 0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E,
326 0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, 0x042C, 0x0406, 0x0417, 0x0428, 0x0404, 0x0429, 0x0427, 0x0407,
327 0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, 0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E,
328 0x043F, 0x044F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, 0x044C, 0x0456, 0x0437, 0x0448, 0x0454, 0x0449, 0x0447, 0x25A0},
330 { ' ', '!', '\"', '#', '$', '%', '&', '\'', '(' , ')' , '*', '+', ',', '-', '.', '/',
331 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', 0x00AB, '=', 0x00BB, '?',
332 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F,
333 0x03A0, 0x03A1, 0x0384, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF,
334 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
335 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0x25A0},
337 { ' ', '!', 0x05F2, 0x00A3, '$', '%', '&', '\'', '(' , ')' , '*', '+', ',', '-', '.', '/',
338 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
339 '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
340 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 0x2190, 0x00BD, 0x2192, 0x2191, '#',
341 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
342 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x20AA, 0x2551, 0x00BE, 0x00F7, 0x25A0},
343 // Arabic G0 Set - Thanks to Habib2006(fannansat)
344 { ' ', '!', 0x05F2, 0x00A3, '$', 0x066A, 0xFEF0, 0xFEF2, 0xFD3F, 0xFD3E, '*', '+', ',', '-', '.', '/',
345 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', 0x061B, '>', '=', '<', 0x061F,
346 0xFE94, 0x0621, 0xFE92, 0x0628, 0xFE98, 0x062A, 0xFE8E, 0xFE8D, 0xFE91, 0xFE93, 0xFE97, 0xFE9B, 0xFE9F, 0xFEA3, 0xFEA7, 0xFEA9,
347 0x0630, 0xFEAD, 0xFEAF, 0xFEB3, 0xFEB7, 0xFEBB, 0xFEBF, 0xFEC1, 0xFEC5, 0xFECB, 0xFECF, 0xFE9C, 0xFEA0, 0xFEA4, 0xFEA8, 0x0023,
348 0x0640, 0xFED3, 0xFED7, 0xFEDB, 0xFEDF, 0xFEE3, 0xFEE7, 0xFEEB, 0xFEED, 0xFEEF, 0xFEF3, 0xFE99, 0xFE9D, 0xFEA1, 0xFEA5, 0xFEF4,
349 0xFEF0, 0xFECC, 0xFED0, 0xFED4, 0xFED1, 0xFED8, 0xFED5, 0xFED9, 0xFEE0, 0xFEDD, 0xFEE4, 0xFEE1, 0xFEE8, 0xFEE5, 0xFEFB, 0x25A0}
352 const unsigned short int nationaltable23[14][2] =
354 { '#', 0x00A4 }, /* 0 */
355 { '#', 0x016F }, /* 1 CS/SK */
356 { 0x00A3, '$' }, /* 2 EN */
357 { '#', 0x00F5 }, /* 3 ET */
358 { 0x00E9, 0x0457 }, /* 4 FR */
359 { '#', '$' }, /* 5 DE */
360 { 0x00A3, '$' }, /* 6 IT */
361 { '#', '$' }, /* 7 LV/LT */
362 { '#', 0x0144 }, /* 8 PL */
363 { 0x00E7, '$' }, /* 9 PT/ES */
364 { '#', 0x00A4 }, /* A RO */
365 { '#', 0x00CB }, /* B SR/HR/SL */
366 { '#', 0x00A4 }, /* C SV/FI/HU */
367 { 0x20A4, 0x011F }, /* D TR */
369 const unsigned short int nationaltable40[14] =
372 0x010D, /* 1 CS/SK */
378 0x0161, /* 7 LV/LT */
380 0x00A1, /* 9 PT/ES */
382 0x010C, /* B SR/HR/SL */
383 0x00C9, /* C SV/FI/HU */
386 const unsigned short int nationaltable5b[14][6] =
388 { '[', '\\', ']', '^', '_', '`' }, /* 0 */
389 { 0x0165, 0x017E, 0x00FD, 0x00ED, 0x0159, 0x00E9 }, /* 1 CS/SK */
390 { 0x2190, 0x00BD, 0x2192, 0x2191, '#', 0x00AD }, /* 2 EN */
391 { 0x00C4, 0x00D6, 0x017D, 0x00DC, 0x00D5, 0x0161 }, /* 3 ET */
392 { 0x0451, 0x00EA, 0x00F9, 0x00EE, '#', 0x00E8 }, /* 4 FR */
393 { 0x00C4, 0x00D6, 0x00DC, '^', '_', 0x00B0 }, /* 5 DE */
394 { 0x00B0, 0x00E7, 0x2192, 0x2191, '#', 0x00F9 }, /* 6 IT */
395 { 0x0117, 0x0119, 0x017D, 0x010D, 0x016B, 0x0161 }, /* 7 LV/LT */
396 { 0x017B, 0x015A, 0x0141, 0x0107, 0x00F3, 0x0119 }, /* 8 PL */
397 { 0x00E1, 0x00E9, 0x00ED, 0x00F3, 0x00FA, 0x00BF }, /* 9 PT/ES */
398 { 0x00C2, 0x015E, 0x01CD, 0x01CF, 0x0131, 0x0163 }, /* A RO */
399 { 0x0106, 0x017D, 0x00D0, 0x0160, 0x0451, 0x010D }, /* B SR/HR/SL */
400 { 0x00C4, 0x00D6, 0x00C5, 0x00DC, '_', 0x00E9 }, /* C SV/FI/HU */
401 { 0x015E, 0x00D6, 0x00C7, 0x00DC, 0x011E, 0x0131 }, /* D TR */
403 const unsigned short int nationaltable7b[14][4] =
405 { '{', '|', '}', '~' }, /* 0 */
406 { 0x00E1, 0x011B, 0x00FA, 0x0161 }, /* 1 CS/SK */
407 { 0x00BC, 0x2551, 0x00BE, 0x00F7 }, /* 2 EN */
408 { 0x00E4, 0x00F6, 0x017E, 0x00FC }, /* 3 ET */
409 { 0x00E2, 0x00F4, 0x00FB, 0x00E7 }, /* 4 FR */
410 { 0x00E4, 0x00F6, 0x00FC, 0x00DF }, /* 5 DE */
411 { 0x00E0, 0x00F3, 0x00E8, 0x00EC }, /* 6 IT */
412 { 0x0105, 0x0173, 0x017E, 0x012F }, /* 7 LV/LT */
413 { 0x017C, 0x015B, 0x0142, 0x017A }, /* 8 PL */
414 { 0x00FC, 0x00F1, 0x00E8, 0x00E0 }, /* 9 PT/ES */
415 { 0x00E2, 0x015F, 0x01CE, 0x00EE }, /* A RO */
416 { 0x0107, 0x017E, 0x0111, 0x0161 }, /* B SR/HR/SL */
417 { 0x00E4, 0x00F6, 0x00E5, 0x00FC }, /* C SV/FI/HU */
418 { 0x015F, 0x00F6, 0x00E7, 0x00FC }, /* D TR */
420 const unsigned short int arrowtable[] =
422 8592, 8594, 8593, 8595, 'O', 'K', 8592, 8592
425 CTeletextDecoder::CTeletextDecoder()
427 memset(&m_RenderInfo, 0, sizeof(TextRenderInfo_t));
429 m_teletextFont = CSpecialProtocol::TranslatePath(TeletextFont);
430 m_TextureBuffer = NULL;
434 m_RenderInfo.ShowFlof = true;
435 m_RenderInfo.Show39 = true;
436 m_RenderInfo.Showl25 = true;
437 m_RenderInfo.Prev_100 = 0x100;
438 m_RenderInfo.Prev_10 = 0x100;
439 m_RenderInfo.Next_100 = 0x100;
440 m_RenderInfo.Next_10 = 0x100;
441 m_RenderInfo.InputCounter = 2;
443 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 };
444 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 };
445 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 };
446 unsigned short tr0[] = {0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
447 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 0x0000 , 0x0000 , 0x0A0A , 0xFFFF, 0x3030 };
452 memcpy(m_RenderInfo.rd0,rd0,TXT_Color_SIZECOLTABLE*sizeof(unsigned short));
453 memcpy(m_RenderInfo.gn0,gn0,TXT_Color_SIZECOLTABLE*sizeof(unsigned short));
454 memcpy(m_RenderInfo.bl0,bl0,TXT_Color_SIZECOLTABLE*sizeof(unsigned short));
455 memcpy(m_RenderInfo.tr0,tr0,TXT_Color_SIZECOLTABLE*sizeof(unsigned short));
467 m_updateTexture = false;
471 CTeletextDecoder::~CTeletextDecoder()
475 bool CTeletextDecoder::HandleAction(const CAction &action)
477 if (m_txtCache == NULL)
479 CLog::Log(LOGERROR, "CTeletextDecoder::HandleAction called without teletext cache");
483 if (action.GetID() == ACTION_MOVE_UP)
485 if (m_RenderInfo.PageCatching)
486 CatchNextPage(-1, -1);
488 GetNextPageOne(true);
491 else if (action.GetID() == ACTION_MOVE_DOWN)
493 if (m_RenderInfo.PageCatching)
496 GetNextPageOne(false);
499 else if (action.GetID() == ACTION_MOVE_RIGHT)
501 if (m_RenderInfo.PageCatching)
503 else if (m_RenderInfo.Boxed)
505 m_RenderInfo.SubtitleDelay++;
506 // display SubtitleDelay
507 m_RenderInfo.PosY = 0;
510 sprintf(ns,"+%d ", m_RenderInfo.SubtitleDelay);
511 RenderCharFB(ns[0], &Text_AtrTable[ATR_WB]);
512 RenderCharFB(ns[1], &Text_AtrTable[ATR_WB]);
513 RenderCharFB(ns[2], &Text_AtrTable[ATR_WB]);
514 RenderCharFB(ns[4], &Text_AtrTable[ATR_WB]);
522 else if (action.GetID() == ACTION_MOVE_LEFT)
524 if (m_RenderInfo.PageCatching)
525 CatchNextPage(0, -1);
526 else if (m_RenderInfo.Boxed)
528 m_RenderInfo.SubtitleDelay--;
530 // display subtitledelay
531 m_RenderInfo.PosY = 0;
534 sprintf(ns,"+%d ", m_RenderInfo.SubtitleDelay);
535 RenderCharFB(ns[0], &Text_AtrTable[ATR_WB]);
536 RenderCharFB(ns[1], &Text_AtrTable[ATR_WB]);
537 RenderCharFB(ns[2], &Text_AtrTable[ATR_WB]);
538 RenderCharFB(ns[4], &Text_AtrTable[ATR_WB]);
546 else if (action.GetID() >= REMOTE_0 && action.GetID() <= REMOTE_9)
548 PageInput(action.GetID() - REMOTE_0);
551 else if (action.GetID() >= KEY_ASCII) // FIXME make it KEY_UNICODE
552 { // input from the keyboard
553 if (action.GetUnicode() >= 48 && action.GetUnicode() < 58)
555 PageInput(action.GetUnicode() - 48);
560 else if (action.GetID() == ACTION_PAGE_UP)
565 else if (action.GetID() == ACTION_PAGE_DOWN)
570 else if (action.GetID() == ACTION_SELECT_ITEM)
572 if (m_txtCache->SubPageTable[m_txtCache->Page] == 0xFF)
575 if (!m_RenderInfo.PageCatching)
583 if (m_RenderInfo.PageCatching)
585 m_txtCache->PageUpdate = true;
586 m_RenderInfo.PageCatching = 0;
590 if (action.GetID() == ACTION_SHOW_INFO)
595 else if (action.GetID() == ACTION_TELETEXT_RED)
597 ColorKey(m_RenderInfo.Prev_100);
600 else if (action.GetID() == ACTION_TELETEXT_GREEN)
602 ColorKey(m_RenderInfo.Prev_10);
605 else if (action.GetID() == ACTION_TELETEXT_YELLOW)
607 ColorKey(m_RenderInfo.Next_10);
610 else if (action.GetID() == ACTION_TELETEXT_BLUE)
612 ColorKey(m_RenderInfo.Next_100);
619 bool CTeletextDecoder::InitDecoder()
623 m_txtCache = g_application.m_pPlayer->GetTeletextCache();
624 if (m_txtCache == NULL)
626 CLog::Log(LOGERROR, "%s: called without teletext cache", __FUNCTION__);
630 /* init fontlibrary */
631 if ((error = FT_Init_FreeType(&m_Library)))
633 CLog::Log(LOGERROR, "%s: <FT_Init_FreeType: 0x%.2X>", __FUNCTION__, error);
638 if ((error = FTC_Manager_New(m_Library, 7, 2, 0, &MyFaceRequester, NULL, &m_Manager)))
640 FT_Done_FreeType(m_Library);
643 CLog::Log(LOGERROR, "%s: <FTC_Manager_New: 0x%.2X>", __FUNCTION__, error);
647 if ((error = FTC_SBitCache_New(m_Manager, &m_Cache)))
649 FTC_Manager_Done(m_Manager);
650 FT_Done_FreeType(m_Library);
653 CLog::Log(LOGERROR, "%s: <FTC_SBit_Cache_New: 0x%.2X>", __FUNCTION__, error);
657 /* calculate font dimensions */
658 m_RenderInfo.Width = (int)(g_graphicsContext.GetWidth()*g_graphicsContext.GetGUIScaleX());
659 m_RenderInfo.Height = (int)(g_graphicsContext.GetHeight()*g_graphicsContext.GetGUIScaleY());
660 m_RenderInfo.FontHeight = m_RenderInfo.Height / 25;
661 m_RenderInfo.FontWidth_Normal = m_RenderInfo.Width / (m_RenderInfo.Show39 ? 39 : 40);
662 SetFontWidth(m_RenderInfo.FontWidth_Normal);
663 for (int i = 0; i <= 10; i++)
664 m_RenderInfo.axdrcs[i+12+1] = (m_RenderInfo.FontHeight * i + 6) / 10;
667 m_TypeTTF.face_id = (FTC_FaceID) m_teletextFont.c_str();
668 m_TypeTTF.height = (FT_UShort) m_RenderInfo.FontHeight;
669 m_TypeTTF.flags = FT_LOAD_MONOCHROME;
670 if (FTC_Manager_LookupFace(m_Manager, m_TypeTTF.face_id, &m_Face))
672 m_TypeTTF.face_id = (FTC_FaceID) m_teletextFont.c_str();
673 if ((error = FTC_Manager_LookupFace(m_Manager, m_TypeTTF.face_id, &m_Face)))
675 CLog::Log(LOGERROR, "%s: <FTC_Manager_Lookup_Face failed with Errorcode 0x%.2X>\n", __FUNCTION__, error);
676 FTC_Manager_Done(m_Manager);
677 FT_Done_FreeType(m_Library);
683 m_Ascender = m_RenderInfo.FontHeight * m_Face->ascender / m_Face->units_per_EM;
685 /* set variable screeninfo for double buffering */
687 m_TextureBuffer = new color_t [4*m_RenderInfo.Height*m_RenderInfo.Width];
689 ClearFB(GetColorRGB(TXT_ColorTransp));
690 ClearBB(GetColorRGB(TXT_ColorTransp)); /* initialize backbuffer */
691 /* set new colormap */
692 SetColors((unsigned short *)DefaultColors, 0, TXT_Color_SIZECOLTABLE);
694 for (int i = 0; i < 40 * 25; i++)
696 m_RenderInfo.PageChar[i] = ' ';
697 m_RenderInfo.PageAtrb[i].fg = TXT_ColorTransp;
698 m_RenderInfo.PageAtrb[i].bg = TXT_ColorTransp;
699 m_RenderInfo.PageAtrb[i].charset = C_G0P;
700 m_RenderInfo.PageAtrb[i].doubleh = 0;
701 m_RenderInfo.PageAtrb[i].doublew = 0;
702 m_RenderInfo.PageAtrb[i].IgnoreAtBlackBgSubst = 0;
705 m_RenderInfo.TranspMode = false;
711 void CTeletextDecoder::EndDecoder()
713 /* clear SubtitleCache */
714 for (int i = 0; i < SUBTITLE_CACHESIZE; i++)
716 if (m_RenderInfo.SubtitleCache[i] != NULL)
718 delete m_RenderInfo.SubtitleCache[i];
719 m_RenderInfo.SubtitleCache[i] = NULL;
725 delete[] m_TextureBuffer;
726 m_TextureBuffer = NULL;
732 FTC_Manager_Done(m_Manager);
736 FT_Done_FreeType(m_Library);
744 CLog::Log(LOGNOTICE, "%s: called without cache", __FUNCTION__);
748 m_txtCache->PageUpdate = true;
749 CLog::Log(LOGDEBUG, "Teletext: Rendering ended");
754 void CTeletextDecoder::PageInput(int Number)
756 m_updateTexture = true;
758 /* clear m_TempPage */
759 if (m_RenderInfo.InputCounter == 2)
762 /* check for 0 & 9 on first position */
763 if (Number == 0 && m_RenderInfo.InputCounter == 2)
766 m_TempPage = m_LastPage; /* 0 toggles to last page as in program switching */
767 m_RenderInfo.InputCounter = -1;
769 else if (Number == 9 && m_RenderInfo.InputCounter == 2)
775 if (m_RenderInfo.ZoomMode == 2)
777 m_RenderInfo.ZoomMode = 1;
781 m_RenderInfo.PosY = 0;
783 switch (m_RenderInfo.InputCounter)
787 RenderCharFB(Number | '0', &Text_AtrTable[ATR_WB]);
788 RenderCharFB('-', &Text_AtrTable[ATR_WB]);
789 RenderCharFB('-', &Text_AtrTable[ATR_WB]);
794 RenderCharFB(Number | '0', &Text_AtrTable[ATR_WB]);
799 RenderCharFB(Number | '0', &Text_AtrTable[ATR_WB]);
803 /* generate pagenumber */
804 m_TempPage |= Number << (m_RenderInfo.InputCounter*4);
806 m_RenderInfo.InputCounter--;
808 if (m_RenderInfo.InputCounter < 0)
810 /* disable SubPage zapping */
811 m_txtCache->ZapSubpageManual = false;
814 m_RenderInfo.InputCounter = 2;
817 m_LastPage = m_txtCache->Page;
819 m_txtCache->Page = m_TempPage;
820 m_RenderInfo.HintMode = false;
823 int subp = m_txtCache->SubPageTable[m_txtCache->Page];
826 m_txtCache->SubPage = subp;
827 m_txtCache->PageUpdate = true;
831 m_txtCache->SubPage = 0;
832 // RenderMessage(PageNotFound);
837 void CTeletextDecoder::GetNextPageOne(bool up)
839 /* disable subpage zapping */
840 m_txtCache->ZapSubpageManual = false;
842 /* abort pageinput */
843 m_RenderInfo.InputCounter = 2;
845 /* find next cached page */
846 m_LastPage = m_txtCache->Page;
851 CDVDTeletextTools::NextDec(&m_txtCache->Page);
853 CDVDTeletextTools::PrevDec(&m_txtCache->Page);
854 subp = m_txtCache->SubPageTable[m_txtCache->Page];
855 } while (subp == 0xFF && m_txtCache->Page != m_LastPage);
858 if (m_txtCache->Page != m_LastPage)
860 if (m_RenderInfo.ZoomMode == 2)
861 m_RenderInfo.ZoomMode = 1;
863 m_txtCache->SubPage = subp;
864 m_RenderInfo.HintMode = false;
865 m_txtCache->PageUpdate = true;
869 void CTeletextDecoder::GetNextSubPage(int offset)
871 /* abort pageinput */
872 m_RenderInfo.InputCounter = 2;
874 for (int loop = m_txtCache->SubPage + offset; loop != m_txtCache->SubPage; loop += offset)
878 else if (loop > 0x79)
880 if (loop == m_txtCache->SubPage)
883 if (m_txtCache->astCachetable[m_txtCache->Page][loop])
885 /* enable manual SubPage zapping */
886 m_txtCache->ZapSubpageManual = true;
889 if (m_RenderInfo.ZoomMode == 2) /* if zoomed to lower half */
890 m_RenderInfo.ZoomMode = 1; /* activate upper half */
892 m_txtCache->SubPage = loop;
893 m_RenderInfo.HintMode = false;
894 m_txtCache->PageUpdate = true;
901 void CTeletextDecoder::SwitchZoomMode()
903 if (m_txtCache->SubPageTable[m_txtCache->Page] != 0xFF)
906 m_RenderInfo.ZoomMode++;
908 if (m_RenderInfo.ZoomMode == 3)
909 m_RenderInfo.ZoomMode = 0;
912 m_txtCache->PageUpdate = true;
916 void CTeletextDecoder::SwitchTranspMode()
919 if (!m_RenderInfo.TranspMode)
920 m_RenderInfo.TranspMode = true;
922 m_RenderInfo.TranspMode = false; /* backward to immediately switch to TV-screen */
925 if (!m_RenderInfo.TranspMode) /* normal text-only */
927 ClearBB(m_txtCache->FullScrColor);
928 m_txtCache->PageUpdate = true;
930 else /* semi-transparent BG with FG text */
932 ClearBB(TXT_ColorTransp);
933 m_txtCache->PageUpdate = true;
937 void CTeletextDecoder::SwitchHintMode()
940 m_RenderInfo.HintMode ^= true;
942 if (!m_RenderInfo.HintMode) /* toggle evaluation of level 2.5 information by explicitly switching off HintMode */
944 m_RenderInfo.Showl25 ^= true;
947 m_txtCache->PageUpdate = true;
950 void CTeletextDecoder::ColorKey(int target)
955 if (m_RenderInfo.ZoomMode == 2)
956 m_RenderInfo.ZoomMode = 1;
958 m_LastPage = m_txtCache->Page;
959 m_txtCache->Page = target;
960 m_txtCache->SubPage = m_txtCache->SubPageTable[m_txtCache->Page];
961 m_RenderInfo.InputCounter = 2;
962 m_RenderInfo.HintMode = false;
963 m_txtCache->PageUpdate = true;
966 void CTeletextDecoder::StartPageCatching()
968 m_RenderInfo.PageCatching = true;
970 /* abort pageinput */
971 m_RenderInfo.InputCounter = 2;
974 m_RenderInfo.ZoomMode = 0;
975 m_RenderInfo.PosX = 0;
976 m_RenderInfo.PosY = 24*m_RenderInfo.FontHeight;
978 /* check for pagenumber(s) */
983 m_PCOldCol = 0; /* no inverted page number to restore yet */
988 m_RenderInfo.PageCatching = false;
989 m_txtCache->PageUpdate = true;
994 void CTeletextDecoder::StopPageCatching()
997 if (m_RenderInfo.ZoomMode == 2)
998 m_RenderInfo.ZoomMode = 1;
1000 m_LastPage = m_txtCache->Page;
1001 m_txtCache->Page = m_CatchedPage;
1002 m_RenderInfo.HintMode = false;
1003 m_txtCache->PageUpdate = true;
1004 m_RenderInfo.PageCatching = false;
1006 int subp = m_txtCache->SubPageTable[m_txtCache->Page];
1008 m_txtCache->SubPage = subp;
1010 m_txtCache->SubPage = 0;
1013 void CTeletextDecoder::CatchNextPage(int firstlineinc, int inc)
1015 int tmp_page, allowwrap = 1; /* allow first wrap around */
1017 /* catch next page */
1020 unsigned char *p = &(m_RenderInfo.PageChar[m_CatchRow*40 + m_CatchCol]);
1021 TextPageAttr_t a = m_RenderInfo.PageAtrb[m_CatchRow*40 + m_CatchCol];
1023 if (!(a.charset == C_G1C || a.charset == C_G1S) && /* no mosaic */
1024 (a.fg != a.bg) && /* not hidden */
1025 (*p >= '1' && *p <= '8' && /* valid page number */
1026 *(p+1) >= '0' && *(p+1) <= '9' &&
1027 *(p+2) >= '0' && *(p+2) <= '9') &&
1028 (m_CatchRow == 0 || (*(p-1) < '0' || *(p-1) > '9')) && /* non-numeric char before and behind */
1029 (m_CatchRow == 37 || (*(p+3) < '0' || *(p+3) > '9')))
1031 tmp_page = ((*p - '0')<<8) | ((*(p+1) - '0')<<4) | (*(p+2) - '0');
1034 if (tmp_page != m_CatchedPage) /* confusing to skip identical page numbers - I want to reach what I aim to */
1037 m_CatchedPage = tmp_page;
1038 RenderCatchedPage();
1039 m_CatchCol += inc; /* FIXME: limit */
1044 if (firstlineinc > 0)
1050 else if (firstlineinc < 0)
1059 if (m_CatchCol > 37)
1064 else if (m_CatchCol < 0)
1070 if (m_CatchRow > 23)
1083 else if (m_CatchRow < 1)
1099 void CTeletextDecoder::RenderCatchedPage()
1102 m_updateTexture = true;
1105 if (m_RenderInfo.ZoomMode)
1108 if (m_PCOldRow || m_PCOldCol) /* not at first call */
1110 /* restore pagenumber */
1111 SetPosX(m_PCOldCol);
1113 if (m_RenderInfo.ZoomMode == 2)
1114 m_RenderInfo.PosY = (m_PCOldRow-12)*m_RenderInfo.FontHeight*((zoom>>10)+1);
1116 m_RenderInfo.PosY = m_PCOldRow*m_RenderInfo.FontHeight*((zoom>>10)+1);
1118 RenderCharFB(m_RenderInfo.PageChar[m_PCOldRow*40 + m_PCOldCol ], &m_RenderInfo.PageAtrb[m_PCOldRow*40 + m_PCOldCol ]);
1119 RenderCharFB(m_RenderInfo.PageChar[m_PCOldRow*40 + m_PCOldCol + 1], &m_RenderInfo.PageAtrb[m_PCOldRow*40 + m_PCOldCol + 1]);
1120 RenderCharFB(m_RenderInfo.PageChar[m_PCOldRow*40 + m_PCOldCol + 2], &m_RenderInfo.PageAtrb[m_PCOldRow*40 + m_PCOldCol + 2]);
1123 m_PCOldRow = m_CatchRow;
1124 m_PCOldCol = m_CatchCol;
1126 /* mark pagenumber */
1127 if (m_RenderInfo.ZoomMode == 1 && m_CatchRow > 11)
1129 m_RenderInfo.ZoomMode = 2;
1132 else if (m_RenderInfo.ZoomMode == 2 && m_CatchRow < 12)
1134 m_RenderInfo.ZoomMode = 1;
1137 SetPosX(m_CatchCol);
1139 if (m_RenderInfo.ZoomMode == 2)
1140 m_RenderInfo.PosY = (m_CatchRow-12)*m_RenderInfo.FontHeight*((zoom>>10)+1);
1142 m_RenderInfo.PosY = m_CatchRow*m_RenderInfo.FontHeight*((zoom>>10)+1);
1144 TextPageAttr_t a0 = m_RenderInfo.PageAtrb[m_CatchRow*40 + m_CatchCol ];
1145 TextPageAttr_t a1 = m_RenderInfo.PageAtrb[m_CatchRow*40 + m_CatchCol + 1];
1146 TextPageAttr_t a2 = m_RenderInfo.PageAtrb[m_CatchRow*40 + m_CatchCol + 2];
1149 /* exchange colors */
1150 t = a0.fg; a0.fg = a0.bg; a0.bg = t;
1151 t = a1.fg; a1.fg = a1.bg; a1.bg = t;
1152 t = a2.fg; a2.fg = a2.bg; a2.bg = t;
1154 RenderCharFB(m_RenderInfo.PageChar[m_CatchRow*40 + m_CatchCol ], &a0);
1155 RenderCharFB(m_RenderInfo.PageChar[m_CatchRow*40 + m_CatchCol + 1], &a1);
1156 RenderCharFB(m_RenderInfo.PageChar[m_CatchRow*40 + m_CatchCol + 2], &a2);
1159 void CTeletextDecoder::RenderPage()
1162 int national_subset_bak = m_txtCache->NationalSubset;
1164 if (m_txtCache->PageUpdate)
1165 m_updateTexture = true;
1167 /* update page or timestring */
1168 if (m_txtCache->PageUpdate && m_txtCache->PageReceiving != m_txtCache->Page && m_RenderInfo.InputCounter == 2)
1170 /* reset update flag */
1171 m_txtCache->PageUpdate = false;
1172 if (m_RenderInfo.Boxed && m_RenderInfo.SubtitleDelay)
1174 TextSubtitleCache_t* c = NULL;
1176 for (int i = 0; i < SUBTITLE_CACHESIZE; i++)
1178 if (j == -1 && !m_RenderInfo.SubtitleCache[i])
1180 if (m_RenderInfo.SubtitleCache[i] && !m_RenderInfo.SubtitleCache[i]->Valid)
1182 c = m_RenderInfo.SubtitleCache[i];
1188 if (j == -1) // no more space in SubtitleCache
1191 c = new TextSubtitleCache_t;
1195 memset(c, 0x00, sizeof(TextSubtitleCache_t));
1196 m_RenderInfo.SubtitleCache[j] = c;
1199 c->Timestamp = XbmcThreads::SystemClockMillis()/1000;
1201 if (m_txtCache->SubPageTable[m_txtCache->Page] != 0xFF)
1203 TextPageinfo_t * p = DecodePage(m_RenderInfo.Showl25, c->PageChar, c->PageAtrb, m_RenderInfo.HintMode, m_RenderInfo.ShowFlof);
1206 m_RenderInfo.Boxed = p->boxed;
1209 m_RenderInfo.DelayStarted = true;
1212 m_RenderInfo.DelayStarted = false;
1214 if (m_txtCache->SubPageTable[m_txtCache->Page] != 0xFF)
1216 TextPageinfo_t * p = DecodePage(m_RenderInfo.Showl25, m_RenderInfo.PageChar, m_RenderInfo.PageAtrb, m_RenderInfo.HintMode, m_RenderInfo.ShowFlof);
1219 m_RenderInfo.PageInfo = p;
1220 m_RenderInfo.Boxed = p->boxed;
1222 if (m_RenderInfo.Boxed || m_RenderInfo.TranspMode)
1223 FillBorder(GetColorRGB(TXT_ColorTransp));
1225 FillBorder(GetColorRGB((enumTeletextColor)m_txtCache->FullScrColor));
1227 if (m_txtCache->ColorTable) /* as late as possible to shorten the time the old page is displayed with the new colors */
1228 SetColors(m_txtCache->ColorTable, 16, 16); /* set colors for CLUTs 2+3 */
1233 DoRenderPage(StartRow, national_subset_bak);
1237 if (m_RenderInfo.DelayStarted)
1239 long now = XbmcThreads::SystemClockMillis()/1000;
1240 for (int i = 0; i < SUBTITLE_CACHESIZE ; i++)
1242 if (m_RenderInfo.SubtitleCache[i] && m_RenderInfo.SubtitleCache[i]->Valid && now - m_RenderInfo.SubtitleCache[i]->Timestamp >= (long)m_RenderInfo.SubtitleDelay)
1244 memcpy(m_RenderInfo.PageChar, m_RenderInfo.SubtitleCache[i]->PageChar, 40 * 25);
1245 memcpy(m_RenderInfo.PageAtrb, m_RenderInfo.SubtitleCache[i]->PageAtrb, 40 * 25 * sizeof(TextPageAttr_t));
1246 DoRenderPage(StartRow, national_subset_bak);
1247 m_RenderInfo.SubtitleCache[i]->Valid = false;
1252 if (m_RenderInfo.ZoomMode != 2)
1254 m_RenderInfo.PosY = 0;
1255 if (m_txtCache->SubPageTable[m_txtCache->Page] == 0xff)
1257 m_RenderInfo.PageAtrb[32].fg = TXT_ColorYellow;
1258 m_RenderInfo.PageAtrb[32].bg = TXT_ColorMenu1;
1259 int showpage = m_txtCache->PageReceiving;
1260 int showsubpage = m_txtCache->SubPageTable[showpage];
1261 if (showsubpage!=0xff)
1263 TextCachedPage_t *pCachedPage;
1264 pCachedPage = m_txtCache->astCachetable[showpage][showsubpage];
1265 if (pCachedPage && IsDec(showpage))
1267 m_RenderInfo.PosX = 0;
1268 if (m_RenderInfo.InputCounter == 2)
1270 if (m_txtCache->BTTok && !m_txtCache->BasicTop[m_txtCache->Page]) /* page non-existent according to TOP (continue search anyway) */
1272 m_RenderInfo.PageAtrb[0].fg = TXT_ColorWhite;
1273 m_RenderInfo.PageAtrb[0].bg = TXT_ColorRed;
1277 m_RenderInfo.PageAtrb[0].fg = TXT_ColorYellow;
1278 m_RenderInfo.PageAtrb[0].bg = TXT_ColorMenu1;
1280 CDVDTeletextTools::Hex2Str((char*)m_RenderInfo.PageChar+3, m_txtCache->Page);
1283 for (col = m_RenderInfo.nofirst; col < 7; col++) // selected page
1285 RenderCharFB(m_RenderInfo.PageChar[col], &m_RenderInfo.PageAtrb[0]);
1287 RenderCharFB(m_RenderInfo.PageChar[col], &m_RenderInfo.PageAtrb[32]);
1292 memcpy(&m_RenderInfo.PageChar[8], pCachedPage->p0, 24); /* header line without timestring */
1293 for (int i = 0; i < 24; i++)
1295 RenderCharFB(pCachedPage->p0[i], &m_RenderInfo.PageAtrb[32]);
1298 /* Update on every Header number change */
1299 if (pCachedPage->p0[2] != prevHeaderPage)
1301 prevHeaderPage = pCachedPage->p0[2];
1302 m_updateTexture = true;
1308 /* update timestring */
1310 for (int i = 0; i < 8; i++)
1312 if (!m_RenderInfo.PageAtrb[32+i].flashing)
1313 RenderCharFB(m_txtCache->TimeString[i], &m_RenderInfo.PageAtrb[32]);
1317 m_RenderInfo.PageChar[32+i] = m_RenderInfo.PageChar[32+i];
1321 /* Update on every changed second */
1322 if (m_txtCache->TimeString[7] != prevTimeSec)
1324 prevTimeSec = m_txtCache->TimeString[7];
1325 m_updateTexture = true;
1328 DoFlashing(StartRow);
1329 m_txtCache->NationalSubset = national_subset_bak;
1333 void CTeletextDecoder::DoFlashing(int startrow)
1335 /* get national subset */
1336 if (m_txtCache->NationalSubset <= NAT_MAX_FROM_HEADER && /* not for GR/RU as long as line28 is not evaluated */
1337 m_RenderInfo.PageInfo && m_RenderInfo.PageInfo->nationalvalid) /* individual subset according to page header */
1339 m_txtCache->NationalSubset = CountryConversionTable[m_RenderInfo.PageInfo->national];
1343 TextPageAttr_t flashattr;
1345 long flashphase = XbmcThreads::SystemClockMillis() % 1000;
1347 int srow = startrow;
1351 switch (m_RenderInfo.ZoomMode)
1353 case 1: erow = 12; factor=2;break;
1354 case 2: srow = 12; factor=2;break;
1357 m_RenderInfo.PosY = startrow*m_RenderInfo.FontHeight*factor;
1358 for (int row = srow; row < erow; row++)
1360 int index = row * 40;
1365 m_RenderInfo.PosX = 0;
1366 for (int col = m_RenderInfo.nofirst; col < 40; col++)
1368 if (m_RenderInfo.PageAtrb[index + col].flashing && m_RenderInfo.PageChar[index + col] > 0x20 && m_RenderInfo.PageChar[index + col] != 0xff )
1371 flashchar = m_RenderInfo.PageChar[index + col];
1372 bool doflash = false;
1373 memcpy(&flashattr, &m_RenderInfo.PageAtrb[index + col], sizeof(TextPageAttr_t));
1374 switch (flashattr.flashing &0x1c) // Flash Rate
1377 if (flashphase>500) doflash = true;
1379 case 0x04 : // 2 Hz Phase 1
1380 if (flashphase<250) doflash = true;
1382 case 0x08 : // 2 Hz Phase 2
1383 if (flashphase>=250 && flashphase<500) doflash = true;
1385 case 0x0c : // 2 Hz Phase 3
1386 if (flashphase>=500 && flashphase<750) doflash = true;
1388 case 0x10 : // incremental flash
1390 if (incflash>3) incflash = 1;
1393 case 1: if (flashphase<250) doflash = true; break;
1394 case 2: if (flashphase>=250 && flashphase<500) doflash = true;break;
1395 case 3: if (flashphase>=500 && flashphase<750) doflash = true;
1398 case 0x14 : // decremental flash
1400 if (decflash<1) decflash = 3;
1403 case 1: if (flashphase<250) doflash = true; break;
1404 case 2: if (flashphase>=250 && flashphase<500) doflash = true;break;
1405 case 3: if (flashphase>=500 && flashphase<750) doflash = true;
1411 switch (flashattr.flashing &0x03) // Flash Mode
1413 case 0x01 : // normal Flashing
1414 if (doflash) flashattr.fg = flashattr.bg;
1416 case 0x02 : // inverted Flashing
1418 if (doflash) flashattr.fg = flashattr.bg;
1420 case 0x03 : // color Flashing
1421 if (doflash) flashattr.fg = flashattr.fg + (flashattr.fg > 7 ? (-8) : 8);
1425 RenderCharFB(flashchar, &flashattr);
1426 if (flashattr.doublew) col++;
1427 if (flashattr.doubleh) dhset = 1;
1429 m_updateTexture = true;
1435 m_RenderInfo.PosY += m_RenderInfo.FontHeight*factor;
1437 m_RenderInfo.PosY += m_RenderInfo.FontHeight*factor;
1441 void CTeletextDecoder::DoRenderPage(int startrow, int national_subset_bak)
1443 /* display first column? */
1444 m_RenderInfo.nofirst = m_RenderInfo.Show39;
1445 for (int row = 1; row < 24; row++)
1447 int Byte = m_RenderInfo.PageChar[row*40];
1448 if (Byte != ' ' && Byte != 0x00 && Byte != 0xFF && m_RenderInfo.PageAtrb[row*40].fg != m_RenderInfo.PageAtrb[row*40].bg)
1450 m_RenderInfo.nofirst = 0;
1455 if (m_RenderInfo.TranspMode || m_RenderInfo.Boxed)
1457 FillBorder(GetColorRGB(TXT_ColorTransp));//ClearBB(transp);
1458 m_RenderInfo.ClearBBColor = TXT_ColorTransp;
1461 /* get national subset */
1462 if (m_txtCache->NationalSubset <= NAT_MAX_FROM_HEADER && /* not for GR/RU as long as line28 is not evaluated */
1463 m_RenderInfo.PageInfo && m_RenderInfo.PageInfo->nationalvalid) /* individual subset according to page header */
1465 m_txtCache->NationalSubset = CountryConversionTable[m_RenderInfo.PageInfo->national];
1468 if (m_RenderInfo.PageInfo && (m_RenderInfo.PageInfo->function == FUNC_GDRCS || m_RenderInfo.PageInfo->function == FUNC_DRCS)) /* character definitions */
1471 #define DRCSCOLS (48/DRCSROWS)
1474 #define DRCSXSPC (12*DRCSZOOMX + 2)
1475 #define DRCSYSPC (10*DRCSZOOMY + 2)
1477 unsigned char ax[] = { /* array[0..12] of x-offsets, array[0..10] of y-offsets for each pixel */
1504 ClearBB(TXT_ColorBlack);
1505 for (int col = 0; col < 24*40; col++)
1506 m_RenderInfo.PageAtrb[col] = Text_AtrTable[ATR_WB];
1508 for (int row = 0; row < DRCSROWS; row++)
1510 for (int col = 0; col < DRCSCOLS; col++)
1512 RenderDRCS(m_RenderInfo.Width,
1513 m_RenderInfo.PageChar + 20 * (DRCSCOLS * row + col + 2),
1515 + (m_RenderInfo.FontHeight + DRCSYSPC * row + m_RenderInfo.Height) * m_RenderInfo.Width
1517 ax, GetColorRGB(TXT_ColorWhite), GetColorRGB(TXT_ColorBlack));
1520 memset(m_RenderInfo.PageChar + 40, 0xff, 24*40); /* don't render any char below row 0 */
1522 m_RenderInfo.PosY = startrow*m_RenderInfo.FontHeight;
1523 for (int row = startrow; row < 24; row++)
1525 int index = row * 40;
1527 m_RenderInfo.PosX = 0;
1528 for (int col = m_RenderInfo.nofirst; col < 40; col++)
1530 RenderCharBB(m_RenderInfo.PageChar[index + col], &m_RenderInfo.PageAtrb[index + col]);
1532 if (m_RenderInfo.PageAtrb[index + col].doubleh && m_RenderInfo.PageChar[index + col] != 0xff) /* disable lower char in case of doubleh setting in l25 objects */
1533 m_RenderInfo.PageChar[index + col + 40] = 0xff;
1534 if (m_RenderInfo.PageAtrb[index + col].doublew) /* skip next column if double width */
1537 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 */
1538 m_RenderInfo.PageChar[index + col + 40] = 0xff;
1541 m_RenderInfo.PosY += m_RenderInfo.FontHeight;
1543 DoFlashing(startrow);
1545 /* update framebuffer */
1547 m_txtCache->NationalSubset = national_subset_bak;
1550 void CTeletextDecoder::Decode_BTT()
1552 /* basic top table */
1553 int current, b1, b2, b3, b4;
1554 unsigned char btt[23*40];
1556 if (m_txtCache->SubPageTable[0x1f0] == 0xff || 0 == m_txtCache->astCachetable[0x1f0][m_txtCache->SubPageTable[0x1f0]]) /* not yet received */
1559 g_application.m_pPlayer->LoadPage(0x1f0, m_txtCache->SubPageTable[0x1f0],btt);
1560 if (btt[799] == ' ') /* not completely received or error */
1564 for (int i = 0; i < 800; i++)
1572 if (b1 == 0xFF) /* hamming error in btt */
1574 btt[799] = ' '; /* mark btt as not received */
1578 m_txtCache->BasicTop[current] = b1;
1579 CDVDTeletextTools::NextDec(¤t);
1581 /* page linking table */
1582 m_txtCache->ADIP_PgMax = -1; /* rebuild table of adip pages */
1583 for (int i = 0; i < 10; i++)
1585 b1 = dehamming[btt[800 + 8*i +0]];
1588 continue; /* unused */
1592 b4 = dehamming[btt[800 + 8*i +7]];
1594 if (b4 != 2) /* only adip, ignore multipage (1) */
1597 b2 = dehamming[btt[800 + 8*i +1]];
1598 b3 = dehamming[btt[800 + 8*i +2]];
1600 if (b1 == 0xFF || b2 == 0xFF || b3 == 0xFF)
1602 CLog::Log(LOGERROR, "CTeletextDecoder::Decode_BTT <Biterror in btt/plt index %d>", i);
1603 btt[799] = ' '; /* mark btt as not received */
1607 b1 = b1<<8 | b2<<4 | b3; /* page number */
1608 m_txtCache->ADIP_Pg[++m_txtCache->ADIP_PgMax] = b1;
1611 m_txtCache->BTTok = true;
1614 void CTeletextDecoder::Decode_ADIP() /* additional information table */
1616 int i, p, j, b1, b2, b3, charfound;
1617 unsigned char padip[23*40];
1619 for (i = 0; i <= m_txtCache->ADIP_PgMax; i++)
1621 p = m_txtCache->ADIP_Pg[i];
1622 if (!p || m_txtCache->SubPageTable[p] == 0xff || 0 == m_txtCache->astCachetable[p][m_txtCache->SubPageTable[p]]) /* not cached (avoid segfault) */
1625 g_application.m_pPlayer->LoadPage(p,m_txtCache->SubPageTable[p],padip);
1626 for (j = 0; j < 44; j++)
1628 b1 = dehamming[padip[20*j+0]];
1630 continue; /* unused */
1635 b2 = dehamming[padip[20*j+1]];
1636 b3 = dehamming[padip[20*j+2]];
1638 if (b1 == 0xFF || b2 == 0xFF || b3 == 0xFF)
1640 CLog::Log(LOGERROR, "CTeletextDecoder::Decode_BTT <Biterror in ait %03x %d %02x %02x %02x %02x %02x %02x>", p, j,
1649 if (b1>8 || b2>9 || b3>9) /* ignore extries with invalid or hex page numbers */
1654 b1 = b1<<8 | b2<<4 | b3; /* page number */
1655 charfound = 0; /* flag: no printable char found */
1657 for (b2 = 11; b2 >= 0; b2--)
1659 b3 = deparity[padip[20*j + 8 + b2]];
1663 if (b3 == ' ' && !charfound)
1664 m_txtCache->ADIPTable[b1][b2] = '\0';
1667 m_txtCache->ADIPTable[b1][b2] = b3;
1673 m_txtCache->ADIP_Pg[i] = 0; /* completely decoded: clear entry */
1674 } /* next adip page i */
1676 while ((m_txtCache->ADIP_PgMax >= 0) && !m_txtCache->ADIP_Pg[m_txtCache->ADIP_PgMax]) /* and shrink table */
1677 m_txtCache->ADIP_PgMax--;
1680 int CTeletextDecoder::TopText_GetNext(int startpage, int up, int findgroup)
1682 int current, nextgrp, nextblk;
1684 int stoppage = (IsDec(startpage) ? startpage : startpage & 0xF00); // avoid endless loop in hexmode
1685 nextgrp = nextblk = 0;
1686 current = startpage;
1690 CDVDTeletextTools::NextDec(¤t);
1692 CDVDTeletextTools::PrevDec(¤t);
1694 if (!m_txtCache->BTTok || m_txtCache->BasicTop[current]) /* only if existent */
1698 if (m_txtCache->BasicTop[current] >= 6 && m_txtCache->BasicTop[current] <= 7)
1700 if (!nextgrp && (current&0x00F) == 0)
1703 if (m_txtCache->BasicTop[current] >= 2 && m_txtCache->BasicTop[current] <= 5) /* always find block */
1706 if (!nextblk && (current&0x0FF) == 0)
1709 } while (current != stoppage);
1719 void CTeletextDecoder::Showlink(int column, int linkpage)
1721 unsigned char line[] = " >??? ";
1722 int oldfontwidth = m_RenderInfo.FontWidth;
1728 yoffset = m_RenderInfo.Height;
1730 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
1731 int width = m_RenderInfo.Width /4;
1733 m_RenderInfo.PosY = 24*m_RenderInfo.FontHeight;
1735 if (m_RenderInfo.Boxed)
1737 m_RenderInfo.PosX = column*width;
1738 FillRect(m_TextureBuffer, m_RenderInfo.Width, m_RenderInfo.PosX, m_RenderInfo.PosY+yoffset, m_RenderInfo.Width, m_RenderInfo.FontHeight, GetColorRGB(TXT_ColorTransp));
1742 if (m_txtCache->ADIPTable[linkpage][0])
1744 m_RenderInfo.PosX = column*width;
1745 int l = strlen(m_txtCache->ADIPTable[linkpage]);
1747 if (l > 9) /* smaller font, if no space for one half space at front and end */
1748 SetFontWidth(oldfontwidth * 10 / (l+1));
1750 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));
1751 m_RenderInfo.PosX += ((width) - (l*m_RenderInfo.FontWidth+l*m_RenderInfo.FontWidth/abx))/2; /* center */
1753 for (char *p = m_txtCache->ADIPTable[linkpage]; *p; p++)
1754 RenderCharBB(*p, &Text_AtrTable[ATR_L250 + column]);
1756 SetFontWidth(oldfontwidth);
1758 else /* display number */
1760 m_RenderInfo.PosX = column*width;
1761 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));
1762 if (linkpage < m_txtCache->Page)
1765 CDVDTeletextTools::Hex2Str((char*)line + 5, linkpage);
1768 CDVDTeletextTools::Hex2Str((char*)line + 6, linkpage);
1770 for (unsigned char *p = line; p < line+9; p++)
1771 RenderCharBB(*p, &Text_AtrTable[ATR_L250 + column]);
1775 void CTeletextDecoder::CreateLine25()
1777 /* btt completely received and not yet decoded */
1778 if (!m_txtCache->BTTok)
1781 if (m_txtCache->ADIP_PgMax >= 0)
1784 if (!m_RenderInfo.ShowHex && m_RenderInfo.ShowFlof &&
1785 (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
1787 m_RenderInfo.Prev_100 = m_txtCache->FlofPages[m_txtCache->Page][0];
1788 m_RenderInfo.Prev_10 = m_txtCache->FlofPages[m_txtCache->Page][1];
1789 m_RenderInfo.Next_10 = m_txtCache->FlofPages[m_txtCache->Page][2];
1790 m_RenderInfo.Next_100 = m_txtCache->FlofPages[m_txtCache->Page][3];
1792 m_RenderInfo.PosY = 24*m_RenderInfo.FontHeight;
1793 m_RenderInfo.PosX = 0;
1794 for (int i=m_RenderInfo.nofirst; i<40; i++)
1795 RenderCharBB(m_RenderInfo.PageChar[24*40 + i], &m_RenderInfo.PageAtrb[24*40 + i]);
1799 /* normal: blk-1, grp+1, grp+2, blk+1 */
1800 /* hex: hex+1, blk-1, grp+1, blk+1 */
1801 if (m_RenderInfo.ShowHex)
1803 /* arguments: startpage, up, findgroup */
1804 m_RenderInfo.Prev_100 = NextHex(m_txtCache->Page);
1805 m_RenderInfo.Prev_10 = TopText_GetNext(m_txtCache->Page, 0, 0);
1806 m_RenderInfo.Next_10 = TopText_GetNext(m_txtCache->Page, 1, 1);
1810 m_RenderInfo.Prev_100 = TopText_GetNext(m_txtCache->Page, 0, 0);
1811 m_RenderInfo.Prev_10 = TopText_GetNext(m_txtCache->Page, 1, 1);
1812 m_RenderInfo.Next_10 = TopText_GetNext(m_RenderInfo.Prev_10, 1, 1);
1814 m_RenderInfo.Next_100 = TopText_GetNext(m_RenderInfo.Next_10, 1, 0);
1815 Showlink(0, m_RenderInfo.Prev_100);
1816 Showlink(1, m_RenderInfo.Prev_10);
1817 Showlink(2, m_RenderInfo.Next_10);
1818 Showlink(3, m_RenderInfo.Next_100);
1822 void CTeletextDecoder::RenderCharFB(int Char, TextPageAttr_t *Attribute)
1824 RenderCharIntern(&m_RenderInfo, Char, Attribute, m_RenderInfo.ZoomMode, m_YOffset);
1827 void CTeletextDecoder::RenderCharBB(int Char, TextPageAttr_t *Attribute)
1829 RenderCharIntern(&m_RenderInfo, Char, Attribute, 0, m_RenderInfo.Height-m_YOffset);
1832 void CTeletextDecoder::CopyBB2FB()
1834 color_t *src, *dst, *topsrc;
1839 if (!m_RenderInfo.PageCatching)
1842 /* copy backbuffer to framebuffer */
1843 if (!m_RenderInfo.ZoomMode)
1848 m_YOffset = m_RenderInfo.Height;
1850 if (m_RenderInfo.ClearBBColor >= 0)
1852 m_RenderInfo.ClearBBColor = -1;
1857 src = dst = topsrc = m_TextureBuffer + m_RenderInfo.Width;
1861 dst += m_RenderInfo.Width * m_RenderInfo.Height;
1865 src += m_RenderInfo.Width * m_RenderInfo.Height;
1866 topsrc += m_RenderInfo.Width * m_RenderInfo.Height;
1869 if (!m_RenderInfo.PageCatching)
1870 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 */
1872 if (m_RenderInfo.TranspMode)
1873 fillcolor = GetColorRGB(TXT_ColorTransp);
1875 fillcolor = GetColorRGB((enumTeletextColor)m_txtCache->FullScrColor);
1877 if (m_RenderInfo.ZoomMode == 2)
1878 src += 12*m_RenderInfo.FontHeight*m_RenderInfo.Width;
1880 screenwidth = m_RenderInfo.Width;
1882 for (int i = 12*m_RenderInfo.FontHeight; i; i--)
1884 SDL_memcpy4(dst, src, screenwidth);
1885 dst += m_RenderInfo.Width;
1886 SDL_memcpy4(dst, src, screenwidth);
1887 dst += m_RenderInfo.Width;
1888 src += m_RenderInfo.Width;
1891 for (int i = m_RenderInfo.Height - 25*m_RenderInfo.FontHeight; i >= 0;i--)
1893 SDL_memset4(dst + m_RenderInfo.Width*(m_RenderInfo.FontHeight+i), fillcolor, screenwidth);
1897 FT_Error CTeletextDecoder::MyFaceRequester(FTC_FaceID face_id, FT_Library library, FT_Pointer request_data, FT_Face *aface)
1899 FT_Error result = FT_New_Face(library, (const char*)face_id, 0, aface);
1902 CLog::Log(LOGNOTICE, "Teletext font %s loaded", (char*)face_id);
1904 CLog::Log(LOGERROR, "Opening of Teletext font %s failed", (char*)face_id);
1909 void CTeletextDecoder::SetFontWidth(int newWidth)
1911 if (m_RenderInfo.FontWidth != newWidth)
1913 m_RenderInfo.FontWidth = newWidth;
1914 m_TypeTTF.width = (FT_UShort) m_RenderInfo.FontWidth;
1916 for (int i = 0; i <= 12; i++)
1917 m_RenderInfo.axdrcs[i] = (m_RenderInfo.FontWidth * i + 6) / 12;
1921 int CTeletextDecoder::GetCurFontWidth()
1923 int mx = (m_RenderInfo.Width)%(40-m_RenderInfo.nofirst); // # of unused pixels
1924 int abx = (mx == 0 ? m_RenderInfo.Width+1 : (m_RenderInfo.Width)/(mx+1)); // distance between 'inserted' pixels
1925 int nx = abx+1-(m_RenderInfo.PosX % (abx+1)); // # of pixels to next insert
1926 return m_RenderInfo.FontWidth+(((m_RenderInfo.PosX+m_RenderInfo.FontWidth+1) <= m_RenderInfo.Width && nx <= m_RenderInfo.FontWidth+1) ? 1 : 0);
1929 void CTeletextDecoder::SetPosX(int column)
1931 m_RenderInfo.PosX = 0;
1933 for (int i = 0; i < column-m_RenderInfo.nofirst; i++)
1934 m_RenderInfo.PosX += GetCurFontWidth();
1937 void CTeletextDecoder::ClearBB(color_t Color)
1939 SDL_memset4(m_TextureBuffer + (m_RenderInfo.Height-m_YOffset)*m_RenderInfo.Width, Color, m_RenderInfo.Width*m_RenderInfo.Height);
1942 void CTeletextDecoder::ClearFB(color_t Color)
1944 SDL_memset4(m_TextureBuffer + m_RenderInfo.Width*m_YOffset, Color, m_RenderInfo.Width*m_RenderInfo.Height);
1947 void CTeletextDecoder::FillBorder(color_t Color)
1949 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);
1950 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);
1953 void CTeletextDecoder::FillRect(color_t *buffer, int xres, int x, int y, int w, int h, color_t Color)
1955 if (!buffer) return;
1957 color_t *p = buffer + x + y * xres;
1961 for ( ; h > 0 ; h--)
1963 SDL_memset4(p, Color, w);
1969 void CTeletextDecoder::DrawVLine(color_t *lfb, int xres, int x, int y, int l, color_t color)
1972 color_t *p = lfb + x + y * xres;
1974 for ( ; l > 0 ; l--)
1981 void CTeletextDecoder::DrawHLine(color_t *lfb, int xres,int x, int y, int l, color_t color)
1985 SDL_memset4(lfb + x + y * xres, color, l);
1988 void CTeletextDecoder::RenderDRCS(int xres,
1989 unsigned char *s, /* pointer to char data, parity undecoded */
1990 color_t *d, /* pointer to frame buffer of top left pixel */
1991 unsigned char *ax, /* array[0..12] of x-offsets, array[0..10] of y-offsets for each pixel */
1992 color_t fgcolor, color_t bgcolor)
1994 if (d == NULL) return;
1996 unsigned char *ay = ax + 13; /* array[0..10] of y-offsets for each pixel */
1998 for (int y = 0; y < 10; y++) /* 10*2 bytes a 6 pixels per char definition */
2000 unsigned char c1 = deparity[*s++];
2001 unsigned char c2 = deparity[*s++];
2002 int h = ay[y+1] - ay[y];
2006 if (((c1 == ' ') && (*(s-2) != ' ')) || ((c2 == ' ') && (*(s-1) != ' '))) /* parity error: stop decoding FIXME */
2008 for (int bit = 0x20, x = 0;
2010 bit >>= 1, x++) /* bit mask (MSB left), column counter */
2012 color_t f1 = (c1 & bit) ? fgcolor : bgcolor;
2013 color_t f2 = (c2 & bit) ? fgcolor : bgcolor;
2014 for (int i = 0; i < h; i++)
2016 if (ax[x+1] > ax[x])
2017 SDL_memset4(d + ax[x], f1, ax[x+1] - ax[x]);
2018 if (ax[x+7] > ax[x+6])
2019 SDL_memset4(d + ax[x+6], f2, ax[x+7] - ax[x+6]); /* 2nd byte 6 pixels to the right */
2028 void CTeletextDecoder::FillRectMosaicSeparated(color_t *lfb, int xres,int x, int y, int w, int h, color_t fgcolor, color_t bgcolor, int set)
2031 FillRect(lfb,xres,x, y, w, h, bgcolor);
2034 FillRect(lfb,xres,x+1, y+1, w-2, h-2, fgcolor);
2038 void CTeletextDecoder::FillTrapez(color_t *lfb, int xres,int x0, int y0, int l0, int xoffset1, int h, int l1, color_t color)
2040 color_t *p = lfb + x0 + y0 * xres;
2043 for (int yoffset = 0; yoffset < h; yoffset++)
2045 l = l0 + ((l1-l0) * yoffset + h/2) / h;
2046 xoffset = (xoffset1 * yoffset + h/2) / h;
2048 SDL_memset4(p + xoffset, color, l);
2053 void CTeletextDecoder::FlipHorz(color_t *lfb, int xres,int x, int y, int w, int h)
2056 color_t *p = lfb + x + y * xres;
2059 for (h1 = 0 ; h1 < h ; h1++)
2061 SDL_memcpy4(buf,p,w);
2062 for (w1 = 0 ; w1 < w ; w1++)
2064 *(p+w1) = buf[w-(w1+1)];
2070 void CTeletextDecoder::FlipVert(color_t *lfb, int xres,int x, int y, int w, int h)
2073 color_t *p = lfb + x + y * xres, *p1, *p2;
2076 for (h1 = 0 ; h1 < h/2 ; h1++)
2079 p2 = (p+(h-(h1+1))*xres);
2080 SDL_memcpy4(buf, p1, w);
2081 SDL_memcpy4(p1, p2, w);
2082 SDL_memcpy4(p2, buf, w);
2086 int CTeletextDecoder::ShapeCoord(int param, int curfontwidth, int curFontHeight)
2091 return curfontwidth/3;
2093 return curfontwidth/2;
2095 return curfontwidth*2/3;
2097 return curfontwidth;
2099 return curfontwidth-3;
2101 return curFontHeight/3;
2103 return curFontHeight/2;
2105 return curFontHeight*2/3;
2107 return curFontHeight;
2113 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)
2115 if (!lfb || shapenumber < 0x20 || shapenumber > 0x7e || (shapenumber == 0x7e && clear))
2118 unsigned char *p = aShapes[shapenumber - 0x20];
2129 FillRect(lfb, xres, x, y, curfontwidth, FontHeight, bgcolor);
2137 int offset = ShapeCoord(*p++, curfontwidth, curFontHeight);
2138 DrawHLine(lfb, xres, x, y + offset, curfontwidth, fgcolor);
2143 int offset = ShapeCoord(*p++, curfontwidth, curFontHeight);
2144 DrawVLine(lfb,xres,x + offset, y, FontHeight, fgcolor);
2148 FlipHorz(lfb,xres,x,y,curfontwidth, FontHeight);
2151 FlipVert(lfb,xres,x,y,curfontwidth, FontHeight);
2155 int xo = ShapeCoord(*p++, curfontwidth, curFontHeight);
2156 int yo = ShapeCoord(*p++, curfontwidth, curFontHeight);
2157 int w = ShapeCoord(*p++, curfontwidth, curFontHeight);
2158 int h = ShapeCoord(*p++, curfontwidth, curFontHeight);
2159 FillRect(lfb,xres,x + xo, y + yo, w, h, fgcolor);
2164 int x0 = ShapeCoord(*p++, curfontwidth, curFontHeight);
2165 int y0 = ShapeCoord(*p++, curfontwidth, curFontHeight);
2166 int l0 = ShapeCoord(*p++, curfontwidth, curFontHeight);
2167 int x1 = ShapeCoord(*p++, curfontwidth, curFontHeight);
2168 int y1 = ShapeCoord(*p++, curfontwidth, curFontHeight);
2169 int l1 = ShapeCoord(*p++, curfontwidth, curFontHeight);
2170 FillTrapez(lfb, xres,x + x0, y + y0, l0, x1-x0, y1-y0, l1, fgcolor);
2175 int x0 = ShapeCoord(*p++, curfontwidth, curFontHeight);
2176 int y0 = ShapeCoord(*p++, curfontwidth, curFontHeight);
2177 int l0 = ShapeCoord(*p++, curfontwidth, curFontHeight);
2178 int x1 = ShapeCoord(*p++, curfontwidth, curFontHeight);
2179 int y1 = ShapeCoord(*p++, curfontwidth, curFontHeight);
2180 int l1 = ShapeCoord(*p++, curfontwidth, curFontHeight);
2181 FillTrapez(lfb, xres, x + x0, y + y0, l0, x1-x0, y1-y0, l1, bgcolor);
2186 DrawShape(lfb,xres,x, y, ShapeCoord(*p, curfontwidth, curFontHeight), curfontwidth, FontHeight, curFontHeight, fgcolor, bgcolor, false);
2195 void CTeletextDecoder::RenderCharIntern(TextRenderInfo_t* RenderInfo, int Char, TextPageAttr_t *Attribute, int zoom, int yoffset)
2199 color_t bgcolor, fgcolor;
2200 int factor, xfactor;
2201 unsigned char *sbitbuffer;
2203 int national_subset_local = m_txtCache->NationalSubset;
2204 int curfontwidth = GetCurFontWidth();
2205 int t = curfontwidth;
2206 m_RenderInfo.PosX += t;
2207 int curfontwidth2 = GetCurFontWidth();
2208 m_RenderInfo.PosX -= t;
2209 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);
2210 if (alphachar <= 0) return;
2212 if (zoom && Attribute->doubleh)
2214 else if (zoom || Attribute->doubleh)
2219 fgcolor = GetColorRGB((enumTeletextColor)Attribute->fg);
2220 if (m_RenderInfo.TranspMode && m_RenderInfo.PosY < 24*m_RenderInfo.FontHeight)
2222 bgcolor = GetColorRGB(TXT_ColorTransp);
2226 bgcolor = GetColorRGB((enumTeletextColor)Attribute->bg);
2229 if (Attribute->doublew)
2231 curfontwidth += curfontwidth2;
2237 if (!(glyph = FT_Get_Char_Index(m_Face, alphachar)))
2239 CLog::Log(LOGERROR, "%s: <FT_Get_Char_Index for Char %x \"%c\" failed", __FUNCTION__, alphachar, alphachar);
2241 FillRect(m_TextureBuffer, m_RenderInfo.Width, m_RenderInfo.PosX, m_RenderInfo.PosY + yoffset, curfontwidth, factor*m_RenderInfo.FontHeight, bgcolor);
2242 m_RenderInfo.PosX += curfontwidth;
2246 if (FTC_SBitCache_Lookup(m_Cache, &m_TypeTTF, glyph, &m_sBit, NULL) != 0)
2248 FillRect(m_TextureBuffer, m_RenderInfo.Width, m_RenderInfo.PosX, m_RenderInfo.PosY + yoffset, curfontwidth, m_RenderInfo.FontHeight, bgcolor);
2249 m_RenderInfo.PosX += curfontwidth;
2254 sbitbuffer = m_sBit->buffer;
2255 unsigned char localbuffer[1000]; // should be enough to store one character-bitmap...
2256 // add diacritical marks
2257 if (Attribute->diacrit)
2259 FTC_SBit sbit_diacrit;
2261 if ((national_subset_local == NAT_SC) || (national_subset_local == NAT_RB) || (national_subset_local == NAT_UA))
2262 Char = G2table[1][0x20+ Attribute->diacrit];
2263 else if (national_subset_local == NAT_GR)
2264 Char = G2table[2][0x20+ Attribute->diacrit];
2265 else if (national_subset_local == NAT_HB)
2266 Char = G2table[3][0x20+ Attribute->diacrit];
2267 else if (national_subset_local == NAT_AR)
2268 Char = G2table[4][0x20+ Attribute->diacrit];
2270 Char = G2table[0][0x20+ Attribute->diacrit];
2271 if ((glyph = FT_Get_Char_Index(m_Face, Char)))
2273 if (FTC_SBitCache_Lookup(m_Cache, &m_TypeTTF, glyph, &sbit_diacrit, NULL) == 0)
2275 sbitbuffer = localbuffer;
2276 memcpy(sbitbuffer,m_sBit->buffer,m_sBit->pitch*m_sBit->height);
2278 for (Row = 0; Row < m_sBit->height; Row++)
2280 for (Pitch = 0; Pitch < m_sBit->pitch; Pitch++)
2282 if (sbit_diacrit->pitch > Pitch && sbit_diacrit->height > Row)
2283 sbitbuffer[Row*m_sBit->pitch+Pitch] |= sbit_diacrit->buffer[Row*m_sBit->pitch+Pitch];
2290 int backupTTFshiftY = m_RenderInfo.TTFShiftY;
2291 if (national_subset_local == NAT_AR)
2292 m_RenderInfo.TTFShiftY = backupTTFshiftY - 2; // for arabic TTF font should be shifted up slightly
2295 int f; /* running counter for zoom factor */
2296 int he = m_sBit->height; // sbit->height should not be altered, I guess
2297 Row = factor * (m_Ascender - m_sBit->top + m_RenderInfo.TTFShiftY);
2300 sbitbuffer -= m_sBit->pitch*Row;
2306 FillRect(m_TextureBuffer, m_RenderInfo.Width, m_RenderInfo.PosX, m_RenderInfo.PosY + yoffset, curfontwidth, Row, bgcolor); /* fill upper margin */
2309 if (m_Ascender - m_sBit->top + m_RenderInfo.TTFShiftY + he > m_RenderInfo.FontHeight)
2310 he = m_RenderInfo.FontHeight - m_Ascender + m_sBit->top - m_RenderInfo.TTFShiftY; /* limit char height to defined/calculated FontHeight */
2311 if (he < 0) he = m_RenderInfo.FontHeight;
2313 p = m_TextureBuffer + m_RenderInfo.PosX + (yoffset + m_RenderInfo.PosY + Row) * m_RenderInfo.Width; /* running pointer into framebuffer */
2314 for (Row = he; Row; Row--) /* row counts up, but down may be a little faster :) */
2316 int pixtodo = m_sBit->width;
2317 color_t *pstart = p;
2319 for (int Bit = xfactor * (m_sBit->left + m_RenderInfo.TTFShiftX); Bit > 0; Bit--) /* fill left margin */
2321 for (f = factor-1; f >= 0; f--)
2322 *(p + f*m_RenderInfo.Width) = bgcolor;
2326 for (Pitch = m_sBit->pitch; Pitch; Pitch--)
2328 for (int Bit = 0x80; Bit; Bit >>= 1)
2335 if (*sbitbuffer & Bit) /* bit set -> foreground */
2337 else /* bit not set -> background */
2340 for (f = factor-1; f >= 0; f--)
2341 *(p + f*m_RenderInfo.Width) = color;
2344 if (xfactor > 1) /* double width */
2346 for (f = factor-1; f >= 0; f--)
2347 *(p + f*m_RenderInfo.Width) = color;
2353 for (int Bit = (curfontwidth - xfactor*(m_sBit->width + m_sBit->left + m_RenderInfo.TTFShiftX));
2354 Bit > 0; Bit--) /* fill rest of char width */
2356 for (f = factor-1; f >= 0; f--)
2357 *(p + f*m_RenderInfo.Width) = bgcolor;
2361 p = pstart + factor*m_RenderInfo.Width;
2364 Row = m_Ascender - m_sBit->top + he + m_RenderInfo.TTFShiftY;
2365 FillRect(m_TextureBuffer,
2368 m_RenderInfo.PosY + yoffset + Row * factor,
2370 (m_RenderInfo.FontHeight - Row) * factor,
2371 bgcolor); /* fill lower margin */
2373 if (Attribute->underline)
2374 FillRect(m_TextureBuffer,
2377 m_RenderInfo.PosY + yoffset + (m_RenderInfo.FontHeight-2)* factor,
2380 fgcolor); /* underline char */
2382 m_RenderInfo.PosX += curfontwidth;
2383 m_RenderInfo.TTFShiftY = backupTTFshiftY; // restore TTFShiftY
2386 int CTeletextDecoder::RenderChar(color_t *buffer, // pointer to render buffer, min. FontHeight*2*xres
2387 int xres, // length of 1 line in render buffer
2388 int Char, // character to render
2389 int *pPosX, // left border for rendering relative to *buffer, will be set to right border after rendering
2390 int PosY, // vertical position of char in *buffer
2391 TextPageAttr_t *Attribute,// Attributes of Char
2392 bool zoom, // 1= character will be rendered in double height
2393 int curfontwidth, // rendering width of character
2394 int curfontwidth2, // rendering width of next character (needed for doublewidth)
2395 int FontHeight, // height of character
2396 bool transpmode, // 1= transparent display
2397 unsigned char *axdrcs, // width and height of DRCS-chars
2398 int Ascender) // Ascender of font
2400 color_t bgcolor, fgcolor;
2401 int factor, xfactor;
2402 int national_subset_local = m_txtCache->NationalSubset;
2404 ymosaic[0] = 0; /* y-offsets for 2*3 mosaic */
2405 ymosaic[1] = (FontHeight + 1) / 3;
2406 ymosaic[2] = (FontHeight * 2 + 1) / 3;
2407 ymosaic[3] = FontHeight;
2409 if (Attribute->setX26)
2411 national_subset_local = 0; // no national subset
2414 // G0+G2 set designation
2415 if (Attribute->setG0G2 != 0x3f)
2417 switch (Attribute->setG0G2)
2420 national_subset_local = NAT_SC;
2423 national_subset_local = NAT_RB;
2426 national_subset_local = NAT_UA;
2429 national_subset_local = NAT_GR;
2432 national_subset_local = NAT_HB;
2436 national_subset_local = NAT_AR;
2439 national_subset_local = CountryConversionTable[Attribute->setG0G2 & 0x07];
2444 if (Attribute->charset == C_G0S) // use secondary charset
2445 national_subset_local = m_txtCache->NationalSubsetSecondary;
2446 if (zoom && Attribute->doubleh)
2448 else if (zoom || Attribute->doubleh)
2453 if (Attribute->doublew)
2455 curfontwidth += curfontwidth2;
2461 if (Char == 0xFF) /* skip doubleheight chars in lower line */
2463 *pPosX += curfontwidth;
2468 if (Attribute->inverted)
2470 int t = Attribute->fg;
2471 Attribute->fg = Attribute->bg;
2474 fgcolor = GetColorRGB((enumTeletextColor)Attribute->fg);
2475 if (transpmode == true && PosY < 24*FontHeight)
2477 bgcolor = GetColorRGB(TXT_ColorTransp);
2481 bgcolor = GetColorRGB((enumTeletextColor)Attribute->bg);
2485 if ((Attribute->charset == C_G1C || Attribute->charset == C_G1S) &&
2486 ((Char&0xA0) == 0x20))
2488 int w1 = (curfontwidth / 2 ) *xfactor;
2489 int w2 = (curfontwidth - w1) *xfactor;
2491 Char = (Char & 0x1f) | ((Char & 0x40) >> 1);
2492 if (Attribute->charset == C_G1S) /* separated mosaic */
2494 for (int y = 0; y < 3; y++)
2496 FillRectMosaicSeparated(buffer, xres,*pPosX, PosY + ymosaic[y]*factor, w1, (ymosaic[y+1] - ymosaic[y])*factor, fgcolor, bgcolor, Char & 0x01);
2497 FillRectMosaicSeparated(buffer, xres,*pPosX + w1, PosY + ymosaic[y]*factor, w2, (ymosaic[y+1] - ymosaic[y])*factor, fgcolor, bgcolor, Char & 0x02);
2503 for (int y = 0; y < 3; y++)
2505 FillRect(buffer, xres, *pPosX, PosY + ymosaic[y]*factor, w1, (ymosaic[y+1] - ymosaic[y])*factor, (Char & 0x01) ? fgcolor : bgcolor);
2506 FillRect(buffer, xres, *pPosX + w1, PosY + ymosaic[y]*factor, w2, (ymosaic[y+1] - ymosaic[y])*factor, (Char & 0x02) ? fgcolor : bgcolor);
2511 *pPosX += curfontwidth;
2515 if (Attribute->charset == C_G3)
2517 if (Char < 0x20 || Char > 0x7d)
2523 if (*aShapes[Char - 0x20] == S_CHR)
2525 unsigned char *p = aShapes[Char - 0x20];
2526 Char = (*(p+1) <<8) + (*(p+2));
2528 else if (*aShapes[Char - 0x20] == S_ADT)
2533 color_t* p = buffer + *pPosX + PosY* xres;
2534 for (y=0; y<FontHeight;y++)
2536 for (f=0; f<factor; f++)
2538 for (x=0; x<curfontwidth*xfactor;x++)
2540 c = (y&4 ? (x/3)&1 :((x+3)/3)&1);
2541 *(p+x) = (c ? fgcolor : bgcolor);
2547 *pPosX += curfontwidth;
2552 DrawShape(buffer, xres,*pPosX, PosY, Char, curfontwidth, FontHeight, factor*FontHeight, fgcolor, bgcolor, true);
2553 *pPosX += curfontwidth;
2558 else if (Attribute->charset >= C_OFFSET_DRCS)
2560 TextCachedPage_t *pcache = m_txtCache->astCachetable[(Attribute->charset & 0x10) ? m_txtCache->drcs : m_txtCache->gdrcs][Attribute->charset & 0x0f];
2563 unsigned char drcs_data[23*40];
2564 g_application.m_pPlayer->LoadPage((Attribute->charset & 0x10) ? m_txtCache->drcs : m_txtCache->gdrcs, Attribute->charset & 0x0f, drcs_data);
2567 p = drcs_data + 20*Char;
2568 else if (pcache->pageinfo.p24)
2569 p = pcache->pageinfo.p24 + 20*(Char - 23*2);
2572 FillRect(buffer, xres,*pPosX, PosY, curfontwidth, factor*FontHeight, bgcolor);
2573 *pPosX += curfontwidth;
2576 axdrcs[12] = curfontwidth; /* adjust last x-offset according to position, FIXME: double width */
2577 RenderDRCS(xres, p, buffer + *pPosX + PosY * xres, axdrcs, fgcolor, bgcolor);
2581 FillRect(buffer,xres,*pPosX, PosY, curfontwidth, factor*FontHeight, bgcolor);
2583 *pPosX += curfontwidth;
2586 else if (Attribute->charset == C_G2 && Char >= 0x20 && Char <= 0x7F)
2588 if ((national_subset_local == NAT_SC) || (national_subset_local == NAT_RB) || (national_subset_local == NAT_UA))
2589 Char = G2table[1][Char-0x20];
2590 else if (national_subset_local == NAT_GR)
2591 Char = G2table[2][Char-0x20];
2592 else if (national_subset_local == NAT_AR)
2593 Char = G2table[3][Char-0x20];
2595 Char = G2table[0][Char-0x20];
2599 // FillRect(buffer,xres,*pPosX, PosY, curfontwidth, factor*Ascender, fgcolor);
2600 // FillRect(buffer,xres,*pPosX, PosY + factor*Ascender, curfontwidth, factor*(FontHeight-Ascender), bgcolor);
2601 // *pPosX += curfontwidth;
2605 else if (national_subset_local == NAT_SC && Char >= 0x20 && Char <= 0x7F) /* remap complete areas for serbian/croatian */
2606 Char = G0table[0][Char-0x20];
2607 else if (national_subset_local == NAT_RB && Char >= 0x20 && Char <= 0x7F) /* remap complete areas for russian/bulgarian */
2608 Char = G0table[1][Char-0x20];
2609 else if (national_subset_local == NAT_UA && Char >= 0x20 && Char <= 0x7F) /* remap complete areas for ukrainian */
2610 Char = G0table[2][Char-0x20];
2611 else if (national_subset_local == NAT_GR && Char >= 0x20 && Char <= 0x7F) /* remap complete areas for greek */
2612 Char = G0table[3][Char-0x20];
2613 else if (national_subset_local == NAT_HB && Char >= 0x20 && Char <= 0x7F) /* remap complete areas for hebrew */
2614 Char = G0table[4][Char-0x20];
2615 else if (national_subset_local == NAT_AR && Char >= 0x20 && Char <= 0x7F) /* remap complete areas for arabic */
2616 Char = G0table[5][Char-0x20];
2624 FillRect(buffer, xres, *pPosX, PosY, curfontwidth, factor*FontHeight, bgcolor);
2625 *pPosX += curfontwidth;
2629 Char = nationaltable23[national_subset_local][Char-0x23];
2632 Char = nationaltable40[national_subset_local];
2640 Char = nationaltable5b[national_subset_local][Char-0x5B];
2646 Char = nationaltable7b[national_subset_local][Char-0x7B];
2649 FillRect(buffer,xres,*pPosX, PosY , curfontwidth, factor*Ascender, fgcolor);
2650 FillRect(buffer,xres,*pPosX, PosY + factor*Ascender, curfontwidth, factor*(FontHeight-Ascender), bgcolor);
2651 *pPosX += curfontwidth;
2654 DrawHLine(buffer,xres,*pPosX, PosY, curfontwidth, fgcolor);
2655 DrawVLine(buffer,xres,*pPosX, PosY +1, FontHeight -1, fgcolor);
2656 FillRect(buffer,xres,*pPosX +1, PosY +1, curfontwidth-1, FontHeight-1, bgcolor);
2657 *pPosX += curfontwidth;
2660 DrawHLine(buffer,xres,*pPosX, PosY, curfontwidth, fgcolor);
2661 FillRect(buffer,xres,*pPosX, PosY +1, curfontwidth, FontHeight-1, bgcolor);
2662 *pPosX += curfontwidth;
2665 DrawHLine(buffer,xres,*pPosX, PosY, curfontwidth, fgcolor);
2666 DrawVLine(buffer,xres,*pPosX + curfontwidth -1, PosY +1, FontHeight -1, fgcolor);
2667 FillRect(buffer,xres,*pPosX, PosY +1, curfontwidth-1, FontHeight-1, bgcolor);
2668 *pPosX += curfontwidth;
2671 DrawVLine(buffer,xres,*pPosX, PosY, FontHeight, fgcolor);
2672 FillRect(buffer,xres,*pPosX +1, PosY, curfontwidth -1, FontHeight, bgcolor);
2673 *pPosX += curfontwidth;
2676 DrawVLine(buffer,xres,*pPosX + curfontwidth -1, PosY, FontHeight, fgcolor);
2677 FillRect(buffer,xres,*pPosX, PosY, curfontwidth -1, FontHeight, bgcolor);
2678 *pPosX += curfontwidth;
2681 DrawHLine(buffer,xres,*pPosX, PosY + FontHeight -1, curfontwidth, fgcolor);
2682 DrawVLine(buffer,xres,*pPosX, PosY, FontHeight -1, fgcolor);
2683 FillRect(buffer,xres,*pPosX +1, PosY, curfontwidth-1, FontHeight-1, bgcolor);
2684 *pPosX += curfontwidth;
2687 DrawHLine(buffer,xres,*pPosX, PosY + FontHeight -1, curfontwidth, fgcolor);
2688 FillRect(buffer,xres,*pPosX, PosY, curfontwidth, FontHeight-1, bgcolor);
2689 *pPosX += curfontwidth;
2692 DrawHLine(buffer,xres,*pPosX, PosY + FontHeight -1, curfontwidth, fgcolor);
2693 DrawVLine(buffer,xres,*pPosX + curfontwidth -1, PosY, FontHeight -1, fgcolor);
2694 FillRect(buffer,xres,*pPosX, PosY, curfontwidth-1, FontHeight-1, bgcolor);
2695 *pPosX += curfontwidth;
2698 FillRect(buffer,xres,*pPosX +1, PosY, curfontwidth -1, FontHeight, bgcolor);
2699 for (int Row=0; Row < curfontwidth/2; Row++)
2700 DrawVLine(buffer,xres,*pPosX + Row, PosY + Row, FontHeight - Row, fgcolor);
2701 *pPosX += curfontwidth;
2704 FillRect(buffer,xres,*pPosX, PosY, curfontwidth/2, FontHeight, fgcolor);
2705 FillRect(buffer,xres,*pPosX + curfontwidth/2, PosY, (curfontwidth+1)/2, FontHeight, bgcolor);
2706 *pPosX += curfontwidth;
2709 FillRect(buffer,xres,*pPosX, PosY, curfontwidth, FontHeight, bgcolor);
2710 FillRect(buffer,xres,*pPosX, PosY, curfontwidth/2, curfontwidth/2, fgcolor);
2711 *pPosX += curfontwidth;
2714 FillRect(buffer,xres,*pPosX, PosY +1, curfontwidth, FontHeight -1, bgcolor);
2715 for (int Row=0; Row < curfontwidth/2; Row++)
2716 DrawHLine(buffer,xres,*pPosX + Row, PosY + Row, curfontwidth - Row, fgcolor);
2717 *pPosX += curfontwidth;
2720 FillRect(buffer, xres,*pPosX, PosY, curfontwidth, curfontwidth/2, fgcolor);
2721 FillRect(buffer, xres,*pPosX, PosY + curfontwidth/2, curfontwidth, FontHeight - curfontwidth/2, bgcolor);
2722 *pPosX += curfontwidth;
2734 Char = arrowtable[Char - 0xED];
2742 FillRect(buffer, xres, *pPosX, PosY, curfontwidth, factor*FontHeight, bgcolor);
2743 *pPosX += curfontwidth;
2746 return Char; // Char is an alphanumeric unicode character
2749 TextPageinfo_t* CTeletextDecoder::DecodePage(bool showl25, // 1=decode Level2.5-graphics
2750 unsigned char* PageChar, // page buffer, min. 25*40
2751 TextPageAttr_t *PageAtrb, // attribut buffer, min 25*40
2752 bool HintMode, // 1=show hidden information
2753 bool showflof) // 1=decode FLOF-line
2757 int foreground, background, doubleheight, doublewidth, charset, previous_charset, mosaictype, IgnoreAtBlackBgSubst, concealed, flashmode, boxwin;
2758 unsigned char held_mosaic, *p;
2759 TextCachedPage_t *pCachedPage;
2761 /* copy page to decode buffer */
2762 if (m_txtCache->SubPageTable[m_txtCache->Page] == 0xff) /* not cached: do nothing */
2765 if (m_txtCache->ZapSubpageManual)
2766 pCachedPage = m_txtCache->astCachetable[m_txtCache->Page][m_txtCache->SubPage];
2768 pCachedPage = m_txtCache->astCachetable[m_txtCache->Page][m_txtCache->SubPageTable[m_txtCache->Page]];
2769 if (!pCachedPage) /* not cached: do nothing */
2772 g_application.m_pPlayer->LoadPage(m_txtCache->Page, m_txtCache->SubPage, &PageChar[40]);
2774 memcpy(&PageChar[8], pCachedPage->p0, 24); /* header line without TimeString */
2776 TextPageinfo_t* PageInfo = &(pCachedPage->pageinfo);
2778 memcpy(&PageChar[24*40], PageInfo->p24, 40); /* line 25 for FLOF */
2780 /* copy TimeString */
2781 memcpy(&PageChar[32], &m_txtCache->TimeString, 8);
2784 /* check for newsflash & subtitle */
2785 if (PageInfo->boxed && IsDec(m_txtCache->Page))
2794 memset(PageChar, ' ', 40);
2798 memset(PageChar, ' ', 8);
2799 CDVDTeletextTools::Hex2Str((char*)PageChar+3, m_txtCache->Page);
2800 if (m_txtCache->SubPage)
2804 CDVDTeletextTools::Hex2Str((char*)PageChar+6, m_txtCache->SubPage);
2808 if (!IsDec(m_txtCache->Page))
2810 TextPageAttr_t atr = { TXT_ColorWhite , TXT_ColorBlack , C_G0P, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, 0x3f};
2811 if (PageInfo->function == FUNC_MOT) /* magazine organization table */
2813 for (col = 0; col < 24*40; col++)
2814 PageAtrb[col] = atr;
2815 for (col = 40; col < 24*40; col++)
2816 PageChar[col] = number2char(PageChar[col]);
2817 return PageInfo; /* don't interpret irregular pages */
2819 else if (PageInfo->function == FUNC_GPOP || PageInfo->function == FUNC_POP) /* object definitions */
2821 for (int col = 0; col < 24*40; col++)
2822 PageAtrb[col] = atr;
2825 for (int row = 1; row < 12; row++)
2827 *p++ = number2char(row); /* first column: number (0-9, A-..) */
2828 for (int col = 1; col < 40; col += 3)
2830 int d = CDVDTeletextTools::deh24(p);
2833 memcpy(p, "???", 3);
2838 *p++ = number2char((d >> 6) & 0x1f); /* mode */
2839 *p++ = number2char(d & 0x3f); /* address */
2840 *p++ = number2char((d >> 11) & 0x7f); /* data */
2844 return PageInfo; /* don't interpret irregular pages */
2846 else if (PageInfo->function == FUNC_GDRCS || PageInfo->function == FUNC_DRCS) /* character definitions */
2848 return PageInfo; /* don't interpret irregular pages */
2852 int h, parityerror = 0;
2854 for (int i = 0; i < 8; i++)
2857 /* decode parity/hamming */
2858 for (unsigned int i = 40; i < sizeof(PageChar); i++)
2863 if (parityerror && h != 0xFF) /* if no regular page (after any parity error) */
2864 CDVDTeletextTools::Hex2Str((char*)p, h); /* first try dehamming */
2867 if (*p == ' ' || deparity[*p] != ' ') /* correct parity */
2872 if (h != 0xFF) /* first parity error: try dehamming */
2873 CDVDTeletextTools::Hex2Str((char*)p, h);
2881 return PageInfo; /* don't interpret irregular pages */
2885 int mosaic_pending,esc_pending;
2887 for (int row = 0; row < ((showflof && PageInfo->p24) ? 25 : 24); row++)
2889 /* start-of-row default conditions */
2890 foreground = TXT_ColorWhite;
2891 background = TXT_ColorBlack;
2894 charset = previous_charset = C_G0P; // remember charset for switching back after mosaic charset was used
2902 IgnoreAtBlackBgSubst = 0;
2903 mosaic_pending = esc_pending = 0; // we need to render at least one mosaic char if 'esc' is received immediatly after mosac charset switch on
2905 if (boxed && memchr(&PageChar[row*40], start_box, 40) == 0)
2907 foreground = TXT_ColorTransp;
2908 background = TXT_ColorTransp;
2911 for (int col = 0; col < 40; col++)
2913 int index = row*40 + col;
2915 PageAtrb[index].fg = foreground;
2916 PageAtrb[index].bg = background;
2917 PageAtrb[index].charset = charset;
2918 PageAtrb[index].doubleh = doubleheight;
2919 PageAtrb[index].doublew = (col < 39 ? doublewidth : 0);
2920 PageAtrb[index].IgnoreAtBlackBgSubst = IgnoreAtBlackBgSubst;
2921 PageAtrb[index].concealed = concealed;
2922 PageAtrb[index].flashing = flashmode;
2923 PageAtrb[index].boxwin = boxwin;
2924 PageAtrb[index].inverted = 0; // only relevant for Level 2.5
2925 PageAtrb[index].underline = 0; // only relevant for Level 2.5
2926 PageAtrb[index].diacrit = 0; // only relevant for Level 2.5
2927 PageAtrb[index].setX26 = 0; // only relevant for Level 2.5
2928 PageAtrb[index].setG0G2 = 0x3f; // only relevant for Level 2.5
2930 if (PageChar[index] < ' ')
2932 if (esc_pending) { // mosaic char has been rendered and we can switch charsets
2933 charset = previous_charset;
2934 if (charset == C_G0P)
2935 charset = previous_charset = C_G0S;
2936 else if (charset == C_G0S)
2937 charset = previous_charset = C_G0P;
2940 switch (PageChar[index])
2951 foreground = PageChar[index] - alpha_black + TXT_ColorBlack;
2952 if (col == 0 && PageChar[index] == alpha_white)
2953 PageAtrb[index].fg = TXT_ColorBlack; // indicate level 1 color change on column 0; (hack)
2954 if ((charset!=C_G0P) && (charset!=C_G0S)) // we need to change charset to state it was before mosaic
2955 charset = previous_charset;
2964 PageAtrb[index].flashing = 0;
2969 IgnoreAtBlackBgSubst = 0;
2980 PageAtrb[index].doubleh = doubleheight;
2981 PageAtrb[index].doublew = doublewidth;
3015 case mosaic_magenta:
3019 foreground = PageChar[index] - mosaic_black + TXT_ColorBlack;
3020 if ((charset==C_G0P) || (charset==C_G0S))
3021 previous_charset=charset;
3022 charset = mosaictype ? C_G1S : C_G1C;
3027 PageAtrb[index].concealed = 1;
3031 foreground = background;
3032 PageAtrb[index].fg = foreground;
3036 case contiguous_mosaic:
3038 if (charset == C_G1S)
3041 PageAtrb[index].charset = charset;
3045 case separated_mosaic:
3047 if (charset == C_G1C)
3050 PageAtrb[index].charset = charset;
3055 if (!mosaic_pending) { // if mosaic is pending we need to wait before mosaic arrives
3056 if ((charset != C_G0P) && (charset != C_G0S)) // we need to switch to charset which was active before mosaic
3057 charset = previous_charset;
3058 if (charset == C_G0P)
3059 charset = previous_charset = C_G0S;
3060 else if (charset == C_G0S)
3061 charset = previous_charset = C_G0P;
3062 } else esc_pending = 1;
3065 case black_background:
3066 background = TXT_ColorBlack;
3067 IgnoreAtBlackBgSubst = 0;
3068 PageAtrb[index].bg = background;
3069 PageAtrb[index].IgnoreAtBlackBgSubst = IgnoreAtBlackBgSubst;
3072 case new_background:
3073 background = foreground;
3074 if (background == TXT_ColorBlack)
3075 IgnoreAtBlackBgSubst = 1;
3077 IgnoreAtBlackBgSubst = 0;
3078 PageAtrb[index].bg = background;
3079 PageAtrb[index].IgnoreAtBlackBgSubst = IgnoreAtBlackBgSubst;
3086 case release_mosaic:
3091 /* handle spacing attributes */
3092 if (hold && (PageAtrb[index].charset == C_G1C || PageAtrb[index].charset == C_G1S))
3093 PageChar[index] = held_mosaic;
3095 PageChar[index] = ' ';
3100 else /* char >= ' ' */
3102 mosaic_pending = 0; // charset will be switched next if esc_pending
3103 /* set new held-mosaic char */
3104 if ((charset == C_G1C || charset == C_G1S) &&
3105 ((PageChar[index]&0xA0) == 0x20))
3106 held_mosaic = PageChar[index];
3107 if (PageAtrb[index].doubleh)
3108 PageChar[index + 40] = 0xFF;
3111 if (!(charset == C_G1C || charset == C_G1S))
3112 held_mosaic = ' '; /* forget if outside mosaic */
3116 /* skip row if doubleheight */
3117 if (row < 23 && dhset)
3119 for (int col = 0; col < 40; col++)
3121 int index = row*40 + col;
3122 PageAtrb[index+40].bg = PageAtrb[index].bg;
3123 PageAtrb[index+40].fg = TXT_ColorWhite;
3124 if (!PageAtrb[index].doubleh)
3125 PageChar[index+40] = ' ';
3126 PageAtrb[index+40].flashing = 0;
3127 PageAtrb[index+40].charset = C_G0P;
3128 PageAtrb[index+40].doubleh = 0;
3129 PageAtrb[index+40].doublew = 0;
3130 PageAtrb[index+40].IgnoreAtBlackBgSubst = 0;
3131 PageAtrb[index+40].concealed = 0;
3132 PageAtrb[index+40].flashing = 0;
3133 PageAtrb[index+40].boxwin = PageAtrb[index].boxwin;
3138 m_txtCache->FullScrColor = TXT_ColorBlack;
3141 Eval_l25(PageChar, PageAtrb, HintMode);
3143 /* handle Black Background Color Substitution and transparency (CLUT1#0) */
3148 for (int r = 0; r < 25; r++)
3150 for (int c = 0; c < 40; c++)
3152 bitmask = (PageAtrb[o].bg == 0x08 ? 0x08 : 0x00) | (m_txtCache->FullRowColor[r] == 0x08 ? 0x04 : 0x00) | (PageAtrb[o].boxwin <<1) | (int)boxed;
3157 if (m_txtCache->FullRowColor[r] == 0x08)
3158 PageAtrb[o].bg = m_txtCache->FullScrColor;
3160 PageAtrb[o].bg = m_txtCache->FullRowColor[r];
3170 PageAtrb[o].bg = TXT_ColorTransp;
3173 bitmask = (PageAtrb[o].fg == 0x08 ? 0x08 : 0x00) | (m_txtCache->FullRowColor[r] == 0x08 ? 0x04 : 0x00) | (PageAtrb[o].boxwin <<1) | (int)boxed;
3178 if (m_txtCache->FullRowColor[r] == 0x08)
3179 PageAtrb[o].fg = m_txtCache->FullScrColor;
3181 PageAtrb[o].fg = m_txtCache->FullRowColor[r];
3191 PageAtrb[o].fg = TXT_ColorTransp;
3201 void CTeletextDecoder::Eval_l25(unsigned char* PageChar, TextPageAttr_t *PageAtrb, bool HintMode)
3203 memset(m_txtCache->FullRowColor, 0, sizeof(m_txtCache->FullRowColor));
3204 m_txtCache->FullScrColor = TXT_ColorBlack;
3205 m_txtCache->ColorTable = NULL;
3207 if (!m_txtCache->astCachetable[m_txtCache->Page][m_txtCache->SubPage])
3211 if (IsDec(m_txtCache->Page))
3213 unsigned char APx0, APy0, APx, APy;
3214 TextPageinfo_t *pi = &(m_txtCache->astCachetable[m_txtCache->Page][m_txtCache->SubPage]->pageinfo);
3215 TextCachedPage_t *pmot = m_txtCache->astCachetable[(m_txtCache->Page & 0xf00) | 0xfe][0];
3216 int p26Received = 0;
3217 int BlackBgSubst = 0;
3218 int ColorTableRemapping = 0;
3220 m_txtCache->pop = m_txtCache->gpop = m_txtCache->drcs = m_txtCache->gdrcs = 0;
3224 TextExtData_t *e = pi->ext;
3231 Textp27_t *p27 = e->p27;
3233 m_txtCache->gpop = p27[0].page;
3235 m_txtCache->pop = p27[1].page;
3237 m_txtCache->gdrcs = p27[2].page;
3239 m_txtCache->drcs = p27[3].page;
3244 m_txtCache->ColorTable = e->bgr;
3245 BlackBgSubst = e->BlackBgSubst;
3246 ColorTableRemapping = e->ColorTableRemapping;
3247 memset(m_txtCache->FullRowColor, e->DefRowColor, sizeof(m_txtCache->FullRowColor));
3248 m_txtCache->FullScrColor = e->DefScreenColor;
3249 m_txtCache->NationalSubset = SetNational(e->DefaultCharset);
3250 m_txtCache->NationalSubsetSecondary = SetNational(e->SecondCharset);
3251 } /* e->p28Received */
3254 if (!m_txtCache->ColorTable && m_txtCache->astP29[m_txtCache->Page >> 8])
3256 TextExtData_t *e = m_txtCache->astP29[m_txtCache->Page >> 8];
3257 m_txtCache->ColorTable = e->bgr;
3258 BlackBgSubst = e->BlackBgSubst;
3259 ColorTableRemapping = e->ColorTableRemapping;
3260 memset(m_txtCache->FullRowColor, e->DefRowColor, sizeof(m_txtCache->FullRowColor));
3261 m_txtCache->FullScrColor = e->DefScreenColor;
3262 m_txtCache->NationalSubset = SetNational(e->DefaultCharset);
3263 m_txtCache->NationalSubsetSecondary = SetNational(e->SecondCharset);
3266 if (ColorTableRemapping)
3268 for (int i = 0; i < 25*40; i++)
3270 PageAtrb[i].fg += MapTblFG[ColorTableRemapping - 1];
3271 if (!BlackBgSubst || PageAtrb[i].bg != TXT_ColorBlack || PageAtrb[i].IgnoreAtBlackBgSubst)
3272 PageAtrb[i].bg += MapTblBG[ColorTableRemapping - 1];
3276 /* determine ?pop/?drcs from MOT */
3279 unsigned char pmot_data[23*40];
3280 g_application.m_pPlayer->LoadPage((m_txtCache->Page & 0xf00) | 0xfe, 0, pmot_data);
3282 unsigned char *p = pmot_data; /* start of link data */
3283 int o = 2 * (((m_txtCache->Page & 0xf0) >> 4) * 10 + (m_txtCache->Page & 0x0f)); /* offset of links for current page */
3284 int opop = p[o] & 0x07; /* index of POP link */
3285 int odrcs = p[o+1] & 0x07; /* index of DRCS link */
3286 unsigned char obj[3*4*4]; /* types* objects * (triplet,packet,subp,high) */
3287 unsigned char type,ct, tstart = 4*4;
3288 memset(obj,0,sizeof(obj));
3290 if (p[o] & 0x08) /* GPOP data used */
3292 if (!m_txtCache->gpop || !(p[18*40] & 0x08)) /* no p27 data or higher prio of MOT link */
3294 m_txtCache->gpop = ((p[18*40] << 8) | (p[18*40+1] << 4) | p[18*40+2]) & 0x7ff;
3295 if ((m_txtCache->gpop & 0xff) == 0xff)
3296 m_txtCache->gpop = 0;
3299 if (m_txtCache->gpop < 0x100)
3300 m_txtCache->gpop += 0x800;
3307 type = (p[18*40+5] >> 2*ct) & 0x03;
3309 if (type == 0) continue;
3310 obj[(type-1)*(tstart)+ct*4 ] = 3 * ((p[18*40+7+ct*2] >> 1) & 0x03) + type; //triplet
3311 obj[(type-1)*(tstart)+ct*4+1] = ((p[18*40+7+ct*2] & 0x08) >> 3) + 1 ; //packet
3312 obj[(type-1)*(tstart)+ct*4+2] = p[18*40+6+ct*2] & 0x0f ; //subp
3313 obj[(type-1)*(tstart)+ct*4+3] = p[18*40+7+ct*2] & 0x01 ; //high
3319 if (opop) /* POP data used */
3321 opop = 18*40 + 10*opop; /* offset to POP link */
3322 if (!m_txtCache->pop || !(p[opop] & 0x08)) /* no p27 data or higher prio of MOT link */
3324 m_txtCache->pop = ((p[opop] << 8) | (p[opop+1] << 4) | p[opop+2]) & 0x7ff;
3325 if ((m_txtCache->pop & 0xff) == 0xff)
3326 m_txtCache->pop = 0;
3329 if (m_txtCache->pop < 0x100)
3330 m_txtCache->pop += 0x800;
3337 type = (p[opop+5] >> 2*ct) & 0x03;
3339 if (type == 0) continue;
3340 obj[(type-1)*(tstart)+(ct+2)*4 ] = 3 * ((p[opop+7+ct*2] >> 1) & 0x03) + type; //triplet
3341 obj[(type-1)*(tstart)+(ct+2)*4+1] = ((p[opop+7+ct*2] & 0x08) >> 3) + 1 ; //packet
3342 obj[(type-1)*(tstart)+(ct+2)*4+2] = p[opop+6+ct*2] ; //subp
3343 obj[(type-1)*(tstart)+(ct+2)*4+3] = p[opop+7+ct*2] & 0x01 ; //high
3349 // eval default objects in correct order
3350 for (int i = 0; i < 12; i++)
3354 APx0 = APy0 = APx = APy = m_txtCache->tAPx = m_txtCache->tAPy = 0;
3355 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);
3359 if (p[o+1] & 0x08) /* GDRCS data used */
3361 if (!m_txtCache->gdrcs || !(p[20*40] & 0x08)) /* no p27 data or higher prio of MOT link */
3363 m_txtCache->gdrcs = ((p[20*40] << 8) | (p[20*40+1] << 4) | p[20*40+2]) & 0x7ff;
3364 if ((m_txtCache->gdrcs & 0xff) == 0xff)
3365 m_txtCache->gdrcs = 0;
3366 else if (m_txtCache->gdrcs < 0x100)
3367 m_txtCache->gdrcs += 0x800;
3370 if (odrcs) /* DRCS data used */
3372 odrcs = 20*40 + 4*odrcs; /* offset to DRCS link */
3373 if (!m_txtCache->drcs || !(p[odrcs] & 0x08)) /* no p27 data or higher prio of MOT link */
3375 m_txtCache->drcs = ((p[odrcs] << 8) | (p[odrcs+1] << 4) | p[odrcs+2]) & 0x7ff;
3376 if ((m_txtCache->drcs & 0xff) == 0xff)
3377 m_txtCache->drcs = 0;
3378 else if (m_txtCache->drcs < 0x100)
3379 m_txtCache->drcs += 0x800;
3382 if (m_txtCache->astCachetable[m_txtCache->gpop][0])
3383 m_txtCache->astCachetable[m_txtCache->gpop][0]->pageinfo.function = FUNC_GPOP;
3384 if (m_txtCache->astCachetable[m_txtCache->pop][0])
3385 m_txtCache->astCachetable[m_txtCache->pop][0]->pageinfo.function = FUNC_POP;
3386 if (m_txtCache->astCachetable[m_txtCache->gdrcs][0])
3387 m_txtCache->astCachetable[m_txtCache->gdrcs][0]->pageinfo.function = FUNC_GDRCS;
3388 if (m_txtCache->astCachetable[m_txtCache->drcs][0])
3389 m_txtCache->astCachetable[m_txtCache->drcs][0]->pageinfo.function = FUNC_DRCS;
3392 /* evaluate local extension data from p26 */
3395 APx0 = APy0 = APx = APy = m_txtCache->tAPx = m_txtCache->tAPy = 0;
3396 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 */
3401 for (int r = 0; r < 25; r++)
3403 for (int c = 0; c < 40; c++)
3405 if (BlackBgSubst && PageAtrb[o].bg == TXT_ColorBlack && !(PageAtrb[o].IgnoreAtBlackBgSubst))
3407 if (m_txtCache->FullRowColor[r] == 0x08)
3408 PageAtrb[o].bg = m_txtCache->FullScrColor;
3410 PageAtrb[o].bg = m_txtCache->FullRowColor[r];
3419 for (int i = 0; i < 25*40; i++)
3421 if (PageAtrb[i].concealed) PageAtrb[i].fg = PageAtrb[i].bg;
3424 } /* is_dec(page) */
3427 /* dump interpreted object data to stdout */
3428 /* in: 18 bit object data */
3429 /* out: termination info, >0 if end of object */
3430 void CTeletextDecoder::Eval_Object(int iONr, TextCachedPage_t *pstCachedPage,
3431 unsigned char *pAPx, unsigned char *pAPy,
3432 unsigned char *pAPx0, unsigned char *pAPy0,
3433 tObjType ObjType, unsigned char* pagedata, unsigned char* PageChar, TextPageAttr_t* PageAtrb)
3436 int iONr1 = iONr + 1; /* don't terminate after first triplet */
3437 unsigned char drcssubp=0, gdrcssubp=0;
3438 signed char endcol = -1; /* last column to which to extend attribute changes */
3439 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 */
3443 iOData = iTripletNumber2Data(iONr, pstCachedPage, pagedata); /* get triplet data, next triplet */
3444 if (iOData < 0) /* invalid number, not cached, or hamming error: terminate */
3449 if (ObjType == OBJ_ACTIVE)
3453 else if (ObjType == OBJ_ADAPTIVE) /* search end of line */
3455 for (int i = iONr; i <= 506; i++)
3457 int iTempOData = iTripletNumber2Data(i, pstCachedPage, pagedata); /* get triplet data, next triplet */
3458 int iAddress = (iTempOData ) & 0x3f;
3459 int iMode = (iTempOData >> 6) & 0x1f;
3460 //int iData = (iTempOData >> 11) & 0x7f;
3461 if (iTempOData < 0 || /* invalid number, not cached, or hamming error: terminate */
3462 (iAddress >= 40 /* new row: row address and */
3463 && (iMode == 0x01 || /* Full Row Color or */
3464 iMode == 0x04 || /* Set Active Position */
3465 (iMode >= 0x15 && iMode <= 0x17) || /* Object Definition */
3466 iMode == 0x17))) /* Object Termination */
3468 if (iAddress < 40 && iMode != 0x06)
3475 while (0 == Eval_Triplet(iOData, pstCachedPage, pAPx, pAPy, pAPx0, pAPy0, &drcssubp, &gdrcssubp, &endcol, &attrPassive, pagedata, PageChar, PageAtrb) || iONr1 == iONr); /* repeat until termination reached */
3478 void CTeletextDecoder::Eval_NumberedObject(int p, int s, int packet, int triplet, int high,
3479 unsigned char *pAPx, unsigned char *pAPy,
3480 unsigned char *pAPx0, unsigned char *pAPy0, unsigned char* PageChar, TextPageAttr_t* PageAtrb)
3482 if (!packet || 0 == m_txtCache->astCachetable[p][s])
3485 unsigned char pagedata[23*40];
3486 g_application.m_pPlayer->LoadPage(p, s,pagedata);
3488 int idata = CDVDTeletextTools::deh24(pagedata + 40*(packet-1) + 1 + 3*triplet);
3491 if (idata < 0) /* hamming error: ignore triplet */
3494 iONr = idata >> 9; /* triplet number of odd object data */
3496 iONr = idata & 0x1ff; /* triplet number of even object data */
3499 Eval_Object(iONr, m_txtCache->astCachetable[p][s], pAPx, pAPy, pAPx0, pAPy0, (tObjType)(triplet % 3),pagedata, PageChar, PageAtrb);
3503 int CTeletextDecoder::Eval_Triplet(int iOData, TextCachedPage_t *pstCachedPage,
3504 unsigned char *pAPx, unsigned char *pAPy,
3505 unsigned char *pAPx0, unsigned char *pAPy0,
3506 unsigned char *drcssubp, unsigned char *gdrcssubp,
3507 signed char *endcol, TextPageAttr_t *attrPassive, unsigned char* pagedata, unsigned char* PageChar, TextPageAttr_t* PageAtrb)
3509 int iAddress = (iOData ) & 0x3f;
3510 int iMode = (iOData >> 6) & 0x1f;
3511 int iData = (iOData >> 11) & 0x7f;
3513 if (iAddress < 40) /* column addresses */
3515 int offset; /* offset to PageChar and PageAtrb */
3518 *pAPx = iAddress; /* new Active Column */
3519 offset = (*pAPy0 + *pAPy) * 40 + *pAPx0 + *pAPx; /* offset to PageChar and PageAtrb */
3524 if (0 == (iData>>5))
3526 int newcolor = iData & 0x1f;
3527 if (*endcol < 0) /* passive object */
3528 attrPassive->fg = newcolor;
3529 else if (*endcol == 40) /* active object */
3531 TextPageAttr_t *p = &PageAtrb[offset];
3532 int oldcolor = (p)->fg; /* current color (set-after) */
3533 int c = *pAPx0 + *pAPx; /* current column absolute */
3539 } while (c < 40 && p->fg == oldcolor); /* stop at change by level 1 page */
3541 else /* adaptive object */
3543 TextPageAttr_t *p = &PageAtrb[offset];
3544 int c = *pAPx; /* current column relative to object origin */
3550 } while (c <= *endcol);
3557 PageChar[offset] = iData;
3558 if (*endcol < 0) /* passive object */
3560 attrPassive->charset = C_G1C; /* FIXME: separated? */
3561 PageAtrb[offset] = *attrPassive;
3563 else if (PageAtrb[offset].charset != C_G1S)
3564 PageAtrb[offset].charset = C_G1C; /* FIXME: separated? */
3569 PageChar[offset] = iData;
3570 if (*endcol < 0) /* passive object */
3572 attrPassive->charset = C_G3;
3573 PageAtrb[offset] = *attrPassive;
3576 PageAtrb[offset].charset = C_G3;
3579 if (0 == (iData>>5))
3581 int newcolor = iData & 0x1f;
3582 if (*endcol < 0) /* passive object */
3583 attrPassive->bg = newcolor;
3584 else if (*endcol == 40) /* active object */
3586 TextPageAttr_t *p = &PageAtrb[offset];
3587 int oldcolor = (p)->bg; /* current color (set-after) */
3588 int c = *pAPx0 + *pAPx; /* current column absolute */
3592 if (newcolor == TXT_ColorBlack)
3593 p->IgnoreAtBlackBgSubst = 1;
3596 } while (c < 40 && p->bg == oldcolor); /* stop at change by level 1 page */
3598 else /* adaptive object */
3600 TextPageAttr_t *p = &PageAtrb[offset];
3601 int c = *pAPx; /* current column relative to object origin */
3605 if (newcolor == TXT_ColorBlack)
3606 p->IgnoreAtBlackBgSubst = 1;
3609 } while (c <= *endcol);
3617 if ((iData & 0x60) != 0) break; // reserved data field
3618 if (*endcol < 0) /* passive object */
3620 attrPassive->flashing=iData & 0x1f;
3621 PageAtrb[offset] = *attrPassive;
3624 PageAtrb[offset].flashing=iData & 0x1f;
3627 if (*endcol < 0) /* passive object */
3629 attrPassive->setG0G2=iData & 0x3f;
3630 PageAtrb[offset] = *attrPassive;
3633 PageAtrb[offset].setG0G2=iData & 0x3f;
3636 PageChar[offset] = iData;
3637 if (*endcol < 0) /* passive object */
3639 attrPassive->charset = C_G0P; /* FIXME: secondary? */
3640 attrPassive->setX26 = 1;
3641 PageAtrb[offset] = *attrPassive;
3645 PageAtrb[offset].charset = C_G0P; /* FIXME: secondary? */
3646 PageAtrb[offset].setX26 = 1;
3649 // case 0x0b: (see 0x02)
3652 int conc = (iData & 0x04);
3653 int inv = (iData & 0x10);
3654 int dw = (iData & 0x40 ?1:0);
3655 int dh = (iData & 0x01 ?1:0);
3656 int sep = (iData & 0x20);
3657 int bw = (iData & 0x02 ?1:0);
3658 if (*endcol < 0) /* passive object */
3662 attrPassive->concealed = 1;
3663 attrPassive->fg = attrPassive->bg;
3665 attrPassive->inverted = (inv ? 1- attrPassive->inverted : 0);
3666 attrPassive->doubleh = dh;
3667 attrPassive->doublew = dw;
3668 attrPassive->boxwin = bw;
3669 if (bw) attrPassive->IgnoreAtBlackBgSubst = 0;
3672 if (attrPassive->charset == C_G1C)
3673 attrPassive->charset = C_G1S;
3675 attrPassive->underline = 1;
3679 if (attrPassive->charset == C_G1S)
3680 attrPassive->charset = C_G1C;
3682 attrPassive->underline = 0;
3688 int c = *pAPx0 + (*endcol == 40 ? *pAPx : 0); /* current column */
3690 TextPageAttr_t *p = &PageAtrb[offset];
3693 p->inverted = (inv ? 1- p->inverted : 0);
3701 if (p->charset == C_G1C)
3708 if (p->charset == C_G1S)
3716 if (bw) p->IgnoreAtBlackBgSubst = 0;
3720 } while (c < *endcol);
3725 PageChar[offset] = iData & 0x3f;
3726 if (*endcol < 0) /* passive object */
3728 attrPassive->charset = C_OFFSET_DRCS + ((iData & 0x40) ? (0x10 + *drcssubp) : *gdrcssubp);
3729 PageAtrb[offset] = *attrPassive;
3732 PageAtrb[offset].charset = C_OFFSET_DRCS + ((iData & 0x40) ? (0x10 + *drcssubp) : *gdrcssubp);
3735 PageChar[offset] = iData;
3736 if (*endcol < 0) /* passive object */
3738 attrPassive->charset = C_G2;
3739 PageAtrb[offset] = *attrPassive;
3742 PageAtrb[offset].charset = C_G2;
3745 if (iMode == 0x10 && iData == 0x2a)
3749 PageChar[offset] = iData;
3750 if (*endcol < 0) /* passive object */
3752 attrPassive->charset = C_G0P;
3753 attrPassive->diacrit = iMode & 0x0f;
3754 attrPassive->setX26 = 1;
3755 PageAtrb[offset] = *attrPassive;
3759 PageAtrb[offset].charset = C_G0P;
3760 PageAtrb[offset].diacrit = iMode & 0x0f;
3761 PageAtrb[offset].setX26 = 1;
3764 break; /* unsupported or not yet implemented mode: ignore */
3765 } /* switch (iMode) */
3767 else /* ================= (iAddress >= 40): row addresses ====================== */
3772 if (0 == (iData>>5))
3774 m_txtCache->FullScrColor = iData & 0x1f;
3778 if (*endcol == 40) /* active object */
3780 *pAPy = RowAddress2Row(iAddress); /* new Active Row */
3782 int color = iData & 0x1f;
3783 int row = *pAPy0 + *pAPy;
3786 if (row <= 24 && 0 == (iData>>5))
3788 else if (3 == (iData>>5))
3792 for (; row <= maxrow; row++)
3793 m_txtCache->FullRowColor[row] = color;
3798 *pAPy = RowAddress2Row(iAddress); /* new Active Row */
3800 *pAPx = iData; /* new Active Column */
3801 *endcol = -1; /* FIXME: check if row changed? */
3804 if (iAddress == 0x3f)
3806 *pAPx = *pAPy = 0; /* new Active Position 0,0 */
3807 if (*endcol == 40) /* active object */
3809 int color = iData & 0x1f;
3810 int row = *pAPy0; // + *pAPy;
3813 if (row <= 24 && 0 == (iData>>5))
3815 else if (3 == (iData>>5))
3819 for (; row <= maxrow; row++)
3820 m_txtCache->FullRowColor[row] = color;
3836 m_txtCache->tAPy = iAddress - 40;
3837 m_txtCache->tAPx = iData;
3842 if (iAddress & 0x10) /* POP or GPOP */
3844 unsigned char APx = 0, APy = 0;
3845 unsigned char APx0 = *pAPx0 + *pAPx + m_txtCache->tAPx, APy0 = *pAPy0 + *pAPy + m_txtCache->tAPy;
3846 int triplet = 3 * ((iData >> 5) & 0x03) + (iMode & 0x03);
3847 int packet = (iAddress & 0x03) + 1;
3848 int subp = iData & 0x0f;
3849 int high = (iData >> 4) & 0x01;
3852 if (APx0 < 40) /* not in side panel */
3854 Eval_NumberedObject((iAddress & 0x08) ? m_txtCache->gpop : m_txtCache->pop, subp, packet, triplet, high, &APx, &APy, &APx0, &APy0, PageChar,PageAtrb);
3857 else if (iAddress & 0x08) /* local: eval invoked object */
3859 unsigned char APx = 0, APy = 0;
3860 unsigned char APx0 = *pAPx0 + *pAPx + m_txtCache->tAPx, APy0 = *pAPy0 + *pAPy + m_txtCache->tAPy;
3861 int descode = ((iAddress & 0x01) << 3) | (iData >> 4);
3862 int triplet = iData & 0x0f;
3864 if (APx0 < 40) /* not in side panel */
3866 Eval_Object(13 * 23 + 13 * descode + triplet, pstCachedPage, &APx, &APy, &APx0, &APy0, (tObjType)(triplet % 3), pagedata, PageChar, PageAtrb);
3873 if (0 == (iAddress & 0x08)) /* Object Definition illegal or only level 3.5 */
3876 m_txtCache->tAPx = m_txtCache->tAPy = 0;
3878 return 0xFF; /* termination by object definition */
3881 if (0 == (iData & 0x10)) /* DRCS Mode reserved or only level 3.5 */
3885 *drcssubp = iData & 0x0f;
3887 *gdrcssubp = iData & 0x0f;
3890 m_txtCache->tAPx = m_txtCache->tAPy = 0;
3892 return 0x80 | iData; /* explicit termination */
3895 break; /* unsupported or not yet implemented mode: ignore */
3896 } /* switch (iMode) */
3897 } /* (iAddress >= 40): row addresses */
3899 if (iAddress < 40 || iMode != 0x10) /* leave temp. AP-Offset unchanged only immediately after definition */
3900 m_txtCache->tAPx = m_txtCache->tAPy = 0;
3902 return 0; /* normal exit, no termination */
3905 /* get object data */
3906 /* in: absolute triplet number (0..506, start at packet 3 byte 1) */
3907 /* in: pointer to cache struct of page data */
3908 /* out: 18 bit triplet data, <0 if invalid number, not cached, or hamming error */
3909 int CTeletextDecoder::iTripletNumber2Data(int iONr, TextCachedPage_t *pstCachedPage, unsigned char* pagedata)
3911 if (iONr > 506 || 0 == pstCachedPage)
3915 int packet = (iONr / 13) + 3;
3916 int packetoffset = 3 * (iONr % 13);
3919 p = pagedata + 40*(packet-1) + packetoffset + 1;
3920 else if (packet <= 25)
3922 if (0 == pstCachedPage->pageinfo.p24)
3924 p = pstCachedPage->pageinfo.p24 + 40*(packet-24) + packetoffset + 1;
3928 int descode = packet - 26;
3929 if (0 == pstCachedPage->pageinfo.ext)
3931 if (0 == pstCachedPage->pageinfo.ext->p26[descode])
3933 p = pstCachedPage->pageinfo.ext->p26[descode] + packetoffset; /* first byte (=designation code) is not cached */
3935 return CDVDTeletextTools::deh24(p);
3938 int CTeletextDecoder::SetNational(unsigned char sec)
3943 return NAT_PL; //polish
3946 return NAT_TR; //turkish
3948 return NAT_SR; //serbian, croatian, slovenian
3950 return NAT_SC; // serbian, croatian
3952 return NAT_RB; // russian, bulgarian
3954 return NAT_UA; // ukrainian
3956 return NAT_ET; // estonian
3958 return NAT_LV; // latvian, lithuanian
3960 return NAT_GR; // greek
3962 return NAT_HB; // hebrew
3965 return NAT_AR; // arabic
3967 return CountryConversionTable[sec & 0x07];
3970 int CTeletextDecoder::NextHex(int i) /* return next existing non-decimal page number */
3973 if (startpage < 0x100)
3983 } while ((m_txtCache->SubPageTable[i] == 0xFF) || IsDec(i));
3987 void CTeletextDecoder::SetColors(unsigned short *pcolormap, int offset, int number)
3989 int j = offset; /* index in global color table */
3991 for (int i = 0; i < number; i++)
3993 int r = ((pcolormap[i] >> 8) & 0xf) << 4;
3994 int g = ((pcolormap[i] >> 4) & 0xf) << 4;
3995 int b = ((pcolormap[i]) & 0xf) << 4;
3997 if (m_RenderInfo.rd0[j] != r)
3999 m_RenderInfo.rd0[j] = r;
4001 if (m_RenderInfo.gn0[j] != g)
4003 m_RenderInfo.gn0[j] = g;
4005 if (m_RenderInfo.bl0[j] != b)
4007 m_RenderInfo.bl0[j] = b;
4013 color_t CTeletextDecoder::GetColorRGB(enumTeletextColor ttc)
4017 case TXT_ColorBlack: return 0xFF000000;
4018 case TXT_ColorRed: return 0xFFFC1414;
4019 case TXT_ColorGreen: return 0xFF24FC24;
4020 case TXT_ColorYellow: return 0xFFFCC024;
4021 case TXT_ColorBlue: return 0xFF0000FC;
4022 case TXT_ColorMagenta: return 0xFFB000FC;
4023 case TXT_ColorCyan: return 0xFF00FCFC;
4024 case TXT_ColorWhite: return 0xFFFCFCFC;
4025 case TXT_ColorTransp: return 0x00000000;
4029 /* Get colors for CLUTs 2+3 */
4030 int index = (int)ttc;
4031 color_t color = (m_RenderInfo.tr0[index] << 24) |
4032 (m_RenderInfo.bl0[index] << 16) |
4033 (m_RenderInfo.gn0[index] << 8) |
4034 m_RenderInfo.rd0[index];