]> git.saurik.com Git - apple/icu.git/blob - icuSources/layoutex/ParagraphLayout.cpp
ICU-400.39.tar.gz
[apple/icu.git] / icuSources / layoutex / ParagraphLayout.cpp
1 /*
2 **********************************************************************
3 * Copyright (C) 2002-2008, International Business Machines
4 * Corporation and others. All Rights Reserved.
5 **********************************************************************
6 */
7
8 /*
9 * paragraphLayout doesn't make much sense without
10 * BreakIterator...
11 */
12 #include "layout/LETypes.h"
13 #include "layout/LEScripts.h"
14 #include "layout/LELanguages.h"
15 #include "layout/LayoutEngine.h"
16 #include "layout/LEFontInstance.h"
17
18 #include "unicode/ubidi.h"
19 #include "unicode/uchriter.h"
20 #include "unicode/brkiter.h"
21
22 #if ! UCONFIG_NO_BREAK_ITERATION
23 #include "LXUtilities.h"
24 #include "usc_impl.h" /* this is currently private! */
25 #include "cstring.h" /* this too! */
26
27 #include "layout/ParagraphLayout.h"
28
29 U_NAMESPACE_BEGIN
30
31 #define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
32
33 /* Leave this copyright notice here! It needs to go somewhere in this library. */
34 static const char copyright[] = U_COPYRIGHT_STRING;
35
36 class StyleRuns
37 {
38 public:
39 StyleRuns(const RunArray *styleRunArrays[], le_int32 styleCount);
40
41 ~StyleRuns();
42
43 le_int32 getRuns(le_int32 runLimits[], le_int32 styleIndices[]);
44
45 private:
46 le_int32 fStyleCount;
47 le_int32 fRunCount;
48
49 le_int32 *fRunLimits;
50 le_int32 *fStyleIndices;
51 };
52
53 StyleRuns::StyleRuns(const RunArray *styleRunArrays[], le_int32 styleCount)
54 : fStyleCount(styleCount), fRunCount(0), fRunLimits(NULL), fStyleIndices(NULL)
55 {
56 le_int32 maxRunCount = 0;
57 le_int32 style, run, runStyle;
58 le_int32 *currentRun = LE_NEW_ARRAY(le_int32, styleCount);
59
60 for (int i = 0; i < styleCount; i += 1) {
61 maxRunCount += styleRunArrays[i]->getCount();
62 }
63
64 maxRunCount -= styleCount - 1;
65
66 fRunLimits = LE_NEW_ARRAY(le_int32, maxRunCount);
67 fStyleIndices = LE_NEW_ARRAY(le_int32, maxRunCount * styleCount);
68
69 for (style = 0; style < styleCount; style += 1) {
70 currentRun[style] = 0;
71 }
72
73 run = 0;
74 runStyle = 0;
75
76 /*
77 * Since the last run limit for each style run must be
78 * the same, all the styles will hit the last limit at
79 * the same time, so we know when we're done when the first
80 * style hits the last limit.
81 */
82 while (currentRun[0] < styleRunArrays[0]->getCount()) {
83 fRunLimits[run] = 0x7FFFFFFF;
84
85 // find the minimum run limit for all the styles
86 for (style = 0; style < styleCount; style += 1) {
87 if (styleRunArrays[style]->getLimit(currentRun[style]) < fRunLimits[run]) {
88 fRunLimits[run] = styleRunArrays[style]->getLimit(currentRun[style]);
89 }
90 }
91
92 // advance all styles whose current run is at this limit to the next run
93 for (style = 0; style < styleCount; style += 1) {
94 fStyleIndices[runStyle++] = currentRun[style];
95
96 if (styleRunArrays[style]->getLimit(currentRun[style]) == fRunLimits[run]) {
97 currentRun[style] += 1;
98 }
99 }
100
101 run += 1;
102 }
103
104 fRunCount = run;
105 LE_DELETE_ARRAY(currentRun);
106 }
107
108 StyleRuns::~StyleRuns()
109 {
110 fRunCount = 0;
111
112 LE_DELETE_ARRAY(fStyleIndices);
113 fStyleIndices = NULL;
114
115 LE_DELETE_ARRAY(fRunLimits);
116 fRunLimits = NULL;
117 }
118
119 le_int32 StyleRuns::getRuns(le_int32 runLimits[], le_int32 styleIndices[])
120 {
121 if (runLimits != NULL) {
122 LE_ARRAY_COPY(runLimits, fRunLimits, fRunCount);
123 }
124
125 if (styleIndices != NULL) {
126 LE_ARRAY_COPY(styleIndices, fStyleIndices, fRunCount * fStyleCount);
127 }
128
129 return fRunCount;
130 }
131
132 /*
133 * NOTE: This table only has "TRUE" values for
134 * those scripts which the LayoutEngine can currently
135 * process, rather for all scripts which require
136 * complex processing for correct rendering.
137 */
138 static const le_bool complexTable[scriptCodeCount] = {
139 FALSE , /* Zyyy */
140 FALSE, /* Qaai */
141 TRUE, /* Arab */
142 FALSE, /* Armn */
143 TRUE, /* Beng */
144 FALSE, /* Bopo */
145 FALSE, /* Cher */
146 FALSE, /* Copt=Qaac */
147 FALSE, /* Cyrl */
148 FALSE, /* Dsrt */
149 TRUE, /* Deva */
150 FALSE, /* Ethi */
151 FALSE, /* Geor */
152 FALSE, /* Goth */
153 FALSE, /* Grek */
154 TRUE, /* Gujr */
155 TRUE, /* Guru */
156 FALSE, /* Hani */
157 FALSE, /* Hang */
158 TRUE, /* Hebr */
159 FALSE, /* Hira */
160 TRUE, /* Knda */
161 FALSE, /* Kana */
162 FALSE, /* Khmr */
163 FALSE, /* Laoo */
164 FALSE, /* Latn */
165 TRUE, /* Mlym */
166 FALSE, /* Mong */
167 FALSE, /* Mymr */
168 FALSE, /* Ogam */
169 FALSE, /* Ital */
170 TRUE, /* Orya */
171 FALSE, /* Runr */
172 FALSE, /* Sinh */
173 FALSE, /* Syrc */
174 TRUE, /* Taml */
175 TRUE, /* Telu */
176 FALSE, /* Thaa */
177 TRUE, /* Thai */
178 FALSE, /* Tibt */
179 FALSE, /* Cans */
180 FALSE, /* Yiii */
181 FALSE, /* Tglg */
182 FALSE, /* Hano */
183 FALSE, /* Buhd */
184 FALSE, /* Tagb */
185 FALSE, /* Brai */
186 FALSE, /* Cprt */
187 FALSE, /* Limb */
188 FALSE, /* Linb */
189 FALSE, /* Osma */
190 FALSE, /* Shaw */
191 FALSE, /* Tale */
192 FALSE, /* Ugar */
193 FALSE, /* Hrkt */
194 FALSE, /* Bugi */
195 FALSE, /* Glag */
196 FALSE, /* Khar */
197 FALSE, /* Sylo */
198 FALSE, /* Talu */
199 FALSE, /* Tfng */
200 FALSE, /* Xpeo */
201 FALSE, /* Bali */
202 FALSE, /* Batk */
203 FALSE, /* Blis */
204 FALSE, /* Brah */
205 FALSE, /* Cham */
206 FALSE, /* Cirt */
207 FALSE, /* Cyrs */
208 FALSE, /* Egyd */
209 FALSE, /* Egyh */
210 FALSE, /* Egyp */
211 FALSE, /* Geok */
212 FALSE, /* Hans */
213 FALSE, /* Hant */
214 FALSE, /* Hmng */
215 FALSE, /* Hung */
216 FALSE, /* Inds */
217 FALSE, /* Java */
218 FALSE, /* Kali */
219 FALSE, /* Latf */
220 FALSE, /* Latg */
221 FALSE, /* Lepc */
222 FALSE, /* Lina */
223 FALSE, /* Mand */
224 FALSE, /* Maya */
225 FALSE, /* Mero */
226 FALSE, /* Nkoo */
227 FALSE, /* Orkh */
228 FALSE, /* Perm */
229 FALSE, /* Phag */
230 FALSE, /* Phnx */
231 FALSE, /* Plrd */
232 FALSE, /* Roro */
233 FALSE, /* Sara */
234 FALSE, /* Syre */
235 FALSE, /* Syrj */
236 FALSE, /* Syrn */
237 FALSE, /* Teng */
238 FALSE, /* Taii */
239 FALSE, /* Visp */
240 FALSE, /* Xsux */
241 FALSE, /* Zxxx */
242 FALSE, /* Zzzz */
243 FALSE, /* Cari */
244 FALSE, /* Jpan */
245 FALSE, /* Lana */
246 FALSE, /* Lyci */
247 FALSE, /* Lydi */
248 FALSE, /* Olck */
249 FALSE, /* Rjng */
250 FALSE, /* Saur */
251 FALSE, /* Sgnw */
252 FALSE, /* Sund */
253 FALSE, /* Moon */
254 FALSE, /* Mtei */
255 FALSE, /* Armi */
256 FALSE, /* Avst */
257 FALSE, /* Cakm */
258 FALSE, /* Kore */
259 FALSE, /* Kthi */
260 FALSE, /* Mani */
261 FALSE, /* Phli */
262 FALSE, /* Phlp */
263 FALSE, /* Phlv */
264 FALSE, /* Prti */
265 FALSE, /* Samr */
266 FALSE, /* Tavt */
267 FALSE, /* Zmth */
268 FALSE /* Zsym */
269 };
270
271
272 const char ParagraphLayout::fgClassID = 0;
273
274 /*
275 * How to deal with composite fonts:
276 *
277 * Don't store the client's FontRuns; we'll need to compute sub-font FontRuns using Doug's
278 * LEFontInstance method. Do that by intersecting the client's FontRuns with fScriptRuns. Use
279 * that to compute fFontRuns, and then intersect fFontRuns, fScriptRuns and fLevelRuns. Doing
280 * it in this order means we do a two-way intersection and a three-way intersection.
281 *
282 * An optimization would be to only do this if there's at least one composite font...
283 *
284 * Other notes:
285 *
286 * * Return the sub-fonts as the run fonts... could keep the mapping back to the client's FontRuns
287 * but that probably makes it more complicated of everyone...
288 *
289 * * Take the LineInfo and LineRun types from Paragraph and use them here, incorporate them into the API.
290 *
291 * * Might want to change the name of the StyleRun type, and make a new one that holds fonts, scripts and levels?
292 *
293 */
294 ParagraphLayout::ParagraphLayout(const LEUnicode chars[], le_int32 count,
295 const FontRuns *fontRuns,
296 const ValueRuns *levelRuns,
297 const ValueRuns *scriptRuns,
298 const LocaleRuns *localeRuns,
299 UBiDiLevel paragraphLevel, le_bool vertical,
300 LEErrorCode &status)
301 : fChars(chars), fCharCount(count),
302 fFontRuns(NULL), fLevelRuns(levelRuns), fScriptRuns(scriptRuns), fLocaleRuns(localeRuns),
303 fVertical(vertical), fClientLevels(TRUE), fClientScripts(TRUE), fClientLocales(TRUE), fEmbeddingLevels(NULL),
304 fAscent(0), fDescent(0), fLeading(0),
305 fGlyphToCharMap(NULL), fCharToMinGlyphMap(NULL), fCharToMaxGlyphMap(NULL), fGlyphWidths(NULL), fGlyphCount(0),
306 fParaBidi(NULL), fLineBidi(NULL),
307 fStyleRunLimits(NULL), fStyleIndices(NULL), fStyleRunCount(0),
308 fBreakIterator(NULL), fLineStart(-1), fLineEnd(0),
309 /*fVisualRuns(NULL), fStyleRunInfo(NULL), fVisualRunCount(-1),
310 fFirstVisualRun(-1), fLastVisualRun(-1),*/ fVisualRunLastX(0), fVisualRunLastY(0)
311 {
312
313 if (LE_FAILURE(status)) {
314 fCharCount = -1;
315 return;
316 }
317
318 // FIXME: should check the limit arrays for consistency...
319
320 computeLevels(paragraphLevel);
321
322 if (scriptRuns == NULL) {
323 computeScripts();
324 }
325
326 if (localeRuns == NULL) {
327 computeLocales();
328 }
329
330 computeSubFonts(fontRuns, status);
331
332 if (LE_FAILURE(status)) {
333 //other stuff?
334 fCharCount = -1;
335 return;
336 }
337
338 // now intersect the font, direction and script runs...
339 const RunArray *styleRunArrays[] = {fFontRuns, fLevelRuns, fScriptRuns, fLocaleRuns};
340 le_int32 styleCount = sizeof styleRunArrays / sizeof styleRunArrays[0];
341 StyleRuns styleRuns(styleRunArrays, styleCount);
342 LEErrorCode layoutStatus = LE_NO_ERROR;
343
344 fStyleRunCount = styleRuns.getRuns(NULL, NULL);
345
346 fStyleRunLimits = LE_NEW_ARRAY(le_int32, fStyleRunCount);
347 fStyleIndices = LE_NEW_ARRAY(le_int32, fStyleRunCount * styleCount);
348
349 styleRuns.getRuns(fStyleRunLimits, fStyleIndices);
350
351 // now build a LayoutEngine for each style run...
352 le_int32 *styleIndices = fStyleIndices;
353 le_int32 run, runStart;
354
355 fStyleRunInfo = LE_NEW_ARRAY(StyleRunInfo, fStyleRunCount);
356
357 fGlyphCount = 0;
358 for (runStart = 0, run = 0; run < fStyleRunCount; run += 1) {
359 fStyleRunInfo[run].font = fFontRuns->getFont(styleIndices[0]);
360 fStyleRunInfo[run].runBase = runStart;
361 fStyleRunInfo[run].runLimit = fStyleRunLimits[run];
362 fStyleRunInfo[run].script = (UScriptCode) fScriptRuns->getValue(styleIndices[2]);
363 fStyleRunInfo[run].locale = fLocaleRuns->getLocale(styleIndices[3]);
364 fStyleRunInfo[run].level = (UBiDiLevel) fLevelRuns->getValue(styleIndices[1]);
365 fStyleRunInfo[run].glyphBase = fGlyphCount;
366
367 fStyleRunInfo[run].engine = LayoutEngine::layoutEngineFactory(fStyleRunInfo[run].font,
368 fStyleRunInfo[run].script, getLanguageCode(fStyleRunInfo[run].locale), layoutStatus);
369
370 fStyleRunInfo[run].glyphCount = fStyleRunInfo[run].engine->layoutChars(fChars, runStart, fStyleRunLimits[run] - runStart, fCharCount,
371 fStyleRunInfo[run].level & 1, 0, 0, layoutStatus);
372
373 runStart = fStyleRunLimits[run];
374 styleIndices += styleCount;
375 fGlyphCount += fStyleRunInfo[run].glyphCount;
376 }
377
378 // Make big arrays for the glyph widths, glyph-to-char and char-to-glyph maps,
379 // in logical order. (Both maps need an extra entry for the end of the text.)
380 //
381 // For each layout get the positions and convert them into glyph widths, in
382 // logical order. Get the glyph-to-char mapping, offset by starting index in the
383 // character array. Swap the glyph width and glyph-to-char arrays into logical order.
384 // Finally, fill in the char-to-glyph mappings.
385 fGlyphWidths = LE_NEW_ARRAY(float, fGlyphCount);
386 fGlyphToCharMap = LE_NEW_ARRAY(le_int32, fGlyphCount + 1);
387 fCharToMinGlyphMap = LE_NEW_ARRAY(le_int32, fCharCount + 1);
388 fCharToMaxGlyphMap = LE_NEW_ARRAY(le_int32, fCharCount + 1);
389
390 le_int32 glyph;
391
392 for (runStart = 0, run = 0; run < fStyleRunCount; run += 1) {
393 LayoutEngine *engine = fStyleRunInfo[run].engine;
394 le_int32 glyphCount = fStyleRunInfo[run].glyphCount;
395 le_int32 glyphBase = fStyleRunInfo[run].glyphBase;
396
397 fStyleRunInfo[run].glyphs = LE_NEW_ARRAY(LEGlyphID, glyphCount);
398 fStyleRunInfo[run].positions = LE_NEW_ARRAY(float, glyphCount * 2 + 2);
399
400 engine->getGlyphs(fStyleRunInfo[run].glyphs, layoutStatus);
401 engine->getGlyphPositions(fStyleRunInfo[run].positions, layoutStatus);
402 engine->getCharIndices(&fGlyphToCharMap[glyphBase], runStart, layoutStatus);
403
404 for (glyph = 0; glyph < glyphCount; glyph += 1) {
405 fGlyphWidths[glyphBase + glyph] = fStyleRunInfo[run].positions[glyph * 2 + 2] - fStyleRunInfo[run].positions[glyph * 2];
406 }
407
408 if ((fStyleRunInfo[run].level & 1) != 0) {
409 LXUtilities::reverse(&fGlyphWidths[glyphBase], glyphCount);
410 LXUtilities::reverse(&fGlyphToCharMap[glyphBase], glyphCount);
411 }
412
413 runStart = fStyleRunLimits[run];
414
415 delete engine;
416 fStyleRunInfo[run].engine = NULL;
417 }
418
419 fGlyphToCharMap[fGlyphCount] = fCharCount;
420
421 for (glyph = fGlyphCount - 1; glyph >= 0; glyph -= 1) {
422 le_int32 ch = fGlyphToCharMap[glyph];
423
424 fCharToMinGlyphMap[ch] = glyph;
425 }
426
427 fCharToMinGlyphMap[fCharCount] = fGlyphCount;
428
429 for (glyph = 0; glyph < fGlyphCount; glyph += 1) {
430 le_int32 ch = fGlyphToCharMap[glyph];
431
432 fCharToMaxGlyphMap[ch] = glyph;
433 }
434
435 fCharToMaxGlyphMap[fCharCount] = fGlyphCount;
436 }
437
438 ParagraphLayout::~ParagraphLayout()
439 {
440 delete (FontRuns *) fFontRuns;
441
442 if (! fClientLevels) {
443 delete (ValueRuns *) fLevelRuns;
444 fLevelRuns = NULL;
445
446 fClientLevels = TRUE;
447 }
448
449 if (! fClientScripts) {
450 delete (ValueRuns *) fScriptRuns;
451 fScriptRuns = NULL;
452
453 fClientScripts = TRUE;
454 }
455
456 if (! fClientLocales) {
457 delete (LocaleRuns *) fLocaleRuns;
458 fLocaleRuns = NULL;
459
460 fClientLocales = TRUE;
461 }
462
463 if (fEmbeddingLevels != NULL) {
464 LE_DELETE_ARRAY(fEmbeddingLevels);
465 fEmbeddingLevels = NULL;
466 }
467
468 if (fGlyphToCharMap != NULL) {
469 LE_DELETE_ARRAY(fGlyphToCharMap);
470 fGlyphToCharMap = NULL;
471 }
472
473 if (fCharToMinGlyphMap != NULL) {
474 LE_DELETE_ARRAY(fCharToMinGlyphMap);
475 fCharToMinGlyphMap = NULL;
476 }
477
478 if (fCharToMaxGlyphMap != NULL) {
479 LE_DELETE_ARRAY(fCharToMaxGlyphMap);
480 fCharToMaxGlyphMap = NULL;
481 }
482
483 if (fGlyphWidths != NULL) {
484 LE_DELETE_ARRAY(fGlyphWidths);
485 fGlyphWidths = NULL;
486 }
487
488 if (fParaBidi != NULL) {
489 ubidi_close(fParaBidi);
490 fParaBidi = NULL;
491 }
492
493 if (fLineBidi != NULL) {
494 ubidi_close(fLineBidi);
495 fLineBidi = NULL;
496 }
497
498 if (fStyleRunCount > 0) {
499 le_int32 run;
500
501 LE_DELETE_ARRAY(fStyleRunLimits);
502 LE_DELETE_ARRAY(fStyleIndices);
503
504 for (run = 0; run < fStyleRunCount; run += 1) {
505 LE_DELETE_ARRAY(fStyleRunInfo[run].glyphs);
506 LE_DELETE_ARRAY(fStyleRunInfo[run].positions);
507
508 fStyleRunInfo[run].glyphs = NULL;
509 fStyleRunInfo[run].positions = NULL;
510 }
511
512 LE_DELETE_ARRAY(fStyleRunInfo);
513
514 fStyleRunLimits = NULL;
515 fStyleIndices = NULL;
516 fStyleRunInfo = NULL;
517 fStyleRunCount = 0;
518 }
519
520 if (fBreakIterator != NULL) {
521 delete fBreakIterator;
522 fBreakIterator = NULL;
523 }
524 }
525
526
527 le_bool ParagraphLayout::isComplex(const LEUnicode chars[], le_int32 count)
528 {
529 UErrorCode scriptStatus = U_ZERO_ERROR;
530 UScriptCode scriptCode = USCRIPT_INVALID_CODE;
531 UScriptRun *sr = uscript_openRun(chars, count, &scriptStatus);
532 le_bool result = FALSE;
533
534 while (uscript_nextRun(sr, NULL, NULL, &scriptCode)) {
535 if (isComplex(scriptCode)) {
536 result = TRUE;
537 break;
538 }
539 }
540
541 uscript_closeRun(sr);
542 return result;
543 }
544
545 le_int32 ParagraphLayout::getAscent() const
546 {
547 if (fAscent <= 0 && fCharCount > 0) {
548 ((ParagraphLayout *) this)->computeMetrics();
549 }
550
551 return fAscent;
552 }
553
554 le_int32 ParagraphLayout::getDescent() const
555 {
556 if (fAscent <= 0 && fCharCount > 0) {
557 ((ParagraphLayout *) this)->computeMetrics();
558 }
559
560 return fDescent;
561 }
562
563 le_int32 ParagraphLayout::getLeading() const
564 {
565 if (fAscent <= 0 && fCharCount > 0) {
566 ((ParagraphLayout *) this)->computeMetrics();
567 }
568
569 return fLeading;
570 }
571
572 ParagraphLayout::Line *ParagraphLayout::nextLine(float width)
573 {
574 if (fLineEnd >= fCharCount) {
575 return NULL;
576 }
577
578 fLineStart = fLineEnd;
579
580 if (width > 0) {
581 le_int32 glyph = fCharToMinGlyphMap[fLineStart];
582 float widthSoFar = 0;
583
584 while (glyph < fGlyphCount && widthSoFar + fGlyphWidths[glyph] <= width) {
585 widthSoFar += fGlyphWidths[glyph++];
586 }
587
588 // If no glyphs fit on the line, force one to fit.
589 //
590 // (There shouldn't be any zero width glyphs at the
591 // start of a line unless the paragraph consists of
592 // only zero width glyphs, because otherwise the zero
593 // width glyphs will have been included on the end of
594 // the previous line...)
595 if (widthSoFar == 0 && glyph < fGlyphCount) {
596 glyph += 1;
597 }
598
599 fLineEnd = previousBreak(fGlyphToCharMap[glyph]);
600
601 // If this break is at or before the last one,
602 // find a glyph, starting at the one which didn't
603 // fit, that produces a break after the last one.
604 while (fLineEnd <= fLineStart) {
605 fLineEnd = fGlyphToCharMap[glyph++];
606 }
607 } else {
608 fLineEnd = fCharCount;
609 }
610
611 return computeVisualRuns();
612 }
613
614 void ParagraphLayout::computeLevels(UBiDiLevel paragraphLevel)
615 {
616 UErrorCode bidiStatus = U_ZERO_ERROR;
617
618 if (fLevelRuns != NULL) {
619 le_int32 ch;
620 le_int32 run;
621
622 fEmbeddingLevels = LE_NEW_ARRAY(UBiDiLevel, fCharCount);
623
624 for (ch = 0, run = 0; run < fLevelRuns->getCount(); run += 1) {
625 UBiDiLevel runLevel = (UBiDiLevel) fLevelRuns->getValue(run) | UBIDI_LEVEL_OVERRIDE;
626 le_int32 runLimit = fLevelRuns->getLimit(run);
627
628 while (ch < runLimit) {
629 fEmbeddingLevels[ch++] = runLevel;
630 }
631 }
632 }
633
634 fParaBidi = ubidi_openSized(fCharCount, 0, &bidiStatus);
635 ubidi_setPara(fParaBidi, fChars, fCharCount, paragraphLevel, fEmbeddingLevels, &bidiStatus);
636
637 if (fLevelRuns == NULL) {
638 le_int32 levelRunCount = ubidi_countRuns(fParaBidi, &bidiStatus);
639 ValueRuns *levelRuns = new ValueRuns(levelRunCount);
640
641 le_int32 logicalStart = 0;
642 le_int32 run;
643 le_int32 limit;
644 UBiDiLevel level;
645
646 for (run = 0; run < levelRunCount; run += 1) {
647 ubidi_getLogicalRun(fParaBidi, logicalStart, &limit, &level);
648 levelRuns->add(level, limit);
649 logicalStart = limit;
650 }
651
652 fLevelRuns = levelRuns;
653 fClientLevels = FALSE;
654 }
655 }
656
657 void ParagraphLayout::computeScripts()
658 {
659 UErrorCode scriptStatus = U_ZERO_ERROR;
660 UScriptRun *sr = uscript_openRun(fChars, fCharCount, &scriptStatus);
661 ValueRuns *scriptRuns = new ValueRuns(0);
662 le_int32 limit;
663 UScriptCode script;
664
665 while (uscript_nextRun(sr, NULL, &limit, &script)) {
666 scriptRuns->add(script, limit);
667 }
668
669 uscript_closeRun(sr);
670
671 fScriptRuns = scriptRuns;
672 fClientScripts = FALSE;
673 }
674
675 void ParagraphLayout::computeLocales()
676 {
677 LocaleRuns *localeRuns = new LocaleRuns(0);
678 const Locale *defaultLocale = &Locale::getDefault();
679
680 localeRuns->add(defaultLocale, fCharCount);
681
682 fLocaleRuns = localeRuns;
683 fClientLocales = FALSE;
684 }
685
686 void ParagraphLayout::computeSubFonts(const FontRuns *fontRuns, LEErrorCode &status)
687 {
688 if (LE_FAILURE(status)) {
689 return;
690 }
691
692 const RunArray *styleRunArrays[] = {fontRuns, fScriptRuns};
693 le_int32 styleCount = sizeof styleRunArrays / sizeof styleRunArrays[0];
694 StyleRuns styleRuns(styleRunArrays, styleCount);
695 le_int32 styleRunCount = styleRuns.getRuns(NULL, NULL);
696 le_int32 *styleRunLimits = LE_NEW_ARRAY(le_int32, styleRunCount);
697 le_int32 *styleIndices = LE_NEW_ARRAY(le_int32, styleRunCount * styleCount);
698 FontRuns *subFontRuns = new FontRuns(0);
699 le_int32 run, offset, *si;
700
701 styleRuns.getRuns(styleRunLimits, styleIndices);
702
703 si = styleIndices;
704 offset = 0;
705
706 for (run = 0; run < styleRunCount; run += 1) {
707 const LEFontInstance *runFont = fontRuns->getFont(si[0]);
708 le_int32 script = fScriptRuns->getValue(si[1]);
709
710 while (offset < styleRunLimits[run]) {
711 const LEFontInstance *subFont = runFont->getSubFont(fChars, &offset, styleRunLimits[run], script, status);
712
713 if (LE_FAILURE(status)) {
714 delete subFontRuns;
715 goto cleanUp;
716 }
717
718 subFontRuns->add(subFont, offset);
719 }
720
721 si += styleCount;
722 }
723
724 fFontRuns = subFontRuns;
725
726 cleanUp:
727 LE_DELETE_ARRAY(styleIndices);
728 LE_DELETE_ARRAY(styleRunLimits);
729 }
730
731 void ParagraphLayout::computeMetrics()
732 {
733 le_int32 i, count = fFontRuns->getCount();
734 le_int32 maxDL = 0;
735
736 for (i = 0; i < count; i += 1) {
737 const LEFontInstance *font = fFontRuns->getFont(i);
738 le_int32 ascent = font->getAscent();
739 le_int32 descent = font->getDescent();
740 le_int32 leading = font->getLeading();
741 le_int32 dl = descent + leading;
742
743 if (ascent > fAscent) {
744 fAscent = ascent;
745 }
746
747 if (descent > fDescent) {
748 fDescent = descent;
749 }
750
751 if (leading > fLeading) {
752 fLeading = leading;
753 }
754
755 if (dl > maxDL) {
756 maxDL = dl;
757 }
758 }
759
760 fLeading = maxDL - fDescent;
761 }
762
763 #if 1
764 struct LanguageMap
765 {
766 const char *localeCode;
767 le_int32 languageCode;
768 };
769
770 static const LanguageMap languageMap[] =
771 {
772 {"afr", afkLanguageCode}, // Afrikaans
773 {"ara", araLanguageCode}, // Arabic
774 {"asm", asmLanguageCode}, // Assamese
775 {"bel", belLanguageCode}, // Belarussian
776 {"ben", benLanguageCode}, // Bengali
777 {"bod", tibLanguageCode}, // Tibetan
778 {"bul", bgrLanguageCode}, // Bulgarian
779 {"cat", catLanguageCode}, // Catalan
780 {"ces", csyLanguageCode}, // Czech
781 {"che", cheLanguageCode}, // Chechen
782 {"cop", copLanguageCode}, // Coptic
783 {"cym", welLanguageCode}, // Welsh
784 {"dan", danLanguageCode}, // Danish
785 {"deu", deuLanguageCode}, // German
786 {"dzo", dznLanguageCode}, // Dzongkha
787 {"ell", ellLanguageCode}, // Greek
788 {"eng", engLanguageCode}, // English
789 {"est", etiLanguageCode}, // Estonian
790 {"eus", euqLanguageCode}, // Basque
791 {"fas", farLanguageCode}, // Farsi
792 {"fin", finLanguageCode}, // Finnish
793 {"fra", fraLanguageCode}, // French
794 {"gle", gaeLanguageCode}, // Irish Gaelic
795 {"guj", gujLanguageCode}, // Gujarati
796 {"hau", hauLanguageCode}, // Hausa
797 {"heb", iwrLanguageCode}, // Hebrew
798 {"hin", hinLanguageCode}, // Hindi
799 {"hrv", hrvLanguageCode}, // Croatian
800 {"hun", hunLanguageCode}, // Hungarian
801 {"hye", hyeLanguageCode}, // Armenian
802 {"ind", indLanguageCode}, // Indonesian
803 {"ita", itaLanguageCode}, // Italian
804 {"jpn", janLanguageCode}, // Japanese
805 {"kan", kanLanguageCode}, // Kannada
806 {"kas", kshLanguageCode}, // Kashmiri
807 {"khm", khmLanguageCode}, // Khmer
808 {"kok", kokLanguageCode}, // Konkani
809 {"kor", korLanguageCode}, // Korean
810 // {"mal_XXX", malLanguageCode}, // Malayalam - Traditional
811 {"mal", mlrLanguageCode}, // Malayalam - Reformed
812 {"mar", marLanguageCode}, // Marathi
813 {"mlt", mtsLanguageCode}, // Maltese
814 {"mni", mniLanguageCode}, // Manipuri
815 {"mon", mngLanguageCode}, // Mongolian
816 {"nep", nepLanguageCode}, // Nepali
817 {"ori", oriLanguageCode}, // Oriya
818 {"pol", plkLanguageCode}, // Polish
819 {"por", ptgLanguageCode}, // Portuguese
820 {"pus", pasLanguageCode}, // Pashto
821 {"ron", romLanguageCode}, // Romanian
822 {"rus", rusLanguageCode}, // Russian
823 {"san", sanLanguageCode}, // Sanskrit
824 {"sin", snhLanguageCode}, // Sinhalese
825 {"slk", skyLanguageCode}, // Slovak
826 {"snd", sndLanguageCode}, // Sindhi
827 {"slv", slvLanguageCode}, // Slovenian
828 {"spa", espLanguageCode}, // Spanish
829 {"sqi", sqiLanguageCode}, // Albanian
830 {"srp", srbLanguageCode}, // Serbian
831 {"swe", sveLanguageCode}, // Swedish
832 {"syr", syrLanguageCode}, // Syriac
833 {"tam", tamLanguageCode}, // Tamil
834 {"tel", telLanguageCode}, // Telugu
835 {"tha", thaLanguageCode}, // Thai
836 {"tur", trkLanguageCode}, // Turkish
837 {"urd", urdLanguageCode}, // Urdu
838 {"yid", jiiLanguageCode}, // Yiddish
839 // {"zhp", zhpLanguageCode}, // Chinese - Phonetic
840 {"zho", zhsLanguageCode}, // Chinese
841 {"zho_CHN", zhsLanguageCode}, // Chinese - China
842 {"zho_HKG", zhsLanguageCode}, // Chinese - Hong Kong
843 {"zho_MAC", zhtLanguageCode}, // Chinese - Macao
844 {"zho_SGP", zhsLanguageCode}, // Chinese - Singapore
845 {"zho_TWN", zhtLanguageCode} // Chinese - Taiwan
846 };
847
848 static const le_int32 languageMapCount = ARRAY_SIZE(languageMap);
849
850 le_int32 ParagraphLayout::getLanguageCode(const Locale *locale)
851 {
852 char code[8] = {0, 0, 0, 0, 0, 0, 0, 0};
853 const char *language = locale->getISO3Language();
854 const char *country = locale->getISO3Country();
855
856 uprv_strcat(code, language);
857
858 if ((uprv_strcmp(language, "zho") == 0) && country != NULL) {
859 uprv_strcat(code, "_");
860 uprv_strcat(code, country);
861 }
862
863 for (le_int32 i = 0; i < languageMapCount; i += 1) {
864 if (uprv_strcmp(code, languageMap[i].localeCode) == 0) {
865 return languageMap[i].languageCode;
866 }
867 }
868
869 return nullLanguageCode;
870 }
871 #elif
872
873 // TODO - dummy implementation for right now...
874 le_int32 ParagraphLayout::getLanguageCode(const Locale *locale)
875 {
876 return nullLanguageCode;
877 }
878 #endif
879
880 le_bool ParagraphLayout::isComplex(UScriptCode script)
881 {
882 if (script < 0 || script >= (UScriptCode) scriptCodeCount) {
883 return FALSE;
884 }
885
886 return complexTable[script];
887 }
888
889 le_int32 ParagraphLayout::previousBreak(le_int32 charIndex)
890 {
891 // skip over any whitespace or control characters,
892 // because they can hang in the margin.
893 while (charIndex < fCharCount &&
894 (u_isWhitespace(fChars[charIndex]) ||
895 u_iscntrl(fChars[charIndex]))) {
896 charIndex += 1;
897 }
898
899 // Create the BreakIterator if we don't already have one
900 if (fBreakIterator == NULL) {
901 Locale thai("th");
902 UCharCharacterIterator *iter = new UCharCharacterIterator(fChars, fCharCount);
903 UErrorCode status = U_ZERO_ERROR;
904
905 fBreakIterator = BreakIterator::createLineInstance(thai, status);
906 fBreakIterator->adoptText(iter);
907 }
908
909 // return the break location that's at or before
910 // the character we stopped on. Note: if we're
911 // on a break, the "+ 1" will cause preceding to
912 // back up to it.
913 return fBreakIterator->preceding(charIndex + 1);
914 }
915
916 ParagraphLayout::Line *ParagraphLayout::computeVisualRuns()
917 {
918 UErrorCode bidiStatus = U_ZERO_ERROR;
919 le_int32 dirRunCount, visualRun;
920
921 fVisualRunLastX = 0;
922 fVisualRunLastY = 0;
923 fFirstVisualRun = getCharRun(fLineStart);
924 fLastVisualRun = getCharRun(fLineEnd - 1);
925
926 if (fLineBidi == NULL) {
927 fLineBidi = ubidi_openSized(fCharCount, 0, &bidiStatus);
928 }
929
930 ubidi_setLine(fParaBidi, fLineStart, fLineEnd, fLineBidi, &bidiStatus);
931 dirRunCount = ubidi_countRuns(fLineBidi, &bidiStatus);
932
933 Line *line = new Line();
934
935 for (visualRun = 0; visualRun < dirRunCount; visualRun += 1) {
936 le_int32 relStart, run, runLength;
937 UBiDiDirection runDirection = ubidi_getVisualRun(fLineBidi, visualRun, &relStart, &runLength);
938 le_int32 runStart = fLineStart + relStart;
939 le_int32 runEnd = runStart + runLength - 1;
940 le_int32 firstRun = getCharRun(runStart);
941 le_int32 lastRun = getCharRun(runEnd);
942 le_int32 startRun = (runDirection == UBIDI_LTR)? firstRun : lastRun;
943 le_int32 stopRun = (runDirection == UBIDI_LTR)? lastRun + 1 : firstRun - 1;
944 le_int32 dir = (runDirection == UBIDI_LTR)? 1 : -1;
945
946 for (run = startRun; run != stopRun; run += dir) {
947 le_int32 firstChar = (run == firstRun)? runStart : fStyleRunInfo[run].runBase;
948 le_int32 lastChar = (run == lastRun)? runEnd : fStyleRunInfo[run].runLimit - 1;
949
950 appendRun(line, run, firstChar, lastChar);
951 }
952 }
953
954 return line;
955 }
956
957 void ParagraphLayout::appendRun(ParagraphLayout::Line *line, le_int32 run, le_int32 firstChar, le_int32 lastChar)
958 {
959 le_int32 glyphBase = fStyleRunInfo[run].glyphBase;
960 le_int32 inGlyph, outGlyph;
961
962 // Get the glyph indices for all the characters between firstChar and lastChar,
963 // make the minimum one be leftGlyph and the maximum one be rightGlyph.
964 // (need to do this to handle local reorderings like Indic left matras)
965 le_int32 leftGlyph = fGlyphCount;
966 le_int32 rightGlyph = -1;
967 le_int32 ch;
968
969 for (ch = firstChar; ch <= lastChar; ch += 1) {
970 le_int32 minGlyph = fCharToMinGlyphMap[ch];
971 le_int32 maxGlyph = fCharToMaxGlyphMap[ch];
972
973 if (minGlyph < leftGlyph) {
974 leftGlyph = minGlyph;
975 }
976
977 if (maxGlyph > rightGlyph) {
978 rightGlyph = maxGlyph;
979 }
980 }
981
982 if ((fStyleRunInfo[run].level & 1) != 0) {
983 le_int32 swap = rightGlyph;
984 le_int32 last = glyphBase + fStyleRunInfo[run].glyphCount - 1;
985
986 // Here, we want to remove the glyphBase bias...
987 rightGlyph = last - leftGlyph;
988 leftGlyph = last - swap;
989 } else {
990 rightGlyph -= glyphBase;
991 leftGlyph -= glyphBase;
992 }
993
994 // Set the position bias for the glyphs. If we're at the start of
995 // a line, we want the first glyph to be at x = 0, even if it comes
996 // from the middle of a layout. If we've got a right-to-left run, we
997 // want the left-most glyph to start at the final x position of the
998 // previous run, even though this glyph may be in the middle of the
999 // run.
1000 fVisualRunLastX -= fStyleRunInfo[run].positions[leftGlyph * 2];
1001
1002 // Make rightGlyph be the glyph just to the right of
1003 // the run's glyphs
1004 rightGlyph += 1;
1005
1006 UBiDiDirection direction = ((fStyleRunInfo[run].level & 1) == 0)? UBIDI_LTR : UBIDI_RTL;
1007 le_int32 glyphCount = rightGlyph - leftGlyph;
1008 LEGlyphID *glyphs = LE_NEW_ARRAY(LEGlyphID, glyphCount);
1009 float *positions = LE_NEW_ARRAY(float, glyphCount * 2 + 2);
1010 le_int32 *glyphToCharMap = LE_NEW_ARRAY(le_int32, glyphCount);
1011
1012 LE_ARRAY_COPY(glyphs, &fStyleRunInfo[run].glyphs[leftGlyph], glyphCount);
1013
1014 for (outGlyph = 0, inGlyph = leftGlyph * 2; inGlyph <= rightGlyph * 2; inGlyph += 2, outGlyph += 2) {
1015 positions[outGlyph] = fStyleRunInfo[run].positions[inGlyph] + fVisualRunLastX;
1016 positions[outGlyph + 1] = fStyleRunInfo[run].positions[inGlyph + 1] /* + fVisualRunLastY */;
1017 }
1018
1019 // Save the ending position of this run
1020 // to use for the start of the next run
1021 fVisualRunLastX = positions[outGlyph - 2];
1022 // fVisualRunLastY = positions[rightGlyph * 2 + 2];
1023
1024 if ((fStyleRunInfo[run].level & 1) == 0) {
1025 for (outGlyph = 0, inGlyph = leftGlyph; inGlyph < rightGlyph; inGlyph += 1, outGlyph += 1) {
1026 glyphToCharMap[outGlyph] = fGlyphToCharMap[glyphBase + inGlyph];
1027 }
1028 } else {
1029 // Because fGlyphToCharMap is stored in logical order to facilitate line breaking,
1030 // we need to map the physical glyph indices to logical indices while we copy the
1031 // character indices.
1032 le_int32 base = glyphBase + fStyleRunInfo[run].glyphCount - 1;
1033
1034 for (outGlyph = 0, inGlyph = leftGlyph; inGlyph < rightGlyph; inGlyph += 1, outGlyph += 1) {
1035 glyphToCharMap[outGlyph] = fGlyphToCharMap[base - inGlyph];
1036 }
1037 }
1038
1039 line->append(fStyleRunInfo[run].font, direction, glyphCount, glyphs, positions, glyphToCharMap);
1040 }
1041
1042 le_int32 ParagraphLayout::getCharRun(le_int32 charIndex)
1043 {
1044 if (charIndex < 0 || charIndex > fCharCount) {
1045 return -1;
1046 }
1047
1048 le_int32 run;
1049
1050 // NOTE: as long as fStyleRunLimits is well-formed
1051 // the above range check guarantees that we'll never
1052 // fall off the end of the array.
1053 run = 0;
1054 while (charIndex >= fStyleRunLimits[run]) {
1055 run += 1;
1056 }
1057
1058 return run;
1059 }
1060
1061
1062 const char ParagraphLayout::Line::fgClassID = 0;
1063
1064 #define INITIAL_RUN_CAPACITY 4
1065 #define RUN_CAPACITY_GROW_LIMIT 16
1066
1067 ParagraphLayout::Line::~Line()
1068 {
1069 le_int32 i;
1070
1071 for (i = 0; i < fRunCount; i += 1) {
1072 delete fRuns[i];
1073 }
1074
1075 LE_DELETE_ARRAY(fRuns);
1076 }
1077
1078 le_int32 ParagraphLayout::Line::getAscent() const
1079 {
1080 if (fAscent <= 0) {
1081 ((ParagraphLayout::Line *)this)->computeMetrics();
1082 }
1083
1084 return fAscent;
1085 }
1086
1087 le_int32 ParagraphLayout::Line::getDescent() const
1088 {
1089 if (fAscent <= 0) {
1090 ((ParagraphLayout::Line *)this)->computeMetrics();
1091 }
1092
1093 return fDescent;
1094 }
1095
1096 le_int32 ParagraphLayout::Line::getLeading() const
1097 {
1098 if (fAscent <= 0) {
1099 ((ParagraphLayout::Line *)this)->computeMetrics();
1100 }
1101
1102 return fLeading;
1103 }
1104
1105 le_int32 ParagraphLayout::Line::getWidth() const
1106 {
1107 const VisualRun *lastRun = getVisualRun(fRunCount - 1);
1108
1109 if (lastRun == NULL) {
1110 return 0;
1111 }
1112
1113 le_int32 glyphCount = lastRun->getGlyphCount();
1114 const float *positions = lastRun->getPositions();
1115
1116 return (le_int32) positions[glyphCount * 2];
1117 }
1118
1119 const ParagraphLayout::VisualRun *ParagraphLayout::Line::getVisualRun(le_int32 runIndex) const
1120 {
1121 if (runIndex < 0 || runIndex >= fRunCount) {
1122 return NULL;
1123 }
1124
1125 return fRuns[runIndex];
1126 }
1127
1128 void ParagraphLayout::Line::append(const LEFontInstance *font, UBiDiDirection direction, le_int32 glyphCount,
1129 const LEGlyphID glyphs[], const float positions[], const le_int32 glyphToCharMap[])
1130 {
1131 if (fRunCount >= fRunCapacity) {
1132 if (fRunCapacity == 0) {
1133 fRunCapacity = INITIAL_RUN_CAPACITY;
1134 fRuns = LE_NEW_ARRAY(ParagraphLayout::VisualRun *, fRunCapacity);
1135 } else {
1136 fRunCapacity += (fRunCapacity < RUN_CAPACITY_GROW_LIMIT? fRunCapacity : RUN_CAPACITY_GROW_LIMIT);
1137 fRuns = (ParagraphLayout::VisualRun **) LE_GROW_ARRAY(fRuns, fRunCapacity);
1138 }
1139 }
1140
1141 fRuns[fRunCount++] = new ParagraphLayout::VisualRun(font, direction, glyphCount, glyphs, positions, glyphToCharMap);
1142 }
1143
1144 void ParagraphLayout::Line::computeMetrics()
1145 {
1146 le_int32 maxDL = 0;
1147
1148 for (le_int32 i = 0; i < fRunCount; i += 1) {
1149 le_int32 ascent = fRuns[i]->getAscent();
1150 le_int32 descent = fRuns[i]->getDescent();
1151 le_int32 leading = fRuns[i]->getLeading();
1152 le_int32 dl = descent + leading;
1153
1154 if (ascent > fAscent) {
1155 fAscent = ascent;
1156 }
1157
1158 if (descent > fDescent) {
1159 fDescent = descent;
1160 }
1161
1162 if (leading > fLeading) {
1163 fLeading = leading;
1164 }
1165
1166 if (dl > maxDL) {
1167 maxDL = dl;
1168 }
1169 }
1170
1171 fLeading = maxDL - fDescent;
1172 }
1173
1174 const char ParagraphLayout::VisualRun::fgClassID = 0;
1175
1176 ParagraphLayout::VisualRun::~VisualRun()
1177 {
1178 LE_DELETE_ARRAY(fGlyphToCharMap);
1179 LE_DELETE_ARRAY(fPositions);
1180 LE_DELETE_ARRAY(fGlyphs);
1181 }
1182
1183 U_NAMESPACE_END
1184
1185 #endif
1186
1187