1 /* 2 * 3 * Copyright (C) 2016 and later: Unicode, Inc. and others. 4 * License & terms of use: http://www.unicode.org/copyright.html#License 5 * 6 * (C) Copyright IBM Corp. 1998-2007 - All Rights Reserved 7 * 8 */ 9 10 #include "unicode/utypes.h" 11 #include "unicode/uchar.h" 12 #include "unicode/ubidi.h" 13 #include "unicode/ustring.h" 14 15 #include "layout/LETypes.h" 16 17 #include "layout/loengine.h" 18 #include "layout/playout.h" 19 #include "layout/plruns.h" 20 21 #include "pflow.h" 22 23 #include "arraymem.h" 24 #include "ucreader.h" 25 26 /* 27 * Move the line below out of this comment 28 * to add a locale run to the pl_paragraphs 29 * that are created. 30 #define TEST_LOCALE "zh_TW" 31 */ 32 33 #define MARGIN 10 34 #define LINE_GROW 32 35 #define PARA_GROW 8 36 37 #define CH_LF 0x000A 38 #define CH_CR 0x000D 39 #define CH_LSEP 0x2028 40 #define CH_PSEP 0x2029 41 42 struct pf_object 43 { 44 pl_paragraph **fParagraphLayout; 45 46 le_int32 fParagraphCount; 47 le_int32 fParagraphMax; 48 le_int32 fParagraphGrow; 49 50 le_int32 fLineCount; 51 le_int32 fLinesMax; 52 le_int32 fLinesGrow; 53 54 pl_line **fLines; 55 56 LEUnicode *fChars; 57 58 le_int32 fLineHeight; 59 le_int32 fAscent; 60 le_int32 fWidth; 61 le_int32 fHeight; 62 UBiDiLevel fParagraphLevel; 63 }; 64 65 typedef struct pf_object pf_object; 66 67 68 static LEUnicode *skipLineEnd(LEUnicode *ptr) 69 { 70 if (ptr[0] == CH_CR && ptr[1] == CH_LF) { 71 ptr += 1; 72 } 73 74 return ptr + 1; 75 } 76 77 static le_int32 findFontRun(const pl_fontRuns *fontRuns, le_int32 offset) 78 { 79 le_int32 runCount = pl_getFontRunCount(fontRuns); 80 le_int32 run; 81 82 for (run = 0; run < runCount; run += 1) { 83 if (pl_getFontRunLimit(fontRuns, run) > offset) { 84 return run; 85 } 86 } 87 88 return -1; 89 } 90 91 static void subsetFontRuns(const pl_fontRuns *fontRuns, le_int32 start, le_int32 limit, pl_fontRuns *sub) 92 { 93 le_int32 startRun = findFontRun(fontRuns, start); 94 le_int32 endRun = findFontRun(fontRuns, limit - 1); 95 le_int32 run; 96 97 pl_resetFontRuns(sub); 98 99 for (run = startRun; run <= endRun; run += 1) { 100 const le_font *runFont = pl_getFontRunFont(fontRuns, run); 101 le_int32 runLimit = pl_getFontRunLimit(fontRuns, run) - start; 102 103 if (run == endRun) { 104 runLimit = limit - start; 105 } 106 107 pl_addFontRun(sub, runFont, runLimit); 108 } 109 } 110 111 pf_flow *pf_create(const LEUnicode chars[], le_int32 charCount, const pl_fontRuns *fontRuns, LEErrorCode *status) 112 { 113 pf_object *flow; 114 le_int32 ascent = 0; 115 le_int32 descent = 0; 116 le_int32 leading = 0; 117 pl_localeRuns *locales = NULL; 118 pl_fontRuns *fr; 119 LEUnicode *pStart; 120 static const LEUnicode separators[] = {CH_LF, CH_CR, CH_LSEP, CH_PSEP, 0x0000}; 121 122 if (LE_FAILURE(*status)) { 123 return NULL; 124 } 125 126 flow = NEW_ARRAY(pf_object, 1); 127 128 flow->fParagraphLayout = NULL; 129 flow->fParagraphCount = 0; 130 flow->fParagraphMax = PARA_GROW; 131 flow->fParagraphGrow = PARA_GROW; 132 flow->fLineCount = 0; 133 flow->fLinesMax = LINE_GROW; 134 flow->fLinesGrow = LINE_GROW; 135 flow->fLines = NULL; 136 flow->fChars = NULL; 137 flow->fLineHeight = -1; 138 flow->fAscent = -1; 139 flow->fWidth = -1; 140 flow->fHeight = -1; 141 flow->fParagraphLevel = UBIDI_DEFAULT_LTR; 142 143 fr = pl_openEmptyFontRuns(0); 144 145 #ifdef TEST_LOCALE 146 locales = pl_openEmptyLocaleRuns(0); 147 #endif 148 149 flow->fLines = NEW_ARRAY(pl_line *, flow->fLinesMax); 150 flow->fParagraphLayout = NEW_ARRAY(pl_paragraph *, flow->fParagraphMax); 151 152 flow->fChars = NEW_ARRAY(LEUnicode, charCount + 1); 153 LE_ARRAY_COPY(flow->fChars, chars, charCount); 154 flow->fChars[charCount] = 0; 155 156 pStart = &flow->fChars[0]; 157 158 while (*pStart != 0) { 159 LEUnicode *pEnd = u_strpbrk(pStart, separators); 160 le_int32 pAscent, pDescent, pLeading; 161 pl_paragraph *paragraphLayout = NULL; 162 163 if (pEnd == NULL) { 164 pEnd = &flow->fChars[charCount]; 165 } 166 167 if (pEnd != pStart) { 168 subsetFontRuns(fontRuns, pStart - flow->fChars, pEnd - flow->fChars, fr); 169 170 #ifdef TEST_LOCALE 171 pl_resetLocaleRuns(locales); 172 pl_addLocaleRun(locales, TEST_LOCALE, pEnd - pStart); 173 #endif 174 175 paragraphLayout = pl_create(pStart, pEnd - pStart, fr, NULL, NULL, locales, flow->fParagraphLevel, FALSE, status); 176 177 if (LE_FAILURE(*status)) { 178 break; /* return? something else? */ 179 } 180 181 if (flow->fParagraphLevel == UBIDI_DEFAULT_LTR) { 182 flow->fParagraphLevel = pl_getParagraphLevel(paragraphLayout); 183 } 184 185 pAscent = pl_getAscent(paragraphLayout); 186 pDescent = pl_getDescent(paragraphLayout); 187 pLeading = pl_getLeading(paragraphLayout); 188 189 if (pAscent > ascent) { 190 ascent = pAscent; 191 } 192 193 if (pDescent > descent) { 194 descent = pDescent; 195 } 196 197 if (pLeading > leading) { 198 leading = pLeading; 199 } 200 } 201 202 if (flow->fParagraphCount >= flow->fParagraphMax) { 203 flow->fParagraphLayout = (pl_paragraph **) GROW_ARRAY(flow->fParagraphLayout, flow->fParagraphMax + flow->fParagraphGrow); 204 flow->fParagraphMax += flow->fParagraphGrow; 205 } 206 207 flow->fParagraphLayout[flow->fParagraphCount++] = paragraphLayout; 208 209 if (*pEnd == 0) { 210 break; 211 } 212 213 pStart = skipLineEnd(pEnd); 214 } 215 216 flow->fLineHeight = ascent + descent + leading; 217 flow->fAscent = ascent; 218 219 pl_closeLocaleRuns(locales); 220 pl_closeFontRuns(fr); 221 222 return (pf_flow *) flow; 223 } 224 225 void pf_close(pf_flow *flow) 226 { 227 pf_object *obj = (pf_object *) flow; 228 le_int32 i; 229 230 for (i = 0; i < obj->fLineCount; i += 1) { 231 DELETE_ARRAY(obj->fLines[i]); 232 } 233 234 DELETE_ARRAY(obj->fLines); 235 236 for (i = 0; i < obj->fParagraphCount; i += 1) { 237 pl_close(obj->fParagraphLayout[i]); 238 } 239 240 DELETE_ARRAY(obj->fParagraphLayout); 241 242 DELETE_ARRAY(obj->fChars); 243 244 DELETE_ARRAY(obj); 245 } 246 247 248 le_int32 pf_getAscent(pf_flow *flow) 249 { 250 pf_object *obj = (pf_object *) flow; 251 252 return obj->fAscent; 253 } 254 255 le_int32 pf_getLineHeight(pf_flow *flow) 256 { 257 pf_object *obj = (pf_object *) flow; 258 259 return obj->fLineHeight; 260 } 261 262 le_int32 pf_getLineCount(pf_flow *flow) 263 { 264 pf_object *obj = (pf_object *) flow; 265 266 return obj->fLineCount; 267 } 268 269 static void addLine(pf_object *obj, pl_line *line) 270 { 271 if (obj->fLineCount >= obj->fLinesMax) { 272 obj->fLines = (pl_line **) GROW_ARRAY(obj->fLines, obj->fLinesMax + obj->fLinesGrow); 273 obj->fLinesMax += obj->fLinesGrow; 274 } 275 276 obj->fLines[obj->fLineCount++] = line; 277 } 278 279 void pf_breakLines(pf_flow *flow, le_int32 width, le_int32 height) 280 { 281 pf_object *obj = (pf_object *) flow; 282 le_int32 li, p; 283 float lineWidth; 284 pl_line *line; 285 286 obj->fHeight = height; 287 288 /* don't re-break if the width hasn't changed */ 289 if (obj->fWidth == width) { 290 return; 291 } 292 293 obj->fWidth = width; 294 295 lineWidth = (float) (width - 2 * MARGIN); 296 297 /* Free the old Lines... */ 298 for (li = 0; li < obj->fLineCount; li += 1) { 299 pl_closeLine(obj->fLines[li]); 300 } 301 302 obj->fLineCount = 0; 303 304 for (p = 0; p < obj->fParagraphCount; p += 1) { 305 pl_paragraph *paragraphLayout = obj->fParagraphLayout[p]; 306 307 if (paragraphLayout != NULL) { 308 pl_reflow(paragraphLayout); 309 while ((line = pl_nextLine(paragraphLayout, lineWidth)) != NULL) { 310 addLine(obj, line); 311 } 312 } else { 313 addLine(obj, NULL); 314 } 315 } 316 } 317 318 void pf_draw(pf_flow *flow, rs_surface *surface, le_int32 firstLine, le_int32 lastLine) 319 { 320 pf_object *obj = (pf_object *) flow; 321 le_int32 li, x, y; 322 323 x = MARGIN; 324 y = obj->fAscent; 325 326 for (li = firstLine; li <= lastLine; li += 1) { 327 const pl_line *line = obj->fLines[li]; 328 329 if (line != NULL) { 330 le_int32 runCount = pl_countLineRuns(line); 331 le_int32 run; 332 333 if (obj->fParagraphLevel == UBIDI_RTL) { 334 le_int32 lastX = pl_getLineWidth(line); 335 336 x = (obj->fWidth - lastX - MARGIN); 337 } 338 339 340 for (run = 0; run < runCount; run += 1) { 341 const pl_visualRun *visualRun = pl_getLineVisualRun(line, run); 342 le_int32 glyphCount = pl_getVisualRunGlyphCount(visualRun); 343 const le_font *font = pl_getVisualRunFont(visualRun); 344 const LEGlyphID *glyphs = pl_getVisualRunGlyphs(visualRun); 345 const float *positions = pl_getVisualRunPositions(visualRun); 346 347 rs_drawGlyphs(surface, font, glyphs, glyphCount, positions, x, y, obj->fWidth, obj->fHeight); 348 } 349 } 350 351 y += obj->fLineHeight; 352 } 353 } 354 355 pf_flow *pf_factory(const char *fileName, const le_font *font, gs_guiSupport *guiSupport) 356 { 357 LEErrorCode status = LE_NO_ERROR; 358 le_int32 charCount; 359 const UChar *text = uc_readFile(fileName, guiSupport, &charCount); 360 pl_fontRuns *fontRuns; 361 pf_flow *result = NULL; 362 363 if (text == NULL) { 364 return NULL; 365 } 366 367 fontRuns = pl_openEmptyFontRuns(0); 368 369 pl_addFontRun(fontRuns, font, charCount); 370 371 result = pf_create(text, charCount, fontRuns, &status); 372 373 if (LE_FAILURE(status)) { 374 pf_close(result); 375 result = NULL; 376 } 377 378 pl_closeFontRuns(fontRuns); 379 380 DELETE_ARRAY(text); 381 382 return result; 383 } 384 385