]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/samples/layout/paragraph.cpp
ICU-8.11.tar.gz
[apple/icu.git] / icuSources / samples / layout / paragraph.cpp
index 2ac4504ed6dda16a604d83c9e6f36d1ac538bd17..315ca04a4b7eed44c515f5cfaadafcf332b9513d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *******************************************************************************
  *
- *   Copyright (C) 1999-2003, International Business Machines
+ *   Copyright (C) 1999-2005, International Business Machines
  *   Corporation and others.  All Rights Reserved.
  *
  *******************************************************************************
@@ -14,6 +14,7 @@
 #include "unicode/utypes.h"
 #include "unicode/uchar.h"
 #include "unicode/ubidi.h"
+#include "unicode/ustring.h"
 
 #include "layout/ParagraphLayout.h"
 
 
 #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
+
+static LEUnicode *skipLineEnd(LEUnicode *ptr)
+{
+    if (ptr[0] == CH_CR && ptr[1] == CH_LF) {
+        ptr += 1;
+    }
+
+    return ptr + 1;
+}
+
+static le_int32 findRun(const RunArray *runArray, le_int32 offset)
+{
+    le_int32 runCount = runArray->getCount();
+
+    for (le_int32 run = 0; run < runCount; run += 1) {
+        if (runArray->getLimit(run) > offset) {
+            return run;
+        }
+    }
+
+    return -1;
+}
+
+static void subsetFontRuns(const FontRuns *fontRuns, le_int32 start, le_int32 limit, FontRuns *sub)
+{
+    le_int32 startRun = findRun(fontRuns, start);
+    le_int32 endRun   = findRun(fontRuns, limit - 1);
+
+    sub->reset();
+
+    for (le_int32 run = startRun; run <= endRun; run += 1) {
+        const LEFontInstance *runFont = fontRuns->getFont(run);
+        le_int32 runLimit = fontRuns->getLimit(run) - start;
+
+        if (run == endRun) {
+            runLimit = limit - start;
+        }
+
+        sub->add(runFont, runLimit);
+    }
+}
 
 Paragraph::Paragraph(const LEUnicode chars[], int32_t charCount, const FontRuns *fontRuns, LEErrorCode &status)
-  : fParagraphLayout(NULL), fLineCount(0), fLinesMax(0), fLinesGrow(LINE_GROW), fLines(NULL), fChars(NULL),
-    fLineHeight(-1), fAscent(-1), fWidth(-1), fHeight(-1)
+  : fParagraphLayout(NULL), fParagraphCount(0), fParagraphMax(PARA_GROW), fParagraphGrow(PARA_GROW),
+    fLineCount(0), fLinesMax(LINE_GROW), fLinesGrow(LINE_GROW), fLines(NULL), fChars(NULL),
+    fLineHeight(-1), fAscent(-1), fWidth(-1), fHeight(-1), fParagraphLevel(UBIDI_DEFAULT_LTR)
 {
+    static const LEUnicode separators[] = {CH_LF, CH_CR, CH_LSEP, CH_PSEP};
+
        if (LE_FAILURE(status)) {
                return;
        }
 
+    le_int32 ascent  = 0;
+    le_int32 descent = 0;
+    le_int32 leading = 0;
+
        LocaleRuns *locales = NULL;
+    FontRuns fr(0);
+
+    fLines = LE_NEW_ARRAY(const ParagraphLayout::Line *, fLinesMax);
+    fParagraphLayout = LE_NEW_ARRAY(ParagraphLayout *, fParagraphMax);
 
-    fChars = LE_NEW_ARRAY(LEUnicode, charCount);
+    fChars = LE_NEW_ARRAY(LEUnicode, charCount + 1);
     LE_ARRAY_COPY(fChars, chars, charCount);
+    fChars[charCount] = 0;
 
-    fParagraphLayout = new ParagraphLayout(fChars, charCount, fontRuns, NULL, NULL, locales, UBIDI_DEFAULT_LTR, FALSE, status);
+    LEUnicode *pStart = &fChars[0];
 
-       if (LE_FAILURE(status)) {
-               return;
-       }
+    while (*pStart != 0) {
+        LEUnicode *pEnd = u_strpbrk(pStart, separators);
+        le_int32 pAscent, pDescent, pLeading;
+        ParagraphLayout *paragraphLayout = NULL;
 
-    le_int32 ascent  = fParagraphLayout->getAscent();
-    le_int32 descent = fParagraphLayout->getDescent();
-    le_int32 leading = fParagraphLayout->getLeading();
+        if (pEnd == NULL) {
+            pEnd = &fChars[charCount];
+        }
+
+        if (pEnd != pStart) {
+            subsetFontRuns(fontRuns, pStart - fChars, pEnd - fChars, &fr);
+
+            paragraphLayout = new ParagraphLayout(pStart, pEnd - pStart, &fr, NULL, NULL, locales, fParagraphLevel, FALSE, status);
+
+            if (LE_FAILURE(status)) {
+                break; // return? something else?
+            }
+
+            if (fParagraphLevel == UBIDI_DEFAULT_LTR) {
+                fParagraphLevel = paragraphLayout->getParagraphLevel();
+            }
+
+            pAscent  = paragraphLayout->getAscent();
+            pDescent = paragraphLayout->getDescent();
+            pLeading = paragraphLayout->getLeading();
+
+            if (pAscent > ascent) {
+                ascent = pAscent;
+            }
+
+            if (pDescent > descent) {
+                descent = pDescent;
+            }
+
+            if (pLeading > leading) {
+                leading = pLeading;
+            }
+        }
+
+        if (fParagraphCount >= fParagraphMax) {
+            fParagraphLayout = (ParagraphLayout **) LE_GROW_ARRAY(fParagraphLayout, fParagraphMax + fParagraphGrow);
+            fParagraphMax += fParagraphGrow;
+        }
+
+        fParagraphLayout[fParagraphCount++] = paragraphLayout;
+
+        if (*pEnd == 0) {
+            break;
+        }
+
+        pStart = skipLineEnd(pEnd);
+    }
 
     fLineHeight = ascent + descent + leading;
     fAscent     = ascent;
@@ -65,6 +170,16 @@ Paragraph::~Paragraph()
     LE_DELETE_ARRAY(fChars);
 }
 
