SkScalerContext.cpp revision ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976e
1
2/*
3 * Copyright 2006 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10#include "SkScalerContext.h"
11#include "SkColorPriv.h"
12#include "SkDescriptor.h"
13#include "SkDraw.h"
14#include "SkFontHost.h"
15#include "SkMaskFilter.h"
16#include "SkPathEffect.h"
17#include "SkRasterizer.h"
18#include "SkRegion.h"
19#include "SkStroke.h"
20#include "SkThread.h"
21
22#define ComputeBWRowBytes(width)        (((unsigned)(width) + 7) >> 3)
23
24static const uint8_t* gBlackGammaTable;
25static const uint8_t* gWhiteGammaTable;
26
27void SkGlyph::toMask(SkMask* mask) const {
28    SkASSERT(mask);
29
30    mask->fImage = (uint8_t*)fImage;
31    mask->fBounds.set(fLeft, fTop, fLeft + fWidth, fTop + fHeight);
32    mask->fRowBytes = this->rowBytes();
33    mask->fFormat = static_cast<SkMask::Format>(fMaskFormat);
34}
35
36size_t SkGlyph::computeImageSize() const {
37    const size_t size = this->rowBytes() * fHeight;
38
39    switch (fMaskFormat) {
40        case SkMask::k3D_Format:
41            return 3 * size;
42        default:
43            return size;
44    }
45}
46
47void SkGlyph::zeroMetrics() {
48    fAdvanceX = 0;
49    fAdvanceY = 0;
50    fWidth    = 0;
51    fHeight   = 0;
52    fTop      = 0;
53    fLeft     = 0;
54    fRsbDelta = 0;
55    fLsbDelta = 0;
56}
57
58///////////////////////////////////////////////////////////////////////////////
59
60#ifdef SK_DEBUG
61    #define DUMP_RECx
62#endif
63
64static SkFlattenable* load_flattenable(const SkDescriptor* desc, uint32_t tag) {
65    SkFlattenable*  obj = NULL;
66    uint32_t        len;
67    const void*     data = desc->findEntry(tag, &len);
68
69    if (data) {
70        SkFlattenableReadBuffer   buffer(data, len);
71        obj = buffer.readFlattenable();
72        SkASSERT(buffer.offset() == buffer.size());
73    }
74    return obj;
75}
76
77SkScalerContext::SkScalerContext(const SkDescriptor* desc)
78    : fPathEffect(NULL), fMaskFilter(NULL)
79{
80    static bool gHaveGammaTables;
81    if (!gHaveGammaTables) {
82        const uint8_t* tables[2];
83        SkFontHost::GetGammaTables(tables);
84        gBlackGammaTable = tables[0];
85        gWhiteGammaTable = tables[1];
86        gHaveGammaTables = true;
87    }
88
89    fBaseGlyphCount = 0;
90    fNextContext = NULL;
91
92    const Rec* rec = (const Rec*)desc->findEntry(kRec_SkDescriptorTag, NULL);
93    SkASSERT(rec);
94
95    fRec = *rec;
96
97#ifdef DUMP_REC
98    desc->assertChecksum();
99    SkDebugf("SkScalarContext checksum %x count %d length %d\n",
100             desc->getChecksum(), desc->getCount(), desc->getLength());
101    SkDebugf(" textsize %g prescale %g preskew %g post [%g %g %g %g]\n",
102        rec->fTextSize, rec->fPreScaleX, rec->fPreSkewX, rec->fPost2x2[0][0],
103        rec->fPost2x2[0][1], rec->fPost2x2[1][0], rec->fPost2x2[1][1]);
104    SkDebugf("  frame %g miter %g hints %d framefill %d format %d join %d\n",
105        rec->fFrameWidth, rec->fMiterLimit, rec->fHints, rec->fFrameAndFill,
106        rec->fMaskFormat, rec->fStrokeJoin);
107    SkDebugf("  pathEffect %x maskFilter %x\n",
108             desc->findEntry(kPathEffect_SkDescriptorTag, NULL),
109        desc->findEntry(kMaskFilter_SkDescriptorTag, NULL));
110#endif
111
112    fPathEffect = (SkPathEffect*)load_flattenable(desc, kPathEffect_SkDescriptorTag);
113    fMaskFilter = (SkMaskFilter*)load_flattenable(desc, kMaskFilter_SkDescriptorTag);
114    fRasterizer = (SkRasterizer*)load_flattenable(desc, kRasterizer_SkDescriptorTag);
115}
116
117SkScalerContext::~SkScalerContext() {
118    SkDELETE(fNextContext);
119
120    SkSafeUnref(fPathEffect);
121    SkSafeUnref(fMaskFilter);
122    SkSafeUnref(fRasterizer);
123}
124
125static SkScalerContext* allocNextContext(const SkScalerContext::Rec& rec) {
126    // fonthost will determine the next possible font to search, based
127    // on the current font in fRec. It will return NULL if ctx is our
128    // last font that can be searched (i.e. ultimate fallback font)
129    uint32_t newFontID = SkFontHost::NextLogicalFont(rec.fFontID, rec.fOrigFontID);
130    if (0 == newFontID) {
131        return NULL;
132    }
133
134    SkAutoDescriptor    ad(sizeof(rec) + SkDescriptor::ComputeOverhead(1));
135    SkDescriptor*       desc = ad.getDesc();
136
137    desc->init();
138    SkScalerContext::Rec* newRec =
139    (SkScalerContext::Rec*)desc->addEntry(kRec_SkDescriptorTag,
140                                          sizeof(rec), &rec);
141    newRec->fFontID = newFontID;
142    desc->computeChecksum();
143
144    return SkFontHost::CreateScalerContext(desc);
145}
146
147/*  Return the next context, creating it if its not already created, but return
148    NULL if the fonthost says there are no more fonts to fallback to.
149 */
150SkScalerContext* SkScalerContext::getNextContext() {
151    SkScalerContext* next = fNextContext;
152    // if next is null, then either it isn't cached yet, or we're at the
153    // end of our possible chain
154    if (NULL == next) {
155        next = allocNextContext(fRec);
156        if (NULL == next) {
157            return NULL;
158        }
159        // next's base is our base + our local count
160        next->setBaseGlyphCount(fBaseGlyphCount + this->getGlyphCount());
161        // cache the answer
162        fNextContext = next;
163    }
164    return next;
165}
166
167SkScalerContext* SkScalerContext::getGlyphContext(const SkGlyph& glyph) {
168    unsigned glyphID = glyph.getGlyphID();
169    SkScalerContext* ctx = this;
170    for (;;) {
171        unsigned count = ctx->getGlyphCount();
172        if (glyphID < count) {
173            break;
174        }
175        glyphID -= count;
176        ctx = ctx->getNextContext();
177        if (NULL == ctx) {
178            SkDebugf("--- no context for glyph %x\n", glyph.getGlyphID());
179            // just return the original context (this)
180            return this;
181        }
182    }
183    return ctx;
184}
185
186/*  This loops through all available fallback contexts (if needed) until it
187    finds some context that can handle the unichar. If all fail, returns 0
188 */
189uint16_t SkScalerContext::charToGlyphID(SkUnichar uni) {
190    SkScalerContext* ctx = this;
191    unsigned glyphID;
192    for (;;) {
193        glyphID = ctx->generateCharToGlyph(uni);
194        if (glyphID) {
195            break;  // found it
196        }
197        ctx = ctx->getNextContext();
198        if (NULL == ctx) {
199            return 0;   // no more contexts, return missing glyph
200        }
201    }
202    // add the ctx's base, making glyphID unique for chain of contexts
203    glyphID += ctx->fBaseGlyphCount;
204    // check for overflow of 16bits, since our glyphID cannot exceed that
205    if (glyphID > 0xFFFF) {
206        glyphID = 0;
207    }
208    return SkToU16(glyphID);
209}
210
211SkUnichar SkScalerContext::glyphIDToChar(uint16_t glyphID) {
212    SkScalerContext* ctx = this;
213    unsigned rangeEnd = 0;
214    do {
215        unsigned rangeStart = rangeEnd;
216
217        rangeEnd += ctx->getGlyphCount();
218        if (rangeStart <= glyphID && glyphID < rangeEnd) {
219            return ctx->generateGlyphToChar(glyphID - rangeStart);
220        }
221        ctx = ctx->getNextContext();
222    } while (NULL != ctx);
223    return 0;
224}
225
226void SkScalerContext::getAdvance(SkGlyph* glyph) {
227    // mark us as just having a valid advance
228    glyph->fMaskFormat = MASK_FORMAT_JUST_ADVANCE;
229    // we mark the format before making the call, in case the impl
230    // internally ends up calling its generateMetrics, which is OK
231    // albeit slower than strictly necessary
232    this->getGlyphContext(*glyph)->generateAdvance(glyph);
233}
234
235void SkScalerContext::getMetrics(SkGlyph* glyph) {
236    this->getGlyphContext(*glyph)->generateMetrics(glyph);
237
238    // for now we have separate cache entries for devkerning on and off
239    // in the future we might share caches, but make our measure/draw
240    // code make the distinction. Thus we zap the values if the caller
241    // has not asked for them.
242    if ((fRec.fFlags & SkScalerContext::kDevKernText_Flag) == 0) {
243        // no devkern, so zap the fields
244        glyph->fLsbDelta = glyph->fRsbDelta = 0;
245    }
246
247    // if either dimension is empty, zap the image bounds of the glyph
248    if (0 == glyph->fWidth || 0 == glyph->fHeight) {
249        glyph->fWidth   = 0;
250        glyph->fHeight  = 0;
251        glyph->fTop     = 0;
252        glyph->fLeft    = 0;
253        glyph->fMaskFormat = 0;
254        return;
255    }
256
257    if (fRec.fFrameWidth > 0 || fPathEffect != NULL || fRasterizer != NULL) {
258        SkPath      devPath, fillPath;
259        SkMatrix    fillToDevMatrix;
260
261        this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix);
262
263        if (fRasterizer) {
264            SkMask  mask;
265
266            if (fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL,
267                                       fMaskFilter, &mask,
268                                       SkMask::kJustComputeBounds_CreateMode)) {
269                glyph->fLeft    = mask.fBounds.fLeft;
270                glyph->fTop     = mask.fBounds.fTop;
271                glyph->fWidth   = SkToU16(mask.fBounds.width());
272                glyph->fHeight  = SkToU16(mask.fBounds.height());
273            } else {
274                goto SK_ERROR;
275            }
276        } else {
277            // just use devPath
278            SkIRect ir;
279            devPath.getBounds().roundOut(&ir);
280
281            if (ir.isEmpty() || !ir.is16Bit()) {
282                goto SK_ERROR;
283            }
284            glyph->fLeft    = ir.fLeft;
285            glyph->fTop     = ir.fTop;
286            glyph->fWidth   = SkToU16(ir.width());
287            glyph->fHeight  = SkToU16(ir.height());
288        }
289    }
290
291	if (SkMask::kARGB32_Format != glyph->fMaskFormat) {
292		glyph->fMaskFormat = fRec.fMaskFormat;
293	}
294
295    if (fMaskFilter) {
296        SkMask      src, dst;
297        SkMatrix    matrix;
298
299        glyph->toMask(&src);
300        fRec.getMatrixFrom2x2(&matrix);
301
302        src.fImage = NULL;  // only want the bounds from the filter
303        if (fMaskFilter->filterMask(&dst, src, matrix, NULL)) {
304            SkASSERT(dst.fImage == NULL);
305            glyph->fLeft    = dst.fBounds.fLeft;
306            glyph->fTop     = dst.fBounds.fTop;
307            glyph->fWidth   = SkToU16(dst.fBounds.width());
308            glyph->fHeight  = SkToU16(dst.fBounds.height());
309            glyph->fMaskFormat = dst.fFormat;
310        }
311    }
312    return;
313
314SK_ERROR:
315    // draw nothing 'cause we failed
316    glyph->fLeft    = 0;
317    glyph->fTop     = 0;
318    glyph->fWidth   = 0;
319    glyph->fHeight  = 0;
320    // put a valid value here, in case it was earlier set to
321    // MASK_FORMAT_JUST_ADVANCE
322    glyph->fMaskFormat = fRec.fMaskFormat;
323}
324
325void SkScalerContext::getImage(const SkGlyph& origGlyph) {
326    const SkGlyph*  glyph = &origGlyph;
327    SkGlyph         tmpGlyph;
328
329    if (fMaskFilter) {   // restore the prefilter bounds
330        tmpGlyph.init(origGlyph.fID);
331
332        // need the original bounds, sans our maskfilter
333        SkMaskFilter* mf = fMaskFilter;
334        fMaskFilter = NULL;             // temp disable
335        this->getMetrics(&tmpGlyph);
336        fMaskFilter = mf;               // restore
337
338        tmpGlyph.fImage = origGlyph.fImage;
339
340        // we need the prefilter bounds to be <= filter bounds
341        SkASSERT(tmpGlyph.fWidth <= origGlyph.fWidth);
342        SkASSERT(tmpGlyph.fHeight <= origGlyph.fHeight);
343        glyph = &tmpGlyph;
344    }
345
346    if (fRec.fFrameWidth > 0 || fPathEffect != NULL || fRasterizer != NULL) {
347        SkPath      devPath, fillPath;
348        SkMatrix    fillToDevMatrix;
349
350        this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix);
351
352        if (fRasterizer) {
353            SkMask  mask;
354
355            glyph->toMask(&mask);
356            mask.fFormat = SkMask::kA8_Format;
357            sk_bzero(glyph->fImage, mask.computeImageSize());
358
359            if (!fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL,
360                                        fMaskFilter, &mask,
361                                        SkMask::kJustRenderImage_CreateMode)) {
362                return;
363            }
364        } else {
365            SkBitmap    bm;
366            SkBitmap::Config config;
367            SkMatrix    matrix;
368            SkRegion    clip;
369            SkPaint     paint;
370            SkDraw      draw;
371
372            if (SkMask::kA8_Format == fRec.fMaskFormat) {
373                config = SkBitmap::kA8_Config;
374                paint.setAntiAlias(true);
375            } else {
376                SkASSERT(SkMask::kBW_Format == fRec.fMaskFormat);
377                config = SkBitmap::kA1_Config;
378                paint.setAntiAlias(false);
379            }
380
381            clip.setRect(0, 0, glyph->fWidth, glyph->fHeight);
382            matrix.setTranslate(-SkIntToScalar(glyph->fLeft),
383                                -SkIntToScalar(glyph->fTop));
384            bm.setConfig(config, glyph->fWidth, glyph->fHeight,
385                         glyph->rowBytes());
386            bm.setPixels(glyph->fImage);
387            sk_bzero(glyph->fImage, bm.height() * bm.rowBytes());
388
389            draw.fClip  = &clip;
390            draw.fMatrix = &matrix;
391            draw.fBitmap = &bm;
392            draw.fBounder = NULL;
393            draw.drawPath(devPath, paint);
394        }
395    } else {
396        this->getGlyphContext(*glyph)->generateImage(*glyph);
397    }
398
399    if (fMaskFilter) {
400        SkMask      srcM, dstM;
401        SkMatrix    matrix;
402
403        // the src glyph image shouldn't be 3D
404        SkASSERT(SkMask::k3D_Format != glyph->fMaskFormat);
405        glyph->toMask(&srcM);
406        fRec.getMatrixFrom2x2(&matrix);
407
408        if (fMaskFilter->filterMask(&dstM, srcM, matrix, NULL)) {
409            int width = SkFastMin32(origGlyph.fWidth, dstM.fBounds.width());
410            int height = SkFastMin32(origGlyph.fHeight, dstM.fBounds.height());
411            int dstRB = origGlyph.rowBytes();
412            int srcRB = dstM.fRowBytes;
413
414            const uint8_t* src = (const uint8_t*)dstM.fImage;
415            uint8_t* dst = (uint8_t*)origGlyph.fImage;
416
417            if (SkMask::k3D_Format == dstM.fFormat) {
418                // we have to copy 3 times as much
419                height *= 3;
420            }
421
422            // clean out our glyph, since it may be larger than dstM
423            //sk_bzero(dst, height * dstRB);
424
425            while (--height >= 0) {
426                memcpy(dst, src, width);
427                src += srcRB;
428                dst += dstRB;
429            }
430            SkMask::FreeImage(dstM.fImage);
431        }
432    }
433
434    // check to see if we should filter the alpha channel
435
436    if (NULL == fMaskFilter &&
437        fRec.fMaskFormat != SkMask::kBW_Format &&
438        fRec.fMaskFormat != SkMask::kLCD16_Format &&
439        fRec.fMaskFormat != SkMask::kLCD32_Format &&
440        (fRec.fFlags & (kGammaForBlack_Flag | kGammaForWhite_Flag)) != 0)
441    {
442        const uint8_t* table = (fRec.fFlags & kGammaForBlack_Flag) ? gBlackGammaTable : gWhiteGammaTable;
443        if (NULL != table) {
444            uint8_t* dst = (uint8_t*)origGlyph.fImage;
445            unsigned rowBytes = origGlyph.rowBytes();
446
447            for (int y = origGlyph.fHeight - 1; y >= 0; --y) {
448                for (int x = origGlyph.fWidth - 1; x >= 0; --x) {
449                    dst[x] = table[dst[x]];
450                }
451                dst += rowBytes;
452            }
453        }
454    }
455}
456
457void SkScalerContext::getPath(const SkGlyph& glyph, SkPath* path) {
458    this->internalGetPath(glyph, NULL, path, NULL);
459}
460
461void SkScalerContext::getFontMetrics(SkPaint::FontMetrics* mx,
462                                     SkPaint::FontMetrics* my) {
463    this->generateFontMetrics(mx, my);
464}
465
466SkUnichar SkScalerContext::generateGlyphToChar(uint16_t glyph) {
467    return 0;
468}
469
470///////////////////////////////////////////////////////////////////////////////
471
472void SkScalerContext::internalGetPath(const SkGlyph& glyph, SkPath* fillPath,
473                                  SkPath* devPath, SkMatrix* fillToDevMatrix) {
474    SkPath  path;
475
476    this->getGlyphContext(glyph)->generatePath(glyph, &path);
477
478    if (fRec.fFrameWidth > 0 || fPathEffect != NULL) {
479        // need the path in user-space, with only the point-size applied
480        // so that our stroking and effects will operate the same way they
481        // would if the user had extracted the path themself, and then
482        // called drawPath
483        SkPath      localPath;
484        SkMatrix    matrix, inverse;
485
486        fRec.getMatrixFrom2x2(&matrix);
487        matrix.invert(&inverse);
488        path.transform(inverse, &localPath);
489        // now localPath is only affected by the paint settings, and not the canvas matrix
490
491        SkScalar width = fRec.fFrameWidth;
492
493        if (fPathEffect) {
494            SkPath effectPath;
495
496            if (fPathEffect->filterPath(&effectPath, localPath, &width)) {
497                localPath.swap(effectPath);
498            }
499        }
500
501        if (width > 0) {
502            SkStroke    stroker;
503            SkPath      outline;
504
505            stroker.setWidth(width);
506            stroker.setMiterLimit(fRec.fMiterLimit);
507            stroker.setJoin((SkPaint::Join)fRec.fStrokeJoin);
508            stroker.setDoFill(SkToBool(fRec.fFlags & kFrameAndFill_Flag));
509            stroker.strokePath(localPath, &outline);
510            localPath.swap(outline);
511        }
512
513        // now return stuff to the caller
514        if (fillToDevMatrix) {
515            *fillToDevMatrix = matrix;
516        }
517        if (devPath) {
518            localPath.transform(matrix, devPath);
519        }
520        if (fillPath) {
521            fillPath->swap(localPath);
522        }
523    } else {   // nothing tricky to do
524        if (fillToDevMatrix) {
525            fillToDevMatrix->reset();
526        }
527        if (devPath) {
528            if (fillPath == NULL) {
529                devPath->swap(path);
530            } else {
531                *devPath = path;
532            }
533        }
534
535        if (fillPath) {
536            fillPath->swap(path);
537        }
538    }
539
540    if (devPath) {
541        devPath->updateBoundsCache();
542    }
543    if (fillPath) {
544        fillPath->updateBoundsCache();
545    }
546}
547
548
549void SkScalerContext::Rec::getMatrixFrom2x2(SkMatrix* dst) const {
550    dst->reset();
551    dst->setScaleX(fPost2x2[0][0]);
552    dst->setSkewX( fPost2x2[0][1]);
553    dst->setSkewY( fPost2x2[1][0]);
554    dst->setScaleY(fPost2x2[1][1]);
555}
556
557void SkScalerContext::Rec::getLocalMatrix(SkMatrix* m) const {
558    m->setScale(SkScalarMul(fTextSize, fPreScaleX), fTextSize);
559    if (fPreSkewX) {
560        m->postSkew(fPreSkewX, 0);
561    }
562}
563
564void SkScalerContext::Rec::getSingleMatrix(SkMatrix* m) const {
565    this->getLocalMatrix(m);
566
567    //  now concat the device matrix
568    SkMatrix    deviceMatrix;
569    this->getMatrixFrom2x2(&deviceMatrix);
570    m->postConcat(deviceMatrix);
571}
572
573///////////////////////////////////////////////////////////////////////////////
574
575#include "SkFontHost.h"
576
577class SkScalerContext_Empty : public SkScalerContext {
578public:
579    SkScalerContext_Empty(const SkDescriptor* desc) : SkScalerContext(desc) {}
580
581protected:
582    virtual unsigned generateGlyphCount() {
583        return 0;
584    }
585    virtual uint16_t generateCharToGlyph(SkUnichar uni) {
586        return 0;
587    }
588    virtual void generateAdvance(SkGlyph* glyph) {
589        glyph->zeroMetrics();
590    }
591    virtual void generateMetrics(SkGlyph* glyph) {
592        glyph->zeroMetrics();
593    }
594    virtual void generateImage(const SkGlyph& glyph) {}
595    virtual void generatePath(const SkGlyph& glyph, SkPath* path) {}
596    virtual void generateFontMetrics(SkPaint::FontMetrics* mx,
597                                     SkPaint::FontMetrics* my) {
598        if (mx) {
599            sk_bzero(mx, sizeof(*mx));
600        }
601        if (my) {
602            sk_bzero(my, sizeof(*my));
603        }
604    }
605};
606
607extern SkScalerContext* SkCreateColorScalerContext(const SkDescriptor* desc);
608
609SkScalerContext* SkScalerContext::Create(const SkDescriptor* desc) {
610	SkScalerContext* c = NULL;  //SkCreateColorScalerContext(desc);
611	if (NULL == c) {
612		c = SkFontHost::CreateScalerContext(desc);
613	}
614    if (NULL == c) {
615        c = SkNEW_ARGS(SkScalerContext_Empty, (desc));
616    }
617    return c;
618}
619
620