MHEG-5  19.3.0
MHEG-5 Documentation
mg_drawtext.c
Go to the documentation of this file.
1 /*******************************************************************************
2  * Copyright © 2014 The DTVKit Open Software Foundation Ltd (www.dtvkit.org)
3  * Copyright © 2008 Ocean Blue Software Ltd
4  *
5  * This file is part of a DTVKit Software Component
6  * You are permitted to copy, modify or distribute this file subject to the terms
7  * of the DTVKit 1.0 Licence which can be found in licence.txt or at www.dtvkit.org
8  *
9  * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
10  * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES
11  * OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
12  *
13  * If you or your organisation is not a member of DTVKit then you have access
14  * to this source code outside of the terms of the licence agreement
15  * and you are expected to delete this and any associated files immediately.
16  * Further information on DTVKit, membership and terms can be found at www.dtvkit.org
17  *******************************************************************************/
25 /*---includes for this file--------------------------------------------------*/
26 #include <stdio.h>
27 #include <string.h>
28 
29 #include "stb_osd.h"
30 #include "mg_font.h"
31 
32 #include "mg_drawtext.h"
33 #include "glue_memory.h"
34 #include "glue_debug.h"
35 #include "mg_osd.h"
36 #include "osd_utils.h" /* for RGBT() */
37 #include "glue_assert.h"
38 #include "glue_debug.h" /* for TRACE */
39 
40 #ifdef HK_PROFILE
41 #include "mg_hkfont.h"
42 #endif
43 
44 /*---constant definitions for this file--------------------------------------*/
45 
46 #define COLOUR_STACK_SIZE 18
47 
48 #ifdef OSD_8_BIT
49  #define TRANSPARENT_COLOUR OFFSET_TRANS
50 #else
51  #define TRANSPARENT_COLOUR 0
52 #endif
53 
54 /* Unicode control characters: non-printable */
55 #define U_CTRL_NULL 0x00
56 #define U_CTRL_A 0x01
57 #define U_CTRL_B 0x02
58 #define U_CTRL_C 0x03
59 #define U_CTRL_D 0x04
60 #define U_CTRL_E 0x05
61 #define U_CTRL_F 0x06
62 #define U_CTRL_G 0x07
63 #define U_CTRL_H 0x08
64 #define U_CTRL_K 0x0B
65 #define U_CTRL_L 0x0C
66 #define U_CTRL_N 0x0E
67 #define U_CTRL_O 0x0F
68 #define U_CTRL_P 0x10
69 #define U_CTRL_Q 0x11
70 #define U_CTRL_R 0x12
71 #define U_CTRL_S 0x13
72 #define U_CTRL_T 0x14
73 #define U_CTRL_U 0x15
74 #define U_CTRL_V 0x16
75 #define U_CTRL_W 0x17
76 #define U_CTRL_X 0x18
77 #define U_CTRL_Y 0x19
78 #define U_CTRL_Z 0x1A
79 #define U_CTRL_FS 0x1C
80 #define U_CTRL_GS 0x1D
81 #define U_CTRL_RS 0x1E
82 #define U_CTRL_US 0x1F
83 
84 /* Unicode character values */
85 #define UNICODE_SPACE (' ')
86 #define UNICODE_TAB ('\t')
87 #define UNICODE_LF (0x0a)
88 #define UNICODE_CR (0x0d)
89 #define UNICODE_ESC (0x1b)
90 #define UNICODE_HARD_SPACE (0xa0)
91 #define UNICODE_FIGURE_SPACE (0x2007)
92 #define UNICODE_APOSTROPHE_N (0x0149)
93 #define UNICODE_HYPER_ANCHOR_START (0x41)
94 #define UNICODE_HYPER_ANCHOR_END (0x61)
95 #define UNICODE_TEXT_COLOUR_START (0x43)
96 #define UNICODE_TEXT_COLOUR_END (0x63)
97 #define UNICODE_HYPER_ATTRIB_START (0x44)
98 #define UNICODE_HYPER_ATTRIB_END (0x64)
99 
100 
101 /**** this ONLY work for ascii chars '!' - '~' (i.e. cached chars)
102  **** in the Tiresias font files ***/
103 #define GLYPH_NDX(x) (x - 30)
104 /****/
105 
106 #define MAX_NUM_LINES 32
107 #define MAX_NUM_CHARS 64
108 
109 #define PNTS_LS_LEN(tls) ((tls + 255) >> 8)
110 #define MTRC_POSN(mll, tls, mr, fsz) mll + (PNTS_LS_LEN(tls) * mr) / fsz
111 
112 /* conversion calculations for local copy of S_PROPERTIES */
113 /* letter spaces plus width of chars - in metric units */
114 #define S_METRIC_POSITION(pp) MTRC_POSN(pp.metric_line_length, pp.total_letter_space, pp.metric_resn, pp.pnts_font_size)
115 /* letter spaces plus width of chars - in points */
116 #define S_POINTS_POSITION(pp) PNTS_LS_LEN(pp.total_letter_space) + ((pp.metric_line_length * pp.pnts_font_size + pp.metric_resn - 1) / pp.metric_resn)
117 /* letter spaces plus width of chars - in SD pixels */
118 #define S_SPIXEL_POSITION(pp) (((((S_POINTS_POSITION(pp)) * 45) + pp.pixel_par_x - 1) / pp.pixel_par_x) + pp.spxl_tab_start)
119 
120 /* conversion calculations for pointer to S_PROPERTIES */
121 /*convert to SD pixels*/
122 #define P_PNTS_2_SPXL(pp, pts) ((((pts) * 45) + pp->pixel_par_x - 1) / pp->pixel_par_x)
123 #define P_MTRC_2_PNTS(pp, mtr) ((mtr) * pp->pnts_font_size + pp->metric_resn - 1) / pp->metric_resn
124 #define P_MTRC_2_SPXL(pp, mtr) P_PNTS_2_SPXL(pp, P_MTRC_2_PNTS(pp, mtr))
125 /* letter spaces plus width of chars - in metric units */
126 #define P_METRIC_POSITION(pp) MTRC_POSN(pp->metric_line_length, pp->total_letter_space, pp->metric_resn, pp->pnts_font_size)
127 /* letter spaces plus width of chars - in points */
128 #define P_POINTS_POSITION(pp) PNTS_LS_LEN(pp->total_letter_space) + ((pp->metric_line_length * pp->pnts_font_size + pp->metric_resn - 1) / pp->metric_resn)
129 /* letter spaces plus width of chars - in SD pixels */
130 #define P_SPIXEL_POSITION(pp) (((((P_POINTS_POSITION(pp)) * 45) + pp->pixel_par_x - 1) / pp->pixel_par_x) + pp->spxl_tab_start)
131 
132 
133 /*---local typedef structs for this file-------------------------------------*/
134 
135 typedef struct _LineLimit
136 {
137  S32BIT position;
138  S32BIT l_width;
139  U16BIT line_num;
140  U16BIT start_ndx;
141  U16BIT end_ndx;
142 } LineLimit;
143 
144 typedef struct _CharData
145 {
146  S32BIT real_position;
147  S32BIT mtrc_position;
148  S16BIT mtrc_advance;
149  U16BIT uni_chr;
150  U16BIT gf_ndx;
151  OSDColor colour;
152  #ifdef TRACE
153  S16BIT spxl_end;
154  #endif
155  U8BIT width;
156 } CharData;
157 
158 typedef enum
159 {
160  NO_BREAK,
161  HAD_BREAK,
162  BREAKING,
163  NEW_LINE,
164  OVER_RUN
165 } EBreakState;
166 
167 typedef struct s_properties
168 {
169  S32BIT hpxl_last_tab,
170  hpxl_pen_posn,
171  hpxl_line_end,
172  metric_resn,
173  metric_line_length,
174  spxl_tab_start,
175  pnts_tab_start,
176  hpxl_letter_offset,
177  total_letter_space,
178  break_letter_space,
179  metric_break_length,
180  pnts_font_size,
181  pixel_par_x,
182  m_to_pix_mlt,
183  m_to_pix_div;
184  S_FontSize *p_font_size;
185  FT_UInt glyph_index,
186  glyph_last;
187  LineLimit *p_current_line;
188  LineLimit break_line;
189  //EBreakState break_state;
190  //CharData* char_data;
191  U16BIT spxl_box_width,
192  hpxl_box_width;
193  S16BIT font_index;
194  S8BIT char_adv,
195  char_left;
196  U8BIT font_style;
197 } S_PROPERTIES;
198 
199 /*---local (static) variable declarations for this file----------------------*/
200 
201 /*---local function definitions----------------------------------------------*/
202 
203 #ifdef TRACING
204 
208 static void traceLine( LineLimit *pLine, CharData *chars, U32BIT f_size, U32BIT m_res )
209 {
210  char str[80];
211  CharData *p_chr;
212  U32BIT mposn, sposn;
213  U16BIT nx;
214  char *pch;
215 
216  for (nx = pLine->start_ndx, pch = str; nx != pLine->end_ndx && pch != str + 79; nx++, pch++)
217  {
218  *pch = (char)chars[nx].uni_chr;
219  }
220  *pch = 0;
221  DBG_PRINTF( "Line %d: start=%ld width=%d start=%d end=%d F-Size=%d M-Res=%d\n",
222  pLine->line_num, pLine->position, pLine->l_width, pLine->start_ndx, pLine->end_ndx, f_size, m_res );
223  DBG_PRINTF( "%s\n", str);
224  nx = pLine->start_ndx;
225  p_chr = chars + nx;
226  while (nx != pLine->end_ndx)
227  {
228  //tmp = (p_chr->spxl_end * 45 * mg_ctxt.screen_x_factor) / (mg_ctxt.normal_x_factor * 56);
229  mposn = p_chr->mtrc_position + p_chr->mtrc_advance;
230  sposn = ((mposn * f_size) + m_res - 1) / m_res;
231  sposn = ((sposn * 45) + 55) / 56; // assuming plain text
232  DBG_PRINTF( "(%c,%ld,%d,%d,%d) ", p_chr->uni_chr, p_chr->real_position - pLine->position, p_chr->width, mposn, sposn);
233  nx++;
234  p_chr++;
235  }
236  DBG_PRINTF( "\n");
237 }
238 
243 static void trace_lines( U16BIT total, LineLimit *lines, CharData *chars, U32BIT f_size, U32BIT m_res )
244 {
245  U16BIT line_num = 0;
246  while (line_num != total)
247  {
248  if (line_num == lines->line_num)
249  {
250  traceLine( lines, chars, f_size, m_res );
251  lines++;
252  }
253  line_num++;
254  }
255 }
256 
257 #endif /*TRACING*/
258 
267 static U16BIT ProcessMarkup( U16BIT *data, OSDColor *cStack, U8BIT *cCount, pHyperAttribs ha )
268 {
269  U16BIT mu_length = 0;
270  if ((*data <= 0x5e) && (*data >= 0x40))
271  {
272  mu_length = data[1] + 1; /* add 1 for the 'length' byte itself */
273  }
274  switch (*data)
275  {
276  case UNICODE_HYPER_ANCHOR_START:
277  if ((ha != NULL) && (*cCount < COLOUR_STACK_SIZE))
278  {
279  ha->number_of_links++;
280  if (ha->markup_state == 0)
281  {
282  ha->markup_state = 2;
283  }
284  else
285  {
286  ha->markup_state++;
287  }
288  ha->save_colour = *cCount;
289  (*cCount)++;
290  /*Note: focus_position should be zero when not interacting so no need for testing (ha->interacting)*/
291  if (ha->focus_position == ha->number_of_links)
292  {
293  cStack[*cCount] = ha->active_colour;
294  }
295  else
296  {
297  cStack[*cCount] = ha->link_colour;
298  }
299  }
300  break;
301 
302  case UNICODE_TEXT_COLOUR_START:
303  if ((mu_length == 5) && (*cCount < COLOUR_STACK_SIZE))
304  {
305  /* correct length byte, so extract the new text colour from the markup */
306  cStack[++(*cCount)] = RGBT( data[2], data[3], data[4], data[5] );
307  }
308  break;
309 
310  case UNICODE_HYPER_ATTRIB_START:
311  if ((ha != NULL) && (mu_length > 1) && (ha->markup_state == 0))
312  {
313  U16BIT mu_lft = mu_length - 2;
314  U16BIT mu_ind = data[2];
315  if (mu_ind & 0x08)
316  {
317  ha->anchor_wrap = TRUE;
318  }
319  else
320  {
321  ha->anchor_wrap = FALSE;
322  }
323  data += 3;
324  if ((mu_ind & 0x40) && (mu_lft > 3))
325  {
326  ha->link_colour = RGBT( data[0], data[1], data[2], data[3] );
327  data += 4;
328  mu_lft -= 4;
329  }
330  if ((mu_ind & 0x20) && (mu_lft > 3))
331  {
332  ha->active_colour = RGBT( data[0], data[1], data[2], data[3] );
333  data += 4;
334  mu_lft -= 4;
335  }
336  if ((mu_ind & 0x10) && (mu_lft > 3))
337  {
338  ha->visit_colour = RGBT( data[0], data[1], data[2], data[3] );
339  }
340  }
341  break;
342 
343  case UNICODE_HYPER_ANCHOR_END:
344  if ((ha != NULL) && (ha->markup_state > 1))
345  {
346  ha->markup_state--;
347  *cCount = ha->save_colour;
348  }
349  break;
350 
351  case UNICODE_TEXT_COLOUR_END:
352  if ((ha != NULL) && (ha->markup_state > 1))
353  {
354  if (ha->save_colour)
355  ha->save_colour--;
356  }
357  else
358  {
359  if (*cCount > 0)
360  (*cCount)--;
361  }
362  break;
363 
364  case UNICODE_HYPER_ATTRIB_END:
365  default:
366  break;
367  }
368  if ((ha != NULL) && (ha->markup_state == 0))
369  {
370  ha->markup_state = 1;
371  }
372  return mu_length;
373 }
374 
380 static void doExtraKernHD( S_PROPERTIES *pp )
381 {
382  U32BIT fsz = pp->pnts_font_size;
383  switch (pp->glyph_last)
384  {
385  case GLYPH_NDX('f'):
386  if (pp->glyph_index == GLYPH_NDX('t'))
387  {
388  /* Otherwise f and t touch in HD */
389  pp->hpxl_pen_posn++;
390  if (fsz == 36)
391  {
392  pp->hpxl_pen_posn++;
393  }
394  }
395  break;
396 
397  default:;
398  }
399 }
400 
406 static void doExtraKernSD( S_PROPERTIES *pp )
407 {
408  U32BIT fsz = pp->pnts_font_size;
409  switch (pp->glyph_last)
410  {
411  case GLYPH_NDX('a'):
412  switch (pp->glyph_index)
413  {
414  case GLYPH_NDX('f'):
415  /*any screen, test 5.5.9 for "waft"*/
416  pp->hpxl_pen_posn--;
417  break;
418 
419  case GLYPH_NDX('r'):
420  if (fsz == 26)
421  {
422  /*any screen, test 3.12.8 for "mark"*/
423  pp->hpxl_pen_posn--;
424  }
425  default:;
426  }
427  break;
428 
429  case GLYPH_NDX('d'):
430  if (pp->glyph_index == GLYPH_NDX('e'))
431  {
432  /*any screen, test 3.12.7 for "BitmapDecodeOffset test:"*/
433  pp->hpxl_pen_posn--;
434  }
435  break;
436 
437  case GLYPH_NDX('e'):
438  switch (pp->glyph_index)
439  {
440  case GLYPH_NDX('f'):
441  /* SD screen: otherwise test ISO 03 T69 scene 10 'refer' loses 'r' */
442  pp->hpxl_pen_posn -= 2;
443  break;
444  case GLYPH_NDX('l'):
445  /*any screen, test 5.5.9 for "rely"*/
446  pp->hpxl_pen_posn--;
447  break;
448  case GLYPH_NDX('t'):
449  /* just coz SD screen had some over-long words */
450  pp->hpxl_pen_posn--;
451  break;
452  default:;
453  }
454  break;
455 
456  case GLYPH_NDX('f'):
457  if (pp->glyph_index == GLYPH_NDX('t'))
458  {
459  /* Otherwise f and t touch in SD */
460  pp->hpxl_pen_posn++;
461  if (fsz == 36)
462  {
463  pp->hpxl_pen_posn++;
464  }
465  }
466  else if ((pp->glyph_index == GLYPH_NDX('i')) ||
467  (pp->glyph_index == GLYPH_NDX('l')))
468  {
469  if (fsz == 24)
470  {
471  /* Otherwise f and (i or l) touch in SD */
472  pp->hpxl_pen_posn++;
473  }
474  }
475  break;
476 
477  case GLYPH_NDX('i'):
478  if ((pp->glyph_index == GLYPH_NDX('f')) ||
479  (pp->glyph_index == GLYPH_NDX('t'))
480  )
481  {
482  if (fsz == 24)
483  {
484  pp->hpxl_pen_posn--;
485  }
486  }
487  break;
488 
489  case GLYPH_NDX('n'):
490  if (pp->glyph_index == GLYPH_NDX('k'))
491  {
492  /*any screen, in test 5.5.9 for "junk"*/
493  pp->hpxl_pen_posn--;
494  }
495  break;
496 
497  case GLYPH_NDX('o'):
498  switch (pp->glyph_index)
499  {
500  case GLYPH_NDX('c'):
501  /*any screen, test 5.5.6.2 for "octal"*/
502  pp->hpxl_pen_posn--;
503  break;
504 
505  case GLYPH_NDX('f'):
506  /*any screen, coz it looks beter */
507  pp->hpxl_pen_posn--;
508  break;
509  case GLYPH_NDX('m'):
510  /*SD screen, test 5.5.9 for "room" */
511  pp->hpxl_pen_posn--;
512  break;
513  default:;
514  }
515  break;
516 
517  case GLYPH_NDX('p'):
518  if (pp->glyph_index == GLYPH_NDX('D'))
519  {
520  /*SD screen, test 3.12.7 for "BitmapDecodeOffset test:"*/
521  pp->hpxl_pen_posn--;
522  }
523  break;
524 
525  case GLYPH_NDX('r'):
526  switch (pp->glyph_index)
527  {
528  case GLYPH_NDX('e'):
529  /* SD screen: otherwise test ISO 03 T69 scene 10 'refer' loses 'r' */
530  pp->hpxl_pen_posn--;
531  break;
532  case GLYPH_NDX('s'):
533  /* otherwise gap too big */
534  pp->hpxl_pen_posn--;
535  break;
536  default:;
537  }
538  break;
539 
540  case GLYPH_NDX('s'):
541  if (pp->glyph_index == GLYPH_NDX('t'))
542  {
543  /*SD screen, test 3.12.7 for "BitmapDecodeOffset test:"*/
544  pp->hpxl_pen_posn--;
545  }
546  break;
547 
548  case GLYPH_NDX('u'):
549  if (pp->glyph_index == GLYPH_NDX('n'))
550  {
551  /*any screen, in test 5.5.9 for "junk"*/
552  pp->hpxl_pen_posn--;
553  }
554  break;
555 
556  case GLYPH_NDX('w'):
557  if (pp->glyph_index == GLYPH_NDX('a') && (fsz == 31))
558  {
559  /*any screen, test 5.5.9 for "waft"*/
560  pp->hpxl_pen_posn--;
561  }
562  break;
563 
564  case GLYPH_NDX('t'):
565  case GLYPH_NDX('T'):
566  if (pp->glyph_index == GLYPH_NDX('h'))
567  {
568  if (fsz == 24)
569  {
570  pp->hpxl_pen_posn++;
571  }
572  }
573  break;
574 
575  default:;
576  } /*hctiws*/
577 }
578 
579 static void AddLetterSpace(S_PROPERTIES *pp, S32BIT tls)
580 {
581  pp->total_letter_space += tls;
582  if (pp->total_letter_space > 0)
583  {
584  tls = ((pp->m_to_pix_mlt * pp->total_letter_space) + (pp->m_to_pix_div - 1)) / pp->m_to_pix_div;
585  /* according to UK profile sec 5.5.5.2, must do round up for the divide by 256 */
586  tls = (tls + 255) / 256;
587  }
588  else
589  {
590  tls = ((pp->m_to_pix_mlt * pp->total_letter_space) - (pp->m_to_pix_div - 1)) / pp->m_to_pix_div;
591  tls = (tls - 255) / 256;
592  }
593  if (pp->hpxl_letter_offset != tls)
594  {
595  pp->hpxl_pen_posn += tls - pp->hpxl_letter_offset;
596  pp->hpxl_letter_offset = tls;
597  }
598 }
599 
605 static void DoTheKerning( pDrawTextAttrib attrib, S_FontDetails *ftd_ptr, S_PROPERTIES *pp )
606 {
607  FT_Vector kerning;
608 
609  if (pp->glyph_last && attrib->letter_space)
610  {
611  AddLetterSpace(pp,attrib->letter_space);
612  }
613 
614  if (ftd_ptr->face_type == FTYPE_PFR)
615  {
616  if (FT_Get_PFR_Kerning(ftd_ptr->face, pp->glyph_last, pp->glyph_index, &kerning) == 0 &&
617  kerning.x != 0)
618  {
619  pp->metric_line_length += kerning.x;
620  kerning.x *= pp->m_to_pix_mlt * pp->pnts_font_size;
621  kerning.y = ftd_ptr->metric_resolution * pp->m_to_pix_div;
622  if (kerning.x < 0)
623  {
624  kerning.x -= kerning.y >> 1;
625  }
626  else
627  {
628  kerning.x += kerning.y >> 2;
629  }
630  pp->hpxl_pen_posn += kerning.x / kerning.y;
631  }
632  }
633  else if (pp->glyph_last != 0)
634  {
635  if (pp->glyph_last != ftd_ptr->glyph_ndx_space)
636  {
637  if (FT_Get_Kerning(ftd_ptr->face, pp->glyph_last, pp->glyph_index, FT_KERNING_UNSCALED, &kerning) == 0)
638  {
639  /* kerning.x in original font units */
640  if (kerning.x != 0)
641  {
642  pp->metric_line_length += kerning.x;
643  kerning.x *= pp->m_to_pix_mlt * pp->pnts_font_size;
644  kerning.y = ftd_ptr->metric_resolution * pp->m_to_pix_div;
645  if (kerning.x < 0)
646  {
647  kerning.x -= kerning.y >> 1;
648  }
649  else
650  {
651  kerning.x += kerning.y >> 2;
652  }
653  pp->hpxl_pen_posn += kerning.x / kerning.y;
654  }
655  }
656  }
657  }
658  /* extra kerning here, to ensure we pass DTG tests
659  * without making the font smaller than it should be */
660  if (pp->font_style == 0 && /* PLAIN */
661  pp->font_index == BUILT_IN_FONT) /* UK Profile: tiresias font */
662  {
663  if (mg_hd_mode == NORMAL_SD)
664  doExtraKernSD( pp );
665  else
666  doExtraKernHD( pp );
667  }
668  pp->glyph_last = pp->glyph_index;
669 }
670 
676 static BOOLEAN LoadPrintableChar( S_FontDetails *ftd_ptr, S_FontSize *f_sz_data,
677  S_PROPERTIES *pp, U16BIT u_chr, CharData *char_data )
678 {
679  FT_Face the_face = ftd_ptr->face;
680  FT_Int32 load_flags;
681 
682  /* First check that FT is using the right font size */
683  if (ftd_ptr->current_fnt_id != f_sz_data->fnt_id)
684  {
685  if (FT_Set_Char_Size( the_face, f_sz_data->width, f_sz_data->height, 72, 72 ) != 0)
686  {
687  TRACE(TERROR, ("FT_Set_Char_Size FAILED: w=%u, h=%u\n", f_sz_data->width, f_sz_data->height))
688  return FALSE;
689  }
690  ftd_ptr->current_fnt_id = f_sz_data->fnt_id;
691  }
692  if (char_data->mtrc_advance == 0) /* when this has non-zero value, it's cachable char but no room for cache */
693  {
694  if (ftd_ptr->face_type == FTYPE_PFR)
695  {
696  FT_Pos advance;
697 
698  if (FT_Get_PFR_Advance( the_face, pp->glyph_index, &advance ) != 0)
699  {
700  TRACE(TERROR, ("FT_Get_PFR_Advance FAILED: gi=%u\n", pp->glyph_index))
701  return FALSE;
702  }
703  else
704  {
705  char_data->mtrc_advance = (S16BIT)advance;
706  }
707  }
708  else
709  {
710  if (FT_Load_Glyph( the_face, pp->glyph_index, FT_LOAD_NO_SCALE ) != 0)
711  {
712  TRACE(TERROR, ("FT_Load_Glyph FAILED: gi=%u\n", pp->glyph_index))
713  return FALSE;
714  }
715  else
716  {
717  char_data->mtrc_advance = (S16BIT)the_face->glyph->metrics.horiAdvance;
718  }
719  }
720  }
721 
722  load_flags = FT_LOAD_RENDER;
723  /* Special cases to overcome a FreeType bug: for
724  * "Latin Small Letter A With Tilde U+00E3",
725  * "Latin Small Letter N With Tilde U+00F1" and
726  * "Latin Small Letter O With Tilde U+00F5"
727  * the "tilde" is rendered as a macron for small font sizes, when
728  * auto-hinting is enabled. We cannot always control the build options,
729  * so a special case is required.
730  */
731  if (u_chr == 0x00e3 || u_chr == 0x00f1 || u_chr == 0x00f5)
732  {
733  load_flags |= FT_LOAD_NO_AUTOHINT;
734  }
735  if (FT_Load_Glyph( the_face, pp->glyph_index, load_flags ) != 0)
736  {
737  return FALSE;
738  }
739 
740  char_data->uni_chr = u_chr;
741  char_data->gf_ndx = pp->glyph_index;
742  char_data->width = the_face->glyph->bitmap.width;
743  pp->char_left = the_face->glyph->bitmap_left;
744  switch (u_chr)
745  {
746  case 0x2215: /* divide */
747  if (ftd_ptr->font_ndx != BUILT_IN_FONT)
748  {
749  pp->char_adv = (S8BIT)((the_face->glyph->linearHoriAdvance + 0x7fff) >> 16);
750  break;
751  }
752  case 0xd7:
753  case 0xf7:
754  case 0x66b:
755  /* case UNICODE_FIGURE_SPACE: not neccessary */
756  case 0x2212:
757  case 0x2214:
758  /* This is a bit of a cheat for getting through the DTG test "5.10B Monospace chars", but
759  * it is quite reasonable. And it's only way to avoid mucking up the rendering elsewhere.
760  */
761  pp->char_adv = f_sz_data->figure_adv;
762  break;
763 
764  case 0x2713:
765  case 0x2717:
766  if ((the_face->glyph->linearHoriAdvance & 0x8000) &&
767  (ftd_ptr->current_fnt_id & 0xff) == 24 && pp->hpxl_last_tab == pp->hpxl_pen_posn)
768  {
769  pp->char_left--;
770  pp->hpxl_last_tab--;
771  pp->char_adv = (S8BIT)(the_face->glyph->linearHoriAdvance >> 16);
772  break;
773  }
774  default:
775  pp->char_adv = (S8BIT)((the_face->glyph->linearHoriAdvance + 0x7fff) >> 16);
776  }
777  return TRUE;
778 }
779 
785 static void InitialiseProperties( pDrawTextAttrib attrib, S_FontSize *f_sz_data, S_PROPERTIES *pp )
786 {
787  pp->glyph_last = 0;
788  pp->hpxl_line_end = 0;
789  pp->font_style = (U8BIT)((f_sz_data->fnt_id >> 8) & 0xFF);
790  if (pp->font_style & FONT_STYLE_NO_SCALE)
791  {
792  pp->m_to_pix_mlt = 1;
793  pp->m_to_pix_div = 1;
794  pp->pixel_par_x = 45;
795  }
796  else if ((pp->font_style & FONT_STYLE_SQUARE) && (mg_hd_mode != NORMAL_SD))
797  {
798  pp->m_to_pix_mlt = mg_ctxt.osd_y.mlt;
799  pp->m_to_pix_div = mg_ctxt.osd_y.div;
800  pp->pixel_par_x = 64;
801  }
802  else
803  {
804  pp->m_to_pix_mlt = mg_ctxt.osd_x.mlt * 9;
805  pp->m_to_pix_div = mg_ctxt.osd_y.div * 14;
806  pp->pixel_par_x = 56;
807  }
808  if ((attrib->justify & JFY_HZ_MASK) == JUSTIFY_H_START)
809  {
810  pp->hpxl_last_tab = f_sz_data->bound_box.left;
811  pp->pnts_tab_start = f_sz_data->pnts_xleftoffset;
812  pp->spxl_tab_start = f_sz_data->spxl_xleftoffset;
813  }
814  else
815  {
816  pp->hpxl_last_tab = 0;
817  pp->spxl_tab_start = 0;
818  }
819  pp->hpxl_pen_posn = pp->hpxl_last_tab;
820  pp->hpxl_letter_offset = 0;
821  pp->total_letter_space = 0;
822  pp->metric_line_length = 0;
823  pp->metric_break_length = 0;
824  pp->pnts_font_size = (S32BIT)f_sz_data->fnt_id & 0xFF;
825  pp->font_index = f_sz_data->fnt_id >> 16;
826 }
827 
833 static void MoveTabPosition( S_PROPERTIES *pp )
834 {
835  S32BIT new_posn;
836  /* get sd pixels, and add xLeftOffset since
837  * "tab logically advances the rendering of the text by at least the width xOffsetLeft" */
838  new_posn = P_SPIXEL_POSITION(pp) + pp->p_font_size->spxl_xleftoffset;
839  /* round up to new tab position */
840  //TRACE(TTEXT,("new_posn=%d pp->spxl_tab_start=%d pp->metric_line_length=%d", new_posn, pp->spxl_tab_start, pp->metric_line_length ))
841  if ((new_posn % 45) != 0)
842  {
843  new_posn += 45 - (new_posn % 45);
844  }
845  pp->spxl_tab_start = new_posn;
846  /* now that size of chars and letter space been used - zero them */
847  pp->metric_line_length = 0;
848  pp->hpxl_letter_offset = 0;
849  pp->total_letter_space = 0;
850  /* calculate tab position in real pixels */
851  new_posn = ((new_posn * mg_ctxt.osd_x.mlt) + (mg_ctxt.osd_x.div >> 1)) / mg_ctxt.osd_x.div;
852  pp->hpxl_pen_posn = pp->p_current_line->position + new_posn;
853  pp->hpxl_last_tab = pp->hpxl_pen_posn;
854  /* forget previous glyph to prevent kerning across a tab character */
855  pp->glyph_last = 0;
856 }
857 
863 static void AddSpaceRendering( pDrawTextAttrib attrib, S_PROPERTIES *pp, CharData *char_data,
864  FT_UInt mt_adv, S8BIT pxl_adv )
865 {
866  if (pp->glyph_last && attrib->letter_space)
867  {
868  AddLetterSpace(pp,attrib->letter_space);
869  if (pp->hpxl_pen_posn < pp->p_current_line->position)
870  {
871  pp->p_current_line->position = pp->hpxl_pen_posn;
872  }
873  }
874  if ((attrib->justify & JFY_HZ_MASK) == JUSTIFY_H_CENTRE)
875  {
876  char_data->mtrc_position = P_METRIC_POSITION(pp);
877  char_data->mtrc_advance = mt_adv;
878  char_data->real_position = pp->hpxl_pen_posn;
879  char_data->colour = TRANSPARENT_COLOUR; /* <- so that rendering function ignors this character data */
880  char_data->width = pxl_adv;
881  }
882  pp->hpxl_pen_posn += pxl_adv;
883  pp->metric_line_length += mt_adv;
884 }
885 
892 static void MinorAdjustOfPenPositionAtSpace( S_PROPERTIES *pp )
893 {
894  S32BIT tmp,psn;
895  psn = P_POINTS_POSITION(pp);
896  tmp = ((pp->m_to_pix_mlt * psn) + (pp->m_to_pix_div >> 1)) / pp->m_to_pix_div;
897  tmp += pp->hpxl_last_tab;
898  if (tmp != pp->hpxl_pen_posn)
899  {
900  TPRINT(TTEXT, ("MAPP(%d,%d,%d,%d,%d)", pp->total_letter_space, pp->metric_line_length, psn, tmp, pp->hpxl_pen_posn));
901  pp->hpxl_pen_posn += (tmp - pp->hpxl_pen_posn) / 2;
902  }
903 }
904 
913 static void ProcessWrappingBreak( S_PROPERTIES *pp, CharData *chars, U16BIT cur_ndx )
914 {
915  S32BIT brk_posn, ndx;
916  pp->metric_line_length -= pp->metric_break_length;
917  brk_posn = MTRC_POSN(pp->metric_break_length, pp->break_letter_space, pp->metric_resn, pp->pnts_font_size);
918  TRACE(TTEXT, ("Metric break-posn=%d; After: start=%d 1st-char=0x%x", brk_posn, pp->break_line.start_ndx, chars[pp->break_line.start_ndx].uni_chr))
919  if (brk_posn)
920  {
921  assert( pp->break_line.start_ndx < cur_ndx );
922  for (ndx = pp->break_line.start_ndx; ndx != cur_ndx; ndx++)
923  {
924  assert( chars[ndx].mtrc_position >= brk_posn );
925  chars[ndx].mtrc_position -= brk_posn;
926  }
927  }
928  pp->metric_break_length = 0;
929  pp->break_letter_space = 0;
930 }
931 
939 static void FudgeForHD( S_PROPERTIES *pp, CharData *chars )
940 {
941  CharData *p_start, *p_other, *p_last;
942  LineLimit *line = pp->p_current_line;
943  S32BIT fudge_size, fudge_last;
944 
945  assert(line->end_ndx > line->start_ndx);
946  p_start = chars + line->start_ndx;
947  p_last = chars + line->end_ndx - 1;
948  assert(line->position <= p_start->real_position);
949 
950  /* width of chars visible at HD */
951  fudge_size = p_last->real_position + p_last->width - line->position;
952 
953  /* is char width > box width, and is there more than one char ? */
954  if (fudge_size > pp->hpxl_box_width && p_start != p_last)
955  {
956  /* Ensure SD displayable chars can be seen in HD */
957  fudge_size -= pp->hpxl_box_width;
958  if (line->position < p_start->real_position)
959  {
960  /* attempt to sort it, by moving whole line left by one pixel
961  * Should not do more than one, coz it would be noticable on
962  * multi-line with left margin being jagged */
963  line->position++;
964  fudge_size--;
965  if (fudge_size == 0)
966  {
967  return; /* fudged it ! */
968  }
969  }
970  /* move end char back by required fudge size */
971  p_last->real_position -= fudge_size;
972  /* now loop until fudging is done or cannot do anymore */
973  do
974  {
975  fudge_last = fudge_size; /* save fudge size */
976  p_other = p_last - 1;
977  /* Start from end, and move chars back */
978  while (p_other != p_start)
979  {
980  p_other->real_position -= fudge_size;
981  if (p_other->real_position + p_other->width + 1 < p_last->real_position)
982  {
983  /* still have gap between chars after fudge, so can decrement fudge size
984  * i.e. lose one pixel between them */
985  fudge_size--;
986  p_other->real_position++;
987  if (fudge_size == 0)
988  {
989  return; /* fudged it ! */
990  }
991  }
992  p_last = p_other;
993  p_other--;
994  }
995  assert(p_other == p_start);
996  TRACE(TTEXT, ("More fudging to do %d", fudge_size))
997  /* This time, start from beginning and move them up */
998  p_last = chars + line->end_ndx - 1;
999  p_other++;
1000  while (p_other != p_last)
1001  {
1002  p_other->real_position += fudge_size;
1003  if (p_start->real_position + p_start->width + 1 < p_other->real_position)
1004  {
1005  /* still have gap between chars after fudge, so can decrement fudge size
1006  * i.e. lose one pixel between them */
1007  fudge_size--;
1008  if (fudge_size == 0)
1009  {
1010  return; /* fudged it ! */
1011  }
1012  }
1013  p_start = p_other;
1014  p_other++;
1015  }
1016  assert(p_other == p_last);
1017  p_start = chars + line->start_ndx;
1018  }
1019  while (fudge_size != fudge_last); /*if these are equal it is not possible to do any more */
1020  TRACE(TERROR, ("fudging failed to complete %d", fudge_size))
1021  }
1022  /* else nothing to do */
1023 }
1024 
1033 static void AdjustLineEnding( S_PROPERTIES *pp, CharData *chars )
1034 {
1035  S32BIT len, mtr_end, width;
1036  CharData *p_cd;
1037  LineLimit *line = pp->p_current_line;
1038  U16BIT ndx;
1039 
1040  assert(line->end_ndx > line->start_ndx);
1041  ndx = line->end_ndx - 1;
1042  p_cd = chars + ndx;
1043  mtr_end = p_cd->mtrc_position + p_cd->mtrc_advance;
1044  width = pp->spxl_box_width - pp->p_font_size->spxl_xleftoffset;
1045 
1046  ndx = line->start_ndx;
1047  p_cd = chars + ndx;
1048 
1049  while (ndx != line->end_ndx)
1050  {
1051  len = P_MTRC_2_SPXL(pp, mtr_end - p_cd->mtrc_position);
1052  if (len <= width)
1053  {
1054  break;
1055  }
1056  p_cd++;
1057  ndx++;
1058  }
1059  assert(ndx <= line->end_ndx);
1060  line->start_ndx = ndx;
1061 
1062  /* adjust rending length so that displayable chars are centred properly */
1063  line->l_width -= p_cd->real_position - line->position;
1064  line->position = p_cd->real_position;
1065 }
1066 
1075 static void AdjustLineMiddle( S_PROPERTIES *pp, CharData *chars, U8BIT justify )
1076 {
1077  S32BIT mleft, mhalf, rright, mright, b_wdth;
1078  CharData *p_ecd, *p_scd;
1079  LineLimit *line = pp->p_current_line;
1080  U16BIT e_ndx, s_ndx;
1081 
1082  assert(line->end_ndx > line->start_ndx);
1083  e_ndx = line->end_ndx - 1;
1084  s_ndx = line->start_ndx;
1085  p_ecd = chars + e_ndx;
1086  if (justify & WRAP_WORDS)
1087  {
1088  /*Strip off extra spaces from end of chars array for this line */
1089  while (e_ndx != s_ndx && p_ecd->uni_chr == UNICODE_SPACE)
1090  {
1091  p_ecd--;
1092  e_ndx--;
1093  }
1094  }
1095  mright = p_ecd->mtrc_position + p_ecd->mtrc_advance;
1096  p_scd = chars + s_ndx;
1097  mleft = p_scd->mtrc_position;
1098  rright = pp->break_line.position;
1099 
1100  #ifdef ACCURATE_CENTRE_TRUNCATION
1101 
1102  mhalf = mright >> 1;
1103  b_wdth = pp->spxl_box_width - pp->p_font_size->spxl_xleftoffset;
1104  while ((e_ndx != s_ndx) && (P_MTRC_2_SPXL(pp, mright - mleft) > b_wdth))
1105  {
1106  if (mright - mhalf > mhalf - mleft)
1107  {
1108  rright = p_ecd->real_position;
1109  p_ecd--;
1110  e_ndx--;
1111  mright = p_ecd->mtrc_position + p_ecd->mtrc_advance;
1112  }
1113  else
1114  {
1115  p_scd++;
1116  s_ndx++;
1117  mleft = p_scd->mtrc_position;
1118  }
1119  }
1120 
1121  #else
1122 
1123  mhalf = mright << 1;
1124  b_wdth = pp->spxl_box_width; /* twice width of right half */
1125  while ((e_ndx != s_ndx) && (P_MTRC_2_SPXL(pp, mhalf - mright) > b_wdth))
1126  {
1127  rright = p_ecd->real_position;
1128  p_ecd--;
1129  e_ndx--;
1130  mhalf = (p_ecd->mtrc_position + p_ecd->mtrc_advance) << 1;
1131  }
1132  b_wdth -= pp->p_font_size->spxl_xleftoffset;
1133  while ((e_ndx != s_ndx) && (P_MTRC_2_SPXL(pp, mright - mleft) > b_wdth))
1134  {
1135  p_scd++;
1136  s_ndx++;
1137  mleft = p_scd->mtrc_position << 1;
1138  }
1139 
1140  #endif /*ACCURATE_CENTRE_TRUNCATION*/
1141 
1142  if (s_ndx != line->start_ndx || e_ndx != (line->end_ndx - 1))
1143  {
1144  assert( rright > p_scd->real_position );
1145  if (rright > p_scd->real_position)
1146  {
1147  assert(s_ndx <= (e_ndx + 1));
1148  line->start_ndx = s_ndx;
1149  line->end_ndx = e_ndx + 1;
1150 
1151  /* adjust rending length so that displayable chars are centred properly */
1152  line->position = p_scd->real_position;
1153  line->l_width = p_ecd->real_position + p_ecd->width - p_scd->real_position;
1154  }
1155  }
1156 }
1157 
1163 void ProcessNewLine( S_PROPERTIES *pp, CharData *chars, S_FontSize *f_sz_data, U16BIT line_num, U8BIT justify )
1164 {
1165  TRACE(TTEXT, ("start=%d bk-end=%d", pp->p_current_line->start_ndx, pp->break_line.end_ndx))
1166  if (pp->p_current_line->start_ndx < pp->break_line.end_ndx)
1167  {
1168  pp->p_current_line->l_width = pp->break_line.l_width;
1169  pp->p_current_line->end_ndx = pp->break_line.end_ndx;
1170  pp->p_current_line->line_num = line_num;
1171  pp->hpxl_last_tab = pp->break_line.position;
1172  switch (justify & JFY_HZ_MASK)
1173  {
1174  case JUSTIFY_H_END:
1175  AdjustLineEnding( pp, chars );
1176  break;
1177 
1178  case JUSTIFY_H_CENTRE:
1179  AdjustLineMiddle( pp, chars, justify );
1180  FudgeForHD( pp, chars );
1181  break;
1182 
1183  default: /*JUSTIFY_H_START and JUSTIFY_H_JUSTIFIED*/
1184  FudgeForHD( pp, chars );
1185  pp->spxl_tab_start = f_sz_data->spxl_xleftoffset;
1186  pp->pnts_tab_start = f_sz_data->pnts_xleftoffset;
1187  pp->break_line.position -= f_sz_data->bound_box.left;
1188  break;
1189  }
1190  pp->hpxl_letter_offset = 0;
1191  pp->total_letter_space = 0;
1192  pp->p_current_line++;
1193  }
1194  else
1195  {
1196  if ((justify & JFY_HZ_MASK) == JUSTIFY_H_START)
1197  {
1198  pp->break_line.position -= f_sz_data->bound_box.left;
1199  }
1200  }
1201  pp->p_current_line->position = pp->break_line.position;
1202  pp->p_current_line->start_ndx = pp->break_line.start_ndx;
1203  pp->break_line.start_ndx = pp->break_line.end_ndx;
1204 }
1205 
1214 static LineLimit* ShuffleUpLines( LineLimit *lines, U16BIT num )
1215 {
1216  U16BIT first = 0;
1217  while (lines[first].line_num < num)
1218  {
1219  first++;
1220  }
1221  num = first;
1222  first = 0;
1223  while (num != MAX_NUM_LINES)
1224  {
1225  lines[first] = lines[num];
1226  first++;
1227  num++;
1228  }
1229  return &lines[first - 1];
1230 }
1231 
1237 static void AddCaretChar( S_PROPERTIES *pp, S_FontDetails *ftd_ptr, S_FontSize *f_sz_data, CharData *char_data,
1238  OSDColor col, U16BIT caret )
1239 {
1240  if (f_sz_data->sbit_cache)
1241  {
1242  CacheSbit *c_sbit = &f_sz_data->sbit_cache[caret - FIRST_CACHE_CHAR];
1243  char_data->width = c_sbit->width;
1244  char_data->real_position = pp->hpxl_pen_posn + c_sbit->left;
1245  char_data->gf_ndx = 0;
1246  }
1247  else
1248  {
1249  FT_Face the_face = ftd_ptr->face;
1250  char_data->gf_ndx = FT_Get_Char_Index( the_face, caret );
1251  if (FT_Load_Glyph( the_face, char_data->gf_ndx, FT_LOAD_RENDER ) == 0)
1252  {
1253  char_data->width = the_face->glyph->bitmap.width;
1254  char_data->real_position = pp->hpxl_pen_posn + the_face->glyph->bitmap_left;
1255  }
1256  }
1257  char_data->mtrc_position = P_METRIC_POSITION(pp);
1258  char_data->mtrc_advance = ftd_ptr->horiz_adv[caret - FIRST_CACHE_CHAR];
1259  char_data->uni_chr = caret;
1260  char_data->colour = col;
1261 }
1262 
1277 static U16BIT PreparePrintableData( const TextString unistr, pDrawTextAttrib attrib, S_FontSize *f_sz_data,
1278  S_FontDetails *ftd_ptr, U16BIT hpxl_box_width, U16BIT spxl_box_width,
1279  U16BIT available_lines, LineLimit *lines, CharData *chars, U16BIT *p_chr_cnt )
1280 {
1281  CharData *char_data = chars;
1282  FT_UInt *hori_advance = ftd_ptr->horiz_adv;
1283  OSDColor colour_stack[COLOUR_STACK_SIZE];
1284  S_PROPERTIES prop;
1285  U16BIT u_chr, uni_pos, char_count;
1286  U16BIT total_lines;
1287  EBreakState break_state;
1288  U8BIT colour_count, hz_justify;
1289  U16BIT spxl_avl_width;
1290 
1291  /* Initialise values, including 'properties' */
1292  lines[0].position = 0;
1293  lines[0].start_ndx = 0;
1294  lines[0].end_ndx = 0;
1295  prop.break_line.start_ndx = 0;
1296  total_lines = 0;
1297  char_count = 0;
1298  colour_count = 0; /* fore colour in 'zero' */
1299  colour_stack[0] = attrib->fore_colour;
1300  break_state = NO_BREAK;
1301  prop.p_font_size = attrib->font.hdl;
1302  prop.p_current_line = lines;
1303  prop.metric_resn = ftd_ptr->metric_resolution;
1304  prop.hpxl_box_width = hpxl_box_width;
1305  prop.spxl_box_width = spxl_box_width;
1306 
1307  InitialiseProperties( attrib, f_sz_data, &prop );
1308 
1309  hz_justify = attrib->justify & JFY_HZ_MASK;
1310  if (hz_justify == JUSTIFY_H_START)
1311  {
1312  spxl_avl_width = spxl_box_width;
1313  }
1314  else
1315  {
1316  spxl_avl_width = spxl_box_width - f_sz_data->spxl_xleftoffset;
1317  }
1318 
1319  /* loop through the string */
1320  for (uni_pos = 0; uni_pos < unistr.len; uni_pos++)
1321  {
1322  if (uni_pos == attrib->entry_point)
1323  {
1324  AddCaretChar( &prop, ftd_ptr, f_sz_data, char_data, colour_stack[colour_count], attrib->caret );
1325  char_count++;
1326  char_data++;
1327  }
1328  u_chr = unistr.data[uni_pos];
1329  switch (u_chr)
1330  {
1331  case UNICODE_LF: case U_CTRL_NULL:
1332  case U_CTRL_A: case U_CTRL_B: case U_CTRL_C: case U_CTRL_D: case U_CTRL_E:
1333  case U_CTRL_F: case U_CTRL_G: case U_CTRL_H: case U_CTRL_K: case U_CTRL_L:
1334  case U_CTRL_N: case U_CTRL_O: case U_CTRL_P: case U_CTRL_Q: case U_CTRL_R:
1335  case U_CTRL_S: case U_CTRL_T: case U_CTRL_U: case U_CTRL_V: case U_CTRL_W:
1336  case U_CTRL_X: case U_CTRL_Y: case U_CTRL_Z: case U_CTRL_FS:
1337  case U_CTRL_GS: case U_CTRL_RS: case U_CTRL_US:
1338  TRACE(TTEXT, ("Ignoring control char 0x%x", u_chr))
1339  break;
1340 
1341  case UNICODE_CR:
1342  prop.break_line.l_width = prop.hpxl_line_end - prop.p_current_line->position;
1343  if (break_state != OVER_RUN)
1344  {
1345  prop.break_line.end_ndx = char_count;
1346  }
1347  prop.break_line.position = prop.hpxl_pen_posn;
1348  prop.break_line.start_ndx = char_count;
1349  prop.hpxl_last_tab = prop.hpxl_pen_posn; /* last screen of test 5.9 */
1350  if (hz_justify == JUSTIFY_H_START)
1351  {
1352  prop.pnts_tab_start = f_sz_data->pnts_xleftoffset;
1353  prop.spxl_tab_start = f_sz_data->spxl_xleftoffset;
1354  }
1355  prop.metric_line_length = 0;
1356  break_state = NEW_LINE;
1357  break;
1358 
1359  case UNICODE_ESC:
1360  /* process markup's */
1361  uni_pos++;
1362  if (uni_pos != unistr.len)
1363  {
1364  uni_pos += ProcessMarkup( &unistr.data[uni_pos], colour_stack, &colour_count, attrib->p_ha );
1365  }
1366  break;
1367 
1368  case UNICODE_TAB:
1369  if (hz_justify == JUSTIFY_H_START)
1370  {
1371  MoveTabPosition( &prop );
1372  }
1373  else
1374  {
1375  u_chr = UNICODE_SPACE;
1376  }
1377  case UNICODE_SPACE:
1378  if (u_chr == UNICODE_SPACE)
1379  {
1380  AddSpaceRendering( attrib, &prop, char_data, ftd_ptr->space_horiz_adv, f_sz_data->space_adv );
1381  if (hz_justify == JUSTIFY_H_CENTRE)
1382  {
1383  /* for centre justify, AddSpaceRendering adds char data,
1384  * gf_ndx and uni_chr do not really matter, but might as well have something */
1385  char_data->gf_ndx = ftd_ptr->glyph_ndx_space;
1386  char_data->uni_chr = u_chr;
1387  #ifdef TRACE
1388  char_data->spxl_end = (S16BIT)S_SPIXEL_POSITION(prop);
1389  #endif
1390  char_count++;
1391  char_data++;
1392  }
1393  prop.glyph_last = ftd_ptr->glyph_ndx_space;
1394  /* Special case, only for SD resolution */
1395  if (mg_ctxt.out_osd_width == 720)
1396  {
1397  MinorAdjustOfPenPositionAtSpace( &prop );
1398  }
1399  }
1400  if ((break_state != BREAKING) && (attrib->justify & WRAP_WORDS))
1401  {
1402  prop.break_line.l_width = prop.hpxl_line_end - prop.p_current_line->position;
1403  if (break_state != OVER_RUN)
1404  {
1405  prop.break_line.end_ndx = char_count;
1406  }
1407  if (S_SPIXEL_POSITION(prop) > spxl_avl_width)
1408  {
1409  TRACE(TTEXT, ("Need line break: sdp=%ld, aw=%d", S_SPIXEL_POSITION(prop), spxl_avl_width))
1410  prop.break_line.position = prop.hpxl_pen_posn;
1411  prop.break_line.start_ndx = char_count;
1412  prop.metric_line_length = 0;
1413  break_state = NEW_LINE;
1414  }
1415  else
1416  {
1417  break_state = BREAKING;
1418  }
1419  }
1420  if (hz_justify == JUSTIFY_H_END)
1421  {
1422  if (prop.hpxl_pen_posn > prop.hpxl_line_end)
1423  {
1424  prop.hpxl_line_end = prop.hpxl_pen_posn;
1425  }
1426  }
1427  break;
1428 #if 0
1429  case UNICODE_HARD_SPACE:
1430  AddSpaceRendering( attrib, &prop, char_data, ftd_ptr->space_horiz_adv, f_sz_data->space_adv );
1431  if (hz_justify == JUSTIFY_H_CENTRE)
1432  {
1433  /* for centre justify, AddSpaceRendering adds char data,
1434  * gf_ndx and uni_chr do not really matter, but might as well have something */
1435  char_data->gf_ndx = ftd_ptr->glyph_ndx_space;
1436  char_data->uni_chr = u_chr;
1437  char_count++;
1438  char_data++;
1439  }
1440  prop.glyph_last = ftd_ptr->glyph_ndx_space;
1441  if (prop.hpxl_pen_posn > prop.hpxl_line_end)
1442  {
1443  prop.hpxl_line_end = prop.hpxl_pen_posn;
1444  }
1445  break;
1446 
1447  case UNICODE_FIGURE_SPACE:
1448  AddSpaceRendering( attrib, &prop, char_data, ftd_ptr->fig_horiz_adv, f_sz_data->figure_adv );
1449  if (hz_justify == JUSTIFY_H_CENTRE)
1450  {
1451  /* for centre justify, AddSpaceRendering adds char data,
1452  * gf_ndx and uni_chr do not really matter, but might as well have something */
1453  char_data->gf_ndx = ftd_ptr->glyph_ndx_space;
1454  char_data->uni_chr = u_chr;
1455  char_count++;
1456  char_data++;
1457  }
1458  prop.glyph_last = ftd_ptr->glyph_ndx_space;
1459  if (prop.hpxl_pen_posn > prop.hpxl_line_end)
1460  {
1461  prop.hpxl_line_end = prop.hpxl_pen_posn;
1462  }
1463  break;
1464 #endif
1465  default:
1466  /* PRINTABLE CHARS */
1467  if (u_chr < (FIRST_CACHE_CHAR + CHAR_CACHE_SIZE))
1468  {
1469  assert(u_chr >= FIRST_CACHE_CHAR);
1470  prop.glyph_index = ftd_ptr->glyph_ndx[u_chr - FIRST_CACHE_CHAR];
1471 
1472  char_data->mtrc_advance = (S16BIT)hori_advance[u_chr - FIRST_CACHE_CHAR];
1473 
1474  if (f_sz_data->sbit_cache)
1475  {
1476  CacheSbit *c_sbit = &f_sz_data->sbit_cache[u_chr - FIRST_CACHE_CHAR];
1477  char_data->uni_chr = u_chr;
1478  char_data->gf_ndx = 0;
1479  char_data->width = c_sbit->width;
1480  prop.char_left = c_sbit->left;
1481  prop.char_adv = c_sbit->advance;
1482  }
1483  else
1484  {
1485  if (prop.glyph_index == 0 ||
1486  !LoadPrintableChar( ftd_ptr, f_sz_data, &prop, u_chr, char_data ))
1487  {
1488  break;
1489  }
1490  }
1491  }
1492  else
1493  {
1494  prop.glyph_index = FT_Get_Char_Index( ftd_ptr->face, u_chr );
1495  char_data->mtrc_advance = 0;
1496  if (prop.glyph_index == 0 ||
1497  !LoadPrintableChar( ftd_ptr, f_sz_data, &prop, u_chr, char_data ))
1498  {
1499  TRACE(TTEXT, ("0x%x is not printable\n", u_chr))
1500  break;
1501  }
1502  }
1503  char_data->colour = colour_stack[colour_count];
1504 
1505  if (break_state == BREAKING)
1506  {
1507  prop.break_line.position = prop.hpxl_pen_posn + prop.char_left;
1508  prop.metric_break_length = prop.metric_line_length;
1509  prop.break_letter_space = prop.total_letter_space;
1510  prop.break_line.end_ndx = char_count;
1511  prop.break_line.start_ndx = char_count;
1512  break_state = HAD_BREAK;
1513  }
1514 
1515  DoTheKerning( attrib, ftd_ptr, &prop );
1516 
1517  {
1518  S32BIT tmp_adv = prop.hpxl_pen_posn + prop.char_left;
1519  char_data->real_position = tmp_adv;
1520  if (tmp_adv < prop.p_current_line->position)
1521  {
1522  prop.p_current_line->position = tmp_adv;
1523  }
1524  tmp_adv += char_data->width;
1525  if (tmp_adv > prop.hpxl_line_end)
1526  {
1527  prop.hpxl_line_end = tmp_adv;
1528  }
1529  }
1530 
1531  prop.hpxl_pen_posn += prop.char_adv;
1532  char_data->mtrc_position = S_METRIC_POSITION(prop);
1533  prop.metric_line_length += char_data->mtrc_advance;
1534  if (prop.hpxl_pen_posn > prop.hpxl_line_end)
1535  {
1536  prop.hpxl_line_end = prop.hpxl_pen_posn;
1537  }
1538  #ifdef TRACE
1539  char_data->spxl_end = (S16BIT)S_SPIXEL_POSITION(prop);
1540  #endif
1541  char_count++;
1542  char_data++;
1543 
1544  if (attrib->justify & WRAP_VERTICAL)
1545  {
1546  /* wrap on every char */
1547  prop.break_line.l_width = prop.hpxl_line_end - prop.p_current_line->position;
1548  prop.break_line.end_ndx = char_count;
1549  prop.break_line.position = prop.hpxl_pen_posn;
1550  prop.metric_line_length = 0;
1551  break_state = NEW_LINE;
1552  }
1553  else
1554  {
1555  if (S_SPIXEL_POSITION(prop) > spxl_avl_width)
1556  {
1557  /* this line now exceeds available width */
1558  TRACE(TTEXT, ("Need line-break: sdp=%ld, aw=%d", S_SPIXEL_POSITION(prop), spxl_avl_width))
1559  #ifdef TRACING
1560  if (TTEXT & mheg_trace_debug)
1561  {
1562  prop.p_current_line->l_width = prop.hpxl_line_end - prop.p_current_line->position;
1563  prop.p_current_line->end_ndx = char_count;
1564  prop.p_current_line->line_num = total_lines;
1565  traceLine( prop.p_current_line, chars, prop.pnts_font_size, prop.metric_resn );
1566  }
1567  #endif
1568  switch (break_state)
1569  {
1570  case HAD_BREAK:
1571  /* Need to remove from total_letter_space, the letter space after the breaking space char */
1572  prop.break_letter_space += attrib->letter_space;
1573  prop.total_letter_space -= prop.break_letter_space;
1574  ProcessWrappingBreak( &prop, chars, char_count );
1575  break_state = NEW_LINE;
1576  break;
1577  default:
1578  if (hz_justify == JUSTIFY_H_START)
1579  {
1580  TRACE(TTEXT, ("Over run at %d", char_count))
1581  assert(break_state == NO_BREAK);
1582  prop.break_line.end_ndx = char_count - 1;
1583  break_state = OVER_RUN;
1584  }
1585  break;
1586  case OVER_RUN:
1587  break;
1588  }
1589  }
1590  }
1591  } /*end: switch(u_chr)*/
1592 
1593  if (break_state == NEW_LINE)
1594  {
1595  ProcessNewLine( &prop, chars, f_sz_data, total_lines, attrib->justify );
1596 
1597  total_lines++;
1598 
1599  if ((total_lines == available_lines) &&
1600  ((attrib->justify & JUSTIFY_V_JUSTIFIED) == JUSTIFY_V_START)
1601  )
1602  {
1603  /* GOOD! we've done enough - let's exit loop */
1604  break;
1605  }
1606  if (prop.p_current_line == &lines[MAX_NUM_LINES - 1])
1607  {
1608  if ((attrib->justify & JUSTIFY_V_JUSTIFIED) != JUSTIFY_V_END)
1609  {
1610  TRACE(TERROR, ("Run out of line space"))
1611  break; /* eek, cannot do anymore */
1612  }
1613  /* for JUSTIFY_V_END, can shuffle up the lines coz only interested in the last ones */
1614  prop.p_current_line = ShuffleUpLines( lines, total_lines - available_lines );
1615  }
1616  prop.glyph_last = 0;
1617  break_state = NO_BREAK;
1618  }
1619  }
1620 
1621  if (uni_pos == attrib->entry_point)
1622  {
1623  /* add 'caret' in the end position */
1624  AddCaretChar( &prop, ftd_ptr, f_sz_data, char_data, colour_stack[colour_count], attrib->caret );
1625  if ((char_data->real_position + char_data->width) > prop.hpxl_line_end)
1626  {
1627  prop.hpxl_line_end = char_data->real_position + char_data->width;
1628  }
1629  char_count++;
1630  }
1631  /* complete stuff for the last line being processed */
1632  TRACE(TTEXT, ("last line: mt=%ld, rt=%ld", prop.metric_line_length, prop.hpxl_line_end))
1633  prop.p_current_line->l_width = prop.hpxl_line_end - prop.p_current_line->position;
1634  prop.p_current_line->line_num = total_lines;
1635  if (break_state == OVER_RUN)
1636  {
1637  prop.p_current_line->end_ndx = prop.break_line.end_ndx;
1638  }
1639  else
1640  {
1641  prop.p_current_line->end_ndx = char_count;
1642  if (prop.p_current_line->start_ndx < char_count)
1643  { /* there are some visible chars */
1644  prop.break_line.position = prop.hpxl_pen_posn;
1645  switch (attrib->justify & JFY_HZ_MASK)
1646  {
1647  case JUSTIFY_H_END:
1648  AdjustLineEnding( &prop, chars );
1649  break;
1650 
1651  case JUSTIFY_H_CENTRE:
1652  AdjustLineMiddle( &prop, chars, attrib->justify );
1653  FudgeForHD( &prop, chars );
1654  break;
1655 
1656  default: /*JUSTIFY_H_START and JUSTIFY_H_JUSTIFIED*/
1657  FudgeForHD( &prop, chars );
1658  break;
1659  }
1660  }
1661  }
1662  if (prop.p_current_line->l_width)
1663  {
1664  total_lines++;
1665  /* TextDrawFn() requires that there is a terminating lines array element
1666  * with line_num equal to total_lines */
1667  prop.p_current_line++;
1668 
1669  prop.p_current_line->line_num = total_lines;
1670  }
1671  *p_chr_cnt = char_count;
1672  return total_lines;
1673 } /* end of PreparePrintableData */
1674 
1675 #ifdef OSD_8_BIT
1676 
1681 #define TextDrawFn TextDraw8Bit
1682 #define RenderGlyphFn RenderGlyph8Bit
1683 #define TDColor U8BIT
1684 #define MakeTDColor(col) OSD_FindNearestColourIndex( col )
1685 #define GreyValue(val) (val >> 6)
1686 #define SRC_FORE_MAX 3
1687 #define IsOpaqueColor( tcol ) (tcol >= OFFSET_OPAQUE)
1688 #define NotTransparent( fcol ) ((fcol >> 24) > 0x18)
1689 #define CombineAlphaColour(pixel, grey_val, fc, tc) if (grey_val) pixel = aa_8bit_cols[grey_val];
1690 //#define SetColorArrayBack(bck_col) aa_8bit_cols[0] = bck_col;
1691 #define CalcColorArray(for_col) \
1692  if (/*for_col != OFFSET_TRANS &&*/ aa_8bit_cols[3] != for_col) { \
1693  U8BIT fa, ba, bck_col = aa_8bit_cols[0]; \
1694  register U32BIT comp, tmp_c, alpha_c; \
1695  comp = mg_palette[for_col] >> 24; \
1696  ba = (U8BIT)(mg_palette[bck_col] >> 24); \
1697  alpha_c = ((((255 ^ ba) * comp) + 382) / 765) + ba; \
1698  tmp_c = alpha_c << 24; \
1699  fa = (U8BIT)((comp + 1) / 3); \
1700  comp = ba; \
1701  ba = (U8BIT)(((255 ^ fa) * comp) + 127) / 255; \
1702  comp = ba * ((mg_palette[bck_col] >> 16) & 0xff) + fa * ((mg_palette[for_col] >> 16) & 0xff); \
1703  tmp_c |= (comp / alpha_c) << 16; \
1704  comp = ba * ((mg_palette[bck_col] >> 8) & 0xff) + fa * ((mg_palette[for_col] >> 8) & 0xff); \
1705  tmp_c |= (comp / alpha_c) << 8; \
1706  comp = ba * (mg_palette[bck_col] & 0xff) + fa * (mg_palette[for_col] & 0xff); \
1707  tmp_c |= (comp / alpha_c); \
1708  aa_8bit_cols[1] = OSD_FindNearestColourIndex(tmp_c); \
1709  comp = 2 * (mg_palette[for_col] >> 24); \
1710  ba = (U8BIT)(mg_palette[bck_col] >> 24); \
1711  alpha_c = ((((255 ^ ba) * comp) + 382) / 765) + ba; \
1712  tmp_c = alpha_c << 24; \
1713  fa = (U8BIT)((comp + 1) / 3); \
1714  comp = ba; \
1715  ba = (U8BIT)(((255 ^ fa) * comp) + 127) / 255; \
1716  comp = ba * ((mg_palette[bck_col] >> 16) & 0xff) + fa * ((mg_palette[for_col] >> 16) & 0xff); \
1717  tmp_c |= (comp / alpha_c) << 16; \
1718  comp = ba * ((mg_palette[bck_col] >> 8) & 0xff) + fa * ((mg_palette[for_col] >> 8) & 0xff); \
1719  tmp_c |= (comp / alpha_c) << 8; \
1720  comp = ba * (mg_palette[bck_col] & 0xff) + fa * (mg_palette[for_col] & 0xff); \
1721  tmp_c |= (comp / alpha_c); \
1722  aa_8bit_cols[2] = OSD_FindNearestColourIndex(tmp_c); \
1723  aa_8bit_cols[3] = for_col; \
1724  }
1725 
1726 static U8BIT aa_8bit_cols[4] = {OFFSET_TRANS, OFFSET_TRANS, OFFSET_TRANS, OFFSET_TRANS};
1727 
1728 #include "textdrawfn.h"
1729 
1730 #undef TextDrawFn
1731 #undef RenderGlyphFn
1732 #undef TDColor
1733 #undef CalcColorArray
1734 #undef MakeTDColor
1735 #undef GreyValue
1736 #undef SRC_FORE_MAX
1737 #undef IsOpaqueColor
1738 #undef NotTransparent
1739 #undef CombineAlphaColour
1740 
1741 #endif /*OSD_8_BIT*/
1742 
1743 
1744 #ifdef OSD_16_BIT
1745 
1750 #define TextDrawFn TextDraw16Bit
1751 #define RenderGlyphFn RenderGlyph16Bit
1752 #define TDColor HD2Color
1753 #define MakeTDColor(col) MakeHD2Color( col )
1754 #define GreyValue(val) val
1755 #define SRC_FORE_MAX 255
1756 #define IsOpaqueColor( tcol ) ((tcol >> 12) == 0xf)
1757 #define NotTransparent( fcol ) ((fcol >> 28) != 0x0)
1758 #define CombineAlphaColour(pixel, grey_val, full_col, fore_col) \
1759  grey_val *= (full_col >> 24); \
1760  if (grey_val & 0xf000) { pixel = (fore_col & 0x0fff) | (grey_val & 0xf000); }
1761 
1762 #include "textdrawfn.h"
1763 
1764 #undef TextDrawFn
1765 #undef RenderGlyphFn
1766 #undef CombineAlphaColour
1767 
1772 #define TextDrawFn TextDraw16BitBlend
1773 #define RenderGlyphFn RenderGlyph16Blend
1774 #define CombineAlphaColour(pixel, grey_val, full_col, fore_col) \
1775  grey_val *= (full_col >> 24); \
1776  if (grey_val & 0xff00) { \
1777  register U32BIT fa, ba, comp, tmp_c, alpha_c; \
1778  ba = (U8BIT)(pixel >> 12); \
1779  comp = ba * 17; \
1780  alpha_c = ((((15 - ba) *grey_val) + 1912) / 3825) + comp; \
1781  fa = (U8BIT)(grey_val / SRC_FORE_MAX); \
1782  ba = (((255 ^ fa) *comp) + 127) / 255; \
1783  tmp_c = (alpha_c / 17) << 12; \
1784  comp = ba * ((pixel >> 8) & 0xf) + fa * ((fore_col >> 8) & 0xf); \
1785  tmp_c |= ((comp + (alpha_c >> 1)) / alpha_c) << 8; \
1786  comp = ba * ((pixel >> 4) & 0xf) + fa * ((fore_col >> 4) & 0xf); \
1787  tmp_c |= ((comp + (alpha_c >> 1)) / alpha_c) << 4; \
1788  comp = ba * (pixel & 0xf) + fa * (fore_col & 0xf); \
1789  tmp_c |= ((comp + (alpha_c >> 1)) / alpha_c); \
1790  pixel = (U16BIT)tmp_c; \
1791  }
1792 
1793 #include "textdrawfn.h"
1794 
1795 #undef TextDrawFn
1796 #undef RenderGlyphFn
1797 #undef TDColor
1798 #undef MakeTDColor
1799 #undef SRC_FORE_MAX
1800 #undef IsOpaqueColor
1801 #undef NotTransparent
1802 #undef CombineAlphaColour
1803 
1804 #endif /* OSD_16_BIT */
1805 
1806 
1807 #if defined(OSD_31_BIT) || defined(OSD_32_BIT)
1808 
1813 #define TextDrawFn TextDraw32Bit
1814 #define RenderGlyphFn RenderGlyph32Bit
1815 #define TDColor OSDColor
1816 #define GreyValue(val) val
1817 #define MakeTDColor(col) AlphaPlatform(col)
1818 #define SRC_FORE_MAX 255
1819 #define IsOpaqueColor( tcol ) ((tcol >> 24) == MAX_ALPHA)
1820 #define NotTransparent( fcol ) ((fcol >> 24) != 0x00)
1821 #define CombineAlphaColour(pixel, grey_val, full_col, fore_col) \
1822  grey_val *= CalcAlpha(fore_col >> 24); \
1823  if (grey_val > 127) { pixel = (fore_col & 0xffffff) | ((grey_val << 16) & 0xff000000); }
1824 
1825 #include "textdrawfn.h"
1826 
1827 #undef TextDrawFn
1828 #undef RenderGlyphFn
1829 #undef CombineAlphaColour
1830 
1835 #define TextDrawFn TextDraw32BitBlend
1836 #define RenderGlyphFn RenderGlyph32Blend
1837 #define CombineAlphaColour(pixel, grey_val, full_col, fore_col) \
1838  grey_val *= CalcAlpha(fore_col >> 24); \
1839  if (grey_val > 127) { \
1840  register U32BIT fa, ba, comp, tmp_c, alpha_c; \
1841  ba = pixel >> 24; \
1842  alpha_c = ((((MAX_ALPHA - ba) *grey_val) + ((MAX_ALPHA *255) / 2)) / (MAX_ALPHA *255)) + ba; \
1843  fa = (U8BIT)(grey_val / SRC_FORE_MAX); \
1844  ba = (((MAX_ALPHA - fa) *ba) + (MAX_ALPHA / 2)) / MAX_ALPHA; \
1845  tmp_c = alpha_c << 24; \
1846  comp = ba * ((pixel >> 16) & 0xff) + fa * ((fore_col >> 16) & 0xff); \
1847  tmp_c |= ((comp + (alpha_c >> 1)) / alpha_c) << 16; \
1848  comp = ba * ((pixel >> 8) & 0xff) + fa * ((fore_col >> 8) & 0xff); \
1849  tmp_c |= ((comp + (alpha_c >> 1)) / alpha_c) << 8; \
1850  comp = ba * (pixel & 0xff) + fa * (fore_col & 0xff); \
1851  tmp_c |= ((comp + (alpha_c >> 1)) / alpha_c); \
1852  pixel = tmp_c; \
1853  }
1854 
1855 #include "textdrawfn.h"
1856 
1857 #undef TextDrawFn
1858 #undef RenderGlyphFn
1859 #undef TDColor
1860 #undef MakeTDColor
1861 #undef SRC_FORE_MAX
1862 #undef IsOpaqueColor
1863 #undef NotTransparent
1864 #undef SignificantFore
1865 #undef CombineAlphaColour
1866 
1867 #endif /* OSD_32_BIT */
1868 
1869 
1870 static CharData* GetCharArray( const TextString unistr, pDrawTextAttrib attrib, CharData *chars )
1871 {
1872  U32BIT m_size, glph_count;
1873  CharData *char_data;
1874  if (unistr.len < MAX_NUM_CHARS)
1875  {
1876  char_data = chars;
1877  }
1878  else
1879  {
1880  /* check that the 'chars' array on the stack is big enough,
1881  * if not get some heap space for it */
1882  m_size = 0;
1883  for (glph_count = 0; glph_count != unistr.len; glph_count++)
1884  {
1885  switch (unistr.data[glph_count])
1886  {
1887  case UNICODE_ESC:
1888  if (glph_count + 1 != unistr.len)
1889  {
1890  /*Markup sequence*/
1891  glph_count++;
1892  if ((unistr.data[glph_count] <= 0x5e) &&
1893  (unistr.data[glph_count] >= 0x40) &&
1894  (glph_count + 1 != unistr.len))
1895  {
1896  glph_count++;
1897  if ((glph_count + unistr.data[glph_count]) <= unistr.len)
1898  {
1899  glph_count += unistr.data[glph_count];
1900  }
1901  }
1902  }
1903  break;
1904 
1905  case UNICODE_SPACE:
1906  case UNICODE_TAB:
1907  #if 0
1908  case UNICODE_HARD_SPACE:
1909  case UNICODE_FIGURE_SPACE:
1910  #endif
1911  if ((attrib->justify & JFY_HZ_MASK) == JUSTIFY_H_CENTRE)
1912  {
1913  m_size++;
1914  }
1915  break;
1916 
1917  default:
1918  if (unistr.data[glph_count] > 0x20)
1919  {
1920  /* assume this is a printable char */
1921  m_size++;
1922  }
1923  }
1924  }
1925  if (attrib->entry_point != -1)
1926  {
1927  m_size++;
1928  }
1929  if (m_size > MAX_NUM_CHARS)
1930  {
1931  /* array 'chars' ain't big enough, so allocate buffer for character descriptions */
1932  char_data = (CharData *)OSD_MemAlloc( sizeof(CharData) * m_size );
1933  TRACE(TTEXT, ("malloc char_data array (sz=%d) at 0x%x", m_size, char_data))
1934  }
1935  else
1936  {
1937  char_data = chars;
1938  }
1939  }
1940  return char_data;
1941 }
1942 
1943 /*---global function definitions---------------------------------------------*/
1944 
1953 void* MG_DrawUKText( const TextString unistr, pDrawTextAttrib attrib, const VRect txt_box )
1954 {
1955  S_FontDetails *font_ptr;
1956  S_FontSize *f_szdata;
1957  S_SURFACE *canvas = 0;
1958  CharData *char_data;
1959  CharData chars[MAX_NUM_CHARS];
1960  LineLimit lines[MAX_NUM_LINES + 1];
1961  U16BIT line_count, glph_count;
1962 
1963  assert( attrib );
1964 
1965  TRACE(TTEXT, ("SD box=(%d,%d,%d,%d)", txt_box.left, txt_box.top, txt_box.left + txt_box.width, txt_box.top + txt_box.height))
1966  TRACE_UNIC(TTEXT, unistr.data, unistr.len)
1967 
1968  f_szdata = attrib->font.hdl;
1969 
1970  if ((f_szdata != NULL) &&
1971  (txt_box.width > f_szdata->bb_sd_width) &&
1972  (txt_box.height >= f_szdata->bb_sd_height))
1973  {
1974  U16BIT available_lines;
1975  S_REGION draw;
1976 
1977  TRACE(TTEXT, ("font=%x width=%d, height=%d posn=(%d,%d) ls=%d", attrib->font.hdl->fnt_id,
1978  txt_box.width, txt_box.height, txt_box.left, txt_box.top, attrib->line_space))
1979  /*See MHEG HD spec in DBook section 14.11.3.2 "Bounding box transformation" for scaling of boxes */
1980  draw.left = (S16BIT)((txt_box.left * mg_ctxt.osd_x.mlt) / mg_ctxt.osd_x.div);
1981  draw.top = (S16BIT)((txt_box.top * mg_ctxt.osd_y.mlt) / mg_ctxt.osd_y.div);
1982  draw.right = (S16BIT)txt_box.width;
1983  draw.bottom = (S16BIT)txt_box.height;
1984  draw.right = (S16BIT)(((draw.right + txt_box.left) * mg_ctxt.osd_x.mlt) / mg_ctxt.osd_x.div);
1985  draw.bottom = (S16BIT)(((draw.bottom + txt_box.top) * mg_ctxt.osd_y.mlt) / mg_ctxt.osd_y.div);
1986 
1987  /* box has some size, and may be able to fit some text in */
1988  if (attrib->line_space == 0)
1989  {
1990  /* infinite lines: all on same place! */
1991  available_lines = MAX_NUM_LINES;
1992  }
1993  else
1994  {
1995  available_lines = (U16BIT)(((txt_box.height - f_szdata->bb_sd_height) / attrib->line_space) + 1);
1996  if (available_lines > MAX_NUM_LINES)
1997  {
1998  /* defensive programming */
1999  TRACE(TERROR, ("Num of text lines was restricted from %d to %d", available_lines, MAX_NUM_LINES))
2000  available_lines = MAX_NUM_LINES;
2001  }
2002  }
2003 
2004  MG_CheckCache( f_szdata );
2005 
2006  char_data = GetCharArray( unistr, attrib, chars );
2007  if (char_data == NULL)
2008  {
2009  /*out of memory*/
2010  return 0;
2011  }
2012  font_ptr = MG_FindFont(f_szdata);
2013  line_count = PreparePrintableData( unistr, attrib, f_szdata, font_ptr, draw.right - draw.left,
2014  (U16BIT)txt_box.width, available_lines, lines, char_data, &glph_count );
2015  if (line_count > 0 && glph_count > 0)
2016  {
2017  #ifdef TRACING
2018  TRACE(TTEXT, ("HD box=(%d,%d,%d,%d)", draw.left, draw.top, draw.right, draw.bottom))
2019  TRACE(TTEXT, ("lines(%d,%d) left=%d avl_width=%d", available_lines, line_count, f_szdata->bound_box.left,
2020  txt_box.width - f_szdata->spxl_xleftoffset))
2021  if (TTEXT & mheg_trace_debug)
2022  trace_lines( line_count, lines, char_data, f_szdata->fnt_id & 0xff, font_ptr->metric_resolution );
2023  #endif /*TRACING*/
2024 
2025  canvas = OSD_MemAlloc( sizeof(S_SURFACE));
2026 
2027  if (canvas != NULL)
2028  {
2029  canvas->width = draw.right - draw.left;
2030  canvas->height = draw.bottom - draw.top;
2031  canvas->srf_type = SRF_TYPE_TXT;
2032  TRACE(TTEXT, ("canvas=(%d,%d)", canvas->width, canvas->height))
2033 
2034  if (attrib->line_space == 0)
2035  {
2036  available_lines = line_count;
2037  }
2038 
2039  IF_COL_DEPTH( COLOUR_FORMAT_PALETTE )
2040  {
2041  #ifdef OSD_8_BIT
2042  canvas->col_buff = OSD_MemAlloc( canvas->width * canvas->height );
2043  canvas->hw_handle = NULL;
2044  if (canvas->col_buff != NULL)
2045  {
2046  canvas->buff_pitch = canvas->width;
2047  memset( canvas->col_buff,
2048  OSD_FindNearestColourIndex(0x00000000),
2049  canvas->width * canvas->height );
2050 
2051  TextDraw8Bit( lines, char_data, f_szdata, font_ptr->face,
2052  attrib->justify & JUSTIFY_V_JUSTIFIED, attrib->justify & JUSTIFY_H_JUSTIFIED,
2053  attrib->line_space, txt_box.top, txt_box.height,
2054  line_count, available_lines, canvas );
2055  }
2056  #endif
2057  }
2058  ELSE IF_COL_DEPTH( COLOUR_FORMAT_ARGB4444 )
2059  {
2060  #ifdef OSD_16_BIT
2061  canvas->hw_handle = STB_OSDMhegCreateSurface( canvas->width, canvas->height,
2062  TRUE, 0x0000 );
2063  OSD_DbgAddSurf( canvas );
2064  if (canvas->hw_handle != NULL)
2065  {
2066  canvas->buff_pitch = canvas->width << 1;
2067  canvas->col_buff = STB_OSDMhegLockBuffer( canvas->hw_handle, &canvas->buff_pitch );
2068  if (canvas->col_buff)
2069  {
2070  TextDraw16Bit( lines, char_data, f_szdata, font_ptr->face,
2071  attrib->justify & JUSTIFY_V_JUSTIFIED, attrib->justify & JUSTIFY_H_JUSTIFIED,
2072  attrib->line_space, txt_box.top, txt_box.height,
2073  line_count, available_lines, canvas );
2074  STB_OSDMhegUnlockBuffer( canvas->hw_handle );
2075  }
2076  }
2077  #endif
2078  }
2079 
2080  ELSE
2081  {
2082  #if defined(OSD_31_BIT) || defined(OSD_32_BIT)
2083  canvas->hw_handle = STB_OSDMhegCreateSurface( canvas->width, canvas->height,
2084  TRUE, 0x00000000 );
2085  OSD_DbgAddSurf( canvas );
2086  if (canvas->hw_handle != NULL)
2087  {
2088  canvas->buff_pitch = canvas->width << 2;
2089  canvas->col_buff = STB_OSDMhegLockBuffer( canvas->hw_handle, &canvas->buff_pitch );
2090  if (canvas->col_buff)
2091  {
2092  TextDraw32Bit( lines, char_data, f_szdata, font_ptr->face,
2093  attrib->justify & JUSTIFY_V_JUSTIFIED, attrib->justify & JUSTIFY_H_JUSTIFIED,
2094  attrib->line_space, txt_box.top, txt_box.height,
2095  line_count, available_lines, canvas );
2096  STB_OSDMhegUnlockBuffer( canvas->hw_handle );
2097  }
2098  }
2099  #endif
2100  }
2101  }
2102  }
2103 
2104  if (char_data != chars)
2105  {
2106  OSD_MemFree( char_data );
2107  }
2108  }
2109 
2110  TRACE(TTEXT, ("return=0x%x\n", canvas))
2111  return canvas;
2112  /* returning NULL is not necessarily an error. It does that when no actual text to be displayed.
2113  * This code assumes that where an empty box is required (as when box is too small for text),
2114  * the higher level software will draw it.
2115  */
2116 }
2117 
2124 S16BIT MG_TextWidth( const TextString unistr, pDrawTextAttrib attrib )
2125 {
2126  CharData *char_data;
2127  CharData chars[MAX_NUM_CHARS];
2128  LineLimit lines[2];
2129  U16BIT line_count, glph_count;
2130  H_FontSize f_sz;
2131 
2132  assert( attrib );
2133 
2134  TRACE_UNIC(TTEXT, unistr.data, unistr.len)
2135 
2136  f_sz = attrib->font.hdl;
2137 
2138  if (f_sz == NULL)
2139  {
2140  TRACE(TERROR, ("f_sz NULL"))
2141  lines[0].l_width = 0;
2142  }
2143  else
2144  {
2145  TRACE(TTEXT, ("font id=%x", f_sz->fnt_id))
2146 
2147  MG_CheckCache( f_sz );
2148 
2149  char_data = GetCharArray( unistr, attrib, chars );
2150  if (char_data != NULL)
2151  {
2152  /* Setting justify to Hz End, means that width of spaces are counted (also tab => space) */
2153  attrib->justify = JUSTIFY_H_END;
2154  line_count = PreparePrintableData( unistr, attrib, f_sz, MG_FindFont(f_sz), mg_ctxt.out_osd_width,
2155  mg_ctxt.out_osd_width, 1, lines, char_data, &glph_count );
2156  if (line_count == 0)
2157  {
2158  lines[0].l_width = 0;
2159  }
2160  if (char_data != chars)
2161  {
2162  OSD_MemFree( char_data );
2163  }
2164  }
2165  }
2166 
2167  TRACE(TTEXT, ("return=%d", lines[0].l_width))
2168  return (S16BIT)lines[0].l_width;
2169 }
2170 
2178 void MG_DrawScreenText( const TextString unistr, pDrawTextAttrib attrib, S_SURFACE *canvas )
2179 {
2180  S_FontDetails *font_ptr;
2181  S_FontSize *f_szdata;
2182  CharData *char_data;
2183  CharData chars[MAX_NUM_CHARS];
2184  LineLimit lines[2];
2185  U16BIT line_count, glph_count;
2186 
2187  assert( attrib );
2188 
2189  TRACE(TTEXT, ("box=%d,%d", canvas->width, canvas->height))
2190  TRACE_UNIC(TTEXT, unistr.data, unistr.len)
2191 
2192  f_szdata = attrib->font.hdl;
2193 
2194  if (f_szdata != NULL && canvas != NULL && canvas->col_buff != NULL &&
2195  (canvas->width > f_szdata->bb_sd_width) &&
2196  (canvas->height >= f_szdata->bb_sd_height))
2197  {
2198  TRACE(TTEXT, ("font=%x ls=%d", attrib->font.hdl->fnt_id, attrib->line_space))
2199 
2200  //MG_CheckCache( f_szdata );
2201 
2202  char_data = GetCharArray( unistr, attrib, chars );
2203  if (char_data != NULL)
2204  {
2205  font_ptr = MG_FindFont(f_szdata);
2206  line_count = PreparePrintableData( unistr, attrib, f_szdata, font_ptr, canvas->width,
2207  canvas->width, 1, lines, char_data, &glph_count );
2208  if (line_count > 0 && glph_count > 0)
2209  {
2210  #ifdef TRACING
2211  TRACE(TTEXT, ("lines(%d,%d)", 1, line_count))
2212  if (TTEXT & mheg_trace_debug)
2213  trace_lines( line_count, lines, char_data, f_szdata->fnt_id & 0xff, font_ptr->metric_resolution );
2214  #endif /*TRACING*/
2215 
2216  if (canvas != NULL)
2217  {
2218  TRACE(TTEXT, ("canvas (buf=%p,%d,%d)", canvas->col_buff, canvas->width, canvas->height))
2219 
2220  IF_COL_DEPTH( COLOUR_FORMAT_PALETTE )
2221  {
2222  #ifdef OSD_8_BIT
2223  TextDraw8Bit( lines, char_data, f_szdata, font_ptr->face,
2224  attrib->justify & JUSTIFY_V_JUSTIFIED, attrib->justify & JUSTIFY_H_JUSTIFIED,
2225  attrib->line_space, 0, canvas->height,
2226  line_count, 1, canvas );
2227  #endif
2228  }
2229  ELSE IF_COL_DEPTH( COLOUR_FORMAT_ARGB4444 )
2230  {
2231  #ifdef OSD_16_BIT
2232  TextDraw16BitBlend( lines, char_data, f_szdata, font_ptr->face,
2233  attrib->justify & JUSTIFY_V_JUSTIFIED, attrib->justify & JUSTIFY_H_JUSTIFIED,
2234  attrib->line_space, 0, canvas->height,
2235  line_count, 1, canvas );
2236  #endif
2237  }
2238 
2239  ELSE
2240  {
2241  #if defined(OSD_31_BIT) || defined(OSD_32_BIT)
2242  TextDraw32BitBlend( lines, char_data, f_szdata, font_ptr->face,
2243  attrib->justify & JUSTIFY_V_JUSTIFIED, attrib->justify & JUSTIFY_H_JUSTIFIED,
2244  attrib->line_space, 0, canvas->height,
2245  line_count, 1, canvas );
2246  #endif
2247  }
2248  }
2249  }
2250 
2251  if (char_data != chars)
2252  {
2253  OSD_MemFree( char_data );
2254  }
2255  }
2256  }
2257  else
2258  {
2259  /* Access often code causes things to end up here - appearance seems ok anyway */
2260  if (f_szdata != NULL && canvas != NULL)
2261  {
2262  TRACE(TTEXT, ("Size too small: (%d < %d)? or (%d < %d)?", canvas->width, f_szdata->bb_sd_width, canvas->height, f_szdata->bb_sd_height));
2263  }
2264  }
2265 }
2266 
2275 void* MG_DrawText( const TextString unistr, pDrawTextAttrib attrib, const VRect txt_box )
2276 {
2277 #ifdef HK_PROFILE
2278  if (attrib->font.fp.index == HK_FNT_MAGIC)
2279  {
2280  return MG_DrawHKText( unistr, attrib, txt_box );
2281  }
2282  else
2283 #endif
2284  {
2285  return MG_DrawUKText( unistr, attrib, txt_box );
2286  }
2287 }
2288 
OSD utility functions.
void * MG_DrawUKText(const TextString unistr, pDrawTextAttrib attrib, const VRect txt_box)
Create Surface and draw text string on it and terminate freetype library.
Definition: mg_drawtext.c:1953
S16BIT MG_TextWidth(const TextString unistr, pDrawTextAttrib attrib)
Definition: mg_drawtext.c:2124
void MG_DrawScreenText(const TextString unistr, pDrawTextAttrib attrib, S_SURFACE *canvas)
Single line text string drawn on existing Surface.
Definition: mg_drawtext.c:2178
Debug tracing.
Font file handling with the Freetype.
void * MG_DrawText(const TextString unistr, pDrawTextAttrib attrib, const VRect txt_box)
Create Surface and draw text string on it and terminate freetype library.
Definition: mg_drawtext.c:2275
void * STB_OSDMhegCreateSurface(U16BIT width, U16BIT height, BOOLEAN init, U32BIT colour)
Creates a hardware surface on which MHEG5 engine will draw an individual MHEG object. At its basic the function can just allocate the buffer to be returned by STB_OSDMhegLockBuffer(). It&#39;s size being: (width * height * bytes_per_pixel) Also, when &#39;init&#39; is TRUE, function initialises surface buffer to the specified colour. For pixel colour format of less than four bytes, use least significant bits of &#39;colour&#39;.
Memory functions.
Interface to OSD.
define asserts
void * STB_OSDMhegLockBuffer(void *surface, U32BIT *pPitch)
Converts hardware surface handle returned by STB_OSDMhegCreateSurface() to buffer address that the en...
S_FontDetails * MG_FindFont(H_FontSize f_sz)
Get font from size.
Definition: mg_font.c:542
MHEG text render that uses the Freetype font library.
void MG_CheckCache(S_FontSize *f_szdata)
Definition: mg_font.c:841
Interface to the MHEG text render that uses Freetype font library.
Interface to the MHEG text render that uses Freetype font library.
Graphics functions required by the HD MHEG5 engine. All references to colour used in these functions ...
void ProcessNewLine(S_PROPERTIES *pp, CharData *chars, S_FontSize *f_sz_data, U16BIT line_num, U8BIT justify)
Process for adding a new line.
Definition: mg_drawtext.c:1163
void STB_OSDMhegUnlockBuffer(void *surface)
This function informs HW that MHEG5 is finished writing to the buffer.
#define TRACE(t, x)
Definition: glue_debug.h:118