SkScalerContext.cpp revision 29bf8625152c240311f851a8a0df3e543ed824c9
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 "SkGlyph.h"
16#include "SkMaskFilter.h"
17#include "SkMaskGamma.h"
18#include "SkOrderedReadBuffer.h"
19#include "SkOrderedWriteBuffer.h"
20#include "SkPathEffect.h"
21#include "SkRasterizer.h"
22#include "SkRasterClip.h"
23#include "SkStroke.h"
24#include "SkThread.h"
25
26#ifdef SK_BUILD_FOR_ANDROID
27    #include "SkTypeface_android.h"
28#endif
29
30#define ComputeBWRowBytes(width)        (((unsigned)(width) + 7) >> 3)
31
32void SkGlyph::toMask(SkMask* mask) const {
33    SkASSERT(mask);
34
35    mask->fImage = (uint8_t*)fImage;
36    mask->fBounds.set(fLeft, fTop, fLeft + fWidth, fTop + fHeight);
37    mask->fRowBytes = this->rowBytes();
38    mask->fFormat = static_cast<SkMask::Format>(fMaskFormat);
39}
40
41size_t SkGlyph::computeImageSize() const {
42    const size_t size = this->rowBytes() * fHeight;
43
44    switch (fMaskFormat) {
45        case SkMask::k3D_Format:
46            return 3 * size;
47        default:
48            return size;
49    }
50}
51
52void SkGlyph::zeroMetrics() {
53    fAdvanceX = 0;
54    fAdvanceY = 0;
55    fWidth    = 0;
56    fHeight   = 0;
57    fTop      = 0;
58    fLeft     = 0;
59    fRsbDelta = 0;
60    fLsbDelta = 0;
61}
62
63///////////////////////////////////////////////////////////////////////////////
64
65#ifdef SK_DEBUG
66    #define DUMP_RECx
67#endif
68
69static SkFlattenable* load_flattenable(const SkDescriptor* desc, uint32_t tag) {
70    SkFlattenable*  obj = NULL;
71    uint32_t        len;
72    const void*     data = desc->findEntry(tag, &len);
73
74    if (data) {
75        SkOrderedReadBuffer   buffer(data, len);
76        obj = buffer.readFlattenable();
77        SkASSERT(buffer.offset() == buffer.size());
78    }
79    return obj;
80}
81
82SkScalerContext::SkScalerContext(SkTypeface* typeface, const SkDescriptor* desc)
83    : fRec(*static_cast<const Rec*>(desc->findEntry(kRec_SkDescriptorTag, NULL)))
84
85    , fBaseGlyphCount(0)
86    , fTypeface(SkRef(typeface))
87    , fPathEffect(static_cast<SkPathEffect*>(load_flattenable(desc, kPathEffect_SkDescriptorTag)))
88    , fMaskFilter(static_cast<SkMaskFilter*>(load_flattenable(desc, kMaskFilter_SkDescriptorTag)))
89    , fRasterizer(static_cast<SkRasterizer*>(load_flattenable(desc, kRasterizer_SkDescriptorTag)))
90
91      // Initialize based on our settings. Subclasses can also force this.
92    , fGenerateImageFromPath(fRec.fFrameWidth > 0 || fPathEffect != NULL || fRasterizer != NULL)
93
94    , fNextContext(NULL)
95
96    , fPreBlend(fMaskFilter ? SkMaskGamma::PreBlend() : SkScalerContext::GetMaskPreBlend(fRec))
97    , fPreBlendForFilter(fMaskFilter ? SkScalerContext::GetMaskPreBlend(fRec)
98                                     : SkMaskGamma::PreBlend())
99{
100#ifdef DUMP_REC
101    desc->assertChecksum();
102    SkDebugf("SkScalarContext checksum %x count %d length %d\n",
103             desc->getChecksum(), desc->getCount(), desc->getLength());
104    SkDebugf(" textsize %g prescale %g preskew %g post [%g %g %g %g]\n",
105        rec->fTextSize, rec->fPreScaleX, rec->fPreSkewX, rec->fPost2x2[0][0],
106        rec->fPost2x2[0][1], rec->fPost2x2[1][0], rec->fPost2x2[1][1]);
107    SkDebugf("  frame %g miter %g hints %d framefill %d format %d join %d\n",
108        rec->fFrameWidth, rec->fMiterLimit, rec->fHints, rec->fFrameAndFill,
109        rec->fMaskFormat, rec->fStrokeJoin);
110    SkDebugf("  pathEffect %x maskFilter %x\n",
111             desc->findEntry(kPathEffect_SkDescriptorTag, NULL),
112        desc->findEntry(kMaskFilter_SkDescriptorTag, NULL));
113#endif
114#ifdef SK_BUILD_FOR_ANDROID
115    uint32_t len;
116    const void* data = desc->findEntry(kAndroidOpts_SkDescriptorTag, &len);
117    if (data) {
118        SkOrderedReadBuffer buffer(data, len);
119        fPaintOptionsAndroid.unflatten(buffer);
120        SkASSERT(buffer.offset() == buffer.size());
121    }
122#endif
123}
124
125SkScalerContext::~SkScalerContext() {
126    SkDELETE(fNextContext);
127
128    SkSafeUnref(fPathEffect);
129    SkSafeUnref(fMaskFilter);
130    SkSafeUnref(fRasterizer);
131}
132
133// Return the context associated with the next logical typeface, or NULL if
134// there are no more entries in the fallback chain.
135SkScalerContext* SkScalerContext::allocNextContext() const {
136#ifdef SK_BUILD_FOR_ANDROID
137    SkTypeface* newFace = SkAndroidNextLogicalTypeface(fRec.fFontID,
138                                                       fRec.fOrigFontID,
139                                                       fPaintOptionsAndroid);
140    if (0 == newFace) {
141        return NULL;
142    }
143
144    SkAutoTUnref<SkTypeface> aur(newFace);
145    uint32_t newFontID = newFace->uniqueID();
146
147    SkOrderedWriteBuffer androidBuffer(128);
148    fPaintOptionsAndroid.flatten(androidBuffer);
149
150    SkAutoDescriptor    ad(sizeof(fRec) + androidBuffer.size() + SkDescriptor::ComputeOverhead(2));
151    SkDescriptor*       desc = ad.getDesc();
152
153    desc->init();
154    SkScalerContext::Rec* newRec =
155    (SkScalerContext::Rec*)desc->addEntry(kRec_SkDescriptorTag,
156                                          sizeof(fRec), &fRec);
157    androidBuffer.writeToMemory(desc->addEntry(kAndroidOpts_SkDescriptorTag,
158                                               androidBuffer.size(), NULL));
159
160    newRec->fFontID = newFontID;
161    desc->computeChecksum();
162
163    return newFace->createScalerContext(desc);
164#else
165    return NULL;
166#endif
167}
168
169/*  Return the next context, creating it if its not already created, but return
170    NULL if the fonthost says there are no more fonts to fallback to.
171 */
172SkScalerContext* SkScalerContext::getNextContext() {
173    SkScalerContext* next = fNextContext;
174    // if next is null, then either it isn't cached yet, or we're at the
175    // end of our possible chain
176    if (NULL == next) {
177        next = this->allocNextContext();
178        if (NULL == next) {
179            return NULL;
180        }
181        // next's base is our base + our local count
182        next->setBaseGlyphCount(fBaseGlyphCount + this->getGlyphCount());
183        // cache the answer
184        fNextContext = next;
185    }
186    return next;
187}
188
189SkScalerContext* SkScalerContext::getGlyphContext(const SkGlyph& glyph) {
190    unsigned glyphID = glyph.getGlyphID();
191    SkScalerContext* ctx = this;
192    for (;;) {
193        unsigned count = ctx->getGlyphCount();
194        if (glyphID < count) {
195            break;
196        }
197        glyphID -= count;
198        ctx = ctx->getNextContext();
199        if (NULL == ctx) {
200//            SkDebugf("--- no context for glyph %x\n", glyph.getGlyphID());
201            // just return the original context (this)
202            return this;
203        }
204    }
205    return ctx;
206}
207
208SkScalerContext* SkScalerContext::getContextFromChar(SkUnichar uni,
209                                                     uint16_t* glyphID) {
210    SkScalerContext* ctx = this;
211    for (;;) {
212        const uint16_t glyph = ctx->generateCharToGlyph(uni);
213        if (glyph) {
214            if (NULL != glyphID) {
215                *glyphID = glyph;
216            }
217            break;  // found it
218        }
219        ctx = ctx->getNextContext();
220        if (NULL == ctx) {
221            return NULL;
222        }
223    }
224    return ctx;
225}
226
227#ifdef SK_BUILD_FOR_ANDROID
228SkFontID SkScalerContext::findTypefaceIdForChar(SkUnichar uni) {
229    SkScalerContext* ctx = this->getContextFromChar(uni, NULL);
230    if (NULL != ctx) {
231        return ctx->fRec.fFontID;
232    } else {
233        return 0;
234    }
235}
236
237/*  This loops through all available fallback contexts (if needed) until it
238    finds some context that can handle the unichar and return it.
239
240    As this is somewhat expensive operation, it should only be done on the first
241    char of a run.
242 */
243unsigned SkScalerContext::getBaseGlyphCount(SkUnichar uni) {
244    SkScalerContext* ctx = this->getContextFromChar(uni, NULL);
245    if (NULL != ctx) {
246        return ctx->fBaseGlyphCount;
247    } else {
248        SkDEBUGF(("--- no context for char %x\n", uni));
249        return this->fBaseGlyphCount;
250    }
251}
252#endif
253
254/*  This loops through all available fallback contexts (if needed) until it
255    finds some context that can handle the unichar. If all fail, returns 0
256 */
257uint16_t SkScalerContext::charToGlyphID(SkUnichar uni) {
258
259    uint16_t tempID;
260    SkScalerContext* ctx = this->getContextFromChar(uni, &tempID);
261    if (NULL == ctx) {
262        return 0; // no more contexts, return missing glyph
263    }
264    // add the ctx's base, making glyphID unique for chain of contexts
265    unsigned glyphID = tempID + ctx->fBaseGlyphCount;
266    // check for overflow of 16bits, since our glyphID cannot exceed that
267    if (glyphID > 0xFFFF) {
268        glyphID = 0;
269    }
270    return SkToU16(glyphID);
271}
272
273SkUnichar SkScalerContext::glyphIDToChar(uint16_t glyphID) {
274    SkScalerContext* ctx = this;
275    unsigned rangeEnd = 0;
276    do {
277        unsigned rangeStart = rangeEnd;
278
279        rangeEnd += ctx->getGlyphCount();
280        if (rangeStart <= glyphID && glyphID < rangeEnd) {
281            return ctx->generateGlyphToChar(glyphID - rangeStart);
282        }
283        ctx = ctx->getNextContext();
284    } while (NULL != ctx);
285    return 0;
286}
287
288void SkScalerContext::getAdvance(SkGlyph* glyph) {
289    // mark us as just having a valid advance
290    glyph->fMaskFormat = MASK_FORMAT_JUST_ADVANCE;
291    // we mark the format before making the call, in case the impl
292    // internally ends up calling its generateMetrics, which is OK
293    // albeit slower than strictly necessary
294    this->getGlyphContext(*glyph)->generateAdvance(glyph);
295}
296
297void SkScalerContext::getMetrics(SkGlyph* glyph) {
298    this->getGlyphContext(*glyph)->generateMetrics(glyph);
299
300    // for now we have separate cache entries for devkerning on and off
301    // in the future we might share caches, but make our measure/draw
302    // code make the distinction. Thus we zap the values if the caller
303    // has not asked for them.
304    if ((fRec.fFlags & SkScalerContext::kDevKernText_Flag) == 0) {
305        // no devkern, so zap the fields
306        glyph->fLsbDelta = glyph->fRsbDelta = 0;
307    }
308
309    // if either dimension is empty, zap the image bounds of the glyph
310    if (0 == glyph->fWidth || 0 == glyph->fHeight) {
311        glyph->fWidth   = 0;
312        glyph->fHeight  = 0;
313        glyph->fTop     = 0;
314        glyph->fLeft    = 0;
315        glyph->fMaskFormat = 0;
316        return;
317    }
318
319    if (fGenerateImageFromPath) {
320        SkPath      devPath, fillPath;
321        SkMatrix    fillToDevMatrix;
322
323        this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix);
324
325        if (fRasterizer) {
326            SkMask  mask;
327
328            if (fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL,
329                                       fMaskFilter, &mask,
330                                       SkMask::kJustComputeBounds_CreateMode)) {
331                glyph->fLeft    = mask.fBounds.fLeft;
332                glyph->fTop     = mask.fBounds.fTop;
333                glyph->fWidth   = SkToU16(mask.fBounds.width());
334                glyph->fHeight  = SkToU16(mask.fBounds.height());
335            } else {
336                goto SK_ERROR;
337            }
338        } else {
339            // just use devPath
340            SkIRect ir;
341            devPath.getBounds().roundOut(&ir);
342
343            if (ir.isEmpty() || !ir.is16Bit()) {
344                goto SK_ERROR;
345            }
346            glyph->fLeft    = ir.fLeft;
347            glyph->fTop     = ir.fTop;
348            glyph->fWidth   = SkToU16(ir.width());
349            glyph->fHeight  = SkToU16(ir.height());
350
351            if (glyph->fWidth > 0) {
352            switch (fRec.fMaskFormat) {
353            case SkMask::kLCD16_Format:
354            case SkMask::kLCD32_Format:
355                glyph->fWidth += 2;
356                glyph->fLeft -= 1;
357                break;
358            default:
359                break;
360            }
361    }
362        }
363    }
364
365    if (SkMask::kARGB32_Format != glyph->fMaskFormat) {
366        glyph->fMaskFormat = fRec.fMaskFormat;
367    }
368
369    // If we are going to create the mask, then we cannot keep the color
370    if ((fGenerateImageFromPath || fMaskFilter) &&
371            SkMask::kARGB32_Format == glyph->fMaskFormat) {
372        glyph->fMaskFormat = SkMask::kA8_Format;
373    }
374
375    if (fMaskFilter) {
376        SkMask      src, dst;
377        SkMatrix    matrix;
378
379        glyph->toMask(&src);
380        fRec.getMatrixFrom2x2(&matrix);
381
382        src.fImage = NULL;  // only want the bounds from the filter
383        if (fMaskFilter->filterMask(&dst, src, matrix, NULL)) {
384            if (dst.fBounds.isEmpty() || !dst.fBounds.is16Bit()) {
385                goto SK_ERROR;
386            }
387            SkASSERT(dst.fImage == NULL);
388            glyph->fLeft    = dst.fBounds.fLeft;
389            glyph->fTop     = dst.fBounds.fTop;
390            glyph->fWidth   = SkToU16(dst.fBounds.width());
391            glyph->fHeight  = SkToU16(dst.fBounds.height());
392            glyph->fMaskFormat = dst.fFormat;
393        }
394    }
395    return;
396
397SK_ERROR:
398    // draw nothing 'cause we failed
399    glyph->fLeft    = 0;
400    glyph->fTop     = 0;
401    glyph->fWidth   = 0;
402    glyph->fHeight  = 0;
403    // put a valid value here, in case it was earlier set to
404    // MASK_FORMAT_JUST_ADVANCE
405    glyph->fMaskFormat = fRec.fMaskFormat;
406}
407
408#define SK_SHOW_TEXT_BLIT_COVERAGE 0
409
410static void applyLUTToA8Mask(const SkMask& mask, const uint8_t* lut) {
411    uint8_t* SK_RESTRICT dst = (uint8_t*)mask.fImage;
412    unsigned rowBytes = mask.fRowBytes;
413
414    for (int y = mask.fBounds.height() - 1; y >= 0; --y) {
415        for (int x = mask.fBounds.width() - 1; x >= 0; --x) {
416            dst[x] = lut[dst[x]];
417        }
418        dst += rowBytes;
419    }
420}
421
422template<bool APPLY_PREBLEND>
423static void pack4xHToLCD16(const SkBitmap& src, const SkMask& dst,
424                           const SkMaskGamma::PreBlend& maskPreBlend) {
425#define SAMPLES_PER_PIXEL 4
426#define LCD_PER_PIXEL 3
427    SkASSERT(SkBitmap::kA8_Config == src.config());
428    SkASSERT(SkMask::kLCD16_Format == dst.fFormat);
429
430    const int sample_width = src.width();
431    const int height = src.height();
432
433    uint16_t* dstP = (uint16_t*)dst.fImage;
434    size_t dstRB = dst.fRowBytes;
435    // An N tap FIR is defined by
436    // out[n] = coeff[0]*x[n] + coeff[1]*x[n-1] + ... + coeff[N]*x[n-N]
437    // or
438    // out[n] = sum(i, 0, N, coeff[i]*x[n-i])
439
440    // The strategy is to use one FIR (different coefficients) for each of r, g, and b.
441    // This means using every 4th FIR output value of each FIR and discarding the rest.
442    // The FIRs are aligned, and the coefficients reach 5 samples to each side of their 'center'.
443    // (For r and b this is technically incorrect, but the coeffs outside round to zero anyway.)
444
445    // These are in some fixed point repesentation.
446    // Adding up to more than one simulates ink spread.
447    // For implementation reasons, these should never add up to more than two.
448
449    // Coefficients determined by a gausian where 5 samples = 3 std deviations (0x110 'contrast').
450    // Calculated using tools/generate_fir_coeff.py
451    // With this one almost no fringing is ever seen, but it is imperceptibly blurry.
452    // The lcd smoothed text is almost imperceptibly different from gray,
453    // but is still sharper on small stems and small rounded corners than gray.
454    // This also seems to be about as wide as one can get and only have a three pixel kernel.
455    // TODO: caculate these at runtime so parameters can be adjusted (esp contrast).
456    static const unsigned int coefficients[LCD_PER_PIXEL][SAMPLES_PER_PIXEL*3] = {
457        //The red subpixel is centered inside the first sample (at 1/6 pixel), and is shifted.
458        { 0x03, 0x0b, 0x1c, 0x33,  0x40, 0x39, 0x24, 0x10,  0x05, 0x01, 0x00, 0x00, },
459        //The green subpixel is centered between two samples (at 1/2 pixel), so is symetric
460        { 0x00, 0x02, 0x08, 0x16,  0x2b, 0x3d, 0x3d, 0x2b,  0x16, 0x08, 0x02, 0x00, },
461        //The blue subpixel is centered inside the last sample (at 5/6 pixel), and is shifted.
462        { 0x00, 0x00, 0x01, 0x05,  0x10, 0x24, 0x39, 0x40,  0x33, 0x1c, 0x0b, 0x03, },
463    };
464
465    for (int y = 0; y < height; ++y) {
466        const uint8_t* srcP = src.getAddr8(0, y);
467
468        // TODO: this fir filter implementation is straight forward, but slow.
469        // It should be possible to make it much faster.
470        for (int sample_x = -4, pixel_x = 0; sample_x < sample_width + 4; sample_x += 4, ++pixel_x) {
471            int fir[LCD_PER_PIXEL] = { 0 };
472            for (int sample_index = SkMax32(0, sample_x - 4), coeff_index = sample_index - (sample_x - 4)
473                ; sample_index < SkMin32(sample_x + 8, sample_width)
474                ; ++sample_index, ++coeff_index)
475            {
476                int sample_value = srcP[sample_index];
477                for (int subpxl_index = 0; subpxl_index < LCD_PER_PIXEL; ++subpxl_index) {
478                    fir[subpxl_index] += coefficients[subpxl_index][coeff_index] * sample_value;
479                }
480            }
481            for (int subpxl_index = 0; subpxl_index < LCD_PER_PIXEL; ++subpxl_index) {
482                fir[subpxl_index] /= 0x100;
483                fir[subpxl_index] = SkMin32(fir[subpxl_index], 255);
484            }
485
486            U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(fir[0], maskPreBlend.fR);
487            U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(fir[1], maskPreBlend.fG);
488            U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(fir[2], maskPreBlend.fB);
489#if SK_SHOW_TEXT_BLIT_COVERAGE
490            r = SkMax32(r, 10); g = SkMax32(g, 10); b = SkMax32(b, 10);
491#endif
492            dstP[pixel_x] = SkPack888ToRGB16(r, g, b);
493        }
494        dstP = (uint16_t*)((char*)dstP + dstRB);
495    }
496}
497
498template<bool APPLY_PREBLEND>
499static void pack4xHToLCD32(const SkBitmap& src, const SkMask& dst,
500                           const SkMaskGamma::PreBlend& maskPreBlend) {
501    SkASSERT(SkBitmap::kA8_Config == src.config());
502    SkASSERT(SkMask::kLCD32_Format == dst.fFormat);
503
504    const int width = dst.fBounds.width();
505    const int height = dst.fBounds.height();
506    SkPMColor* dstP = (SkPMColor*)dst.fImage;
507    size_t dstRB = dst.fRowBytes;
508
509    for (int y = 0; y < height; ++y) {
510        const uint8_t* srcP = src.getAddr8(0, y);
511
512        // TODO: need to use fir filter here as well.
513        for (int x = 0; x < width; ++x) {
514            U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlend.fR);
515            U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlend.fG);
516            U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlend.fB);
517            dstP[x] = SkPackARGB32(0xFF, r, g, b);
518        }
519        dstP = (SkPMColor*)((char*)dstP + dstRB);
520    }
521}
522
523static void generateMask(const SkMask& mask, const SkPath& path,
524                         const SkMaskGamma::PreBlend& maskPreBlend) {
525    SkBitmap::Config config;
526    SkPaint     paint;
527
528    int srcW = mask.fBounds.width();
529    int srcH = mask.fBounds.height();
530    int dstW = srcW;
531    int dstH = srcH;
532    int dstRB = mask.fRowBytes;
533
534    SkMatrix matrix;
535    matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft),
536                        -SkIntToScalar(mask.fBounds.fTop));
537
538    if (SkMask::kBW_Format == mask.fFormat) {
539        config = SkBitmap::kA1_Config;
540        paint.setAntiAlias(false);
541    } else {
542        config = SkBitmap::kA8_Config;
543        paint.setAntiAlias(true);
544        switch (mask.fFormat) {
545            case SkMask::kA8_Format:
546                break;
547            case SkMask::kLCD16_Format:
548            case SkMask::kLCD32_Format:
549                // TODO: trigger off LCD orientation
550                dstW = 4*dstW - 8;
551                matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft + 1),
552                                    -SkIntToScalar(mask.fBounds.fTop));
553                matrix.postScale(SkIntToScalar(4), SK_Scalar1);
554                dstRB = 0;  // signals we need a copy
555                break;
556            default:
557                SkDEBUGFAIL("unexpected mask format");
558        }
559    }
560
561    SkRasterClip clip;
562    clip.setRect(SkIRect::MakeWH(dstW, dstH));
563
564    SkBitmap bm;
565    bm.setConfig(config, dstW, dstH, dstRB);
566
567    if (0 == dstRB) {
568        if (!bm.allocPixels()) {
569            // can't allocate offscreen, so empty the mask and return
570            sk_bzero(mask.fImage, mask.computeImageSize());
571            return;
572        }
573        bm.lockPixels();
574    } else {
575        bm.setPixels(mask.fImage);
576    }
577    sk_bzero(bm.getPixels(), bm.getSafeSize());
578
579    SkDraw  draw;
580    draw.fRC    = &clip;
581    draw.fClip  = &clip.bwRgn();
582    draw.fMatrix = &matrix;
583    draw.fBitmap = &bm;
584    draw.drawPath(path, paint);
585
586    switch (mask.fFormat) {
587        case SkMask::kA8_Format:
588            if (maskPreBlend.isApplicable()) {
589                applyLUTToA8Mask(mask, maskPreBlend.fG);
590            }
591            break;
592        case SkMask::kLCD16_Format:
593            if (maskPreBlend.isApplicable()) {
594                pack4xHToLCD16<true>(bm, mask, maskPreBlend);
595            } else {
596                pack4xHToLCD16<false>(bm, mask, maskPreBlend);
597            }
598            break;
599        case SkMask::kLCD32_Format:
600            if (maskPreBlend.isApplicable()) {
601                pack4xHToLCD32<true>(bm, mask, maskPreBlend);
602            } else {
603                pack4xHToLCD32<false>(bm, mask, maskPreBlend);
604            }
605            break;
606        default:
607            break;
608    }
609}
610
611static void extract_alpha(const SkMask& dst,
612                          const SkPMColor* srcRow, size_t srcRB) {
613    int width = dst.fBounds.width();
614    int height = dst.fBounds.height();
615    int dstRB = dst.fRowBytes;
616    uint8_t* dstRow = dst.fImage;
617
618    for (int y = 0; y < height; ++y) {
619        for (int x = 0; x < width; ++x) {
620            dstRow[x] = SkGetPackedA32(srcRow[x]);
621        }
622        // zero any padding on each row
623        for (int x = width; x < dstRB; ++x) {
624            dstRow[x] = 0;
625        }
626        dstRow += dstRB;
627        srcRow = (const SkPMColor*)((const char*)srcRow + srcRB);
628    }
629}
630
631void SkScalerContext::getImage(const SkGlyph& origGlyph) {
632    const SkGlyph*  glyph = &origGlyph;
633    SkGlyph         tmpGlyph;
634
635    // in case we need to call generateImage on a mask-format that is different
636    // (i.e. larger) than what our caller allocated by looking at origGlyph.
637    SkAutoMalloc tmpGlyphImageStorage;
638
639    // If we are going to draw-from-path, then we cannot generate color, since
640    // the path only makes a mask. This case should have been caught up in
641    // generateMetrics().
642    SkASSERT(!fGenerateImageFromPath ||
643             SkMask::kARGB32_Format != origGlyph.fMaskFormat);
644
645    if (fMaskFilter) {   // restore the prefilter bounds
646        tmpGlyph.init(origGlyph.fID);
647
648        // need the original bounds, sans our maskfilter
649        SkMaskFilter* mf = fMaskFilter;
650        fMaskFilter = NULL;             // temp disable
651        this->getMetrics(&tmpGlyph);
652        fMaskFilter = mf;               // restore
653
654        // we need the prefilter bounds to be <= filter bounds
655        SkASSERT(tmpGlyph.fWidth <= origGlyph.fWidth);
656        SkASSERT(tmpGlyph.fHeight <= origGlyph.fHeight);
657
658        if (tmpGlyph.fMaskFormat == origGlyph.fMaskFormat) {
659            tmpGlyph.fImage = origGlyph.fImage;
660        } else {
661            tmpGlyphImageStorage.reset(tmpGlyph.computeImageSize());
662            tmpGlyph.fImage = tmpGlyphImageStorage.get();
663        }
664        glyph = &tmpGlyph;
665    }
666
667    if (fGenerateImageFromPath) {
668        SkPath      devPath, fillPath;
669        SkMatrix    fillToDevMatrix;
670        SkMask      mask;
671
672        this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix);
673        glyph->toMask(&mask);
674
675        if (fRasterizer) {
676            mask.fFormat = SkMask::kA8_Format;
677            sk_bzero(glyph->fImage, mask.computeImageSize());
678
679            if (!fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL,
680                                        fMaskFilter, &mask,
681                                        SkMask::kJustRenderImage_CreateMode)) {
682                return;
683            }
684            if (fPreBlend.isApplicable()) {
685                applyLUTToA8Mask(mask, fPreBlend.fG);
686            }
687        } else {
688            SkASSERT(SkMask::kARGB32_Format != mask.fFormat);
689            generateMask(mask, devPath, fPreBlend);
690        }
691    } else {
692        this->getGlyphContext(*glyph)->generateImage(*glyph);
693    }
694
695    if (fMaskFilter) {
696        SkMask      srcM, dstM;
697        SkMatrix    matrix;
698
699        // the src glyph image shouldn't be 3D
700        SkASSERT(SkMask::k3D_Format != glyph->fMaskFormat);
701
702        SkAutoSMalloc<32*32> a8storage;
703        glyph->toMask(&srcM);
704        if (SkMask::kARGB32_Format == srcM.fFormat) {
705            // now we need to extract the alpha-channel from the glyph's image
706            // and copy it into a temp buffer, and then point srcM at that temp.
707            srcM.fFormat = SkMask::kA8_Format;
708            srcM.fRowBytes = SkAlign4(srcM.fBounds.width());
709            size_t size = srcM.computeImageSize();
710            a8storage.reset(size);
711            srcM.fImage = (uint8_t*)a8storage.get();
712            extract_alpha(srcM,
713                          (const SkPMColor*)glyph->fImage, glyph->rowBytes());
714        }
715
716        fRec.getMatrixFrom2x2(&matrix);
717
718        if (fMaskFilter->filterMask(&dstM, srcM, matrix, NULL)) {
719            int width = SkFastMin32(origGlyph.fWidth, dstM.fBounds.width());
720            int height = SkFastMin32(origGlyph.fHeight, dstM.fBounds.height());
721            int dstRB = origGlyph.rowBytes();
722            int srcRB = dstM.fRowBytes;
723
724            const uint8_t* src = (const uint8_t*)dstM.fImage;
725            uint8_t* dst = (uint8_t*)origGlyph.fImage;
726
727            if (SkMask::k3D_Format == dstM.fFormat) {
728                // we have to copy 3 times as much
729                height *= 3;
730            }
731
732            // clean out our glyph, since it may be larger than dstM
733            //sk_bzero(dst, height * dstRB);
734
735            while (--height >= 0) {
736                memcpy(dst, src, width);
737                src += srcRB;
738                dst += dstRB;
739            }
740            SkMask::FreeImage(dstM.fImage);
741
742            if (fPreBlendForFilter.isApplicable()) {
743                applyLUTToA8Mask(srcM, fPreBlendForFilter.fG);
744            }
745        }
746    }
747}
748
749void SkScalerContext::getPath(const SkGlyph& glyph, SkPath* path) {
750    this->internalGetPath(glyph, NULL, path, NULL);
751}
752
753void SkScalerContext::getFontMetrics(SkPaint::FontMetrics* fm) {
754    // All of this complexity should go away when we change generateFontMetrics
755    // to just take one parameter (since it knows if it is vertical or not)
756    SkPaint::FontMetrics* mx = NULL;
757    SkPaint::FontMetrics* my = NULL;
758    if (fRec.fFlags & kVertical_Flag) {
759        mx = fm;
760    } else {
761        my = fm;
762    }
763    this->generateFontMetrics(mx, my);
764}
765
766SkUnichar SkScalerContext::generateGlyphToChar(uint16_t glyph) {
767    return 0;
768}
769
770///////////////////////////////////////////////////////////////////////////////
771
772void SkScalerContext::internalGetPath(const SkGlyph& glyph, SkPath* fillPath,
773                                  SkPath* devPath, SkMatrix* fillToDevMatrix) {
774    SkPath  path;
775
776    this->getGlyphContext(glyph)->generatePath(glyph, &path);
777
778    if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) {
779        SkFixed dx = glyph.getSubXFixed();
780        SkFixed dy = glyph.getSubYFixed();
781        if (dx | dy) {
782            path.offset(SkFixedToScalar(dx), SkFixedToScalar(dy));
783        }
784    }
785
786    if (fRec.fFrameWidth > 0 || fPathEffect != NULL) {
787        // need the path in user-space, with only the point-size applied
788        // so that our stroking and effects will operate the same way they
789        // would if the user had extracted the path themself, and then
790        // called drawPath
791        SkPath      localPath;
792        SkMatrix    matrix, inverse;
793
794        fRec.getMatrixFrom2x2(&matrix);
795        if (!matrix.invert(&inverse)) {
796            // assume fillPath and devPath are already empty.
797            return;
798        }
799        path.transform(inverse, &localPath);
800        // now localPath is only affected by the paint settings, and not the canvas matrix
801
802        SkStrokeRec rec(SkStrokeRec::kFill_InitStyle);
803
804        if (fRec.fFrameWidth > 0) {
805            rec.setStrokeStyle(fRec.fFrameWidth,
806                               SkToBool(fRec.fFlags & kFrameAndFill_Flag));
807            // glyphs are always closed contours, so cap type is ignored,
808            // so we just pass something.
809            rec.setStrokeParams(SkPaint::kButt_Cap,
810                                (SkPaint::Join)fRec.fStrokeJoin,
811                                fRec.fMiterLimit);
812        }
813
814        if (fPathEffect) {
815            SkPath effectPath;
816            if (fPathEffect->filterPath(&effectPath, localPath, &rec, NULL)) {
817                localPath.swap(effectPath);
818            }
819        }
820
821        if (rec.needToApply()) {
822            SkPath strokePath;
823            if (rec.applyToPath(&strokePath, localPath)) {
824                localPath.swap(strokePath);
825            }
826        }
827
828        // now return stuff to the caller
829        if (fillToDevMatrix) {
830            *fillToDevMatrix = matrix;
831        }
832        if (devPath) {
833            localPath.transform(matrix, devPath);
834        }
835        if (fillPath) {
836            fillPath->swap(localPath);
837        }
838    } else {   // nothing tricky to do
839        if (fillToDevMatrix) {
840            fillToDevMatrix->reset();
841        }
842        if (devPath) {
843            if (fillPath == NULL) {
844                devPath->swap(path);
845            } else {
846                *devPath = path;
847            }
848        }
849
850        if (fillPath) {
851            fillPath->swap(path);
852        }
853    }
854
855    if (devPath) {
856        devPath->updateBoundsCache();
857    }
858    if (fillPath) {
859        fillPath->updateBoundsCache();
860    }
861}
862
863
864void SkScalerContextRec::getMatrixFrom2x2(SkMatrix* dst) const {
865    dst->setAll(fPost2x2[0][0], fPost2x2[0][1], 0,
866                fPost2x2[1][0], fPost2x2[1][1], 0,
867                0,              0,              SkScalarToPersp(SK_Scalar1));
868}
869
870void SkScalerContextRec::getLocalMatrix(SkMatrix* m) const {
871    SkPaint::SetTextMatrix(m, fTextSize, fPreScaleX, fPreSkewX);
872}
873
874void SkScalerContextRec::getSingleMatrix(SkMatrix* m) const {
875    this->getLocalMatrix(m);
876
877    //  now concat the device matrix
878    SkMatrix    deviceMatrix;
879    this->getMatrixFrom2x2(&deviceMatrix);
880    m->postConcat(deviceMatrix);
881}
882
883SkAxisAlignment SkComputeAxisAlignmentForHText(const SkMatrix& matrix) {
884    SkASSERT(!matrix.hasPerspective());
885
886    if (0 == matrix[SkMatrix::kMSkewY]) {
887        return kX_SkAxisAlignment;
888    }
889    if (0 == matrix[SkMatrix::kMScaleX]) {
890        return kY_SkAxisAlignment;
891    }
892    return kNone_SkAxisAlignment;
893}
894
895///////////////////////////////////////////////////////////////////////////////
896
897#include "SkFontHost.h"
898
899class SkScalerContext_Empty : public SkScalerContext {
900public:
901    SkScalerContext_Empty(SkTypeface* face, const SkDescriptor* desc)
902        : SkScalerContext(face, desc) {}
903
904protected:
905    virtual unsigned generateGlyphCount() SK_OVERRIDE {
906        return 0;
907    }
908    virtual uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE {
909        return 0;
910    }
911    virtual void generateAdvance(SkGlyph* glyph) SK_OVERRIDE {
912        glyph->zeroMetrics();
913    }
914    virtual void generateMetrics(SkGlyph* glyph) SK_OVERRIDE {
915        glyph->zeroMetrics();
916    }
917    virtual void generateImage(const SkGlyph& glyph) SK_OVERRIDE {}
918    virtual void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE {}
919    virtual void generateFontMetrics(SkPaint::FontMetrics* mx,
920                                     SkPaint::FontMetrics* my) SK_OVERRIDE {
921        if (mx) {
922            sk_bzero(mx, sizeof(*mx));
923        }
924        if (my) {
925            sk_bzero(my, sizeof(*my));
926        }
927    }
928};
929
930extern SkScalerContext* SkCreateColorScalerContext(const SkDescriptor* desc);
931
932SkScalerContext* SkTypeface::createScalerContext(const SkDescriptor* desc,
933                                                 bool allowFailure) const {
934    SkScalerContext* c = this->onCreateScalerContext(desc);
935
936    if (!c && !allowFailure) {
937        c = SkNEW_ARGS(SkScalerContext_Empty,
938                       (const_cast<SkTypeface*>(this), desc));
939    }
940    return c;
941}
942