blob: 854c4de8a301daaeed131433f108f4267c1ebb34 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/* libs/graphics/sgl/SkScalerContext.cpp
2**
3** Copyright 2006, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#include "SkScalerContext.h"
19#include "SkDescriptor.h"
20#include "SkDraw.h"
21#include "SkFontHost.h"
22#include "SkMaskFilter.h"
23#include "SkPathEffect.h"
24#include "SkRasterizer.h"
25#include "SkRegion.h"
26#include "SkStroke.h"
27#include "SkThread.h"
28
29#ifdef SK_DEBUG
30// #define TRACK_MISSING_CHARS
31#endif
32
33#define ComputeBWRowBytes(width) (((unsigned)(width) + 7) >> 3)
34
35static const uint8_t* gBlackGammaTable;
36static const uint8_t* gWhiteGammaTable;
37
38void SkGlyph::toMask(SkMask* mask) const {
39 SkASSERT(mask);
40
41 mask->fImage = (uint8_t*)fImage;
42 mask->fBounds.set(fLeft, fTop, fLeft + fWidth, fTop + fHeight);
43 mask->fRowBytes = this->rowBytes();
44 mask->fFormat = fMaskFormat;
45}
46
47size_t SkGlyph::computeImageSize() const {
48 size_t size = this->rowBytes() * fHeight;
49 if (fMaskFormat == SkMask::k3D_Format) {
50 size *= 3;
51 }
52 return size;
53}
54
55#ifdef SK_DEBUG
56 #define DUMP_RECx
57#endif
58
59static SkFlattenable* load_flattenable(const SkDescriptor* desc, uint32_t tag) {
60 SkFlattenable* obj = NULL;
61 uint32_t len;
62 const void* data = desc->findEntry(tag, &len);
63
64 if (data) {
65 SkFlattenableReadBuffer buffer(data, len);
66 obj = buffer.readFlattenable();
67 SkASSERT(buffer.offset() == buffer.size());
68 }
69 return obj;
70}
71
72SkScalerContext::SkScalerContext(const SkDescriptor* desc)
73 : fPathEffect(NULL), fMaskFilter(NULL)
74{
75 static bool gHaveGammaTables;
76 if (!gHaveGammaTables) {
77 const uint8_t* tables[2];
78 SkFontHost::GetGammaTables(tables);
79 gBlackGammaTable = tables[0];
80 gWhiteGammaTable = tables[1];
81 gHaveGammaTables = true;
82 }
83
84 fBaseGlyphCount = 0;
85 fAuxScalerContext = NULL;
86
87 const Rec* rec = (const Rec*)desc->findEntry(kRec_SkDescriptorTag, NULL);
88 SkASSERT(rec);
89
90 fRec = *rec;
91
92#ifdef DUMP_REC
93 desc->assertChecksum();
94 SkDebugf("SkScalarContext checksum %x count %d length %d\n", desc->getChecksum(), desc->getCount(), desc->getLength());
95 SkDebugf(" textsize %g prescale %g preskew %g post [%g %g %g %g]\n",
96 rec->fTextSize, rec->fPreScaleX, rec->fPreSkewX, rec->fPost2x2[0][0],
97 rec->fPost2x2[0][1], rec->fPost2x2[1][0], rec->fPost2x2[1][1]);
98 SkDebugf(" frame %g miter %g hints %d framefill %d format %d join %d\n",
99 rec->fFrameWidth, rec->fMiterLimit, rec->fHints, rec->fFrameAndFill,
100 rec->fMaskFormat, rec->fStrokeJoin);
101 SkDebugf(" pathEffect %x maskFilter %x\n", desc->findEntry(kPathEffect_SkDescriptorTag, NULL),
102 desc->findEntry(kMaskFilter_SkDescriptorTag, NULL));
103#endif
104
105 fPathEffect = (SkPathEffect*)load_flattenable(desc, kPathEffect_SkDescriptorTag);
106 fMaskFilter = (SkMaskFilter*)load_flattenable(desc, kMaskFilter_SkDescriptorTag);
107 fRasterizer = (SkRasterizer*)load_flattenable(desc, kRasterizer_SkDescriptorTag);
108}
109
110SkScalerContext::~SkScalerContext() {
111 fPathEffect->safeUnref();
112 fMaskFilter->safeUnref();
113 fRasterizer->safeUnref();
114
115 SkDELETE(fAuxScalerContext);
116}
117
118SkScalerContext* SkScalerContext::loadAuxContext() const {
119 if (NULL == fAuxScalerContext) {
120 fAuxScalerContext = SkFontHost::CreateFallbackScalerContext(fRec);
121 if (NULL != fAuxScalerContext) {
122 fAuxScalerContext->setBaseGlyphCount(this->getGlyphCount());
123 }
124 }
125 return fAuxScalerContext;
126}
127
128#ifdef TRACK_MISSING_CHARS
129 static uint8_t gMissingChars[1 << 13];
130#endif
131
132uint16_t SkScalerContext::charToGlyphID(SkUnichar uni) {
133 unsigned glyphID = this->generateCharToGlyph(uni);
134
135 if (0 == glyphID) { // try auxcontext
136 SkScalerContext* ctx = this->loadAuxContext();
137 if (NULL != ctx) {
138 glyphID = ctx->generateCharToGlyph(uni);
139 if (0 != glyphID) { // only fiddle with it if its not missing
140 glyphID += this->getGlyphCount();
141 if (glyphID > 0xFFFF) {
142 glyphID = 0;
143 }
144 }
145 }
146 }
147#ifdef TRACK_MISSING_CHARS
148 if (0 == glyphID) {
149 bool announce = false;
150 if (uni > 0xFFFF) { // we don't record these
151 announce = true;
152 } else {
153 unsigned index = uni >> 3;
154 unsigned mask = 1 << (uni & 7);
155 SkASSERT(index < SK_ARRAY_COUNT(gMissingChars));
156 if ((gMissingChars[index] & mask) == 0) {
157 gMissingChars[index] |= mask;
158 announce = true;
159 }
160 }
161 if (announce) {
162 printf(">>> MISSING CHAR <<< 0x%04X\n", uni);
163 }
164 }
165#endif
166 return SkToU16(glyphID);
167}
168
169/* Internal routine to resolve auxContextID into a real context.
170 Only makes sense to call once the glyph has been given a
171 valid auxGlyphID.
172*/
173SkScalerContext* SkScalerContext::getGlyphContext(const SkGlyph& glyph) const {
174 SkScalerContext* ctx = const_cast<SkScalerContext*>(this);
175
176 if (glyph.getGlyphID() >= this->getGlyphCount()) {
177 ctx = this->loadAuxContext();
178 if (NULL == ctx) { // if no aux, just return us
179 ctx = const_cast<SkScalerContext*>(this);
180 }
181 }
182 return ctx;
183}
184
185static int plus_minus_pin(int value, int max) {
186 SkASSERT(max >= 0);
187
188 if (value > max) {
189 value = max;
190 } else if (value < -max) {
191 value = -max;
192 }
193 return value;
194}
195
196void SkScalerContext::getAdvance(SkGlyph* glyph) {
197 // mark us as just having a valid advance
198 glyph->fMaskFormat = MASK_FORMAT_JUST_ADVANCE;
199 // we mark the format before making the call, in case the impl
200 // internally ends up calling its generateMetrics, which is OK
201 // albeit slower than strictly necessary
202 this->getGlyphContext(*glyph)->generateAdvance(glyph);
203}
204
205void SkScalerContext::getMetrics(SkGlyph* glyph) {
206 this->getGlyphContext(*glyph)->generateMetrics(glyph);
207
208 // for now we have separate cache entries for devkerning on and off
209 // in the future we might share caches, but make our measure/draw
210 // code make the distinction. Thus we zap the values if the caller
211 // has not asked for them.
212 if ((fRec.fFlags & SkScalerContext::kDevKernText_Flag) == 0) {
213 // no devkern, so zap the fields
214 glyph->fLsbDelta = glyph->fRsbDelta = 0;
215 }
216
217 // if either dimension is empty, zap the image bounds of the glyph
218 if (0 == glyph->fWidth || 0 == glyph->fHeight) {
219 glyph->fWidth = 0;
220 glyph->fHeight = 0;
221 glyph->fTop = 0;
222 glyph->fLeft = 0;
223 glyph->fMaskFormat = 0;
224 return;
225 }
226
227 if (fRec.fFrameWidth > 0 || fPathEffect != NULL || fRasterizer != NULL) {
228 SkPath devPath, fillPath;
229 SkMatrix fillToDevMatrix;
230
231 this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix);
232
233 if (fRasterizer) {
234 SkMask mask;
235
236 if (fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL,
237 fMaskFilter, &mask,
238 SkMask::kJustComputeBounds_CreateMode)) {
239 glyph->fLeft = mask.fBounds.fLeft;
240 glyph->fTop = mask.fBounds.fTop;
241 glyph->fWidth = SkToU16(mask.fBounds.width());
242 glyph->fHeight = SkToU16(mask.fBounds.height());
243 } else {
244 // draw nothing 'cause we failed
245 glyph->fLeft = 0;
246 glyph->fTop = 0;
247 glyph->fWidth = 0;
248 glyph->fHeight = 0;
249 return;
250 }
251 } else {
252 // just use devPath
253 SkRect r;
254 SkIRect ir;
255
256 devPath.computeBounds(&r, SkPath::kExact_BoundsType);
257 r.roundOut(&ir);
258
259 glyph->fLeft = ir.fLeft;
260 glyph->fTop = ir.fTop;
261 glyph->fWidth = SkToU16(ir.width());
262 glyph->fHeight = SkToU16(ir.height());
263 }
264 }
265
266 glyph->fMaskFormat = fRec.fMaskFormat;
267
268 if (fMaskFilter) {
269 SkMask src, dst;
270 SkMatrix matrix;
271
272 glyph->toMask(&src);
273 fRec.getMatrixFrom2x2(&matrix);
274
275 src.fImage = NULL; // only want the bounds from the filter
276 if (fMaskFilter->filterMask(&dst, src, matrix, NULL)) {
277 SkASSERT(dst.fImage == NULL);
278 glyph->fLeft = dst.fBounds.fLeft;
279 glyph->fTop = dst.fBounds.fTop;
280 glyph->fWidth = SkToU16(dst.fBounds.width());
281 glyph->fHeight = SkToU16(dst.fBounds.height());
282 glyph->fMaskFormat = dst.fFormat;
283 }
284 }
285}
286
287void SkScalerContext::getImage(const SkGlyph& origGlyph) {
288 const SkGlyph* glyph = &origGlyph;
289 SkGlyph tmpGlyph;
290
291 if (fMaskFilter) { // restore the prefilter bounds
292 tmpGlyph.fID = origGlyph.fID;
293
294 // need the original bounds, sans our maskfilter
295 SkMaskFilter* mf = fMaskFilter;
296 fMaskFilter = NULL; // temp disable
297 this->getMetrics(&tmpGlyph);
298 fMaskFilter = mf; // restore
299
300 tmpGlyph.fImage = origGlyph.fImage;
301
302 // we need the prefilter bounds to be <= filter bounds
303 SkASSERT(tmpGlyph.fWidth <= origGlyph.fWidth);
304 SkASSERT(tmpGlyph.fHeight <= origGlyph.fHeight);
305 glyph = &tmpGlyph;
306 }
307
308 if (fRec.fFrameWidth > 0 || fPathEffect != NULL || fRasterizer != NULL) {
309 SkPath devPath, fillPath;
310 SkMatrix fillToDevMatrix;
311
312 this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix);
313
314 if (fRasterizer) {
315 SkMask mask;
316
317 glyph->toMask(&mask);
318 mask.fFormat = SkMask::kA8_Format;
319 bzero(glyph->fImage, mask.computeImageSize());
320
321 if (!fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL,
322 fMaskFilter, &mask,
323 SkMask::kJustRenderImage_CreateMode)) {
324 return;
325 }
326 } else {
327 SkBitmap bm;
328 SkBitmap::Config config;
329 SkMatrix matrix;
330 SkRegion clip;
331 SkPaint paint;
332 SkDraw draw;
333
334 if (SkMask::kA8_Format == fRec.fMaskFormat) {
335 config = SkBitmap::kA8_Config;
336 paint.setAntiAlias(true);
337 } else {
338 SkASSERT(SkMask::kBW_Format == fRec.fMaskFormat);
339 config = SkBitmap::kA1_Config;
340 paint.setAntiAlias(false);
341 }
342
343 clip.setRect(0, 0, glyph->fWidth, glyph->fHeight);
344 matrix.setTranslate(-SkIntToScalar(glyph->fLeft),
345 -SkIntToScalar(glyph->fTop));
346 bm.setConfig(config, glyph->fWidth, glyph->fHeight,
347 glyph->rowBytes());
348 bm.setPixels(glyph->fImage);
349 bzero(glyph->fImage, bm.height() * bm.rowBytes());
350
351 draw.fClip = &clip;
352 draw.fMatrix = &matrix;
353 draw.fBitmap = &bm;
354 draw.fBounder = NULL;
355 draw.drawPath(devPath, paint);
356 }
357 } else {
358 this->getGlyphContext(*glyph)->generateImage(*glyph);
359 }
360
361 if (fMaskFilter) {
362 SkMask srcM, dstM;
363 SkMatrix matrix;
364
365 // the src glyph image shouldn't be 3D
366 SkASSERT(SkMask::k3D_Format != glyph->fMaskFormat);
367 glyph->toMask(&srcM);
368 fRec.getMatrixFrom2x2(&matrix);
369
370 if (fMaskFilter->filterMask(&dstM, srcM, matrix, NULL)) {
371 int width = SkFastMin32(origGlyph.fWidth, dstM.fBounds.width());
372 int height = SkFastMin32(origGlyph.fHeight, dstM.fBounds.height());
373 int dstRB = origGlyph.rowBytes();
374 int srcRB = dstM.fRowBytes;
375
376 const uint8_t* src = (const uint8_t*)dstM.fImage;
377 uint8_t* dst = (uint8_t*)origGlyph.fImage;
378
379 if (SkMask::k3D_Format == dstM.fFormat) {
380 // we have to copy 3 times as much
381 height *= 3;
382 }
383
384 // clean out our glyph, since it may be larger than dstM
385 //bzero(dst, height * dstRB);
386
387 while (--height >= 0) {
388 memcpy(dst, src, width);
389 src += srcRB;
390 dst += dstRB;
391 }
392 SkMask::FreeImage(dstM.fImage);
393 }
394 }
395
396 // check to see if we should filter the alpha channel
397
398 if (NULL == fMaskFilter &&
399 fRec.fMaskFormat != SkMask::kBW_Format &&
400 (fRec.fFlags & (kGammaForBlack_Flag | kGammaForWhite_Flag)) != 0)
401 {
402 const uint8_t* table = (fRec.fFlags & kGammaForBlack_Flag) ? gBlackGammaTable : gWhiteGammaTable;
403 if (NULL != table)
404 {
405 uint8_t* dst = (uint8_t*)origGlyph.fImage;
406 unsigned rowBytes = origGlyph.rowBytes();
407
408 for (int y = origGlyph.fHeight - 1; y >= 0; --y)
409 {
410 for (int x = origGlyph.fWidth - 1; x >= 0; --x)
411 dst[x] = table[dst[x]];
412 dst += rowBytes;
413 }
414 }
415 }
416}
417
418void SkScalerContext::getPath(const SkGlyph& glyph, SkPath* path)
419{
420 this->internalGetPath(glyph, NULL, path, NULL);
421}
422
423void SkScalerContext::getFontMetrics(SkPaint::FontMetrics* mx, SkPaint::FontMetrics* my)
424{
425 this->generateFontMetrics(mx, my);
426}
427
428///////////////////////////////////////////////////////////////////////
429
430void SkScalerContext::internalGetPath(const SkGlyph& glyph, SkPath* fillPath, SkPath* devPath, SkMatrix* fillToDevMatrix)
431{
432 SkPath path;
433
434 this->getGlyphContext(glyph)->generatePath(glyph, &path);
435
436 if (fRec.fFrameWidth > 0 || fPathEffect != NULL)
437 {
438 // need the path in user-space, with only the point-size applied
439 // so that our stroking and effects will operate the same way they
440 // would if the user had extracted the path themself, and then
441 // called drawPath
442 SkPath localPath;
443 SkMatrix matrix, inverse;
444
445 fRec.getMatrixFrom2x2(&matrix);
446 matrix.invert(&inverse);
447 path.transform(inverse, &localPath);
448 // now localPath is only affected by the paint settings, and not the canvas matrix
449
450 SkScalar width = fRec.fFrameWidth;
451
452 if (fPathEffect)
453 {
454 SkPath effectPath;
455
456 if (fPathEffect->filterPath(&effectPath, localPath, &width))
457 localPath.swap(effectPath);
458 }
459
460 if (width > 0)
461 {
462 SkStroke stroker;
463 SkPath outline;
464
465 stroker.setWidth(width);
466 stroker.setMiterLimit(fRec.fMiterLimit);
467 stroker.setJoin((SkPaint::Join)fRec.fStrokeJoin);
468 stroker.setDoFill(SkToBool(fRec.fFlags & kFrameAndFill_Flag));
469 stroker.strokePath(localPath, &outline);
470 localPath.swap(outline);
471 }
472
473 // now return stuff to the caller
474 if (fillToDevMatrix)
475 *fillToDevMatrix = matrix;
476
477 if (devPath)
478 localPath.transform(matrix, devPath);
479
480 if (fillPath)
481 fillPath->swap(localPath);
482 }
483 else // nothing tricky to do
484 {
485 if (fillToDevMatrix)
486 fillToDevMatrix->reset();
487
488 if (devPath)
489 {
490 if (fillPath == NULL)
491 devPath->swap(path);
492 else
493 *devPath = path;
494 }
495
496 if (fillPath)
497 fillPath->swap(path);
498 }
499
500 if (devPath)
501 devPath->updateBoundsCache();
502 if (fillPath)
503 fillPath->updateBoundsCache();
504}
505
506
507void SkScalerContext::Rec::getMatrixFrom2x2(SkMatrix* dst) const
508{
509 dst->reset();
510 dst->setScaleX(fPost2x2[0][0]);
511 dst->setSkewX( fPost2x2[0][1]);
512 dst->setSkewY( fPost2x2[1][0]);
513 dst->setScaleY(fPost2x2[1][1]);
514}
515
516void SkScalerContext::Rec::getLocalMatrix(SkMatrix* m) const
517{
518 m->setScale(SkScalarMul(fTextSize, fPreScaleX), fTextSize);
519 if (fPreSkewX)
520 m->postSkew(fPreSkewX, 0);
521}
522
523void SkScalerContext::Rec::getSingleMatrix(SkMatrix* m) const
524{
525 this->getLocalMatrix(m);
526
527 // now concat the device matrix
528 {
529 SkMatrix deviceMatrix;
530 this->getMatrixFrom2x2(&deviceMatrix);
531 m->postConcat(deviceMatrix);
532 }
533}
534
535#include "SkFontHost.h"
536
537SkScalerContext* SkScalerContext::Create(const SkDescriptor* desc)
538{
539 return SkFontHost::CreateScalerContext(desc);
540}
541