+void Paragraph::addLine(const ParagraphLayout::Line *line)
+{
+    if (fLineCount >= fLinesMax) {
+        fLines = (const ParagraphLayout::Line **) LE_GROW_ARRAY(fLines, fLinesMax + fLinesGrow);
+        fLinesMax += fLinesGrow;
+    }
+
+    fLines[fLineCount++] = line;
+}
+
 void Paragraph::breakLines(le_int32 width, le_int32 height)
 {
     fHeight = height;
@@ -78,26 +193,26 @@ void Paragraph::breakLines(le_int32 width, le_int32 height)
 
     float lineWidth = (float) (width - 2 * MARGIN);
     const ParagraphLayout::Line *line;
-    le_int32 li;
 
     // Free the old LineInfo's...
-    for (li = 0; li < fLineCount; li += 1) {
+    for (le_int32 li = 0; li < fLineCount; li += 1) {
         delete fLines[li];
     }
 
-    li = 0;
-    fParagraphLayout->reflow();
-    while ((line = fParagraphLayout->nextLine(lineWidth)) != NULL) {
-        // grow the line array, if we need to.
-        if (li >= fLinesMax) {
-            fLines = (const ParagraphLayout::Line **) LE_GROW_ARRAY(fLines, fLinesMax + fLinesGrow);
-            fLinesMax += fLinesGrow;
-        }
+    fLineCount = 0;
 
-        fLines[li++] = line;
-    }
+    for (le_int32 p = 0; p < fParagraphCount; p += 1) {
+        ParagraphLayout *paragraphLayout = fParagraphLayout[p];
 
-    fLineCount = li;
+        if (paragraphLayout != NULL) {
+            paragraphLayout->reflow();
+            while ((line = paragraphLayout->nextLine(lineWidth)) != NULL) {
+                addLine(line);
+            }
+        } else {
+            addLine(NULL);
+        }
+    }
 }
 
 void Paragraph::draw(RenderingSurface *surface, le_int32 firstLine, le_int32 lastLine)
@@ -109,24 +224,27 @@ void Paragraph::draw(RenderingSurface *surface, le_int32 firstLine, le_int32 las
 
     for (li = firstLine; li <= lastLine; li += 1) {
         const ParagraphLayout::Line *line = fLines[li];
-        le_int32 runCount = line->countRuns();
-        le_int32 run;
 
-               if (fParagraphLayout->getParagraphLevel() == UBIDI_RTL) {
-                       le_int32 lastX = line->getWidth();
+        if (line != NULL) {
+            le_int32 runCount = line->countRuns();
+            le_int32 run;
+
+                   if (fParagraphLevel == UBIDI_RTL) {
+                           le_int32 lastX = line->getWidth();
 
-                       x = (fWidth - lastX - MARGIN);
-               }
+                           x = (fWidth - lastX - MARGIN);
+                   }
 
 
-        for (run = 0; run < runCount; run += 1) {
-            const ParagraphLayout::VisualRun *visualRun = line->getVisualRun(run);
-            le_int32 glyphCount = visualRun->getGlyphCount();
-            const LEFontInstance *font = visualRun->getFont();
-            const LEGlyphID *glyphs = visualRun->getGlyphs();
-            const float *positions = visualRun->getPositions();
+            for (run = 0; run < runCount; run += 1) {
+                const ParagraphLayout::VisualRun *visualRun = line->getVisualRun(run);
+                le_int32 glyphCount = visualRun->getGlyphCount();
+                const LEFontInstance *font = visualRun->getFont();
+                const LEGlyphID *glyphs = visualRun->getGlyphs();
+                const float *positions = visualRun->getPositions();
 
-            surface->drawGlyphs(font, glyphs, glyphCount, positions, x, y, fWidth, fHeight);
+                surface->drawGlyphs(font, glyphs, glyphCount, positions, x, y, fWidth, fHeight);
+            }
         }
 
         y += fLineHeight;