Viewing file: pflow.c (9.27 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/* * * © 2016 and later: Unicode, Inc. and others. * License & terms of use: http://www.unicode.org/copyright.html#License * * (C) Copyright IBM Corp. 1998-2007 - All Rights Reserved * */
#include "unicode/utypes.h" #include "unicode/uchar.h" #include "unicode/ubidi.h" #include "unicode/ustring.h"
#include "layout/LETypes.h"
#include "layout/loengine.h" #include "layout/playout.h" #include "layout/plruns.h"
#include "pflow.h"
#include "arraymem.h" #include "ucreader.h"
/* * Move the line below out of this comment * to add a locale run to the pl_paragraphs * that are created. #define TEST_LOCALE "zh_TW" */
#define MARGIN 10 #define LINE_GROW 32 #define PARA_GROW 8
#define CH_LF 0x000A #define CH_CR 0x000D #define CH_LSEP 0x2028 #define CH_PSEP 0x2029
struct pf_object { pl_paragraph **fParagraphLayout;
le_int32 fParagraphCount; le_int32 fParagraphMax; le_int32 fParagraphGrow; le_int32 fLineCount; le_int32 fLinesMax; le_int32 fLinesGrow;
pl_line **fLines;
LEUnicode *fChars;
le_int32 fLineHeight; le_int32 fAscent; le_int32 fWidth; le_int32 fHeight; UBiDiLevel fParagraphLevel; };
typedef struct pf_object pf_object;
static LEUnicode *skipLineEnd(LEUnicode *ptr) { if (ptr[0] == CH_CR && ptr[1] == CH_LF) { ptr += 1; }
return ptr + 1; }
static le_int32 findFontRun(const pl_fontRuns *fontRuns, le_int32 offset) { le_int32 runCount = pl_getFontRunCount(fontRuns); le_int32 run;
for (run = 0; run < runCount; run += 1) { if (pl_getFontRunLimit(fontRuns, run) > offset) { return run; } }
return -1; }
static void subsetFontRuns(const pl_fontRuns *fontRuns, le_int32 start, le_int32 limit, pl_fontRuns *sub) { le_int32 startRun = findFontRun(fontRuns, start); le_int32 endRun = findFontRun(fontRuns, limit - 1); le_int32 run;
pl_resetFontRuns(sub);
for (run = startRun; run <= endRun; run += 1) { const le_font *runFont = pl_getFontRunFont(fontRuns, run); le_int32 runLimit = pl_getFontRunLimit(fontRuns, run) - start;
if (run == endRun) { runLimit = limit - start; }
pl_addFontRun(sub, runFont, runLimit); } }
pf_flow *pf_create(const LEUnicode chars[], le_int32 charCount, const pl_fontRuns *fontRuns, LEErrorCode *status) { pf_object *flow; le_int32 ascent = 0; le_int32 descent = 0; le_int32 leading = 0; pl_localeRuns *locales = NULL; pl_fontRuns *fr; LEUnicode *pStart; static const LEUnicode separators[] = {CH_LF, CH_CR, CH_LSEP, CH_PSEP, 0x0000};
if (LE_FAILURE(*status)) { return NULL; }
flow = NEW_ARRAY(pf_object, 1);
flow->fParagraphLayout = NULL; flow->fParagraphCount = 0; flow->fParagraphMax = PARA_GROW; flow->fParagraphGrow = PARA_GROW; flow->fLineCount = 0; flow->fLinesMax = LINE_GROW; flow->fLinesGrow = LINE_GROW; flow->fLines = NULL; flow->fChars = NULL; flow->fLineHeight = -1; flow->fAscent = -1; flow->fWidth = -1; flow->fHeight = -1; flow->fParagraphLevel = UBIDI_DEFAULT_LTR;
fr = pl_openEmptyFontRuns(0);
#ifdef TEST_LOCALE locales = pl_openEmptyLocaleRuns(0); #endif
flow->fLines = NEW_ARRAY(pl_line *, flow->fLinesMax); flow->fParagraphLayout = NEW_ARRAY(pl_paragraph *, flow->fParagraphMax);
flow->fChars = NEW_ARRAY(LEUnicode, charCount + 1); LE_ARRAY_COPY(flow->fChars, chars, charCount); flow->fChars[charCount] = 0;
pStart = &flow->fChars[0];
while (*pStart != 0) { LEUnicode *pEnd = u_strpbrk(pStart, separators); le_int32 pAscent, pDescent, pLeading; pl_paragraph *paragraphLayout = NULL;
if (pEnd == NULL) { pEnd = &flow->fChars[charCount]; }
if (pEnd != pStart) { subsetFontRuns(fontRuns, pStart - flow->fChars, pEnd - flow->fChars, fr);
#ifdef TEST_LOCALE pl_resetLocaleRuns(locales); pl_addLocaleRun(locales, TEST_LOCALE, pEnd - pStart); #endif
paragraphLayout = pl_create(pStart, pEnd - pStart, fr, NULL, NULL, locales, flow->fParagraphLevel, FALSE, status);
if (LE_FAILURE(*status)) { break; /* return? something else? */ }
if (flow->fParagraphLevel == UBIDI_DEFAULT_LTR) { flow->fParagraphLevel = pl_getParagraphLevel(paragraphLayout); }
pAscent = pl_getAscent(paragraphLayout); pDescent = pl_getDescent(paragraphLayout); pLeading = pl_getLeading(paragraphLayout);
if (pAscent > ascent) { ascent = pAscent; }
if (pDescent > descent) { descent = pDescent; }
if (pLeading > leading) { leading = pLeading; } }
if (flow->fParagraphCount >= flow->fParagraphMax) { flow->fParagraphLayout = (pl_paragraph **) GROW_ARRAY(flow->fParagraphLayout, flow->fParagraphMax + flow->fParagraphGrow); flow->fParagraphMax += flow->fParagraphGrow; }
flow->fParagraphLayout[flow->fParagraphCount++] = paragraphLayout;
if (*pEnd == 0) { break; }
pStart = skipLineEnd(pEnd); }
flow->fLineHeight = ascent + descent + leading; flow->fAscent = ascent;
pl_closeLocaleRuns(locales); pl_closeFontRuns(fr);
return (pf_flow *) flow; }
void pf_close(pf_flow *flow) { pf_object *obj = (pf_object *) flow; le_int32 i;
for (i = 0; i < obj->fLineCount; i += 1) { DELETE_ARRAY(obj->fLines[i]); }
DELETE_ARRAY(obj->fLines);
for (i = 0; i < obj->fParagraphCount; i += 1) { pl_close(obj->fParagraphLayout[i]); }
DELETE_ARRAY(obj->fParagraphLayout);
DELETE_ARRAY(obj->fChars);
DELETE_ARRAY(obj); }
le_int32 pf_getAscent(pf_flow *flow) { pf_object *obj = (pf_object *) flow;
return obj->fAscent; }
le_int32 pf_getLineHeight(pf_flow *flow) { pf_object *obj = (pf_object *) flow;
return obj->fLineHeight; }
le_int32 pf_getLineCount(pf_flow *flow) { pf_object *obj = (pf_object *) flow;
return obj->fLineCount; }
static void addLine(pf_object *obj, pl_line *line) { if (obj->fLineCount >= obj->fLinesMax) { obj->fLines = (pl_line **) GROW_ARRAY(obj->fLines, obj->fLinesMax + obj->fLinesGrow); obj->fLinesMax += obj->fLinesGrow; }
obj->fLines[obj->fLineCount++] = line; }
void pf_breakLines(pf_flow *flow, le_int32 width, le_int32 height) { pf_object *obj = (pf_object *) flow; le_int32 li, p; float lineWidth; pl_line *line;
obj->fHeight = height;
/* don't re-break if the width hasn't changed */ if (obj->fWidth == width) { return; }
obj->fWidth = width;
lineWidth = (float) (width - 2 * MARGIN);
/* Free the old Lines... */ for (li = 0; li < obj->fLineCount; li += 1) { pl_closeLine(obj->fLines[li]); }
obj->fLineCount = 0;
for (p = 0; p < obj->fParagraphCount; p += 1) { pl_paragraph *paragraphLayout = obj->fParagraphLayout[p];
if (paragraphLayout != NULL) { pl_reflow(paragraphLayout); while ((line = pl_nextLine(paragraphLayout, lineWidth)) != NULL) { addLine(obj, line); } } else { addLine(obj, NULL); } } }
void pf_draw(pf_flow *flow, rs_surface *surface, le_int32 firstLine, le_int32 lastLine) { pf_object *obj = (pf_object *) flow; le_int32 li, x, y;
x = MARGIN; y = obj->fAscent;
for (li = firstLine; li <= lastLine; li += 1) { const pl_line *line = obj->fLines[li];
if (line != NULL) { le_int32 runCount = pl_countLineRuns(line); le_int32 run;
if (obj->fParagraphLevel == UBIDI_RTL) { le_int32 lastX = pl_getLineWidth(line);
x = (obj->fWidth - lastX - MARGIN); }
for (run = 0; run < runCount; run += 1) { const pl_visualRun *visualRun = pl_getLineVisualRun(line, run); le_int32 glyphCount = pl_getVisualRunGlyphCount(visualRun); const le_font *font = pl_getVisualRunFont(visualRun); const LEGlyphID *glyphs = pl_getVisualRunGlyphs(visualRun); const float *positions = pl_getVisualRunPositions(visualRun);
rs_drawGlyphs(surface, font, glyphs, glyphCount, positions, x, y, obj->fWidth, obj->fHeight); } }
y += obj->fLineHeight; } }
pf_flow *pf_factory(const char *fileName, const le_font *font, gs_guiSupport *guiSupport) { LEErrorCode status = LE_NO_ERROR; le_int32 charCount; const UChar *text = uc_readFile(fileName, guiSupport, &charCount); pl_fontRuns *fontRuns; pf_flow *result = NULL;
if (text == NULL) { return NULL; }
fontRuns = pl_openEmptyFontRuns(0);
pl_addFontRun(fontRuns, font, charCount);
result = pf_create(text, charCount, fontRuns, &status);
if (LE_FAILURE(status)) { pf_close(result); result = NULL; }
pl_closeFontRuns(fontRuns);
DELETE_ARRAY(text);
return result; }
|