]> git.saurik.com Git - apple/icu.git/blame - icuSources/layoutex/ParagraphLayout.cpp
ICU-461.18.tar.gz
[apple/icu.git] / icuSources / layoutex / ParagraphLayout.cpp
CommitLineData
b75a7d8f
A
1/*
2 **********************************************************************
729e4ab9 3 * Copyright (C) 2002-2010, International Business Machines
b75a7d8f
A
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"
73c04bcf 13#include "layout/LEScripts.h"
b75a7d8f
A
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
29U_NAMESPACE_BEGIN
30
31#define ARRAY_SIZE(array) (sizeof array / sizeof array[0])
32
46f4442e
A
33/* Leave this copyright notice here! It needs to go somewhere in this library. */
34static const char copyright[] = U_COPYRIGHT_STRING;
35
b75a7d8f
A
36class StyleRuns
37{
38public:
39 StyleRuns(const RunArray *styleRunArrays[], le_int32 styleCount);
40
41 ~StyleRuns();
42
43 le_int32 getRuns(le_int32 runLimits[], le_int32 styleIndices[]);
44
45private:
46 le_int32 fStyleCount;
47 le_int32 fRunCount;
48
49 le_int32 *fRunLimits;
50 le_int32 *fStyleIndices;
51};
52
53StyleRuns::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
108StyleRuns::~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
119le_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/*
374ca955 133 * NOTE: This table only has "TRUE" values for
b75a7d8f
A
134 * those scripts which the LayoutEngine can currently
135 * process, rather for all scripts which require
136 * complex processing for correct rendering.
137 */
73c04bcf 138static const le_bool complexTable[scriptCodeCount] = {
374ca955
A
139 FALSE , /* Zyyy */
140 FALSE, /* Qaai */
141 TRUE, /* Arab */
142 FALSE, /* Armn */
143 TRUE, /* Beng */
144 FALSE, /* Bopo */
145 FALSE, /* Cher */
73c04bcf 146 FALSE, /* Copt=Qaac */
374ca955
A
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 */
73c04bcf
A
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 */
46f4442e
A
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 */
729e4ab9
A
268 FALSE, /* Zsym */
269 FALSE, /* Bamu */
270 FALSE, /* Lisu */
271 FALSE, /* Nkgb */
272 FALSE /* Sarb */
b75a7d8f
A
273};
274
275
276const char ParagraphLayout::fgClassID = 0;
277
729e4ab9
A
278static void fillMissingCharToGlyphMapValues(le_int32 *charToGlyphMap,
279 le_int32 charCount) {
280 le_int32 lastValidGlyph = -1;
281 le_int32 ch;
282 for (ch = 0; ch <= charCount; ch += 1) {
283 if (charToGlyphMap[ch] == -1) {
284 charToGlyphMap[ch] = lastValidGlyph;
285 } else {
286 lastValidGlyph = charToGlyphMap[ch];
287 }
288 }
289}
290
b75a7d8f
A
291/*
292 * How to deal with composite fonts:
293 *
294 * Don't store the client's FontRuns; we'll need to compute sub-font FontRuns using Doug's
295 * LEFontInstance method. Do that by intersecting the client's FontRuns with fScriptRuns. Use
296 * that to compute fFontRuns, and then intersect fFontRuns, fScriptRuns and fLevelRuns. Doing
297 * it in this order means we do a two-way intersection and a three-way intersection.
298 *
299 * An optimization would be to only do this if there's at least one composite font...
300 *
301 * Other notes:
302 *
303 * * Return the sub-fonts as the run fonts... could keep the mapping back to the client's FontRuns
304 * but that probably makes it more complicated of everyone...
305 *
306 * * Take the LineInfo and LineRun types from Paragraph and use them here, incorporate them into the API.
307 *
308 * * Might want to change the name of the StyleRun type, and make a new one that holds fonts, scripts and levels?
309 *
310 */
311ParagraphLayout::ParagraphLayout(const LEUnicode chars[], le_int32 count,
312 const FontRuns *fontRuns,
313 const ValueRuns *levelRuns,
314 const ValueRuns *scriptRuns,
315 const LocaleRuns *localeRuns,
374ca955
A
316 UBiDiLevel paragraphLevel, le_bool vertical,
317 LEErrorCode &status)
b75a7d8f
A
318 : fChars(chars), fCharCount(count),
319 fFontRuns(NULL), fLevelRuns(levelRuns), fScriptRuns(scriptRuns), fLocaleRuns(localeRuns),
374ca955 320 fVertical(vertical), fClientLevels(TRUE), fClientScripts(TRUE), fClientLocales(TRUE), fEmbeddingLevels(NULL),
b75a7d8f 321 fAscent(0), fDescent(0), fLeading(0),
374ca955 322 fGlyphToCharMap(NULL), fCharToMinGlyphMap(NULL), fCharToMaxGlyphMap(NULL), fGlyphWidths(NULL), fGlyphCount(0),
b75a7d8f
A
323 fParaBidi(NULL), fLineBidi(NULL),
324 fStyleRunLimits(NULL), fStyleIndices(NULL), fStyleRunCount(0),
325 fBreakIterator(NULL), fLineStart(-1), fLineEnd(0),
326 /*fVisualRuns(NULL), fStyleRunInfo(NULL), fVisualRunCount(-1),
327 fFirstVisualRun(-1), fLastVisualRun(-1),*/ fVisualRunLastX(0), fVisualRunLastY(0)
328{
374ca955
A
329
330 if (LE_FAILURE(status)) {
331 fCharCount = -1;
332 return;
333 }
334
b75a7d8f
A
335 // FIXME: should check the limit arrays for consistency...
336
337 computeLevels(paragraphLevel);
338
339 if (scriptRuns == NULL) {
340 computeScripts();
341 }
342
343 if (localeRuns == NULL) {
344 computeLocales();
345 }
346
374ca955
A
347 computeSubFonts(fontRuns, status);
348
349 if (LE_FAILURE(status)) {
350 //other stuff?
351 fCharCount = -1;
352 return;
353 }
b75a7d8f
A
354
355 // now intersect the font, direction and script runs...
356 const RunArray *styleRunArrays[] = {fFontRuns, fLevelRuns, fScriptRuns, fLocaleRuns};
357 le_int32 styleCount = sizeof styleRunArrays / sizeof styleRunArrays[0];
358 StyleRuns styleRuns(styleRunArrays, styleCount);
359 LEErrorCode layoutStatus = LE_NO_ERROR;
360
361 fStyleRunCount = styleRuns.getRuns(NULL, NULL);
362
363 fStyleRunLimits = LE_NEW_ARRAY(le_int32, fStyleRunCount);
364 fStyleIndices = LE_NEW_ARRAY(le_int32, fStyleRunCount * styleCount);
729e4ab9
A
365 if ((fStyleRunLimits == NULL) || (fStyleIndices == NULL)) {
366 status = LE_MEMORY_ALLOCATION_ERROR;
367 return;
368 }
369
b75a7d8f
A
370 styleRuns.getRuns(fStyleRunLimits, fStyleIndices);
371
372 // now build a LayoutEngine for each style run...
373 le_int32 *styleIndices = fStyleIndices;
374 le_int32 run, runStart;
375
376 fStyleRunInfo = LE_NEW_ARRAY(StyleRunInfo, fStyleRunCount);
729e4ab9
A
377 if (fStyleRunInfo == NULL) {
378 status = LE_MEMORY_ALLOCATION_ERROR;
379 return;
380 }
381 else {
382 // initialize
383 for (runStart = 0, run = 0; run < fStyleRunCount; run += 1) {
384 fStyleRunInfo[run].font = NULL;
385 fStyleRunInfo[run].runBase = 0;
386 fStyleRunInfo[run].runLimit = 0;
387 fStyleRunInfo[run].script = (UScriptCode)0;
388 fStyleRunInfo[run].locale = NULL;
389 fStyleRunInfo[run].level = 0;
390 fStyleRunInfo[run].glyphBase = 0;
391 fStyleRunInfo[run].engine = NULL;
392 fStyleRunInfo[run].glyphCount = 0;
393 fStyleRunInfo[run].glyphs = NULL;
394 fStyleRunInfo[run].positions = NULL;
395 }
396 }
b75a7d8f
A
397
398 fGlyphCount = 0;
399 for (runStart = 0, run = 0; run < fStyleRunCount; run += 1) {
400 fStyleRunInfo[run].font = fFontRuns->getFont(styleIndices[0]);
401 fStyleRunInfo[run].runBase = runStart;
402 fStyleRunInfo[run].runLimit = fStyleRunLimits[run];
403 fStyleRunInfo[run].script = (UScriptCode) fScriptRuns->getValue(styleIndices[2]);
404 fStyleRunInfo[run].locale = fLocaleRuns->getLocale(styleIndices[3]);
405 fStyleRunInfo[run].level = (UBiDiLevel) fLevelRuns->getValue(styleIndices[1]);
406 fStyleRunInfo[run].glyphBase = fGlyphCount;
407
408 fStyleRunInfo[run].engine = LayoutEngine::layoutEngineFactory(fStyleRunInfo[run].font,
409 fStyleRunInfo[run].script, getLanguageCode(fStyleRunInfo[run].locale), layoutStatus);
729e4ab9
A
410 if (LE_FAILURE(layoutStatus)) {
411 status = layoutStatus;
412 return;
413 }
b75a7d8f
A
414
415 fStyleRunInfo[run].glyphCount = fStyleRunInfo[run].engine->layoutChars(fChars, runStart, fStyleRunLimits[run] - runStart, fCharCount,
416 fStyleRunInfo[run].level & 1, 0, 0, layoutStatus);
729e4ab9
A
417 if (LE_FAILURE(layoutStatus)) {
418 status = layoutStatus;
419 return;
420 }
b75a7d8f
A
421
422 runStart = fStyleRunLimits[run];
423 styleIndices += styleCount;
424 fGlyphCount += fStyleRunInfo[run].glyphCount;
425 }
426
427 // Make big arrays for the glyph widths, glyph-to-char and char-to-glyph maps,
428 // in logical order. (Both maps need an extra entry for the end of the text.)
429 //
430 // For each layout get the positions and convert them into glyph widths, in
431 // logical order. Get the glyph-to-char mapping, offset by starting index in the
374ca955
A
432 // character array. Swap the glyph width and glyph-to-char arrays into logical order.
433 // Finally, fill in the char-to-glyph mappings.
434 fGlyphWidths = LE_NEW_ARRAY(float, fGlyphCount);
435 fGlyphToCharMap = LE_NEW_ARRAY(le_int32, fGlyphCount + 1);
436 fCharToMinGlyphMap = LE_NEW_ARRAY(le_int32, fCharCount + 1);
437 fCharToMaxGlyphMap = LE_NEW_ARRAY(le_int32, fCharCount + 1);
729e4ab9
A
438 if ((fGlyphWidths == NULL) || (fGlyphToCharMap == NULL) ||
439 (fCharToMinGlyphMap == NULL) || (fCharToMaxGlyphMap == NULL)) {
440 status = LE_MEMORY_ALLOCATION_ERROR;
441 return;
442 }
374ca955
A
443
444 le_int32 glyph;
b75a7d8f
A
445
446 for (runStart = 0, run = 0; run < fStyleRunCount; run += 1) {
447 LayoutEngine *engine = fStyleRunInfo[run].engine;
448 le_int32 glyphCount = fStyleRunInfo[run].glyphCount;
449 le_int32 glyphBase = fStyleRunInfo[run].glyphBase;
b75a7d8f
A
450
451 fStyleRunInfo[run].glyphs = LE_NEW_ARRAY(LEGlyphID, glyphCount);
452 fStyleRunInfo[run].positions = LE_NEW_ARRAY(float, glyphCount * 2 + 2);
729e4ab9
A
453 if ((fStyleRunInfo[run].glyphs == NULL) ||
454 (fStyleRunInfo[run].positions == NULL)) {
455 status = LE_MEMORY_ALLOCATION_ERROR;
456 return;
457 }
b75a7d8f
A
458
459 engine->getGlyphs(fStyleRunInfo[run].glyphs, layoutStatus);
729e4ab9
A
460 if (LE_FAILURE(layoutStatus)) {
461 status = layoutStatus;
462 return;
463 }
464
b75a7d8f 465 engine->getGlyphPositions(fStyleRunInfo[run].positions, layoutStatus);
729e4ab9
A
466 if (LE_FAILURE(layoutStatus)) {
467 status = layoutStatus;
468 return;
469 }
470
b75a7d8f 471 engine->getCharIndices(&fGlyphToCharMap[glyphBase], runStart, layoutStatus);
729e4ab9
A
472 if (LE_FAILURE(layoutStatus)) {
473 status = layoutStatus;
474 return;
475 }
b75a7d8f
A
476
477 for (glyph = 0; glyph < glyphCount; glyph += 1) {
478 fGlyphWidths[glyphBase + glyph] = fStyleRunInfo[run].positions[glyph * 2 + 2] - fStyleRunInfo[run].positions[glyph * 2];
b75a7d8f
A
479 }
480
481 if ((fStyleRunInfo[run].level & 1) != 0) {
482 LXUtilities::reverse(&fGlyphWidths[glyphBase], glyphCount);
483 LXUtilities::reverse(&fGlyphToCharMap[glyphBase], glyphCount);
b75a7d8f
A
484 }
485
486 runStart = fStyleRunLimits[run];
487
488 delete engine;
489 fStyleRunInfo[run].engine = NULL;
490 }
491
b75a7d8f 492 fGlyphToCharMap[fGlyphCount] = fCharCount;
374ca955 493
729e4ab9
A
494 // Initialize the char-to-glyph maps to -1 so that we can later figure out
495 // whether any of the entries in the map aren't filled in below.
496 le_int32 chIndex;
497 for (chIndex = 0; chIndex <= fCharCount; chIndex += 1) {
498 fCharToMinGlyphMap[chIndex] = -1;
499 fCharToMaxGlyphMap[chIndex] = -1;
500 }
501
374ca955
A
502 for (glyph = fGlyphCount - 1; glyph >= 0; glyph -= 1) {
503 le_int32 ch = fGlyphToCharMap[glyph];
504
505 fCharToMinGlyphMap[ch] = glyph;
506 }
507
508 fCharToMinGlyphMap[fCharCount] = fGlyphCount;
509
510 for (glyph = 0; glyph < fGlyphCount; glyph += 1) {
511 le_int32 ch = fGlyphToCharMap[glyph];
512
513 fCharToMaxGlyphMap[ch] = glyph;
514 }
515
516 fCharToMaxGlyphMap[fCharCount] = fGlyphCount;
729e4ab9
A
517
518 // Now fill in the missing values in the char-to-glyph maps.
519 fillMissingCharToGlyphMapValues(fCharToMinGlyphMap, fCharCount);
520 fillMissingCharToGlyphMapValues(fCharToMaxGlyphMap, fCharCount);
b75a7d8f
A
521}
522
523ParagraphLayout::~ParagraphLayout()
524{
525 delete (FontRuns *) fFontRuns;
526
527 if (! fClientLevels) {
528 delete (ValueRuns *) fLevelRuns;
529 fLevelRuns = NULL;
530
374ca955 531 fClientLevels = TRUE;
b75a7d8f
A
532 }
533
534 if (! fClientScripts) {
535 delete (ValueRuns *) fScriptRuns;
536 fScriptRuns = NULL;
537
374ca955 538 fClientScripts = TRUE;
b75a7d8f
A
539 }
540
541 if (! fClientLocales) {
542 delete (LocaleRuns *) fLocaleRuns;
543 fLocaleRuns = NULL;
544
374ca955 545 fClientLocales = TRUE;
b75a7d8f
A
546 }
547
548 if (fEmbeddingLevels != NULL) {
549 LE_DELETE_ARRAY(fEmbeddingLevels);
550 fEmbeddingLevels = NULL;
551 }
552
553 if (fGlyphToCharMap != NULL) {
554 LE_DELETE_ARRAY(fGlyphToCharMap);
555 fGlyphToCharMap = NULL;
556 }
557
374ca955
A
558 if (fCharToMinGlyphMap != NULL) {
559 LE_DELETE_ARRAY(fCharToMinGlyphMap);
560 fCharToMinGlyphMap = NULL;
561 }
562
563 if (fCharToMaxGlyphMap != NULL) {
564 LE_DELETE_ARRAY(fCharToMaxGlyphMap);
565 fCharToMaxGlyphMap = NULL;
b75a7d8f
A
566 }
567
568 if (fGlyphWidths != NULL) {
569 LE_DELETE_ARRAY(fGlyphWidths);
570 fGlyphWidths = NULL;
571 }
572
573 if (fParaBidi != NULL) {
574 ubidi_close(fParaBidi);
575 fParaBidi = NULL;
576 }
577
578 if (fLineBidi != NULL) {
579 ubidi_close(fLineBidi);
580 fLineBidi = NULL;
581 }
582
583 if (fStyleRunCount > 0) {
584 le_int32 run;
585
586 LE_DELETE_ARRAY(fStyleRunLimits);
587 LE_DELETE_ARRAY(fStyleIndices);
588
589 for (run = 0; run < fStyleRunCount; run += 1) {
590 LE_DELETE_ARRAY(fStyleRunInfo[run].glyphs);
591 LE_DELETE_ARRAY(fStyleRunInfo[run].positions);
592
593 fStyleRunInfo[run].glyphs = NULL;
594 fStyleRunInfo[run].positions = NULL;
595 }
596
597 LE_DELETE_ARRAY(fStyleRunInfo);
598
599 fStyleRunLimits = NULL;
600 fStyleIndices = NULL;
601 fStyleRunInfo = NULL;
602 fStyleRunCount = 0;
603 }
604
605 if (fBreakIterator != NULL) {
606 delete fBreakIterator;
607 fBreakIterator = NULL;
608 }
609}
610
611
612le_bool ParagraphLayout::isComplex(const LEUnicode chars[], le_int32 count)
613{
614 UErrorCode scriptStatus = U_ZERO_ERROR;
615 UScriptCode scriptCode = USCRIPT_INVALID_CODE;
616 UScriptRun *sr = uscript_openRun(chars, count, &scriptStatus);
73c04bcf 617 le_bool result = FALSE;
b75a7d8f
A
618
619 while (uscript_nextRun(sr, NULL, NULL, &scriptCode)) {
620 if (isComplex(scriptCode)) {
73c04bcf
A
621 result = TRUE;
622 break;
b75a7d8f
A
623 }
624 }
625
73c04bcf
A
626 uscript_closeRun(sr);
627 return result;
b75a7d8f
A
628}
629
630le_int32 ParagraphLayout::getAscent() const
631{
374ca955 632 if (fAscent <= 0 && fCharCount > 0) {
b75a7d8f
A
633 ((ParagraphLayout *) this)->computeMetrics();
634 }
635
636 return fAscent;
637}
638
639le_int32 ParagraphLayout::getDescent() const
640{
374ca955 641 if (fAscent <= 0 && fCharCount > 0) {
b75a7d8f
A
642 ((ParagraphLayout *) this)->computeMetrics();
643 }
644
645 return fDescent;
646}
647
648le_int32 ParagraphLayout::getLeading() const
649{
374ca955 650 if (fAscent <= 0 && fCharCount > 0) {
b75a7d8f
A
651 ((ParagraphLayout *) this)->computeMetrics();
652 }
653
654 return fLeading;
655}
656
729e4ab9
A
657le_bool ParagraphLayout::isDone() const
658{
659 return fLineEnd >= fCharCount;
660}
661
b75a7d8f
A
662ParagraphLayout::Line *ParagraphLayout::nextLine(float width)
663{
729e4ab9 664 if (isDone()) {
b75a7d8f
A
665 return NULL;
666 }
667
668 fLineStart = fLineEnd;
669
670 if (width > 0) {
374ca955 671 le_int32 glyph = fCharToMinGlyphMap[fLineStart];
b75a7d8f
A
672 float widthSoFar = 0;
673
674 while (glyph < fGlyphCount && widthSoFar + fGlyphWidths[glyph] <= width) {
675 widthSoFar += fGlyphWidths[glyph++];
676 }
677
678 // If no glyphs fit on the line, force one to fit.
679 //
680 // (There shouldn't be any zero width glyphs at the
681 // start of a line unless the paragraph consists of
682 // only zero width glyphs, because otherwise the zero
683 // width glyphs will have been included on the end of
684 // the previous line...)
685 if (widthSoFar == 0 && glyph < fGlyphCount) {
686 glyph += 1;
687 }
688
689 fLineEnd = previousBreak(fGlyphToCharMap[glyph]);
690
374ca955
A
691 // If this break is at or before the last one,
692 // find a glyph, starting at the one which didn't
693 // fit, that produces a break after the last one.
694 while (fLineEnd <= fLineStart) {
695 fLineEnd = fGlyphToCharMap[glyph++];
b75a7d8f
A
696 }
697 } else {
698 fLineEnd = fCharCount;
699 }
700
701 return computeVisualRuns();
702}
703
704void ParagraphLayout::computeLevels(UBiDiLevel paragraphLevel)
705{
706 UErrorCode bidiStatus = U_ZERO_ERROR;
707
708 if (fLevelRuns != NULL) {
709 le_int32 ch;
710 le_int32 run;
711
712 fEmbeddingLevels = LE_NEW_ARRAY(UBiDiLevel, fCharCount);
713
714 for (ch = 0, run = 0; run < fLevelRuns->getCount(); run += 1) {
715 UBiDiLevel runLevel = (UBiDiLevel) fLevelRuns->getValue(run) | UBIDI_LEVEL_OVERRIDE;
716 le_int32 runLimit = fLevelRuns->getLimit(run);
717
718 while (ch < runLimit) {
719 fEmbeddingLevels[ch++] = runLevel;
720 }
721 }
722 }
723
724 fParaBidi = ubidi_openSized(fCharCount, 0, &bidiStatus);
725 ubidi_setPara(fParaBidi, fChars, fCharCount, paragraphLevel, fEmbeddingLevels, &bidiStatus);
726
727 if (fLevelRuns == NULL) {
728 le_int32 levelRunCount = ubidi_countRuns(fParaBidi, &bidiStatus);
729 ValueRuns *levelRuns = new ValueRuns(levelRunCount);
730
731 le_int32 logicalStart = 0;
732 le_int32 run;
733 le_int32 limit;
734 UBiDiLevel level;
735
736 for (run = 0; run < levelRunCount; run += 1) {
737 ubidi_getLogicalRun(fParaBidi, logicalStart, &limit, &level);
738 levelRuns->add(level, limit);
739 logicalStart = limit;
740 }
741
742 fLevelRuns = levelRuns;
374ca955 743 fClientLevels = FALSE;
b75a7d8f
A
744 }
745}
746
747void ParagraphLayout::computeScripts()
748{
749 UErrorCode scriptStatus = U_ZERO_ERROR;
750 UScriptRun *sr = uscript_openRun(fChars, fCharCount, &scriptStatus);
751 ValueRuns *scriptRuns = new ValueRuns(0);
752 le_int32 limit;
753 UScriptCode script;
754
755 while (uscript_nextRun(sr, NULL, &limit, &script)) {
756 scriptRuns->add(script, limit);
757 }
758
759 uscript_closeRun(sr);
760
761 fScriptRuns = scriptRuns;
374ca955 762 fClientScripts = FALSE;
b75a7d8f
A
763}
764
765void ParagraphLayout::computeLocales()
766{
767 LocaleRuns *localeRuns = new LocaleRuns(0);
768 const Locale *defaultLocale = &Locale::getDefault();
769
770 localeRuns->add(defaultLocale, fCharCount);
771
772 fLocaleRuns = localeRuns;
374ca955 773 fClientLocales = FALSE;
b75a7d8f
A
774}
775
374ca955 776void ParagraphLayout::computeSubFonts(const FontRuns *fontRuns, LEErrorCode &status)
b75a7d8f 777{
374ca955
A
778 if (LE_FAILURE(status)) {
779 return;
780 }
781
b75a7d8f
A
782 const RunArray *styleRunArrays[] = {fontRuns, fScriptRuns};
783 le_int32 styleCount = sizeof styleRunArrays / sizeof styleRunArrays[0];
784 StyleRuns styleRuns(styleRunArrays, styleCount);
785 le_int32 styleRunCount = styleRuns.getRuns(NULL, NULL);
786 le_int32 *styleRunLimits = LE_NEW_ARRAY(le_int32, styleRunCount);
787 le_int32 *styleIndices = LE_NEW_ARRAY(le_int32, styleRunCount * styleCount);
788 FontRuns *subFontRuns = new FontRuns(0);
789 le_int32 run, offset, *si;
790
791 styleRuns.getRuns(styleRunLimits, styleIndices);
792
793 si = styleIndices;
794 offset = 0;
795
796 for (run = 0; run < styleRunCount; run += 1) {
797 const LEFontInstance *runFont = fontRuns->getFont(si[0]);
798 le_int32 script = fScriptRuns->getValue(si[1]);
b75a7d8f
A
799
800 while (offset < styleRunLimits[run]) {
374ca955
A
801 const LEFontInstance *subFont = runFont->getSubFont(fChars, &offset, styleRunLimits[run], script, status);
802
803 if (LE_FAILURE(status)) {
804 delete subFontRuns;
805 goto cleanUp;
806 }
b75a7d8f
A
807
808 subFontRuns->add(subFont, offset);
809 }
810
811 si += styleCount;
812 }
813
814 fFontRuns = subFontRuns;
815
374ca955 816cleanUp:
b75a7d8f
A
817 LE_DELETE_ARRAY(styleIndices);
818 LE_DELETE_ARRAY(styleRunLimits);
819}
820
821void ParagraphLayout::computeMetrics()
822{
823 le_int32 i, count = fFontRuns->getCount();
824 le_int32 maxDL = 0;
825
826 for (i = 0; i < count; i += 1) {
827 const LEFontInstance *font = fFontRuns->getFont(i);
828 le_int32 ascent = font->getAscent();
829 le_int32 descent = font->getDescent();
830 le_int32 leading = font->getLeading();
831 le_int32 dl = descent + leading;
832
833 if (ascent > fAscent) {
834 fAscent = ascent;
835 }
836
837 if (descent > fDescent) {
838 fDescent = descent;
839 }
840
841 if (leading > fLeading) {
842 fLeading = leading;
843 }
844
845 if (dl > maxDL) {
846 maxDL = dl;
847 }
848 }
849
850 fLeading = maxDL - fDescent;
851}
852
853#if 1
854struct LanguageMap
855{
856 const char *localeCode;
857 le_int32 languageCode;
858};
859
860static const LanguageMap languageMap[] =
861{
46f4442e 862 {"afr", afkLanguageCode}, // Afrikaans
b75a7d8f
A
863 {"ara", araLanguageCode}, // Arabic
864 {"asm", asmLanguageCode}, // Assamese
46f4442e 865 {"bel", belLanguageCode}, // Belarussian
b75a7d8f 866 {"ben", benLanguageCode}, // Bengali
46f4442e
A
867 {"bod", tibLanguageCode}, // Tibetan
868 {"bul", bgrLanguageCode}, // Bulgarian
869 {"cat", catLanguageCode}, // Catalan
870 {"ces", csyLanguageCode}, // Czech
871 {"che", cheLanguageCode}, // Chechen
872 {"cop", copLanguageCode}, // Coptic
873 {"cym", welLanguageCode}, // Welsh
874 {"dan", danLanguageCode}, // Danish
875 {"deu", deuLanguageCode}, // German
876 {"dzo", dznLanguageCode}, // Dzongkha
877 {"ell", ellLanguageCode}, // Greek
878 {"eng", engLanguageCode}, // English
879 {"est", etiLanguageCode}, // Estonian
880 {"eus", euqLanguageCode}, // Basque
b75a7d8f 881 {"fas", farLanguageCode}, // Farsi
46f4442e
A
882 {"fin", finLanguageCode}, // Finnish
883 {"fra", fraLanguageCode}, // French
884 {"gle", gaeLanguageCode}, // Irish Gaelic
b75a7d8f 885 {"guj", gujLanguageCode}, // Gujarati
46f4442e 886 {"hau", hauLanguageCode}, // Hausa
b75a7d8f
A
887 {"heb", iwrLanguageCode}, // Hebrew
888 {"hin", hinLanguageCode}, // Hindi
46f4442e
A
889 {"hrv", hrvLanguageCode}, // Croatian
890 {"hun", hunLanguageCode}, // Hungarian
891 {"hye", hyeLanguageCode}, // Armenian
892 {"ind", indLanguageCode}, // Indonesian
893 {"ita", itaLanguageCode}, // Italian
b75a7d8f
A
894 {"jpn", janLanguageCode}, // Japanese
895 {"kan", kanLanguageCode}, // Kannada
896 {"kas", kshLanguageCode}, // Kashmiri
46f4442e 897 {"khm", khmLanguageCode}, // Khmer
b75a7d8f
A
898 {"kok", kokLanguageCode}, // Konkani
899 {"kor", korLanguageCode}, // Korean
900// {"mal_XXX", malLanguageCode}, // Malayalam - Traditional
901 {"mal", mlrLanguageCode}, // Malayalam - Reformed
902 {"mar", marLanguageCode}, // Marathi
46f4442e 903 {"mlt", mtsLanguageCode}, // Maltese
b75a7d8f 904 {"mni", mniLanguageCode}, // Manipuri
46f4442e
A
905 {"mon", mngLanguageCode}, // Mongolian
906 {"nep", nepLanguageCode}, // Nepali
b75a7d8f 907 {"ori", oriLanguageCode}, // Oriya
46f4442e
A
908 {"pol", plkLanguageCode}, // Polish
909 {"por", ptgLanguageCode}, // Portuguese
910 {"pus", pasLanguageCode}, // Pashto
911 {"ron", romLanguageCode}, // Romanian
912 {"rus", rusLanguageCode}, // Russian
b75a7d8f 913 {"san", sanLanguageCode}, // Sanskrit
b75a7d8f 914 {"sin", snhLanguageCode}, // Sinhalese
46f4442e
A
915 {"slk", skyLanguageCode}, // Slovak
916 {"snd", sndLanguageCode}, // Sindhi
917 {"slv", slvLanguageCode}, // Slovenian
918 {"spa", espLanguageCode}, // Spanish
919 {"sqi", sqiLanguageCode}, // Albanian
920 {"srp", srbLanguageCode}, // Serbian
921 {"swe", sveLanguageCode}, // Swedish
b75a7d8f
A
922 {"syr", syrLanguageCode}, // Syriac
923 {"tam", tamLanguageCode}, // Tamil
924 {"tel", telLanguageCode}, // Telugu
925 {"tha", thaLanguageCode}, // Thai
46f4442e 926 {"tur", trkLanguageCode}, // Turkish
b75a7d8f
A
927 {"urd", urdLanguageCode}, // Urdu
928 {"yid", jiiLanguageCode}, // Yiddish
929// {"zhp", zhpLanguageCode}, // Chinese - Phonetic
930 {"zho", zhsLanguageCode}, // Chinese
931 {"zho_CHN", zhsLanguageCode}, // Chinese - China
932 {"zho_HKG", zhsLanguageCode}, // Chinese - Hong Kong
933 {"zho_MAC", zhtLanguageCode}, // Chinese - Macao
934 {"zho_SGP", zhsLanguageCode}, // Chinese - Singapore
935 {"zho_TWN", zhtLanguageCode} // Chinese - Taiwan
936};
937
938static const le_int32 languageMapCount = ARRAY_SIZE(languageMap);
939
940le_int32 ParagraphLayout::getLanguageCode(const Locale *locale)
941{
942 char code[8] = {0, 0, 0, 0, 0, 0, 0, 0};
943 const char *language = locale->getISO3Language();
944 const char *country = locale->getISO3Country();
945
946 uprv_strcat(code, language);
947
948 if ((uprv_strcmp(language, "zho") == 0) && country != NULL) {
949 uprv_strcat(code, "_");
950 uprv_strcat(code, country);
951 }
952
953 for (le_int32 i = 0; i < languageMapCount; i += 1) {
954 if (uprv_strcmp(code, languageMap[i].localeCode) == 0) {
955 return languageMap[i].languageCode;
956 }
957 }
958
959 return nullLanguageCode;
960}
729e4ab9 961#else
b75a7d8f
A
962
963// TODO - dummy implementation for right now...
964le_int32 ParagraphLayout::getLanguageCode(const Locale *locale)
965{
966 return nullLanguageCode;
967}
968#endif
969
970le_bool ParagraphLayout::isComplex(UScriptCode script)
971{
46f4442e 972 if (script < 0 || script >= (UScriptCode) scriptCodeCount) {
374ca955 973 return FALSE;
b75a7d8f
A
974 }
975
976 return complexTable[script];
977}
978
979le_int32 ParagraphLayout::previousBreak(le_int32 charIndex)
980{
981 // skip over any whitespace or control characters,
982 // because they can hang in the margin.
983 while (charIndex < fCharCount &&
984 (u_isWhitespace(fChars[charIndex]) ||
985 u_iscntrl(fChars[charIndex]))) {
986 charIndex += 1;
987 }
988
989 // Create the BreakIterator if we don't already have one
990 if (fBreakIterator == NULL) {
991 Locale thai("th");
992 UCharCharacterIterator *iter = new UCharCharacterIterator(fChars, fCharCount);
993 UErrorCode status = U_ZERO_ERROR;
994
995 fBreakIterator = BreakIterator::createLineInstance(thai, status);
996 fBreakIterator->adoptText(iter);
997 }
998
999 // return the break location that's at or before
1000 // the character we stopped on. Note: if we're
1001 // on a break, the "+ 1" will cause preceding to
1002 // back up to it.
1003 return fBreakIterator->preceding(charIndex + 1);
1004}
1005
1006ParagraphLayout::Line *ParagraphLayout::computeVisualRuns()
1007{
1008 UErrorCode bidiStatus = U_ZERO_ERROR;
1009 le_int32 dirRunCount, visualRun;
1010
1011 fVisualRunLastX = 0;
1012 fVisualRunLastY = 0;
1013 fFirstVisualRun = getCharRun(fLineStart);
1014 fLastVisualRun = getCharRun(fLineEnd - 1);
1015
1016 if (fLineBidi == NULL) {
1017 fLineBidi = ubidi_openSized(fCharCount, 0, &bidiStatus);
1018 }
1019
1020 ubidi_setLine(fParaBidi, fLineStart, fLineEnd, fLineBidi, &bidiStatus);
1021 dirRunCount = ubidi_countRuns(fLineBidi, &bidiStatus);
1022
1023 Line *line = new Line();
1024
1025 for (visualRun = 0; visualRun < dirRunCount; visualRun += 1) {
1026 le_int32 relStart, run, runLength;
1027 UBiDiDirection runDirection = ubidi_getVisualRun(fLineBidi, visualRun, &relStart, &runLength);
1028 le_int32 runStart = fLineStart + relStart;
1029 le_int32 runEnd = runStart + runLength - 1;
1030 le_int32 firstRun = getCharRun(runStart);
1031 le_int32 lastRun = getCharRun(runEnd);
1032 le_int32 startRun = (runDirection == UBIDI_LTR)? firstRun : lastRun;
1033 le_int32 stopRun = (runDirection == UBIDI_LTR)? lastRun + 1 : firstRun - 1;
1034 le_int32 dir = (runDirection == UBIDI_LTR)? 1 : -1;
1035
1036 for (run = startRun; run != stopRun; run += dir) {
1037 le_int32 firstChar = (run == firstRun)? runStart : fStyleRunInfo[run].runBase;
1038 le_int32 lastChar = (run == lastRun)? runEnd : fStyleRunInfo[run].runLimit - 1;
1039
1040 appendRun(line, run, firstChar, lastChar);
1041 }
1042 }
1043
1044 return line;
1045}
1046
1047void ParagraphLayout::appendRun(ParagraphLayout::Line *line, le_int32 run, le_int32 firstChar, le_int32 lastChar)
1048{
1049 le_int32 glyphBase = fStyleRunInfo[run].glyphBase;
1050 le_int32 inGlyph, outGlyph;
1051
1052 // Get the glyph indices for all the characters between firstChar and lastChar,
1053 // make the minimum one be leftGlyph and the maximum one be rightGlyph.
1054 // (need to do this to handle local reorderings like Indic left matras)
1055 le_int32 leftGlyph = fGlyphCount;
1056 le_int32 rightGlyph = -1;
1057 le_int32 ch;
1058
1059 for (ch = firstChar; ch <= lastChar; ch += 1) {
374ca955
A
1060 le_int32 minGlyph = fCharToMinGlyphMap[ch];
1061 le_int32 maxGlyph = fCharToMaxGlyphMap[ch];
b75a7d8f 1062
374ca955
A
1063 if (minGlyph < leftGlyph) {
1064 leftGlyph = minGlyph;
b75a7d8f
A
1065 }
1066
374ca955
A
1067 if (maxGlyph > rightGlyph) {
1068 rightGlyph = maxGlyph;
b75a7d8f
A
1069 }
1070 }
1071
1072 if ((fStyleRunInfo[run].level & 1) != 0) {
1073 le_int32 swap = rightGlyph;
1074 le_int32 last = glyphBase + fStyleRunInfo[run].glyphCount - 1;
1075
1076 // Here, we want to remove the glyphBase bias...
1077 rightGlyph = last - leftGlyph;
1078 leftGlyph = last - swap;
1079 } else {
1080 rightGlyph -= glyphBase;
1081 leftGlyph -= glyphBase;
1082 }
1083
1084 // Set the position bias for the glyphs. If we're at the start of
1085 // a line, we want the first glyph to be at x = 0, even if it comes
1086 // from the middle of a layout. If we've got a right-to-left run, we
1087 // want the left-most glyph to start at the final x position of the
1088 // previous run, even though this glyph may be in the middle of the
374ca955
A
1089 // run.
1090 fVisualRunLastX -= fStyleRunInfo[run].positions[leftGlyph * 2];
b75a7d8f
A
1091
1092 // Make rightGlyph be the glyph just to the right of
1093 // the run's glyphs
1094 rightGlyph += 1;
1095
1096 UBiDiDirection direction = ((fStyleRunInfo[run].level & 1) == 0)? UBIDI_LTR : UBIDI_RTL;
1097 le_int32 glyphCount = rightGlyph - leftGlyph;
1098 LEGlyphID *glyphs = LE_NEW_ARRAY(LEGlyphID, glyphCount);
1099 float *positions = LE_NEW_ARRAY(float, glyphCount * 2 + 2);
1100 le_int32 *glyphToCharMap = LE_NEW_ARRAY(le_int32, glyphCount);
1101
1102 LE_ARRAY_COPY(glyphs, &fStyleRunInfo[run].glyphs[leftGlyph], glyphCount);
1103
1104 for (outGlyph = 0, inGlyph = leftGlyph * 2; inGlyph <= rightGlyph * 2; inGlyph += 2, outGlyph += 2) {
1105 positions[outGlyph] = fStyleRunInfo[run].positions[inGlyph] + fVisualRunLastX;
729e4ab9 1106 positions[outGlyph + 1] = fStyleRunInfo[run].positions[inGlyph + 1] + fVisualRunLastY;
b75a7d8f
A
1107 }
1108
1109 // Save the ending position of this run
1110 // to use for the start of the next run
1111 fVisualRunLastX = positions[outGlyph - 2];
729e4ab9 1112 fVisualRunLastY = positions[outGlyph - 1];
b75a7d8f
A
1113
1114 if ((fStyleRunInfo[run].level & 1) == 0) {
1115 for (outGlyph = 0, inGlyph = leftGlyph; inGlyph < rightGlyph; inGlyph += 1, outGlyph += 1) {
1116 glyphToCharMap[outGlyph] = fGlyphToCharMap[glyphBase + inGlyph];
1117 }
1118 } else {
46f4442e
A
1119 // Because fGlyphToCharMap is stored in logical order to facilitate line breaking,
1120 // we need to map the physical glyph indices to logical indices while we copy the
1121 // character indices.
1122 le_int32 base = glyphBase + fStyleRunInfo[run].glyphCount - 1;
1123
1124 for (outGlyph = 0, inGlyph = leftGlyph; inGlyph < rightGlyph; inGlyph += 1, outGlyph += 1) {
1125 glyphToCharMap[outGlyph] = fGlyphToCharMap[base - inGlyph];
b75a7d8f
A
1126 }
1127 }
1128
1129 line->append(fStyleRunInfo[run].font, direction, glyphCount, glyphs, positions, glyphToCharMap);
1130}
1131
1132le_int32 ParagraphLayout::getCharRun(le_int32 charIndex)
1133{
1134 if (charIndex < 0 || charIndex > fCharCount) {
1135 return -1;
1136 }
1137
1138 le_int32 run;
1139
1140 // NOTE: as long as fStyleRunLimits is well-formed
1141 // the above range check guarantees that we'll never
1142 // fall off the end of the array.
1143 run = 0;
1144 while (charIndex >= fStyleRunLimits[run]) {
1145 run += 1;
1146 }
1147
1148 return run;
1149}
1150
1151
1152const char ParagraphLayout::Line::fgClassID = 0;
1153
1154#define INITIAL_RUN_CAPACITY 4
1155#define RUN_CAPACITY_GROW_LIMIT 16
1156
1157ParagraphLayout::Line::~Line()
1158{
1159 le_int32 i;
1160
1161 for (i = 0; i < fRunCount; i += 1) {
1162 delete fRuns[i];
1163 }
1164
1165 LE_DELETE_ARRAY(fRuns);
1166}
1167
1168le_int32 ParagraphLayout::Line::getAscent() const
1169{
1170 if (fAscent <= 0) {
1171 ((ParagraphLayout::Line *)this)->computeMetrics();
1172 }
1173
1174 return fAscent;
1175}
1176
1177le_int32 ParagraphLayout::Line::getDescent() const
1178{
1179 if (fAscent <= 0) {
1180 ((ParagraphLayout::Line *)this)->computeMetrics();
1181 }
1182
1183 return fDescent;
1184}
1185
1186le_int32 ParagraphLayout::Line::getLeading() const
1187{
1188 if (fAscent <= 0) {
1189 ((ParagraphLayout::Line *)this)->computeMetrics();
1190 }
1191
1192 return fLeading;
1193}
1194
374ca955
A
1195le_int32 ParagraphLayout::Line::getWidth() const
1196{
1197 const VisualRun *lastRun = getVisualRun(fRunCount - 1);
46f4442e
A
1198
1199 if (lastRun == NULL) {
1200 return 0;
1201 }
1202
374ca955
A
1203 le_int32 glyphCount = lastRun->getGlyphCount();
1204 const float *positions = lastRun->getPositions();
1205
1206 return (le_int32) positions[glyphCount * 2];
1207}
1208
b75a7d8f
A
1209const ParagraphLayout::VisualRun *ParagraphLayout::Line::getVisualRun(le_int32 runIndex) const
1210{
1211 if (runIndex < 0 || runIndex >= fRunCount) {
1212 return NULL;
1213 }
1214
1215 return fRuns[runIndex];
1216}
1217
1218void ParagraphLayout::Line::append(const LEFontInstance *font, UBiDiDirection direction, le_int32 glyphCount,
1219 const LEGlyphID glyphs[], const float positions[], const le_int32 glyphToCharMap[])
1220{
1221 if (fRunCount >= fRunCapacity) {
1222 if (fRunCapacity == 0) {
1223 fRunCapacity = INITIAL_RUN_CAPACITY;
1224 fRuns = LE_NEW_ARRAY(ParagraphLayout::VisualRun *, fRunCapacity);
1225 } else {
1226 fRunCapacity += (fRunCapacity < RUN_CAPACITY_GROW_LIMIT? fRunCapacity : RUN_CAPACITY_GROW_LIMIT);
1227 fRuns = (ParagraphLayout::VisualRun **) LE_GROW_ARRAY(fRuns, fRunCapacity);
1228 }
1229 }
1230
1231 fRuns[fRunCount++] = new ParagraphLayout::VisualRun(font, direction, glyphCount, glyphs, positions, glyphToCharMap);
1232}
1233
1234void ParagraphLayout::Line::computeMetrics()
1235{
1236 le_int32 maxDL = 0;
1237
1238 for (le_int32 i = 0; i < fRunCount; i += 1) {
1239 le_int32 ascent = fRuns[i]->getAscent();
1240 le_int32 descent = fRuns[i]->getDescent();
1241 le_int32 leading = fRuns[i]->getLeading();
1242 le_int32 dl = descent + leading;
1243
1244 if (ascent > fAscent) {
1245 fAscent = ascent;
1246 }
1247
1248 if (descent > fDescent) {
1249 fDescent = descent;
1250 }
1251
1252 if (leading > fLeading) {
1253 fLeading = leading;
1254 }
1255
1256 if (dl > maxDL) {
1257 maxDL = dl;
1258 }
1259 }
1260
1261 fLeading = maxDL - fDescent;
1262}
1263
1264const char ParagraphLayout::VisualRun::fgClassID = 0;
1265
374ca955
A
1266ParagraphLayout::VisualRun::~VisualRun()
1267{
1268 LE_DELETE_ARRAY(fGlyphToCharMap);
1269 LE_DELETE_ARRAY(fPositions);
1270 LE_DELETE_ARRAY(fGlyphs);
1271}
1272
b75a7d8f
A
1273U_NAMESPACE_END
1274
1275#endif
1276