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