blob: 8fdae48a2adde48c7f5f1ffd42e7f8299ddf461f [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
reed@google.comac10a2d2010-12-22 21:39:39 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2010 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
reed@google.comac10a2d2010-12-22 21:39:39 +00007 */
8
9
bsalomon@google.coma3201942012-06-21 19:58:20 +000010#include "GrTemplates.h"
reed@google.comac10a2d2010-12-22 21:39:39 +000011#include "SkGr.h"
12#include "SkDescriptor.h"
13#include "SkGlyphCache.h"
14
15class SkGrDescKey : public GrKey {
16public:
17 explicit SkGrDescKey(const SkDescriptor& desc);
18 virtual ~SkGrDescKey();
reed@google.com1fcd51e2011-01-05 15:50:27 +000019
reed@google.comac10a2d2010-12-22 21:39:39 +000020protected:
21 // overrides
22 virtual bool lt(const GrKey& rh) const;
23 virtual bool eq(const GrKey& rh) const;
reed@google.com1fcd51e2011-01-05 15:50:27 +000024
reed@google.comac10a2d2010-12-22 21:39:39 +000025private:
26 SkDescriptor* fDesc;
27 enum {
28 kMaxStorageInts = 16
29 };
30 uint32_t fStorage[kMaxStorageInts];
31};
32
33///////////////////////////////////////////////////////////////////////////////
34
35SkGrDescKey::SkGrDescKey(const SkDescriptor& desc) : GrKey(desc.getChecksum()) {
36 size_t size = desc.getLength();
37 if (size <= sizeof(fStorage)) {
reed@google.com1fcd51e2011-01-05 15:50:27 +000038 fDesc = GrTCast<SkDescriptor*>(fStorage);
reed@google.comac10a2d2010-12-22 21:39:39 +000039 } else {
40 fDesc = SkDescriptor::Alloc(size);
41 }
42 memcpy(fDesc, &desc, size);
43}
44
45SkGrDescKey::~SkGrDescKey() {
reed@google.com1fcd51e2011-01-05 15:50:27 +000046 if (fDesc != GrTCast<SkDescriptor*>(fStorage)) {
reed@google.comac10a2d2010-12-22 21:39:39 +000047 SkDescriptor::Free(fDesc);
48 }
49}
50
51bool SkGrDescKey::lt(const GrKey& rh) const {
52 const SkDescriptor* srcDesc = ((const SkGrDescKey*)&rh)->fDesc;
53 size_t lenLH = fDesc->getLength();
54 size_t lenRH = srcDesc->getLength();
robertphillips@google.comadacc702013-10-14 21:53:24 +000055 int cmp = memcmp(fDesc, srcDesc, SkTMin<size_t>(lenLH, lenRH));
reed@google.comac10a2d2010-12-22 21:39:39 +000056 if (0 == cmp) {
57 return lenLH < lenRH;
58 } else {
59 return cmp < 0;
60 }
61}
62
63bool SkGrDescKey::eq(const GrKey& rh) const {
64 const SkDescriptor* srcDesc = ((const SkGrDescKey*)&rh)->fDesc;
65 return fDesc->equals(*srcDesc);
66}
67
68///////////////////////////////////////////////////////////////////////////////
69
70SkGrFontScaler::SkGrFontScaler(SkGlyphCache* strike) {
71 fStrike = strike;
72 fKey = NULL;
73}
74
75SkGrFontScaler::~SkGrFontScaler() {
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +000076 SkSafeUnref(fKey);
reed@google.comac10a2d2010-12-22 21:39:39 +000077}
78
reed@google.com98539c62011-03-15 15:40:16 +000079GrMaskFormat SkGrFontScaler::getMaskFormat() {
80 SkMask::Format format = fStrike->getMaskFormat();
81 switch (format) {
mike@reedtribe.orgc34effe2011-04-06 00:54:45 +000082 case SkMask::kBW_Format:
83 // fall through to kA8 -- we store BW glyphs in our 8-bit cache
reed@google.com98539c62011-03-15 15:40:16 +000084 case SkMask::kA8_Format:
85 return kA8_GrMaskFormat;
86 case SkMask::kLCD16_Format:
87 return kA565_GrMaskFormat;
caryclark@google.com1eeaf0b2011-06-22 13:19:43 +000088 case SkMask::kLCD32_Format:
89 return kA888_GrMaskFormat;
commit-bot@chromium.orgf8cb1842013-12-03 19:45:22 +000090 case SkMask::kARGB32_Format:
91 return kARGB_GrMaskFormat;
reed@google.com98539c62011-03-15 15:40:16 +000092 default:
mtklein@google.com330313a2013-08-22 15:37:26 +000093 SkDEBUGFAIL("unsupported SkMask::Format");
reed@google.com98539c62011-03-15 15:40:16 +000094 return kA8_GrMaskFormat;
95 }
96}
97
reed@google.comac10a2d2010-12-22 21:39:39 +000098const GrKey* SkGrFontScaler::getKey() {
99 if (NULL == fKey) {
tomhudson@google.comc377baf2012-07-09 20:17:56 +0000100 fKey = SkNEW_ARGS(SkGrDescKey, (fStrike->getDescriptor()));
reed@google.comac10a2d2010-12-22 21:39:39 +0000101 }
102 return fKey;
103}
104
105bool SkGrFontScaler::getPackedGlyphBounds(GrGlyph::PackedID packed,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000106 SkIRect* bounds) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000107 const SkGlyph& glyph = fStrike->getGlyphIDMetrics(GrGlyph::UnpackID(packed),
108 GrGlyph::UnpackFixedX(packed),
109 GrGlyph::UnpackFixedY(packed));
110 bounds->setXYWH(glyph.fLeft, glyph.fTop, glyph.fWidth, glyph.fHeight);
111 return true;
reed@google.com1fcd51e2011-01-05 15:50:27 +0000112
reed@google.comac10a2d2010-12-22 21:39:39 +0000113}
114
bsalomon@google.comc8699ef2012-09-10 13:28:00 +0000115namespace {
116// expands each bit in a bitmask to 0 or ~0 of type INT_TYPE. Used to expand a BW glyph mask to
117// A8, RGB565, or RGBA8888.
118template <typename INT_TYPE>
119void expand_bits(INT_TYPE* dst,
120 const uint8_t* src,
121 int width,
122 int height,
123 int dstRowBytes,
124 int srcRowBytes) {
125 for (int i = 0; i < height; ++i) {
126 int rowWritesLeft = width;
127 const uint8_t* s = src;
128 INT_TYPE* d = dst;
129 while (rowWritesLeft > 0) {
130 unsigned mask = *s++;
131 for (int i = 7; i >= 0 && rowWritesLeft; --i, --rowWritesLeft) {
132 *d++ = (mask & (1 << i)) ? (INT_TYPE)(~0UL) : 0;
mike@reedtribe.orgc34effe2011-04-06 00:54:45 +0000133 }
134 }
bsalomon@google.comc8699ef2012-09-10 13:28:00 +0000135 dst = reinterpret_cast<INT_TYPE*>(reinterpret_cast<intptr_t>(dst) + dstRowBytes);
136 src += srcRowBytes;
mike@reedtribe.orgc34effe2011-04-06 00:54:45 +0000137 }
138}
bsalomon@google.comc8699ef2012-09-10 13:28:00 +0000139}
mike@reedtribe.orgc34effe2011-04-06 00:54:45 +0000140
reed@google.comac10a2d2010-12-22 21:39:39 +0000141bool SkGrFontScaler::getPackedGlyphImage(GrGlyph::PackedID packed,
142 int width, int height,
143 int dstRB, void* dst) {
144 const SkGlyph& glyph = fStrike->getGlyphIDMetrics(GrGlyph::UnpackID(packed),
145 GrGlyph::UnpackFixedX(packed),
146 GrGlyph::UnpackFixedY(packed));
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000147 SkASSERT(glyph.fWidth == width);
148 SkASSERT(glyph.fHeight == height);
reed@google.comac10a2d2010-12-22 21:39:39 +0000149 const void* src = fStrike->findImage(glyph);
150 if (NULL == src) {
151 return false;
152 }
153
154 int srcRB = glyph.rowBytes();
bsalomon@google.comc8699ef2012-09-10 13:28:00 +0000155 // The windows font host sometimes has BW glyphs in a non-BW strike. So it is important here to
156 // check the glyph's format, not the strike's format, and to be able to convert to any of the
157 // GrMaskFormats.
158 if (SkMask::kBW_Format == glyph.fMaskFormat) {
159 // expand bits to our mask type
mike@reedtribe.orgc34effe2011-04-06 00:54:45 +0000160 const uint8_t* bits = reinterpret_cast<const uint8_t*>(src);
bsalomon@google.comc8699ef2012-09-10 13:28:00 +0000161 switch (this->getMaskFormat()) {
162 case kA8_GrMaskFormat:{
163 uint8_t* bytes = reinterpret_cast<uint8_t*>(dst);
164 expand_bits(bytes, bits, width, height, dstRB, srcRB);
165 break;
166 }
167 case kA565_GrMaskFormat: {
168 uint16_t* rgb565 = reinterpret_cast<uint16_t*>(dst);
169 expand_bits(rgb565, bits, width, height, dstRB, srcRB);
170 break;
171 }
172 case kA888_GrMaskFormat: {
173 uint32_t* rgba8888 = reinterpret_cast<uint32_t*>(dst);
174 expand_bits(rgba8888, bits, width, height, dstRB, srcRB);
175 break;
176 }
commit-bot@chromium.orgf8cb1842013-12-03 19:45:22 +0000177 default:
178 GrCrash("Invalid GrMaskFormat");
mike@reedtribe.orgc34effe2011-04-06 00:54:45 +0000179 }
180 } else if (srcRB == dstRB) {
reed@google.comac10a2d2010-12-22 21:39:39 +0000181 memcpy(dst, src, dstRB * height);
182 } else {
reed@google.com98539c62011-03-15 15:40:16 +0000183 const int bbp = GrMaskFormatBytesPerPixel(this->getMaskFormat());
reed@google.comac10a2d2010-12-22 21:39:39 +0000184 for (int y = 0; y < height; y++) {
reed@google.com98539c62011-03-15 15:40:16 +0000185 memcpy(dst, src, width * bbp);
reed@google.comac10a2d2010-12-22 21:39:39 +0000186 src = (const char*)src + srcRB;
187 dst = (char*)dst + dstRB;
188 }
189 }
190 return true;
191}
192
reed@google.com07f3ee12011-05-16 17:21:57 +0000193// we should just return const SkPath* (NULL means false)
bsalomon@google.com8d033a12012-04-27 15:52:53 +0000194bool SkGrFontScaler::getGlyphPath(uint16_t glyphID, SkPath* path) {
reed@google.com1fcd51e2011-01-05 15:50:27 +0000195
reed@google.comac10a2d2010-12-22 21:39:39 +0000196 const SkGlyph& glyph = fStrike->getGlyphIDMetrics(glyphID);
197 const SkPath* skPath = fStrike->findPath(glyph);
198 if (skPath) {
reed@google.com07f3ee12011-05-16 17:21:57 +0000199 *path = *skPath;
reed@google.comac10a2d2010-12-22 21:39:39 +0000200 return true;
201 }
202 return false;
203}