have paint's measure calls respect vertical

git-svn-id: http://skia.googlecode.com/svn/trunk@2660 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
reed@google.com 2011-11-10 20:04:47 +00:00
parent 4e27d6e000
commit 44da42e92f
3 changed files with 93 additions and 51 deletions

View File

@ -149,6 +149,7 @@ private:
const SkPath* fPath; // returned in next const SkPath* fPath; // returned in next
SkScalar fXPos; // accumulated xpos, returned in next SkScalar fXPos; // accumulated xpos, returned in next
SkAutoKern fAutoKern; SkAutoKern fAutoKern;
int fXYIndex; // cache for horizontal -vs- vertical text
}; };
#endif #endif

View File

@ -762,23 +762,29 @@ public:
return this->textToGlyphs(text, byteLength, NULL); return this->textToGlyphs(text, byteLength, NULL);
} }
/** Return the width of the text. /** Return the width of the text. This will return the vertical measure
@param text The text to be measured * if isVerticalText() is true, in which case the returned value should
@param length Number of bytes of text to measure * be treated has a height instead of a width.
@param bounds If not NULL, returns the bounds of the text, *
relative to (0, 0). * @param text The text to be measured
@param scale If not 0, return width as if the canvas were scaled * @param length Number of bytes of text to measure
by this value * @param bounds If not NULL, returns the bounds of the text,
@return The advance width 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, SkScalar measureText(const void* text, size_t length,
SkRect* bounds, SkScalar scale = 0) const; SkRect* bounds, SkScalar scale = 0) const;
/** Return the width of the text. /** Return the width of the text. This will return the vertical measure
@param text Address of the text * if isVerticalText() is true, in which case the returned value should
@param length Number of bytes of text to measure * be treated has a height instead of a width.
@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
*/
SkScalar measureText(const void* text, size_t length) const { SkScalar measureText(const void* text, size_t length) const {
return this->measureText(text, length, NULL, 0); return this->measureText(text, length, NULL, 0);
} }
@ -796,33 +802,38 @@ public:
kBackward_TextBufferDirection kBackward_TextBufferDirection
}; };
/** Return the width of the text. /** Return the number of bytes of text that were measured. If
@param text The text to be measured * isVerticalText() is true, then the vertical advances are used for
@param length Number of bytes of text to measure * the measurement.
@param maxWidth Maximum width. Only the subset of text whose accumulated *
widths are <= maxWidth are measured. * @param text The text to be measured
@param measuredWidth Optional. If non-null, this returns the actual * @param length Number of bytes of text to measure
width of the measured text. * @param maxWidth Maximum width. Only the subset of text whose accumulated
@param tbd Optional. The direction the text buffer should be * widths are <= maxWidth are measured.
traversed during measuring. * @param measuredWidth Optional. If non-null, this returns the actual
@return The number of bytes of text that were measured. Will be * width of the measured text.
<= length. * @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, size_t breakText(const void* text, size_t length, SkScalar maxWidth,
SkScalar* measuredWidth = NULL, SkScalar* measuredWidth = NULL,
TextBufferDirection tbd = kForward_TextBufferDirection) TextBufferDirection tbd = kForward_TextBufferDirection)
const; const;
/** Return the advance widths for the characters in the string. /** Return the advances for the text. These will be vertical advances if
@param text the text * isVerticalText() returns true.
@param byteLength number of bytes to of text *
@param widths If not null, returns the array of advance widths of * @param text the text
the glyphs. If not NULL, must be at least a large * @param byteLength number of bytes to of text
as the number of unichars in the specified text. * @param widths If not null, returns the array of advances for
@param bounds If not null, returns the bounds for each of * the glyphs. If not NULL, must be at least a large
character, relative to (0, 0) * as the number of unichars in the specified text.
@return 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[], int getTextWidths(const void* text, size_t byteLength, SkScalar widths[],
SkRect bounds[] = NULL) const; SkRect bounds[] = NULL) const;

View File

@ -801,7 +801,7 @@ typedef int64_t Sk48Dot16;
} }
#endif #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); SkScalar sx = Sk48Dot16ToScalar(dx);
bounds->join(SkIntToScalar(g.fLeft) + sx, bounds->join(SkIntToScalar(g.fLeft) + sx,
SkIntToScalar(g.fTop), SkIntToScalar(g.fTop),
@ -809,6 +809,22 @@ static void join_bounds(const SkGlyph& g, SkRect* bounds, Sk48Dot16 dx) {
SkIntToScalar(g.fTop + g.fHeight)); 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, SkScalar SkPaint::measure_text(SkGlyphCache* cache,
const char* text, size_t byteLength, const char* text, size_t byteLength,
int* count, SkRect* bounds) const { int* count, SkRect* bounds) const {
@ -825,13 +841,23 @@ SkScalar SkPaint::measure_text(SkGlyphCache* cache,
glyphCacheProc = this->getMeasureCacheProc(kForward_TextBufferDirection, glyphCacheProc = this->getMeasureCacheProc(kForward_TextBufferDirection,
NULL != bounds); 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; int n = 1;
const char* stop = (const char*)text + byteLength; const char* stop = (const char*)text + byteLength;
const SkGlyph* g = &glyphCacheProc(cache, &text); const SkGlyph* g = &glyphCacheProc(cache, &text);
// our accumulated fixed-point advances might overflow 16.16, so we use // 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 // a 48.16 (64bit) accumulator, and then convert that to scalar at the
// very end. // very end.
Sk48Dot16 x = g->fAdvanceX; Sk48Dot16 x = advance(*g, xyIndex);
SkAutoKern autokern; SkAutoKern autokern;
@ -841,11 +867,11 @@ SkScalar SkPaint::measure_text(SkGlyphCache* cache,
for (; text < stop; n++) { for (; text < stop; n++) {
rsb = g->fRsbDelta; rsb = g->fRsbDelta;
g = &glyphCacheProc(cache, &text); g = &glyphCacheProc(cache, &text);
x += SkAutoKern_AdjustF(rsb, g->fLsbDelta) + g->fAdvanceX; x += SkAutoKern_AdjustF(rsb, g->fLsbDelta) + advance(*g, xyIndex);
} }
} else { } else {
for (; text < stop; n++) { for (; text < stop; n++) {
x += glyphCacheProc(cache, &text).fAdvanceX; x += advance(glyphCacheProc(cache, &text), xyIndex);
} }
} }
} else { } else {
@ -856,14 +882,14 @@ SkScalar SkPaint::measure_text(SkGlyphCache* cache,
rsb = g->fRsbDelta; rsb = g->fRsbDelta;
g = &glyphCacheProc(cache, &text); g = &glyphCacheProc(cache, &text);
x += SkAutoKern_AdjustF(rsb, g->fLsbDelta); x += SkAutoKern_AdjustF(rsb, g->fLsbDelta);
join_bounds(*g, bounds, x); joinBoundsProc(*g, bounds, x);
x += g->fAdvanceX; x += advance(*g, xyIndex);
} }
} else { } else {
for (; text < stop; n++) { for (; text < stop; n++) {
g = &glyphCacheProc(cache, &text); g = &glyphCacheProc(cache, &text);
join_bounds(*g, bounds, x); joinBoundsProc(*g, bounds, x);
x += g->fAdvanceX; 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); SkMeasureCacheProc glyphCacheProc = this->getMeasureCacheProc(tbd, false);
const char* stop; const char* stop;
SkTextBufferPred pred = chooseTextBufferPred(tbd, &text, length, &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 // use 64bits for our accumulator, to avoid overflowing 16.16
Sk48Dot16 max = SkScalarToFixed(maxWidth); Sk48Dot16 max = SkScalarToFixed(maxWidth);
Sk48Dot16 width = 0; Sk48Dot16 width = 0;
@ -979,7 +1006,7 @@ size_t SkPaint::breakText(const void* textD, size_t length, SkScalar maxWidth,
while (pred(text, stop)) { while (pred(text, stop)) {
const char* curr = text; const char* curr = text;
const SkGlyph& g = glyphCacheProc(cache, &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) { if ((width += x) > max) {
width -= x; width -= x;
text = curr; text = curr;
@ -990,7 +1017,7 @@ size_t SkPaint::breakText(const void* textD, size_t length, SkScalar maxWidth,
} else { } else {
while (pred(text, stop)) { while (pred(text, stop)) {
const char* curr = text; const char* curr = text;
SkFixed x = glyphCacheProc(cache, &text).fAdvanceX; SkFixed x = advance(glyphCacheProc(cache, &text), xyIndex);
if ((width += x) > max) { if ((width += x) > max) {
width -= x; width -= x;
text = curr; text = curr;
@ -1100,6 +1127,7 @@ int SkPaint::getTextWidths(const void* textData, size_t byteLength,
const char* text = (const char*)textData; const char* text = (const char*)textData;
const char* stop = text + byteLength; const char* stop = text + byteLength;
int count = 0; int count = 0;
const int xyIndex = this->isVerticalText() ? 1 : 0;
if (this->isDevKernText()) { if (this->isDevKernText()) {
// we adjust the widths returned here through auto-kerning // 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); SkScalar w = SkFixedToScalar(prevWidth + adjust);
*widths++ = SkScalarMul(w, scale); *widths++ = SkScalarMul(w, scale);
} }
prevWidth = g.fAdvanceX; prevWidth = advance(g, xyIndex);
} }
if (bounds) { if (bounds) {
set_bounds(g, bounds++, scale); set_bounds(g, bounds++, scale);
@ -1135,7 +1163,7 @@ int SkPaint::getTextWidths(const void* textData, size_t byteLength,
if (count > 0) { if (count > 0) {
*widths++ = SkFixedToScalar(prevWidth + adjust); *widths++ = SkFixedToScalar(prevWidth + adjust);
} }
prevWidth = g.fAdvanceX; prevWidth = advance(g, xyIndex);
} }
if (bounds) { if (bounds) {
set_bounds(g, bounds++); set_bounds(g, bounds++);
@ -1151,7 +1179,7 @@ int SkPaint::getTextWidths(const void* textData, size_t byteLength,
while (text < stop) { while (text < stop) {
const SkGlyph& g = glyphCacheProc(cache, &text); const SkGlyph& g = glyphCacheProc(cache, &text);
if (widths) { if (widths) {
*widths++ = SkScalarMul(SkFixedToScalar(g.fAdvanceX), *widths++ = SkScalarMul(SkFixedToScalar(advance(g, xyIndex)),
scale); scale);
} }
if (bounds) { if (bounds) {
@ -1163,7 +1191,7 @@ int SkPaint::getTextWidths(const void* textData, size_t byteLength,
while (text < stop) { while (text < stop) {
const SkGlyph& g = glyphCacheProc(cache, &text); const SkGlyph& g = glyphCacheProc(cache, &text);
if (widths) { if (widths) {
*widths++ = SkFixedToScalar(g.fAdvanceX); *widths++ = SkFixedToScalar(advance(g, xyIndex));
} }
if (bounds) { if (bounds) {
set_bounds(g, bounds++); set_bounds(g, bounds++);
@ -1845,6 +1873,8 @@ SkTextToPathIter::SkTextToPathIter( const char text[], size_t length,
fText = text; fText = text;
fStop = text + length; fStop = text + length;
fXYIndex = paint.isVerticalText() ? 1 : 0;
} }
SkTextToPathIter::~SkTextToPathIter() { SkTextToPathIter::~SkTextToPathIter() {
@ -1856,7 +1886,7 @@ const SkPath* SkTextToPathIter::next(SkScalar* xpos) {
const SkGlyph& glyph = fGlyphCacheProc(fCache, &fText); const SkGlyph& glyph = fGlyphCacheProc(fCache, &fText);
fXPos += SkScalarMul(SkFixedToScalar(fPrevAdvance + fAutoKern.adjust(glyph)), fScale); fXPos += SkScalarMul(SkFixedToScalar(fPrevAdvance + fAutoKern.adjust(glyph)), fScale);
fPrevAdvance = glyph.fAdvanceX; // + fPaint.getTextTracking(); fPrevAdvance = advance(glyph, fXYIndex); // + fPaint.getTextTracking();
if (glyph.fWidth) { if (glyph.fWidth) {
if (xpos) { if (xpos) {