diff options
Diffstat (limited to 'skia/sgl/SkPaint.cpp')
-rw-r--r-- | skia/sgl/SkPaint.cpp | 1571 |
1 files changed, 0 insertions, 1571 deletions
diff --git a/skia/sgl/SkPaint.cpp b/skia/sgl/SkPaint.cpp deleted file mode 100644 index bb6b31e..0000000 --- a/skia/sgl/SkPaint.cpp +++ /dev/null @@ -1,1571 +0,0 @@ -/* libs/graphics/sgl/SkPaint.cpp -** -** Copyright 2006, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -#include "SkPaint.h" -#include "SkColorFilter.h" -#include "SkDrawLooper.h" -#include "SkFontHost.h" -#include "SkMaskFilter.h" -#include "SkPathEffect.h" -#include "SkRasterizer.h" -#include "SkShader.h" -#include "SkScalerContext.h" -#include "SkStroke.h" -#include "SkTypeface.h" -#include "SkXfermode.h" -#include "SkAutoKern.h" - -#define SK_DefaultTextSize SkIntToScalar(12) - -#define SK_DefaultFlags 0 //(kNativeHintsText_Flag) - -SkPaint::SkPaint() -{ - fTypeface = NULL; - fTextSize = SK_DefaultTextSize; - fTextScaleX = SK_Scalar1; - fTextSkewX = 0; - - fPathEffect = NULL; - fShader = NULL; - fXfermode = NULL; - fMaskFilter = NULL; - fColorFilter = NULL; - fRasterizer = NULL; - fLooper = NULL; - - fColor = SK_ColorBLACK; - fWidth = 0; - fMiterLimit = SK_DefaultMiterLimit; - fFlags = SK_DefaultFlags; - fCapType = kDefault_Cap; - fJoinType = kDefault_Join; - fTextAlign = kLeft_Align; - fStyle = kFill_Style; - fTextEncoding = kUTF8_TextEncoding; -} - -SkPaint::SkPaint(const SkPaint& src) -{ - memcpy(this, &src, sizeof(src)); - - fTypeface->safeRef(); - fPathEffect->safeRef(); - fShader->safeRef(); - fXfermode->safeRef(); - fMaskFilter->safeRef(); - fColorFilter->safeRef(); - fRasterizer->safeRef(); - fLooper->safeRef(); -} - -SkPaint::~SkPaint() -{ - fTypeface->safeUnref(); - fPathEffect->safeUnref(); - fShader->safeUnref(); - fXfermode->safeUnref(); - fMaskFilter->safeUnref(); - fColorFilter->safeUnref(); - fRasterizer->safeUnref(); - fLooper->safeUnref(); -} - -SkPaint& SkPaint::operator=(const SkPaint& src) -{ - SkASSERT(&src); - - src.fTypeface->safeRef(); - src.fPathEffect->safeRef(); - src.fShader->safeRef(); - src.fXfermode->safeRef(); - src.fMaskFilter->safeRef(); - src.fColorFilter->safeRef(); - src.fRasterizer->safeRef(); - src.fLooper->safeRef(); - - fTypeface->safeUnref(); - fPathEffect->safeUnref(); - fShader->safeUnref(); - fXfermode->safeUnref(); - fMaskFilter->safeUnref(); - fColorFilter->safeUnref(); - fRasterizer->safeUnref(); - fLooper->safeUnref(); - - memcpy(this, &src, sizeof(src)); - - return *this; -} - -int operator==(const SkPaint& a, const SkPaint& b) -{ - return memcmp(&a, &b, sizeof(a)) == 0; -} - -void SkPaint::reset() -{ - SkPaint init; - - *this = init; -} - -void SkPaint::setFlags(uint32_t flags) -{ - fFlags = flags; -} - -void SkPaint::setAntiAlias(bool doAA) -{ - this->setFlags(SkSetClearMask(fFlags, doAA, kAntiAlias_Flag)); -} - -void SkPaint::setDither(bool doDither) -{ - this->setFlags(SkSetClearMask(fFlags, doDither, kDither_Flag)); -} - -void SkPaint::setSubpixelText(bool doSubpixel) -{ - this->setFlags(SkSetClearMask(fFlags, doSubpixel, kSubpixelText_Flag)); -} - -void SkPaint::setLinearText(bool doLinearText) -{ - this->setFlags(SkSetClearMask(fFlags, doLinearText, kLinearText_Flag)); -} - -void SkPaint::setUnderlineText(bool doUnderline) -{ - this->setFlags(SkSetClearMask(fFlags, doUnderline, kUnderlineText_Flag)); -} - -void SkPaint::setStrikeThruText(bool doStrikeThru) -{ - this->setFlags(SkSetClearMask(fFlags, doStrikeThru, kStrikeThruText_Flag)); -} - -void SkPaint::setFakeBoldText(bool doFakeBold) -{ - this->setFlags(SkSetClearMask(fFlags, doFakeBold, kFakeBoldText_Flag)); -} - -void SkPaint::setDevKernText(bool doDevKern) -{ - this->setFlags(SkSetClearMask(fFlags, doDevKern, kDevKernText_Flag)); -} - -void SkPaint::setFilterBitmap(bool doFilter) -{ - this->setFlags(SkSetClearMask(fFlags, doFilter, kFilterBitmap_Flag)); -} - -void SkPaint::setStyle(Style style) -{ - if ((unsigned)style < kStyleCount) - fStyle = style; -#ifdef SK_DEBUG - else - SkDebugf("SkPaint::setStyle(%d) out of range\n", style); -#endif -} - -void SkPaint::setColor(SkColor color) -{ - fColor = color; -} - -void SkPaint::setAlpha(U8CPU a) -{ - fColor = SkColorSetARGB(a, SkColorGetR(fColor), SkColorGetG(fColor), SkColorGetB(fColor)); -} - -void SkPaint::setARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b) -{ - fColor = SkColorSetARGB(a, r, g, b); -} - -void SkPaint::setStrokeWidth(SkScalar width) -{ - if (width >= 0) - fWidth = width; -#ifdef SK_DEBUG - else - SkDebugf("SkPaint::setStrokeWidth() called with negative value\n"); -#endif -} - -void SkPaint::setStrokeMiter(SkScalar limit) -{ - if (limit >= 0) - fMiterLimit = limit; -#ifdef SK_DEBUG - else - SkDebugf("SkPaint::setStrokeMiter() called with negative value\n"); -#endif -} - -void SkPaint::setStrokeCap(Cap ct) -{ - if ((unsigned)ct < kCapCount) - fCapType = SkToU8(ct); -#ifdef SK_DEBUG - else - SkDebugf("SkPaint::setStrokeCap(%d) out of range\n", ct); -#endif -} - -void SkPaint::setStrokeJoin(Join jt) -{ - if ((unsigned)jt < kJoinCount) - fJoinType = SkToU8(jt); -#ifdef SK_DEBUG - else - SkDebugf("SkPaint::setStrokeJoin(%d) out of range\n", jt); -#endif -} - -////////////////////////////////////////////////////////////////// - -void SkPaint::setTextAlign(Align align) -{ - if ((unsigned)align < kAlignCount) - fTextAlign = SkToU8(align); -#ifdef SK_DEBUG - else - SkDebugf("SkPaint::setTextAlign(%d) out of range\n", align); -#endif -} - -void SkPaint::setTextSize(SkScalar ts) -{ - if (ts > 0) - fTextSize = ts; -#ifdef SK_DEBUG - else - SkDebugf("SkPaint::setTextSize() called with non-positive value\n"); -#endif -} - -void SkPaint::setTextScaleX(SkScalar scaleX) -{ - fTextScaleX = scaleX; -} - -void SkPaint::setTextSkewX(SkScalar skewX) -{ - fTextSkewX = skewX; -} - -void SkPaint::setTextEncoding(TextEncoding encoding) -{ - if ((unsigned)encoding <= kGlyphID_TextEncoding) - fTextEncoding = encoding; -#ifdef SK_DEBUG - else - SkDebugf("SkPaint::setTextEncoding(%d) out of range\n", encoding); -#endif -} - -/////////////////////////////////////////////////////////////////////////////////////// - -SkTypeface* SkPaint::setTypeface(SkTypeface* font) -{ - SkRefCnt_SafeAssign(fTypeface, font); - return font; -} - -SkRasterizer* SkPaint::setRasterizer(SkRasterizer* r) -{ - SkRefCnt_SafeAssign(fRasterizer, r); - return r; -} - -SkDrawLooper* SkPaint::setLooper(SkDrawLooper* looper) -{ - SkRefCnt_SafeAssign(fLooper, looper); - return looper; -} - -/////////////////////////////////////////////////////////////////////////////// - -#include "SkGlyphCache.h" -#include "SkUtils.h" - -int SkPaint::textToGlyphs(const void* textData, size_t byteLength, - uint16_t glyphs[]) const { - if (byteLength == 0) { - return 0; - } - - SkASSERT(textData != NULL); - - if (NULL == glyphs) { - switch (this->getTextEncoding()) { - case kUTF8_TextEncoding: - return SkUTF8_CountUnichars((const char*)textData, byteLength); - case kUTF16_TextEncoding: - return SkUTF16_CountUnichars((const uint16_t*)textData, - byteLength >> 1); - case kGlyphID_TextEncoding: - return byteLength >> 1; - default: - SkASSERT(!"unknown text encoding"); - } - return 0; - } - - // if we get here, we have a valid glyphs[] array, so time to fill it in - - // handle this encoding before the setup for the glyphcache - if (this->getTextEncoding() == kGlyphID_TextEncoding) { - // we want to ignore the low bit of byteLength - memcpy(glyphs, textData, byteLength >> 1 << 1); - return byteLength >> 1; - } - - SkAutoGlyphCache autoCache(*this, NULL); - SkGlyphCache* cache = autoCache.getCache(); - - const char* text = (const char*)textData; - const char* stop = text + byteLength; - uint16_t* gptr = glyphs; - - switch (this->getTextEncoding()) { - case SkPaint::kUTF8_TextEncoding: - while (text < stop) { - *gptr++ = cache->unicharToGlyph(SkUTF8_NextUnichar(&text)); - } - break; - case SkPaint::kUTF16_TextEncoding: { - const uint16_t* text16 = (const uint16_t*)text; - const uint16_t* stop16 = (const uint16_t*)stop; - while (text16 < stop16) { - *gptr++ = cache->unicharToGlyph(SkUTF16_NextUnichar(&text16)); - } - break; - } - default: - SkASSERT(!"unknown text encoding"); - } - return gptr - glyphs; -} - -/////////////////////////////////////////////////////////////////////////////// - -static uint32_t sk_glyphID_next(const char** text) -{ - const uint16_t* glyph = (const uint16_t*)text; - int32_t value = *glyph; - glyph += 1; - *text = (const char*)glyph; - return value; -} - -static uint32_t sk_glyphID_prev(const char** text) -{ - const uint16_t* glyph = (const uint16_t*)text; - glyph -= 1; - int32_t value = *glyph; - *text = (const char*)glyph; - return value; -} - -////////////////////////////////////////////////////////////////////////////// - -static const SkGlyph& sk_getMetrics_utf8_next(SkGlyphCache* cache, const char** text) -{ - SkASSERT(cache != NULL); - SkASSERT(text != NULL); - - return cache->getUnicharMetrics(SkUTF8_NextUnichar(text)); -} - -static const SkGlyph& sk_getMetrics_utf8_prev(SkGlyphCache* cache, const char** text) -{ - SkASSERT(cache != NULL); - SkASSERT(text != NULL); - - return cache->getUnicharMetrics(SkUTF8_PrevUnichar(text)); -} - -static const SkGlyph& sk_getMetrics_utf16_next(SkGlyphCache* cache, const char** text) -{ - SkASSERT(cache != NULL); - SkASSERT(text != NULL); - - return cache->getUnicharMetrics(SkUTF16_NextUnichar((const uint16_t**)text)); -} - -static const SkGlyph& sk_getMetrics_utf16_prev(SkGlyphCache* cache, const char** text) -{ - SkASSERT(cache != NULL); - SkASSERT(text != NULL); - - return cache->getUnicharMetrics(SkUTF16_PrevUnichar((const uint16_t**)text)); -} - -static const SkGlyph& sk_getMetrics_glyph_next(SkGlyphCache* cache, const char** text) -{ - SkASSERT(cache != NULL); - SkASSERT(text != NULL); - - const uint16_t* ptr = *(const uint16_t**)text; - unsigned glyphID = *ptr; - ptr += 1; - *text = (const char*)ptr; - return cache->getGlyphIDMetrics(glyphID); -} - -static const SkGlyph& sk_getMetrics_glyph_prev(SkGlyphCache* cache, const char** text) -{ - SkASSERT(cache != NULL); - SkASSERT(text != NULL); - - const uint16_t* ptr = *(const uint16_t**)text; - ptr -= 1; - unsigned glyphID = *ptr; - *text = (const char*)ptr; - return cache->getGlyphIDMetrics(glyphID); -} - -/// - -static const SkGlyph& sk_getAdvance_utf8_next(SkGlyphCache* cache, const char** text) -{ - SkASSERT(cache != NULL); - SkASSERT(text != NULL); - - return cache->getUnicharAdvance(SkUTF8_NextUnichar(text)); -} - -static const SkGlyph& sk_getAdvance_utf8_prev(SkGlyphCache* cache, const char** text) -{ - SkASSERT(cache != NULL); - SkASSERT(text != NULL); - - return cache->getUnicharAdvance(SkUTF8_PrevUnichar(text)); -} - -static const SkGlyph& sk_getAdvance_utf16_next(SkGlyphCache* cache, const char** text) -{ - SkASSERT(cache != NULL); - SkASSERT(text != NULL); - - return cache->getUnicharAdvance(SkUTF16_NextUnichar((const uint16_t**)text)); -} - -static const SkGlyph& sk_getAdvance_utf16_prev(SkGlyphCache* cache, const char** text) -{ - SkASSERT(cache != NULL); - SkASSERT(text != NULL); - - return cache->getUnicharAdvance(SkUTF16_PrevUnichar((const uint16_t**)text)); -} - -static const SkGlyph& sk_getAdvance_glyph_next(SkGlyphCache* cache, const char** text) -{ - SkASSERT(cache != NULL); - SkASSERT(text != NULL); - - const uint16_t* ptr = *(const uint16_t**)text; - unsigned glyphID = *ptr; - ptr += 1; - *text = (const char*)ptr; - return cache->getGlyphIDAdvance(glyphID); -} - -static const SkGlyph& sk_getAdvance_glyph_prev(SkGlyphCache* cache, const char** text) -{ - SkASSERT(cache != NULL); - SkASSERT(text != NULL); - - const uint16_t* ptr = *(const uint16_t**)text; - ptr -= 1; - unsigned glyphID = *ptr; - *text = (const char*)ptr; - return cache->getGlyphIDAdvance(glyphID); -} - -SkMeasureCacheProc SkPaint::getMeasureCacheProc(TextBufferDirection tbd, - bool needFullMetrics) const -{ - static const SkMeasureCacheProc gMeasureCacheProcs[] = { - sk_getMetrics_utf8_next, - sk_getMetrics_utf16_next, - sk_getMetrics_glyph_next, - - sk_getMetrics_utf8_prev, - sk_getMetrics_utf16_prev, - sk_getMetrics_glyph_prev, - - sk_getAdvance_utf8_next, - sk_getAdvance_utf16_next, - sk_getAdvance_glyph_next, - - sk_getAdvance_utf8_prev, - sk_getAdvance_utf16_prev, - sk_getAdvance_glyph_prev - }; - - unsigned index = this->getTextEncoding(); - - if (kBackward_TextBufferDirection == tbd) - index += 3; - if (!needFullMetrics && !this->isDevKernText()) - index += 6; - - SkASSERT(index < SK_ARRAY_COUNT(gMeasureCacheProcs)); - return gMeasureCacheProcs[index]; -} - -/////////////////////////////////////////////////////////////////////////////// - -static const SkGlyph& sk_getMetrics_utf8_00(SkGlyphCache* cache, - const char** text, SkFixed, SkFixed) -{ - SkASSERT(cache != NULL); - SkASSERT(text != NULL); - - return cache->getUnicharMetrics(SkUTF8_NextUnichar(text)); -} - -static const SkGlyph& sk_getMetrics_utf8_xy(SkGlyphCache* cache, - const char** text, SkFixed x, SkFixed y) -{ - SkASSERT(cache != NULL); - SkASSERT(text != NULL); - - return cache->getUnicharMetrics(SkUTF8_NextUnichar(text), x, y); -} - -static const SkGlyph& sk_getMetrics_utf16_00(SkGlyphCache* cache, const char** text, - SkFixed, SkFixed) -{ - SkASSERT(cache != NULL); - SkASSERT(text != NULL); - - return cache->getUnicharMetrics(SkUTF16_NextUnichar((const uint16_t**)text)); -} - -static const SkGlyph& sk_getMetrics_utf16_xy(SkGlyphCache* cache, - const char** text, SkFixed x, SkFixed y) -{ - SkASSERT(cache != NULL); - SkASSERT(text != NULL); - - return cache->getUnicharMetrics(SkUTF16_NextUnichar((const uint16_t**)text), - x, y); -} - -static const SkGlyph& sk_getMetrics_glyph_00(SkGlyphCache* cache, const char** text, - SkFixed, SkFixed) -{ - SkASSERT(cache != NULL); - SkASSERT(text != NULL); - - const uint16_t* ptr = *(const uint16_t**)text; - unsigned glyphID = *ptr; - ptr += 1; - *text = (const char*)ptr; - return cache->getGlyphIDMetrics(glyphID); -} - -static const SkGlyph& sk_getMetrics_glyph_xy(SkGlyphCache* cache, - const char** text, SkFixed x, SkFixed y) -{ - SkASSERT(cache != NULL); - SkASSERT(text != NULL); - - const uint16_t* ptr = *(const uint16_t**)text; - unsigned glyphID = *ptr; - ptr += 1; - *text = (const char*)ptr; - return cache->getGlyphIDMetrics(glyphID, x, y); -} - -SkDrawCacheProc SkPaint::getDrawCacheProc() const -{ - static const SkDrawCacheProc gDrawCacheProcs[] = { - sk_getMetrics_utf8_00, - sk_getMetrics_utf16_00, - sk_getMetrics_glyph_00, - - sk_getMetrics_utf8_xy, - sk_getMetrics_utf16_xy, - sk_getMetrics_glyph_xy - }; - - unsigned index = this->getTextEncoding(); - if (fFlags & kSubpixelText_Flag) - index += 3; - - SkASSERT(index < SK_ARRAY_COUNT(gDrawCacheProcs)); - return gDrawCacheProcs[index]; -} - -/////////////////////////////////////////////////////////////////////////////// - -class SkAutoRestorePaintTextSizeAndFrame { -public: - SkAutoRestorePaintTextSizeAndFrame(const SkPaint* paint) : fPaint((SkPaint*)paint) - { - fTextSize = paint->getTextSize(); - fStyle = paint->getStyle(); - fPaint->setStyle(SkPaint::kFill_Style); - } - ~SkAutoRestorePaintTextSizeAndFrame() - { - fPaint->setStyle(fStyle); - fPaint->setTextSize(fTextSize); - } - -private: - SkPaint* fPaint; - SkScalar fTextSize; - SkPaint::Style fStyle; -}; - -static void set_bounds(const SkGlyph& g, SkRect* bounds) -{ - bounds->set(SkIntToScalar(g.fLeft), - SkIntToScalar(g.fTop), - SkIntToScalar(g.fLeft + g.fWidth), - SkIntToScalar(g.fTop + g.fHeight)); -} - -static void join_bounds(const SkGlyph& g, SkRect* bounds, SkFixed dx) -{ - SkScalar sx = SkFixedToScalar(dx); - bounds->join(SkIntToScalar(g.fLeft) + sx, - SkIntToScalar(g.fTop), - SkIntToScalar(g.fLeft + g.fWidth) + sx, - SkIntToScalar(g.fTop + g.fHeight)); -} - -SkScalar SkPaint::measure_text(SkGlyphCache* cache, - const char* text, size_t byteLength, - int* count, SkRect* bounds) const -{ - SkASSERT(count); - if (byteLength == 0) - { - *count = 0; - if (bounds) - bounds->setEmpty(); - return 0; - } - - SkMeasureCacheProc glyphCacheProc; - glyphCacheProc = this->getMeasureCacheProc(kForward_TextBufferDirection, - NULL != bounds); - - int n = 1; - const char* stop = (const char*)text + byteLength; - const SkGlyph* g = &glyphCacheProc(cache, &text); - SkFixed x = g->fAdvanceX; - - SkAutoKern autokern; - - if (NULL == bounds) - { - if (this->isDevKernText()) - { - int rsb; - for (; text < stop; n++) { - rsb = g->fRsbDelta; - g = &glyphCacheProc(cache, &text); - x += SkAutoKern_AdjustF(rsb, g->fLsbDelta) + g->fAdvanceX; - } - } - else - { - for (; text < stop; n++) { - x += glyphCacheProc(cache, &text).fAdvanceX; - } - } - } - else - { - set_bounds(*g, bounds); - if (this->isDevKernText()) - { - int rsb; - for (; text < stop; n++) { - rsb = g->fRsbDelta; - g = &glyphCacheProc(cache, &text); - x += SkAutoKern_AdjustF(rsb, g->fLsbDelta); - join_bounds(*g, bounds, x); - x += g->fAdvanceX; - } - } - else - { - for (; text < stop; n++) { - g = &glyphCacheProc(cache, &text); - join_bounds(*g, bounds, x); - x += g->fAdvanceX; - } - } - } - SkASSERT(text == stop); - - *count = n; - return SkFixedToScalar(x); -} - -SkScalar SkPaint::measureText(const void* textData, size_t length, - SkRect* bounds, SkScalar zoom) const -{ - const char* text = (const char*)textData; - SkASSERT(text != NULL || length == 0); - - SkScalar scale = 0; - SkAutoRestorePaintTextSizeAndFrame restore(this); - - if (this->isLinearText()) - { - scale = fTextSize / kCanonicalTextSizeForPaths; - // this gets restored by restore - ((SkPaint*)this)->setTextSize(SkIntToScalar(kCanonicalTextSizeForPaths)); - } - - SkMatrix zoomMatrix, *zoomPtr = NULL; - if (zoom) - { - zoomMatrix.setScale(zoom, zoom); - zoomPtr = &zoomMatrix; - } - - SkAutoGlyphCache autoCache(*this, zoomPtr); - SkGlyphCache* cache = autoCache.getCache(); - - SkScalar width = 0; - - if (length > 0) - { - int tempCount; - - width = this->measure_text(cache, text, length, &tempCount, bounds); - if (scale) - { - width = SkScalarMul(width, scale); - if (bounds) - { - bounds->fLeft = SkScalarMul(bounds->fLeft, scale); - bounds->fTop = SkScalarMul(bounds->fTop, scale); - bounds->fRight = SkScalarMul(bounds->fRight, scale); - bounds->fBottom = SkScalarMul(bounds->fBottom, scale); - } - } - } - return width; -} - -typedef bool (*SkTextBufferPred)(const char* text, const char* stop); - -static bool forward_textBufferPred(const char* text, const char* stop) -{ - return text < stop; -} - -static bool backward_textBufferPred(const char* text, const char* stop) -{ - return text > stop; -} - -static SkTextBufferPred chooseTextBufferPred(SkPaint::TextBufferDirection tbd, - const char** text, size_t length, const char** stop) -{ - if (SkPaint::kForward_TextBufferDirection == tbd) - { - *stop = *text + length; - return forward_textBufferPred; - } - else - { - // text should point to the end of the buffer, and stop to the beginning - *stop = *text; - *text += length; - return backward_textBufferPred; - } -} - -size_t SkPaint::breakText(const void* textD, size_t length, SkScalar maxWidth, - SkScalar* measuredWidth, - TextBufferDirection tbd) const -{ - if (0 == length || 0 >= maxWidth) - { - if (measuredWidth) - *measuredWidth = 0; - return 0; - } - - SkASSERT(textD != NULL); - const char* text = (const char*)textD; - - SkScalar scale = 0; - SkAutoRestorePaintTextSizeAndFrame restore(this); - - if (this->isLinearText()) - { - scale = fTextSize / kCanonicalTextSizeForPaths; - // this gets restored by restore - ((SkPaint*)this)->setTextSize(SkIntToScalar(kCanonicalTextSizeForPaths)); - } - - SkAutoGlyphCache autoCache(*this, NULL); - SkGlyphCache* cache = autoCache.getCache(); - - SkMeasureCacheProc glyphCacheProc = this->getMeasureCacheProc(tbd, false); - const char* stop; - SkTextBufferPred pred = chooseTextBufferPred(tbd, &text, length, &stop); - SkFixed max = SkScalarToFixed(maxWidth); - SkFixed width = 0; - - SkAutoKern autokern; - - if (this->isDevKernText()) - { - int rsb = 0; - while (pred(text, stop)) - { - const char* curr = text; - const SkGlyph& g = glyphCacheProc(cache, &text); - SkFixed x = SkAutoKern_AdjustF(rsb, g.fLsbDelta) + g.fAdvanceX; - if ((width += x) > max) - { - width -= x; - text = curr; - break; - } - rsb = g.fRsbDelta; - } - } - else - { - while (pred(text, stop)) - { - const char* curr = text; - SkFixed x = glyphCacheProc(cache, &text).fAdvanceX; - if ((width += x) > max) - { - width -= x; - text = curr; - break; - } - } - } - - if (measuredWidth) - { - - SkScalar scalarWidth = SkFixedToScalar(width); - if (scale) - scalarWidth = SkScalarMul(scalarWidth, scale); - *measuredWidth = scalarWidth; - } - - // return the number of bytes measured - return (kForward_TextBufferDirection == tbd) ? - text - stop + length : stop - text + length; -} - -/////////////////////////////////////////////////////////////////////////////// - -static bool FontMetricsCacheProc(const SkGlyphCache* cache, void* context) -{ - *(SkPaint::FontMetrics*)context = cache->getFontMetricsY(); - return false; // don't detach the cache -} - -static void FontMetricsDescProc(const SkDescriptor* desc, void* context) -{ - SkGlyphCache::VisitCache(desc, FontMetricsCacheProc, context); -} - -SkScalar SkPaint::getFontMetrics(FontMetrics* metrics, SkScalar zoom) const -{ - SkScalar scale = 0; - SkAutoRestorePaintTextSizeAndFrame restore(this); - - if (this->isLinearText()) - { - scale = fTextSize / kCanonicalTextSizeForPaths; - // this gets restored by restore - ((SkPaint*)this)->setTextSize(SkIntToScalar(kCanonicalTextSizeForPaths)); - } - - SkMatrix zoomMatrix, *zoomPtr = NULL; - if (zoom) - { - zoomMatrix.setScale(zoom, zoom); - zoomPtr = &zoomMatrix; - } - -#if 0 - SkAutoGlyphCache autoCache(*this, zoomPtr); - SkGlyphCache* cache = autoCache.getCache(); - const FontMetrics& my = cache->getFontMetricsY(); -#endif - FontMetrics storage; - if (NULL == metrics) - metrics = &storage; - - this->descriptorProc(zoomPtr, FontMetricsDescProc, metrics); - - if (scale) - { - metrics->fTop = SkScalarMul(metrics->fTop, scale); - metrics->fAscent = SkScalarMul(metrics->fAscent, scale); - metrics->fDescent = SkScalarMul(metrics->fDescent, scale); - metrics->fBottom = SkScalarMul(metrics->fBottom, scale); - metrics->fLeading = SkScalarMul(metrics->fLeading, scale); - } - return metrics->fDescent - metrics->fAscent + metrics->fLeading; -} - -//////////////////////////////////////////////////////////////////////////////////////////// - -static void set_bounds(const SkGlyph& g, SkRect* bounds, SkScalar scale) -{ - bounds->set(g.fLeft * scale, - g.fTop * scale, - (g.fLeft + g.fWidth) * scale, - (g.fTop + g.fHeight) * scale); -} - -int SkPaint::getTextWidths(const void* textData, size_t byteLength, SkScalar widths[], - SkRect bounds[]) const -{ - if (0 == byteLength) - return 0; - - SkASSERT(NULL != textData); - - if (NULL == widths && NULL == bounds) - return this->countText(textData, byteLength); - - SkAutoRestorePaintTextSizeAndFrame restore(this); - SkScalar scale = 0; - - if (this->isLinearText()) - { - scale = fTextSize / kCanonicalTextSizeForPaths; - // this gets restored by restore - ((SkPaint*)this)->setTextSize(SkIntToScalar(kCanonicalTextSizeForPaths)); - } - - SkAutoGlyphCache autoCache(*this, NULL); - SkGlyphCache* cache = autoCache.getCache(); - SkMeasureCacheProc glyphCacheProc; - glyphCacheProc = this->getMeasureCacheProc(kForward_TextBufferDirection, - NULL != bounds); - - const char* text = (const char*)textData; - const char* stop = text + byteLength; - int count = 0; - - if (this->isDevKernText()) - { - // we adjust the widths returned here through auto-kerning - SkAutoKern autokern; - SkFixed prevWidth = 0; - - if (scale) { - while (text < stop) { - const SkGlyph& g = glyphCacheProc(cache, &text); - if (widths) { - SkFixed adjust = autokern.adjust(g); - - if (count > 0) { - SkScalar w = SkFixedToScalar(prevWidth + adjust); - *widths++ = SkScalarMul(w, scale); - } - prevWidth = g.fAdvanceX; - } - if (bounds) { - set_bounds(g, bounds++, scale); - } - ++count; - } - if (count > 0 && widths) { - *widths = SkScalarMul(SkFixedToScalar(prevWidth), scale); - } - } else { - while (text < stop) { - const SkGlyph& g = glyphCacheProc(cache, &text); - if (widths) { - SkFixed adjust = autokern.adjust(g); - - if (count > 0) { - *widths++ = SkFixedToScalar(prevWidth + adjust); - } - prevWidth = g.fAdvanceX; - } - if (bounds) { - set_bounds(g, bounds++); - } - ++count; - } - if (count > 0 && widths) { - *widths = SkFixedToScalar(prevWidth); - } - } - } else { // no devkern - if (scale) { - while (text < stop) { - const SkGlyph& g = glyphCacheProc(cache, &text); - if (widths) { - *widths++ = SkScalarMul(SkFixedToScalar(g.fAdvanceX), - scale); - } - if (bounds) { - set_bounds(g, bounds++, scale); - } - ++count; - } - } else { - while (text < stop) { - const SkGlyph& g = glyphCacheProc(cache, &text); - if (widths) { - *widths++ = SkFixedToScalar(g.fAdvanceX); - } - if (bounds) { - set_bounds(g, bounds++); - } - ++count; - } - } - } - - SkASSERT(text == stop); - return count; -} - -//////////////////////////////////////////////////////////////////////////////////////////// - -#include "SkDraw.h" - -void SkPaint::getTextPath(const void* textData, size_t length, SkScalar x, SkScalar y, SkPath* path) const -{ - const char* text = (const char*)textData; - SkASSERT(length == 0 || text != NULL); - if (text == NULL || length == 0 || path == NULL) - return; - - SkTextToPathIter iter(text, length, *this, false, true); - SkMatrix matrix; - SkScalar prevXPos = 0; - - matrix.setScale(iter.getPathScale(), iter.getPathScale()); - matrix.postTranslate(x, y); - path->reset(); - - SkScalar xpos; - const SkPath* iterPath; - while ((iterPath = iter.next(&xpos)) != NULL) - { - matrix.postTranslate(xpos - prevXPos, 0); - path->addPath(*iterPath, matrix); - prevXPos = xpos; - } -} - -static void add_flattenable(SkDescriptor* desc, uint32_t tag, - SkFlattenableWriteBuffer* buffer) { - buffer->flatten(desc->addEntry(tag, buffer->size(), NULL)); -} - -/* - * interpolates to find the right value for key, in the function represented by the 'length' number of pairs: (keys[i], values[i]) - inspired by a desire to change the multiplier for thickness in fakebold - therefore, i assumed number of pairs (length) will be small, so a linear search is sufficient - repeated keys are allowed for discontinuous functions (so long as keys is monotonically increasing), and if - key is the value of a repeated scalar in keys, the first one will be used - - this may change if a binary search is used - - also, this ensures that there is no divide by zero (an assert also checks for that) -*/ -static SkScalar interpolate(SkScalar key, const SkScalar keys[], const SkScalar values[], int length) -{ - - SkASSERT(length > 0); - SkASSERT(keys != NULL); - SkASSERT(values != NULL); -#ifdef SK_DEBUG - for (int i = 1; i < length; i++) - SkASSERT(keys[i] >= keys[i-1]); -#endif - int right = 0; - while (right < length && key > keys[right]) - right++; - //could use sentinal values to eliminate conditionals - //i assume i am not in control of input values, so i want to make it simple - if (length == right) - return values[length-1]; - if (0 == right) - return values[0]; - //otherwise, we interpolate between right-1 and right - SkScalar rVal = values[right]; - SkScalar lVal = values[right-1]; - SkScalar rightKey = keys[right]; - SkScalar leftKey = keys[right-1]; - SkASSERT(rightKey != leftKey); - //fractional amount which we will multiply by the difference in the left value and right value - SkScalar fract = SkScalarDiv(key-leftKey,rightKey-leftKey); - return lVal + SkScalarMul(fract, rVal-lVal); -} - -//used for interpolating in fakeBold -static const SkScalar pointSizes[] = { SkIntToScalar(9), SkIntToScalar(36) }; -static const SkScalar multipliers[] = { SK_Scalar1/24, SK_Scalar1/32 }; - -static SkMask::Format computeMaskFormat(const SkPaint& paint) -{ - uint32_t flags = paint.getFlags(); - - return (flags & SkPaint::kAntiAlias_Flag) ? SkMask::kA8_Format : SkMask::kBW_Format; -} - -static SkScalerContext::Hints computeScalerHints(const SkPaint& paint) -{ - uint32_t flags = paint.getFlags(); - - if (flags & SkPaint::kLinearText_Flag) - return SkScalerContext::kNo_Hints; - else if (flags & SkPaint::kSubpixelText_Flag) - return SkScalerContext::kSubpixel_Hints; - else - return SkScalerContext::kNormal_Hints; -} - -void SkScalerContext::MakeRec(const SkPaint& paint, const SkMatrix* deviceMatrix, Rec* rec) -{ - SkASSERT(deviceMatrix == NULL || (deviceMatrix->getType() & SkMatrix::kPerspective_Mask) == 0); - - rec->fFontID = SkTypeface::UniqueID(paint.getTypeface()); - rec->fTextSize = paint.getTextSize(); - rec->fPreScaleX = paint.getTextScaleX(); - rec->fPreSkewX = paint.getTextSkewX(); - - if (deviceMatrix) - { - rec->fPost2x2[0][0] = deviceMatrix->getScaleX(); - rec->fPost2x2[0][1] = deviceMatrix->getSkewX(); - rec->fPost2x2[1][0] = deviceMatrix->getSkewY(); - rec->fPost2x2[1][1] = deviceMatrix->getScaleY(); - } - else - { - rec->fPost2x2[0][0] = rec->fPost2x2[1][1] = SK_Scalar1; - rec->fPost2x2[0][1] = rec->fPost2x2[1][0] = 0; - } - - SkPaint::Style style = paint.getStyle(); - SkScalar strokeWidth = paint.getStrokeWidth(); - - if (paint.isFakeBoldText()) - { - SkScalar fakeBoldScale = interpolate(paint.getTextSize(), pointSizes, multipliers, 2); - SkScalar extra = SkScalarMul(paint.getTextSize(), fakeBoldScale); - - if (style == SkPaint::kFill_Style) - { - style = SkPaint::kStrokeAndFill_Style; - strokeWidth = extra; // ignore paint's strokeWidth if it was "fill" - } - else - strokeWidth += extra; - } - - unsigned flags = SkFontHost::ComputeGammaFlag(paint); - - if (paint.isDevKernText()) - flags |= SkScalerContext::kDevKernText_Flag; - - if (style != SkPaint::kFill_Style && strokeWidth > 0) - { - rec->fFrameWidth = strokeWidth; - rec->fMiterLimit = paint.getStrokeMiter(); - rec->fStrokeJoin = SkToU8(paint.getStrokeJoin()); - - if (style == SkPaint::kStrokeAndFill_Style) - flags |= SkScalerContext::kFrameAndFill_Flag; - } - else - { - rec->fFrameWidth = 0; - rec->fMiterLimit = 0; - rec->fStrokeJoin = 0; - } - - rec->fHints = SkToU8(computeScalerHints(paint)); - rec->fMaskFormat = SkToU8(computeMaskFormat(paint)); - rec->fFlags = SkToU8(flags); -} - -#define MIN_SIZE_FOR_EFFECT_BUFFER 1024 - -void SkPaint::descriptorProc(const SkMatrix* deviceMatrix, - void (*proc)(const SkDescriptor*, void*), - void* context) const -{ - SkScalerContext::Rec rec; - - SkScalerContext::MakeRec(*this, deviceMatrix, &rec); - - size_t descSize = sizeof(rec); - int entryCount = 1; - SkPathEffect* pe = this->getPathEffect(); - SkMaskFilter* mf = this->getMaskFilter(); - SkRasterizer* ra = this->getRasterizer(); - - SkFlattenableWriteBuffer peBuffer(MIN_SIZE_FOR_EFFECT_BUFFER); - SkFlattenableWriteBuffer mfBuffer(MIN_SIZE_FOR_EFFECT_BUFFER); - SkFlattenableWriteBuffer raBuffer(MIN_SIZE_FOR_EFFECT_BUFFER); - - if (pe) { - peBuffer.writeFlattenable(pe); - descSize += peBuffer.size(); - entryCount += 1; - rec.fMaskFormat = SkMask::kA8_Format; // force antialiasing when we do the scan conversion - // seems like we could support kLCD as well at this point... - } - if (mf) { - mfBuffer.writeFlattenable(mf); - descSize += mfBuffer.size(); - entryCount += 1; - rec.fMaskFormat = SkMask::kA8_Format; // force antialiasing with maskfilters - } - if (ra) { - raBuffer.writeFlattenable(ra); - descSize += raBuffer.size(); - entryCount += 1; - rec.fMaskFormat = SkMask::kA8_Format; // force antialiasing when we do the scan conversion - } - descSize += SkDescriptor::ComputeOverhead(entryCount); - - SkAutoDescriptor ad(descSize); - SkDescriptor* desc = ad.getDesc(); - - desc->init(); - desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec); - - if (pe) { - add_flattenable(desc, kPathEffect_SkDescriptorTag, &peBuffer); - } - if (mf) { - add_flattenable(desc, kMaskFilter_SkDescriptorTag, &mfBuffer); - } - if (ra) { - add_flattenable(desc, kRasterizer_SkDescriptorTag, &raBuffer); - } - - SkASSERT(descSize == desc->getLength()); - desc->computeChecksum(); - - proc(desc, context); -} - -static void DetachDescProc(const SkDescriptor* desc, void* context) -{ - *((SkGlyphCache**)context) = SkGlyphCache::DetachCache(desc); -} - -SkGlyphCache* SkPaint::detachCache(const SkMatrix* deviceMatrix) const -{ - SkGlyphCache* cache; - this->descriptorProc(deviceMatrix, DetachDescProc, &cache); - return cache; -} - -/////////////////////////////////////////////////////////////////////////////// - -#include "SkStream.h" - -void SkPaint::flatten(SkFlattenableWriteBuffer& buffer) const { - buffer.writeTypeface(this->getTypeface()); - buffer.writeScalar(this->getTextSize()); - buffer.writeScalar(this->getTextScaleX()); - buffer.writeScalar(this->getTextSkewX()); - buffer.writeFlattenable(this->getPathEffect()); - buffer.writeFlattenable(this->getShader()); - buffer.writeFlattenable(this->getXfermode()); - buffer.writeFlattenable(this->getMaskFilter()); - buffer.writeFlattenable(this->getColorFilter()); - buffer.writeFlattenable(this->getRasterizer()); - buffer.writeFlattenable(this->getLooper()); - buffer.write32(this->getColor()); - buffer.writeScalar(this->getStrokeWidth()); - buffer.writeScalar(this->getStrokeMiter()); - buffer.write16(this->getFlags()); - buffer.write8(this->getTextAlign()); - buffer.write8(this->getStrokeCap()); - buffer.write8(this->getStrokeJoin()); - buffer.write8(this->getStyle()); - buffer.write8(this->getTextEncoding()); -} - -void SkPaint::unflatten(SkFlattenableReadBuffer& buffer) { - this->setTypeface(buffer.readTypeface()); - this->setTextSize(buffer.readScalar()); - this->setTextScaleX(buffer.readScalar()); - this->setTextSkewX(buffer.readScalar()); - this->setPathEffect((SkPathEffect*) buffer.readFlattenable())->safeUnref(); - this->setShader((SkShader*) buffer.readFlattenable())->safeUnref(); - this->setXfermode((SkXfermode*) buffer.readFlattenable())->safeUnref(); - this->setMaskFilter((SkMaskFilter*) buffer.readFlattenable())->safeUnref(); - this->setColorFilter((SkColorFilter*) buffer.readFlattenable())->safeUnref(); - this->setRasterizer((SkRasterizer*) buffer.readFlattenable())->safeUnref(); - this->setLooper((SkDrawLooper*) buffer.readFlattenable())->safeUnref(); - this->setColor(buffer.readU32()); - this->setStrokeWidth(buffer.readScalar()); - this->setStrokeMiter(buffer.readScalar()); - this->setFlags(buffer.readU16()); - this->setTextAlign((SkPaint::Align) buffer.readU8()); - this->setStrokeCap((SkPaint::Cap) buffer.readU8()); - this->setStrokeJoin((SkPaint::Join) buffer.readU8()); - this->setStyle((SkPaint::Style) buffer.readU8()); - this->setTextEncoding((SkPaint::TextEncoding) buffer.readU8()); -} - -/////////////////////////////////////////////////////////////////////////////// - -SkShader* SkPaint::setShader(SkShader* shader) -{ - SkRefCnt_SafeAssign(fShader, shader); - return shader; -} - -SkColorFilter* SkPaint::setColorFilter(SkColorFilter* filter) -{ - SkRefCnt_SafeAssign(fColorFilter, filter); - return filter; -} - -SkXfermode* SkPaint::setXfermode(SkXfermode* mode) -{ - SkRefCnt_SafeAssign(fXfermode, mode); - return mode; -} - -SkXfermode* SkPaint::setPorterDuffXfermode(SkPorterDuff::Mode mode) -{ - fXfermode->safeUnref(); - fXfermode = SkPorterDuff::CreateXfermode(mode); - return fXfermode; -} - -SkPathEffect* SkPaint::setPathEffect(SkPathEffect* effect) -{ - SkRefCnt_SafeAssign(fPathEffect, effect); - return effect; -} - -SkMaskFilter* SkPaint::setMaskFilter(SkMaskFilter* filter) -{ - SkRefCnt_SafeAssign(fMaskFilter, filter); - return filter; -} - -//////////////////////////////////////////////////////////////////////////////////////// - -bool SkPaint::getFillPath(const SkPath& src, SkPath* dst) const -{ - SkPath effectPath, strokePath; - const SkPath* path = &src; - - SkScalar width = this->getStrokeWidth(); - - switch (this->getStyle()) { - case SkPaint::kFill_Style: - width = -1; // mark it as no-stroke - break; - case SkPaint::kStrokeAndFill_Style: - if (width == 0) - width = -1; // mark it as no-stroke - break; - case SkPaint::kStroke_Style: - break; - default: - SkASSERT(!"unknown paint style"); - } - - if (this->getPathEffect()) - { - // lie to the pathEffect if our style is strokeandfill, so that it treats us as just fill - if (this->getStyle() == SkPaint::kStrokeAndFill_Style) - width = -1; // mark it as no-stroke - - if (this->getPathEffect()->filterPath(&effectPath, src, &width)) - path = &effectPath; - - // restore the width if we earlier had to lie, and if we're still set to no-stroke - // note: if we're now stroke (width >= 0), then the pathEffect asked for that change - // and we want to respect that (i.e. don't overwrite their setting for width) - if (this->getStyle() == SkPaint::kStrokeAndFill_Style && width < 0) - { - width = this->getStrokeWidth(); - if (width == 0) - width = -1; - } - } - - if (width > 0 && !path->isEmpty()) - { - SkStroke stroker(*this, width); - stroker.strokePath(*path, &strokePath); - path = &strokePath; - } - - if (path == &src) - *dst = src; - else - { - SkASSERT(path == &effectPath || path == &strokePath); - dst->swap(*(SkPath*)path); - } - - return width != 0; // return true if we're filled, or false if we're hairline (width == 0) -} - -bool SkPaint::canComputeFastBounds() const { - // use bit-or since no need for early exit - return (reinterpret_cast<uintptr_t>(this->getMaskFilter()) | - reinterpret_cast<uintptr_t>(this->getLooper()) | - reinterpret_cast<uintptr_t>(this->getRasterizer()) | - reinterpret_cast<uintptr_t>(this->getPathEffect())) == 0; -} - -const SkRect& SkPaint::computeFastBounds(const SkRect& src, - SkRect* storage) const { - SkASSERT(storage); - - if (this->getStyle() != SkPaint::kFill_Style) { - // if we're stroked, outset the rect by the radius (and join type) - SkScalar radius = SkScalarHalf(this->getStrokeWidth()); - - if (0 == radius) { // hairline - radius = SK_Scalar1; - } else if (this->getStrokeJoin() == SkPaint::kMiter_Join) { - SkScalar scale = this->getStrokeMiter(); - if (scale > SK_Scalar1) { - radius = SkScalarMul(radius, scale); - } - } - storage->set(src.fLeft - radius, src.fTop - radius, - src.fRight + radius, src.fBottom + radius); - return *storage; - } - // no adjustments needed, just return the original rect - return src; -} - -//////////////////////////////////////////////////////////////////////////////////////// - -static bool has_thick_frame(const SkPaint& paint) -{ - return paint.getStrokeWidth() > 0 && paint.getStyle() != SkPaint::kFill_Style; -} - -SkTextToPathIter::SkTextToPathIter( const char text[], size_t length, - const SkPaint& paint, - bool applyStrokeAndPathEffects, - bool forceLinearTextOn) - : fPaint(paint) /* make a copy of the paint */ -{ - fGlyphCacheProc = paint.getMeasureCacheProc(SkPaint::kForward_TextBufferDirection, - true); - - if (forceLinearTextOn) - fPaint.setLinearText(true); - fPaint.setMaskFilter(NULL); // don't want this affecting our path-cache lookup - - if (fPaint.getPathEffect() == NULL && !has_thick_frame(fPaint)) - applyStrokeAndPathEffects = false; - - // can't use our canonical size if we need to apply patheffects/strokes - if (fPaint.isLinearText() && !applyStrokeAndPathEffects) - { - fPaint.setTextSize(SkIntToScalar(SkPaint::kCanonicalTextSizeForPaths)); - fScale = paint.getTextSize() / SkPaint::kCanonicalTextSizeForPaths; - } - else - fScale = SK_Scalar1; - - if (!applyStrokeAndPathEffects) - { - fPaint.setStyle(SkPaint::kFill_Style); - fPaint.setPathEffect(NULL); - } - - fCache = fPaint.detachCache(NULL); - - SkPaint::Style style = SkPaint::kFill_Style; - SkPathEffect* pe = NULL; - - if (!applyStrokeAndPathEffects) - { - style = paint.getStyle(); // restore - pe = paint.getPathEffect(); // restore - } - fPaint.setStyle(style); - fPaint.setPathEffect(pe); - fPaint.setMaskFilter(paint.getMaskFilter()); // restore - - // now compute fXOffset if needed - - SkScalar xOffset = 0; - if (paint.getTextAlign() != SkPaint::kLeft_Align) // need to measure first - { - int count; - SkScalar width = SkScalarMul(fPaint.measure_text(fCache, text, length, &count, NULL), fScale); - if (paint.getTextAlign() == SkPaint::kCenter_Align) - width = SkScalarHalf(width); - xOffset = -width; - } - fXPos = xOffset; - fPrevAdvance = 0; - - fText = text; - fStop = text + length; -} - -SkTextToPathIter::~SkTextToPathIter() -{ - SkGlyphCache::AttachCache(fCache); -} - -const SkPath* SkTextToPathIter::next(SkScalar* xpos) -{ - while (fText < fStop) - { - const SkGlyph& glyph = fGlyphCacheProc(fCache, &fText); - - fXPos += SkScalarMul(SkFixedToScalar(fPrevAdvance + fAutoKern.adjust(glyph)), fScale); - fPrevAdvance = glyph.fAdvanceX; // + fPaint.getTextTracking(); - - if (glyph.fWidth) - { - if (xpos) - *xpos = fXPos; - return fCache->findPath(glyph); - } - } - return NULL; -} |