diff options
Diffstat (limited to 'gpu/SkGrFontScaler.cpp')
-rw-r--r-- | gpu/SkGrFontScaler.cpp | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/gpu/SkGrFontScaler.cpp b/gpu/SkGrFontScaler.cpp new file mode 100644 index 00000000..35be3d04 --- /dev/null +++ b/gpu/SkGrFontScaler.cpp @@ -0,0 +1,201 @@ + +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#include "GrTemplates.h" +#include "SkGr.h" +#include "SkDescriptor.h" +#include "SkGlyphCache.h" + +class SkGrDescKey : public GrKey { +public: + explicit SkGrDescKey(const SkDescriptor& desc); + virtual ~SkGrDescKey(); + +protected: + // overrides + virtual bool lt(const GrKey& rh) const; + virtual bool eq(const GrKey& rh) const; + +private: + SkDescriptor* fDesc; + enum { + kMaxStorageInts = 16 + }; + uint32_t fStorage[kMaxStorageInts]; +}; + +/////////////////////////////////////////////////////////////////////////////// + +SkGrDescKey::SkGrDescKey(const SkDescriptor& desc) : GrKey(desc.getChecksum()) { + size_t size = desc.getLength(); + if (size <= sizeof(fStorage)) { + fDesc = GrTCast<SkDescriptor*>(fStorage); + } else { + fDesc = SkDescriptor::Alloc(size); + } + memcpy(fDesc, &desc, size); +} + +SkGrDescKey::~SkGrDescKey() { + if (fDesc != GrTCast<SkDescriptor*>(fStorage)) { + SkDescriptor::Free(fDesc); + } +} + +bool SkGrDescKey::lt(const GrKey& rh) const { + const SkDescriptor* srcDesc = ((const SkGrDescKey*)&rh)->fDesc; + size_t lenLH = fDesc->getLength(); + size_t lenRH = srcDesc->getLength(); + int cmp = memcmp(fDesc, srcDesc, SkMin32(lenLH, lenRH)); + if (0 == cmp) { + return lenLH < lenRH; + } else { + return cmp < 0; + } +} + +bool SkGrDescKey::eq(const GrKey& rh) const { + const SkDescriptor* srcDesc = ((const SkGrDescKey*)&rh)->fDesc; + return fDesc->equals(*srcDesc); +} + +/////////////////////////////////////////////////////////////////////////////// + +SkGrFontScaler::SkGrFontScaler(SkGlyphCache* strike) { + fStrike = strike; + fKey = NULL; +} + +SkGrFontScaler::~SkGrFontScaler() { + GrSafeUnref(fKey); +} + +GrMaskFormat SkGrFontScaler::getMaskFormat() { + SkMask::Format format = fStrike->getMaskFormat(); + switch (format) { + case SkMask::kBW_Format: + // fall through to kA8 -- we store BW glyphs in our 8-bit cache + case SkMask::kA8_Format: + return kA8_GrMaskFormat; + case SkMask::kLCD16_Format: + return kA565_GrMaskFormat; + case SkMask::kLCD32_Format: + return kA888_GrMaskFormat; + default: + GrAssert(!"unsupported SkMask::Format"); + return kA8_GrMaskFormat; + } +} + +const GrKey* SkGrFontScaler::getKey() { + if (NULL == fKey) { + fKey = SkNEW_ARGS(SkGrDescKey, (fStrike->getDescriptor())); + } + return fKey; +} + +bool SkGrFontScaler::getPackedGlyphBounds(GrGlyph::PackedID packed, + SkIRect* bounds) { + const SkGlyph& glyph = fStrike->getGlyphIDMetrics(GrGlyph::UnpackID(packed), + GrGlyph::UnpackFixedX(packed), + GrGlyph::UnpackFixedY(packed)); + bounds->setXYWH(glyph.fLeft, glyph.fTop, glyph.fWidth, glyph.fHeight); + return true; + +} + +namespace { +// expands each bit in a bitmask to 0 or ~0 of type INT_TYPE. Used to expand a BW glyph mask to +// A8, RGB565, or RGBA8888. +template <typename INT_TYPE> +void expand_bits(INT_TYPE* dst, + const uint8_t* src, + int width, + int height, + int dstRowBytes, + int srcRowBytes) { + for (int i = 0; i < height; ++i) { + int rowWritesLeft = width; + const uint8_t* s = src; + INT_TYPE* d = dst; + while (rowWritesLeft > 0) { + unsigned mask = *s++; + for (int i = 7; i >= 0 && rowWritesLeft; --i, --rowWritesLeft) { + *d++ = (mask & (1 << i)) ? (INT_TYPE)(~0UL) : 0; + } + } + dst = reinterpret_cast<INT_TYPE*>(reinterpret_cast<intptr_t>(dst) + dstRowBytes); + src += srcRowBytes; + } +} +} + +bool SkGrFontScaler::getPackedGlyphImage(GrGlyph::PackedID packed, + int width, int height, + int dstRB, void* dst) { + const SkGlyph& glyph = fStrike->getGlyphIDMetrics(GrGlyph::UnpackID(packed), + GrGlyph::UnpackFixedX(packed), + GrGlyph::UnpackFixedY(packed)); + GrAssert(glyph.fWidth == width); + GrAssert(glyph.fHeight == height); + const void* src = fStrike->findImage(glyph); + if (NULL == src) { + return false; + } + + int srcRB = glyph.rowBytes(); + // The windows font host sometimes has BW glyphs in a non-BW strike. So it is important here to + // check the glyph's format, not the strike's format, and to be able to convert to any of the + // GrMaskFormats. + if (SkMask::kBW_Format == glyph.fMaskFormat) { + // expand bits to our mask type + const uint8_t* bits = reinterpret_cast<const uint8_t*>(src); + switch (this->getMaskFormat()) { + case kA8_GrMaskFormat:{ + uint8_t* bytes = reinterpret_cast<uint8_t*>(dst); + expand_bits(bytes, bits, width, height, dstRB, srcRB); + break; + } + case kA565_GrMaskFormat: { + uint16_t* rgb565 = reinterpret_cast<uint16_t*>(dst); + expand_bits(rgb565, bits, width, height, dstRB, srcRB); + break; + } + case kA888_GrMaskFormat: { + uint32_t* rgba8888 = reinterpret_cast<uint32_t*>(dst); + expand_bits(rgba8888, bits, width, height, dstRB, srcRB); + break; + } + default: + GrCrash("Unknown GrMaskFormat"); + } + } else if (srcRB == dstRB) { + memcpy(dst, src, dstRB * height); + } else { + const int bbp = GrMaskFormatBytesPerPixel(this->getMaskFormat()); + for (int y = 0; y < height; y++) { + memcpy(dst, src, width * bbp); + src = (const char*)src + srcRB; + dst = (char*)dst + dstRB; + } + } + return true; +} + +// we should just return const SkPath* (NULL means false) +bool SkGrFontScaler::getGlyphPath(uint16_t glyphID, SkPath* path) { + + const SkGlyph& glyph = fStrike->getGlyphIDMetrics(glyphID); + const SkPath* skPath = fStrike->findPath(glyph); + if (skPath) { + *path = *skPath; + return true; + } + return false; +} |