From 44da42e92f46cae9e96003999f02db04b8b5ff2d Mon Sep 17 00:00:00 2001 From: "reed@google.com" Date: Thu, 10 Nov 2011 20:04:47 +0000 Subject: [PATCH] have paint's measure calls respect vertical git-svn-id: http://skia.googlecode.com/svn/trunk@2660 2bbb7eff-a529-9590-31e7-b0007b416f81 --- include/core/SkDraw.h | 1 + include/core/SkPaint.h | 83 ++++++++++++++++++++++++------------------ src/core/SkPaint.cpp | 60 ++++++++++++++++++++++-------- 3 files changed, 93 insertions(+), 51 deletions(-) diff --git a/include/core/SkDraw.h b/include/core/SkDraw.h index f1e126a2c5..8c659c2389 100644 --- a/include/core/SkDraw.h +++ b/include/core/SkDraw.h @@ -149,6 +149,7 @@ private: const SkPath* fPath; // returned in next SkScalar fXPos; // accumulated xpos, returned in next SkAutoKern fAutoKern; + int fXYIndex; // cache for horizontal -vs- vertical text }; #endif diff --git a/include/core/SkPaint.h b/include/core/SkPaint.h index 9073e2049e..8649ea227f 100644 --- a/include/core/SkPaint.h +++ b/include/core/SkPaint.h @@ -762,23 +762,29 @@ public: return this->textToGlyphs(text, byteLength, NULL); } - /** Return the width of the text. - @param text The text to be measured - @param length Number of bytes of text to measure - @param bounds If not NULL, returns the bounds of the text, - relative to (0, 0). - @param scale If not 0, return width as if the canvas were scaled - by this value - @return The advance width of the text - */ + /** Return the width of the text. This will return the vertical measure + * if isVerticalText() is true, in which case the returned value should + * be treated has a height instead of a width. + * + * @param text The text to be measured + * @param length Number of bytes of text to measure + * @param bounds If not NULL, returns the bounds of the text, + * relative to (0, 0). + * @param scale If not 0, return width as if the canvas were scaled + * by this value + * @return The advance width of the text + */ SkScalar measureText(const void* text, size_t length, SkRect* bounds, SkScalar scale = 0) const; - /** Return the width of the text. - @param text Address of the text - @param length Number of bytes of text to measure - @return The width of the text - */ + /** Return the width of the text. This will return the vertical measure + * if isVerticalText() is true, in which case the returned value should + * be treated has a height instead of a width. + * + * @param text Address of the text + * @param length Number of bytes of text to measure + * @return The width of the text + */ SkScalar measureText(const void* text, size_t length) const { return this->measureText(text, length, NULL, 0); } @@ -796,33 +802,38 @@ public: kBackward_TextBufferDirection }; - /** Return the width of the text. - @param text The text to be measured - @param length Number of bytes of text to measure - @param maxWidth Maximum width. Only the subset of text whose accumulated - widths are <= maxWidth are measured. - @param measuredWidth Optional. If non-null, this returns the actual - width of the measured text. - @param tbd Optional. The direction the text buffer should be - traversed during measuring. - @return The number of bytes of text that were measured. Will be - <= length. - */ + /** Return the number of bytes of text that were measured. If + * isVerticalText() is true, then the vertical advances are used for + * the measurement. + * + * @param text The text to be measured + * @param length Number of bytes of text to measure + * @param maxWidth Maximum width. Only the subset of text whose accumulated + * widths are <= maxWidth are measured. + * @param measuredWidth Optional. If non-null, this returns the actual + * width of the measured text. + * @param tbd Optional. The direction the text buffer should be + * traversed during measuring. + * @return The number of bytes of text that were measured. Will be + * <= length. + */ size_t breakText(const void* text, size_t length, SkScalar maxWidth, SkScalar* measuredWidth = NULL, TextBufferDirection tbd = kForward_TextBufferDirection) const; - /** Return the advance widths for the characters in the string. - @param text the text - @param byteLength number of bytes to of text - @param widths If not null, returns the array of advance widths of - the glyphs. If not NULL, must be at least a large - as the number of unichars in the specified text. - @param bounds If not null, returns the bounds for each of - character, relative to (0, 0) - @return the number of unichars in the specified text. - */ + /** Return the advances for the text. These will be vertical advances if + * isVerticalText() returns true. + * + * @param text the text + * @param byteLength number of bytes to of text + * @param widths If not null, returns the array of advances for + * the glyphs. If not NULL, must be at least a large + * as the number of unichars in the specified text. + * @param bounds If not null, returns the bounds for each of + * character, relative to (0, 0) + * @return the number of unichars in the specified text. + */ int getTextWidths(const void* text, size_t byteLength, SkScalar widths[], SkRect bounds[] = NULL) const; diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp index 3a889dfa11..2d0cfe463b 100644 --- a/src/core/SkPaint.cpp +++ b/src/core/SkPaint.cpp @@ -801,7 +801,7 @@ typedef int64_t Sk48Dot16; } #endif -static void join_bounds(const SkGlyph& g, SkRect* bounds, Sk48Dot16 dx) { +static void join_bounds_x(const SkGlyph& g, SkRect* bounds, Sk48Dot16 dx) { SkScalar sx = Sk48Dot16ToScalar(dx); bounds->join(SkIntToScalar(g.fLeft) + sx, SkIntToScalar(g.fTop), @@ -809,6 +809,22 @@ static void join_bounds(const SkGlyph& g, SkRect* bounds, Sk48Dot16 dx) { SkIntToScalar(g.fTop + g.fHeight)); } +static void join_bounds_y(const SkGlyph& g, SkRect* bounds, Sk48Dot16 dy) { + SkScalar sy = Sk48Dot16ToScalar(dy); + bounds->join(SkIntToScalar(g.fLeft), + SkIntToScalar(g.fTop) + sy, + SkIntToScalar(g.fLeft + g.fWidth), + SkIntToScalar(g.fTop + g.fHeight) + sy); +} + +typedef void (*JoinBoundsProc)(const SkGlyph&, SkRect*, Sk48Dot16); + +// xyIndex is 0 for fAdvanceX or 1 for fAdvanceY +static SkFixed advance(const SkGlyph& glyph, int xyIndex) { + SkASSERT(0 == xyIndex || 1 == xyIndex); + return (&glyph.fAdvanceX)[xyIndex]; +} + SkScalar SkPaint::measure_text(SkGlyphCache* cache, const char* text, size_t byteLength, int* count, SkRect* bounds) const { @@ -825,13 +841,23 @@ SkScalar SkPaint::measure_text(SkGlyphCache* cache, glyphCacheProc = this->getMeasureCacheProc(kForward_TextBufferDirection, NULL != bounds); + int xyIndex; + JoinBoundsProc joinBoundsProc; + if (this->isVerticalText()) { + xyIndex = 1; + joinBoundsProc = join_bounds_y; + } else { + xyIndex = 0; + joinBoundsProc = join_bounds_x; + } + int n = 1; const char* stop = (const char*)text + byteLength; const SkGlyph* g = &glyphCacheProc(cache, &text); // our accumulated fixed-point advances might overflow 16.16, so we use // a 48.16 (64bit) accumulator, and then convert that to scalar at the // very end. - Sk48Dot16 x = g->fAdvanceX; + Sk48Dot16 x = advance(*g, xyIndex); SkAutoKern autokern; @@ -841,11 +867,11 @@ SkScalar SkPaint::measure_text(SkGlyphCache* cache, for (; text < stop; n++) { rsb = g->fRsbDelta; g = &glyphCacheProc(cache, &text); - x += SkAutoKern_AdjustF(rsb, g->fLsbDelta) + g->fAdvanceX; + x += SkAutoKern_AdjustF(rsb, g->fLsbDelta) + advance(*g, xyIndex); } } else { for (; text < stop; n++) { - x += glyphCacheProc(cache, &text).fAdvanceX; + x += advance(glyphCacheProc(cache, &text), xyIndex); } } } else { @@ -856,14 +882,14 @@ SkScalar SkPaint::measure_text(SkGlyphCache* cache, rsb = g->fRsbDelta; g = &glyphCacheProc(cache, &text); x += SkAutoKern_AdjustF(rsb, g->fLsbDelta); - join_bounds(*g, bounds, x); - x += g->fAdvanceX; + joinBoundsProc(*g, bounds, x); + x += advance(*g, xyIndex); } } else { for (; text < stop; n++) { g = &glyphCacheProc(cache, &text); - join_bounds(*g, bounds, x); - x += g->fAdvanceX; + joinBoundsProc(*g, bounds, x); + x += advance(*g, xyIndex); } } } @@ -968,6 +994,7 @@ size_t SkPaint::breakText(const void* textD, size_t length, SkScalar maxWidth, SkMeasureCacheProc glyphCacheProc = this->getMeasureCacheProc(tbd, false); const char* stop; SkTextBufferPred pred = chooseTextBufferPred(tbd, &text, length, &stop); + const int xyIndex = this->isVerticalText() ? 1 : 0; // use 64bits for our accumulator, to avoid overflowing 16.16 Sk48Dot16 max = SkScalarToFixed(maxWidth); Sk48Dot16 width = 0; @@ -979,7 +1006,7 @@ size_t SkPaint::breakText(const void* textD, size_t length, SkScalar maxWidth, while (pred(text, stop)) { const char* curr = text; const SkGlyph& g = glyphCacheProc(cache, &text); - SkFixed x = SkAutoKern_AdjustF(rsb, g.fLsbDelta) + g.fAdvanceX; + SkFixed x = SkAutoKern_AdjustF(rsb, g.fLsbDelta) + advance(g, xyIndex); if ((width += x) > max) { width -= x; text = curr; @@ -990,7 +1017,7 @@ size_t SkPaint::breakText(const void* textD, size_t length, SkScalar maxWidth, } else { while (pred(text, stop)) { const char* curr = text; - SkFixed x = glyphCacheProc(cache, &text).fAdvanceX; + SkFixed x = advance(glyphCacheProc(cache, &text), xyIndex); if ((width += x) > max) { width -= x; text = curr; @@ -1100,6 +1127,7 @@ int SkPaint::getTextWidths(const void* textData, size_t byteLength, const char* text = (const char*)textData; const char* stop = text + byteLength; int count = 0; + const int xyIndex = this->isVerticalText() ? 1 : 0; if (this->isDevKernText()) { // we adjust the widths returned here through auto-kerning @@ -1116,7 +1144,7 @@ int SkPaint::getTextWidths(const void* textData, size_t byteLength, SkScalar w = SkFixedToScalar(prevWidth + adjust); *widths++ = SkScalarMul(w, scale); } - prevWidth = g.fAdvanceX; + prevWidth = advance(g, xyIndex); } if (bounds) { set_bounds(g, bounds++, scale); @@ -1135,7 +1163,7 @@ int SkPaint::getTextWidths(const void* textData, size_t byteLength, if (count > 0) { *widths++ = SkFixedToScalar(prevWidth + adjust); } - prevWidth = g.fAdvanceX; + prevWidth = advance(g, xyIndex); } if (bounds) { set_bounds(g, bounds++); @@ -1151,7 +1179,7 @@ int SkPaint::getTextWidths(const void* textData, size_t byteLength, while (text < stop) { const SkGlyph& g = glyphCacheProc(cache, &text); if (widths) { - *widths++ = SkScalarMul(SkFixedToScalar(g.fAdvanceX), + *widths++ = SkScalarMul(SkFixedToScalar(advance(g, xyIndex)), scale); } if (bounds) { @@ -1163,7 +1191,7 @@ int SkPaint::getTextWidths(const void* textData, size_t byteLength, while (text < stop) { const SkGlyph& g = glyphCacheProc(cache, &text); if (widths) { - *widths++ = SkFixedToScalar(g.fAdvanceX); + *widths++ = SkFixedToScalar(advance(g, xyIndex)); } if (bounds) { set_bounds(g, bounds++); @@ -1845,6 +1873,8 @@ SkTextToPathIter::SkTextToPathIter( const char text[], size_t length, fText = text; fStop = text + length; + + fXYIndex = paint.isVerticalText() ? 1 : 0; } SkTextToPathIter::~SkTextToPathIter() { @@ -1856,7 +1886,7 @@ const SkPath* SkTextToPathIter::next(SkScalar* xpos) { const SkGlyph& glyph = fGlyphCacheProc(fCache, &fText); fXPos += SkScalarMul(SkFixedToScalar(fPrevAdvance + fAutoKern.adjust(glyph)), fScale); - fPrevAdvance = glyph.fAdvanceX; // + fPaint.getTextTracking(); + fPrevAdvance = advance(glyph, fXYIndex); // + fPaint.getTextTracking(); if (glyph.fWidth) { if (xpos) {