SkScalerContext.cpp revision 8a1c16ff38322f0210116fa7293eb8817c7e477e
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 = 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
542