gfx/skia/trunk/src/core/SkScalerContext.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/skia/trunk/src/core/SkScalerContext.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,990 @@
     1.4 +
     1.5 +/*
     1.6 + * Copyright 2006 The Android Open Source Project
     1.7 + *
     1.8 + * Use of this source code is governed by a BSD-style license that can be
     1.9 + * found in the LICENSE file.
    1.10 + */
    1.11 +
    1.12 +
    1.13 +#include "SkScalerContext.h"
    1.14 +#include "SkColorPriv.h"
    1.15 +#include "SkDescriptor.h"
    1.16 +#include "SkDraw.h"
    1.17 +#include "SkFontHost.h"
    1.18 +#include "SkGlyph.h"
    1.19 +#include "SkMaskFilter.h"
    1.20 +#include "SkMaskGamma.h"
    1.21 +#include "SkReadBuffer.h"
    1.22 +#include "SkWriteBuffer.h"
    1.23 +#include "SkPathEffect.h"
    1.24 +#include "SkRasterizer.h"
    1.25 +#include "SkRasterClip.h"
    1.26 +#include "SkStroke.h"
    1.27 +#include "SkThread.h"
    1.28 +
    1.29 +#ifdef SK_BUILD_FOR_ANDROID
    1.30 +    #include "SkTypeface_android.h"
    1.31 +#endif
    1.32 +
    1.33 +#define ComputeBWRowBytes(width)        (((unsigned)(width) + 7) >> 3)
    1.34 +
    1.35 +void SkGlyph::toMask(SkMask* mask) const {
    1.36 +    SkASSERT(mask);
    1.37 +
    1.38 +    mask->fImage = (uint8_t*)fImage;
    1.39 +    mask->fBounds.set(fLeft, fTop, fLeft + fWidth, fTop + fHeight);
    1.40 +    mask->fRowBytes = this->rowBytes();
    1.41 +    mask->fFormat = static_cast<SkMask::Format>(fMaskFormat);
    1.42 +}
    1.43 +
    1.44 +size_t SkGlyph::computeImageSize() const {
    1.45 +    const size_t size = this->rowBytes() * fHeight;
    1.46 +
    1.47 +    switch (fMaskFormat) {
    1.48 +        case SkMask::k3D_Format:
    1.49 +            return 3 * size;
    1.50 +        default:
    1.51 +            return size;
    1.52 +    }
    1.53 +}
    1.54 +
    1.55 +void SkGlyph::zeroMetrics() {
    1.56 +    fAdvanceX = 0;
    1.57 +    fAdvanceY = 0;
    1.58 +    fWidth    = 0;
    1.59 +    fHeight   = 0;
    1.60 +    fTop      = 0;
    1.61 +    fLeft     = 0;
    1.62 +    fRsbDelta = 0;
    1.63 +    fLsbDelta = 0;
    1.64 +}
    1.65 +
    1.66 +///////////////////////////////////////////////////////////////////////////////
    1.67 +
    1.68 +#ifdef SK_DEBUG
    1.69 +    #define DUMP_RECx
    1.70 +#endif
    1.71 +
    1.72 +static SkFlattenable* load_flattenable(const SkDescriptor* desc, uint32_t tag,
    1.73 +                                       SkFlattenable::Type ft) {
    1.74 +    SkFlattenable*  obj = NULL;
    1.75 +    uint32_t        len;
    1.76 +    const void*     data = desc->findEntry(tag, &len);
    1.77 +
    1.78 +    if (data) {
    1.79 +        SkReadBuffer buffer(data, len);
    1.80 +        obj = buffer.readFlattenable(ft);
    1.81 +        SkASSERT(buffer.offset() == buffer.size());
    1.82 +    }
    1.83 +    return obj;
    1.84 +}
    1.85 +
    1.86 +SkScalerContext::SkScalerContext(SkTypeface* typeface, const SkDescriptor* desc)
    1.87 +    : fRec(*static_cast<const Rec*>(desc->findEntry(kRec_SkDescriptorTag, NULL)))
    1.88 +
    1.89 +    , fBaseGlyphCount(0)
    1.90 +    , fTypeface(SkRef(typeface))
    1.91 +    , fPathEffect(static_cast<SkPathEffect*>(load_flattenable(desc, kPathEffect_SkDescriptorTag,
    1.92 +                                             SkFlattenable::kSkPathEffect_Type)))
    1.93 +    , fMaskFilter(static_cast<SkMaskFilter*>(load_flattenable(desc, kMaskFilter_SkDescriptorTag,
    1.94 +                                             SkFlattenable::kSkMaskFilter_Type)))
    1.95 +    , fRasterizer(static_cast<SkRasterizer*>(load_flattenable(desc, kRasterizer_SkDescriptorTag,
    1.96 +                                             SkFlattenable::kSkRasterizer_Type)))
    1.97 +      // Initialize based on our settings. Subclasses can also force this.
    1.98 +    , fGenerateImageFromPath(fRec.fFrameWidth > 0 || fPathEffect != NULL || fRasterizer != NULL)
    1.99 +
   1.100 +    , fNextContext(NULL)
   1.101 +
   1.102 +    , fPreBlend(fMaskFilter ? SkMaskGamma::PreBlend() : SkScalerContext::GetMaskPreBlend(fRec))
   1.103 +    , fPreBlendForFilter(fMaskFilter ? SkScalerContext::GetMaskPreBlend(fRec)
   1.104 +                                     : SkMaskGamma::PreBlend())
   1.105 +{
   1.106 +#ifdef DUMP_REC
   1.107 +    desc->assertChecksum();
   1.108 +    SkDebugf("SkScalerContext checksum %x count %d length %d\n",
   1.109 +             desc->getChecksum(), desc->getCount(), desc->getLength());
   1.110 +    SkDebugf(" textsize %g prescale %g preskew %g post [%g %g %g %g]\n",
   1.111 +        rec->fTextSize, rec->fPreScaleX, rec->fPreSkewX, rec->fPost2x2[0][0],
   1.112 +        rec->fPost2x2[0][1], rec->fPost2x2[1][0], rec->fPost2x2[1][1]);
   1.113 +    SkDebugf("  frame %g miter %g hints %d framefill %d format %d join %d\n",
   1.114 +        rec->fFrameWidth, rec->fMiterLimit, rec->fHints, rec->fFrameAndFill,
   1.115 +        rec->fMaskFormat, rec->fStrokeJoin);
   1.116 +    SkDebugf("  pathEffect %x maskFilter %x\n",
   1.117 +             desc->findEntry(kPathEffect_SkDescriptorTag, NULL),
   1.118 +        desc->findEntry(kMaskFilter_SkDescriptorTag, NULL));
   1.119 +#endif
   1.120 +#ifdef SK_BUILD_FOR_ANDROID
   1.121 +    uint32_t len;
   1.122 +    const void* data = desc->findEntry(kAndroidOpts_SkDescriptorTag, &len);
   1.123 +    if (data) {
   1.124 +        SkReadBuffer buffer(data, len);
   1.125 +        fPaintOptionsAndroid.unflatten(buffer);
   1.126 +        SkASSERT(buffer.offset() == buffer.size());
   1.127 +    }
   1.128 +#endif
   1.129 +}
   1.130 +
   1.131 +SkScalerContext::~SkScalerContext() {
   1.132 +    SkDELETE(fNextContext);
   1.133 +
   1.134 +    SkSafeUnref(fPathEffect);
   1.135 +    SkSafeUnref(fMaskFilter);
   1.136 +    SkSafeUnref(fRasterizer);
   1.137 +}
   1.138 +
   1.139 +// Return the context associated with the next logical typeface, or NULL if
   1.140 +// there are no more entries in the fallback chain.
   1.141 +SkScalerContext* SkScalerContext::allocNextContext() const {
   1.142 +#ifdef SK_BUILD_FOR_ANDROID
   1.143 +    SkTypeface* newFace = SkAndroidNextLogicalTypeface(fRec.fFontID,
   1.144 +                                                       fRec.fOrigFontID,
   1.145 +                                                       fPaintOptionsAndroid);
   1.146 +    if (0 == newFace) {
   1.147 +        return NULL;
   1.148 +    }
   1.149 +
   1.150 +    SkAutoTUnref<SkTypeface> aur(newFace);
   1.151 +    uint32_t newFontID = newFace->uniqueID();
   1.152 +
   1.153 +    SkWriteBuffer androidBuffer;
   1.154 +    fPaintOptionsAndroid.flatten(androidBuffer);
   1.155 +
   1.156 +    SkAutoDescriptor    ad(sizeof(fRec) + androidBuffer.bytesWritten()
   1.157 +                           + SkDescriptor::ComputeOverhead(2));
   1.158 +    SkDescriptor*       desc = ad.getDesc();
   1.159 +
   1.160 +    desc->init();
   1.161 +    SkScalerContext::Rec* newRec =
   1.162 +    (SkScalerContext::Rec*)desc->addEntry(kRec_SkDescriptorTag,
   1.163 +                                          sizeof(fRec), &fRec);
   1.164 +    androidBuffer.writeToMemory(desc->addEntry(kAndroidOpts_SkDescriptorTag,
   1.165 +                                               androidBuffer.bytesWritten(), NULL));
   1.166 +
   1.167 +    newRec->fFontID = newFontID;
   1.168 +    desc->computeChecksum();
   1.169 +
   1.170 +    return newFace->createScalerContext(desc);
   1.171 +#else
   1.172 +    return NULL;
   1.173 +#endif
   1.174 +}
   1.175 +
   1.176 +/*  Return the next context, creating it if its not already created, but return
   1.177 +    NULL if the fonthost says there are no more fonts to fallback to.
   1.178 + */
   1.179 +SkScalerContext* SkScalerContext::getNextContext() {
   1.180 +    SkScalerContext* next = fNextContext;
   1.181 +    // if next is null, then either it isn't cached yet, or we're at the
   1.182 +    // end of our possible chain
   1.183 +    if (NULL == next) {
   1.184 +        next = this->allocNextContext();
   1.185 +        if (NULL == next) {
   1.186 +            return NULL;
   1.187 +        }
   1.188 +        // next's base is our base + our local count
   1.189 +        next->setBaseGlyphCount(fBaseGlyphCount + this->getGlyphCount());
   1.190 +        // cache the answer
   1.191 +        fNextContext = next;
   1.192 +    }
   1.193 +    return next;
   1.194 +}
   1.195 +
   1.196 +SkScalerContext* SkScalerContext::getGlyphContext(const SkGlyph& glyph) {
   1.197 +    unsigned glyphID = glyph.getGlyphID();
   1.198 +    SkScalerContext* ctx = this;
   1.199 +    for (;;) {
   1.200 +        unsigned count = ctx->getGlyphCount();
   1.201 +        if (glyphID < count) {
   1.202 +            break;
   1.203 +        }
   1.204 +        glyphID -= count;
   1.205 +        ctx = ctx->getNextContext();
   1.206 +        if (NULL == ctx) {
   1.207 +//            SkDebugf("--- no context for glyph %x\n", glyph.getGlyphID());
   1.208 +            // just return the original context (this)
   1.209 +            return this;
   1.210 +        }
   1.211 +    }
   1.212 +    return ctx;
   1.213 +}
   1.214 +
   1.215 +SkScalerContext* SkScalerContext::getContextFromChar(SkUnichar uni,
   1.216 +                                                     uint16_t* glyphID) {
   1.217 +    SkScalerContext* ctx = this;
   1.218 +    for (;;) {
   1.219 +        const uint16_t glyph = ctx->generateCharToGlyph(uni);
   1.220 +        if (glyph) {
   1.221 +            if (NULL != glyphID) {
   1.222 +                *glyphID = glyph;
   1.223 +            }
   1.224 +            break;  // found it
   1.225 +        }
   1.226 +        ctx = ctx->getNextContext();
   1.227 +        if (NULL == ctx) {
   1.228 +            return NULL;
   1.229 +        }
   1.230 +    }
   1.231 +    return ctx;
   1.232 +}
   1.233 +
   1.234 +#ifdef SK_BUILD_FOR_ANDROID
   1.235 +SkFontID SkScalerContext::findTypefaceIdForChar(SkUnichar uni) {
   1.236 +    SkScalerContext* ctx = this->getContextFromChar(uni, NULL);
   1.237 +    if (NULL != ctx) {
   1.238 +        return ctx->fRec.fFontID;
   1.239 +    } else {
   1.240 +        return 0;
   1.241 +    }
   1.242 +}
   1.243 +
   1.244 +/*  This loops through all available fallback contexts (if needed) until it
   1.245 +    finds some context that can handle the unichar and return it.
   1.246 +
   1.247 +    As this is somewhat expensive operation, it should only be done on the first
   1.248 +    char of a run.
   1.249 + */
   1.250 +unsigned SkScalerContext::getBaseGlyphCount(SkUnichar uni) {
   1.251 +    SkScalerContext* ctx = this->getContextFromChar(uni, NULL);
   1.252 +    if (NULL != ctx) {
   1.253 +        return ctx->fBaseGlyphCount;
   1.254 +    } else {
   1.255 +        SkDEBUGF(("--- no context for char %x\n", uni));
   1.256 +        return this->fBaseGlyphCount;
   1.257 +    }
   1.258 +}
   1.259 +#endif
   1.260 +
   1.261 +/*  This loops through all available fallback contexts (if needed) until it
   1.262 +    finds some context that can handle the unichar. If all fail, returns 0
   1.263 + */
   1.264 +uint16_t SkScalerContext::charToGlyphID(SkUnichar uni) {
   1.265 +
   1.266 +    uint16_t tempID;
   1.267 +    SkScalerContext* ctx = this->getContextFromChar(uni, &tempID);
   1.268 +    if (NULL == ctx) {
   1.269 +        return 0; // no more contexts, return missing glyph
   1.270 +    }
   1.271 +    // add the ctx's base, making glyphID unique for chain of contexts
   1.272 +    unsigned glyphID = tempID + ctx->fBaseGlyphCount;
   1.273 +    // check for overflow of 16bits, since our glyphID cannot exceed that
   1.274 +    if (glyphID > 0xFFFF) {
   1.275 +        glyphID = 0;
   1.276 +    }
   1.277 +    return SkToU16(glyphID);
   1.278 +}
   1.279 +
   1.280 +SkUnichar SkScalerContext::glyphIDToChar(uint16_t glyphID) {
   1.281 +    SkScalerContext* ctx = this;
   1.282 +    unsigned rangeEnd = 0;
   1.283 +    do {
   1.284 +        unsigned rangeStart = rangeEnd;
   1.285 +
   1.286 +        rangeEnd += ctx->getGlyphCount();
   1.287 +        if (rangeStart <= glyphID && glyphID < rangeEnd) {
   1.288 +            return ctx->generateGlyphToChar(glyphID - rangeStart);
   1.289 +        }
   1.290 +        ctx = ctx->getNextContext();
   1.291 +    } while (NULL != ctx);
   1.292 +    return 0;
   1.293 +}
   1.294 +
   1.295 +void SkScalerContext::getAdvance(SkGlyph* glyph) {
   1.296 +    // mark us as just having a valid advance
   1.297 +    glyph->fMaskFormat = MASK_FORMAT_JUST_ADVANCE;
   1.298 +    // we mark the format before making the call, in case the impl
   1.299 +    // internally ends up calling its generateMetrics, which is OK
   1.300 +    // albeit slower than strictly necessary
   1.301 +    this->getGlyphContext(*glyph)->generateAdvance(glyph);
   1.302 +}
   1.303 +
   1.304 +void SkScalerContext::getMetrics(SkGlyph* glyph) {
   1.305 +    this->getGlyphContext(*glyph)->generateMetrics(glyph);
   1.306 +
   1.307 +    // for now we have separate cache entries for devkerning on and off
   1.308 +    // in the future we might share caches, but make our measure/draw
   1.309 +    // code make the distinction. Thus we zap the values if the caller
   1.310 +    // has not asked for them.
   1.311 +    if ((fRec.fFlags & SkScalerContext::kDevKernText_Flag) == 0) {
   1.312 +        // no devkern, so zap the fields
   1.313 +        glyph->fLsbDelta = glyph->fRsbDelta = 0;
   1.314 +    }
   1.315 +
   1.316 +    // if either dimension is empty, zap the image bounds of the glyph
   1.317 +    if (0 == glyph->fWidth || 0 == glyph->fHeight) {
   1.318 +        glyph->fWidth   = 0;
   1.319 +        glyph->fHeight  = 0;
   1.320 +        glyph->fTop     = 0;
   1.321 +        glyph->fLeft    = 0;
   1.322 +        glyph->fMaskFormat = 0;
   1.323 +        return;
   1.324 +    }
   1.325 +
   1.326 +    if (fGenerateImageFromPath) {
   1.327 +        SkPath      devPath, fillPath;
   1.328 +        SkMatrix    fillToDevMatrix;
   1.329 +
   1.330 +        this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix);
   1.331 +
   1.332 +        if (fRasterizer) {
   1.333 +            SkMask  mask;
   1.334 +
   1.335 +            if (fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL,
   1.336 +                                       fMaskFilter, &mask,
   1.337 +                                       SkMask::kJustComputeBounds_CreateMode)) {
   1.338 +                glyph->fLeft    = mask.fBounds.fLeft;
   1.339 +                glyph->fTop     = mask.fBounds.fTop;
   1.340 +                glyph->fWidth   = SkToU16(mask.fBounds.width());
   1.341 +                glyph->fHeight  = SkToU16(mask.fBounds.height());
   1.342 +            } else {
   1.343 +                goto SK_ERROR;
   1.344 +            }
   1.345 +        } else {
   1.346 +            // just use devPath
   1.347 +            SkIRect ir;
   1.348 +            devPath.getBounds().roundOut(&ir);
   1.349 +
   1.350 +            if (ir.isEmpty() || !ir.is16Bit()) {
   1.351 +                goto SK_ERROR;
   1.352 +            }
   1.353 +            glyph->fLeft    = ir.fLeft;
   1.354 +            glyph->fTop     = ir.fTop;
   1.355 +            glyph->fWidth   = SkToU16(ir.width());
   1.356 +            glyph->fHeight  = SkToU16(ir.height());
   1.357 +
   1.358 +            if (glyph->fWidth > 0) {
   1.359 +                switch (fRec.fMaskFormat) {
   1.360 +                case SkMask::kLCD16_Format:
   1.361 +                case SkMask::kLCD32_Format:
   1.362 +                    glyph->fWidth += 2;
   1.363 +                    glyph->fLeft -= 1;
   1.364 +                    break;
   1.365 +                default:
   1.366 +                    break;
   1.367 +                }
   1.368 +            }
   1.369 +        }
   1.370 +    }
   1.371 +
   1.372 +    if (SkMask::kARGB32_Format != glyph->fMaskFormat) {
   1.373 +        glyph->fMaskFormat = fRec.fMaskFormat;
   1.374 +    }
   1.375 +
   1.376 +    // If we are going to create the mask, then we cannot keep the color
   1.377 +    if ((fGenerateImageFromPath || fMaskFilter) &&
   1.378 +            SkMask::kARGB32_Format == glyph->fMaskFormat) {
   1.379 +        glyph->fMaskFormat = SkMask::kA8_Format;
   1.380 +    }
   1.381 +
   1.382 +    if (fMaskFilter) {
   1.383 +        SkMask      src, dst;
   1.384 +        SkMatrix    matrix;
   1.385 +
   1.386 +        glyph->toMask(&src);
   1.387 +        fRec.getMatrixFrom2x2(&matrix);
   1.388 +
   1.389 +        src.fImage = NULL;  // only want the bounds from the filter
   1.390 +        if (fMaskFilter->filterMask(&dst, src, matrix, NULL)) {
   1.391 +            if (dst.fBounds.isEmpty() || !dst.fBounds.is16Bit()) {
   1.392 +                goto SK_ERROR;
   1.393 +            }
   1.394 +            SkASSERT(dst.fImage == NULL);
   1.395 +            glyph->fLeft    = dst.fBounds.fLeft;
   1.396 +            glyph->fTop     = dst.fBounds.fTop;
   1.397 +            glyph->fWidth   = SkToU16(dst.fBounds.width());
   1.398 +            glyph->fHeight  = SkToU16(dst.fBounds.height());
   1.399 +            glyph->fMaskFormat = dst.fFormat;
   1.400 +        }
   1.401 +    }
   1.402 +    return;
   1.403 +
   1.404 +SK_ERROR:
   1.405 +    // draw nothing 'cause we failed
   1.406 +    glyph->fLeft    = 0;
   1.407 +    glyph->fTop     = 0;
   1.408 +    glyph->fWidth   = 0;
   1.409 +    glyph->fHeight  = 0;
   1.410 +    // put a valid value here, in case it was earlier set to
   1.411 +    // MASK_FORMAT_JUST_ADVANCE
   1.412 +    glyph->fMaskFormat = fRec.fMaskFormat;
   1.413 +}
   1.414 +
   1.415 +#define SK_SHOW_TEXT_BLIT_COVERAGE 0
   1.416 +
   1.417 +static void applyLUTToA8Mask(const SkMask& mask, const uint8_t* lut) {
   1.418 +    uint8_t* SK_RESTRICT dst = (uint8_t*)mask.fImage;
   1.419 +    unsigned rowBytes = mask.fRowBytes;
   1.420 +
   1.421 +    for (int y = mask.fBounds.height() - 1; y >= 0; --y) {
   1.422 +        for (int x = mask.fBounds.width() - 1; x >= 0; --x) {
   1.423 +            dst[x] = lut[dst[x]];
   1.424 +        }
   1.425 +        dst += rowBytes;
   1.426 +    }
   1.427 +}
   1.428 +
   1.429 +template<bool APPLY_PREBLEND>
   1.430 +static void pack4xHToLCD16(const SkBitmap& src, const SkMask& dst,
   1.431 +                           const SkMaskGamma::PreBlend& maskPreBlend) {
   1.432 +#define SAMPLES_PER_PIXEL 4
   1.433 +#define LCD_PER_PIXEL 3
   1.434 +    SkASSERT(kAlpha_8_SkColorType == src.colorType());
   1.435 +    SkASSERT(SkMask::kLCD16_Format == dst.fFormat);
   1.436 +
   1.437 +    const int sample_width = src.width();
   1.438 +    const int height = src.height();
   1.439 +
   1.440 +    uint16_t* dstP = (uint16_t*)dst.fImage;
   1.441 +    size_t dstRB = dst.fRowBytes;
   1.442 +    // An N tap FIR is defined by
   1.443 +    // out[n] = coeff[0]*x[n] + coeff[1]*x[n-1] + ... + coeff[N]*x[n-N]
   1.444 +    // or
   1.445 +    // out[n] = sum(i, 0, N, coeff[i]*x[n-i])
   1.446 +
   1.447 +    // The strategy is to use one FIR (different coefficients) for each of r, g, and b.
   1.448 +    // This means using every 4th FIR output value of each FIR and discarding the rest.
   1.449 +    // The FIRs are aligned, and the coefficients reach 5 samples to each side of their 'center'.
   1.450 +    // (For r and b this is technically incorrect, but the coeffs outside round to zero anyway.)
   1.451 +
   1.452 +    // These are in some fixed point repesentation.
   1.453 +    // Adding up to more than one simulates ink spread.
   1.454 +    // For implementation reasons, these should never add up to more than two.
   1.455 +
   1.456 +    // Coefficients determined by a gausian where 5 samples = 3 std deviations (0x110 'contrast').
   1.457 +    // Calculated using tools/generate_fir_coeff.py
   1.458 +    // With this one almost no fringing is ever seen, but it is imperceptibly blurry.
   1.459 +    // The lcd smoothed text is almost imperceptibly different from gray,
   1.460 +    // but is still sharper on small stems and small rounded corners than gray.
   1.461 +    // This also seems to be about as wide as one can get and only have a three pixel kernel.
   1.462 +    // TODO: caculate these at runtime so parameters can be adjusted (esp contrast).
   1.463 +    static const unsigned int coefficients[LCD_PER_PIXEL][SAMPLES_PER_PIXEL*3] = {
   1.464 +        //The red subpixel is centered inside the first sample (at 1/6 pixel), and is shifted.
   1.465 +        { 0x03, 0x0b, 0x1c, 0x33,  0x40, 0x39, 0x24, 0x10,  0x05, 0x01, 0x00, 0x00, },
   1.466 +        //The green subpixel is centered between two samples (at 1/2 pixel), so is symetric
   1.467 +        { 0x00, 0x02, 0x08, 0x16,  0x2b, 0x3d, 0x3d, 0x2b,  0x16, 0x08, 0x02, 0x00, },
   1.468 +        //The blue subpixel is centered inside the last sample (at 5/6 pixel), and is shifted.
   1.469 +        { 0x00, 0x00, 0x01, 0x05,  0x10, 0x24, 0x39, 0x40,  0x33, 0x1c, 0x0b, 0x03, },
   1.470 +    };
   1.471 +
   1.472 +    for (int y = 0; y < height; ++y) {
   1.473 +        const uint8_t* srcP = src.getAddr8(0, y);
   1.474 +
   1.475 +        // TODO: this fir filter implementation is straight forward, but slow.
   1.476 +        // It should be possible to make it much faster.
   1.477 +        for (int sample_x = -4, pixel_x = 0; sample_x < sample_width + 4; sample_x += 4, ++pixel_x) {
   1.478 +            int fir[LCD_PER_PIXEL] = { 0 };
   1.479 +            for (int sample_index = SkMax32(0, sample_x - 4), coeff_index = sample_index - (sample_x - 4)
   1.480 +                ; sample_index < SkMin32(sample_x + 8, sample_width)
   1.481 +                ; ++sample_index, ++coeff_index)
   1.482 +            {
   1.483 +                int sample_value = srcP[sample_index];
   1.484 +                for (int subpxl_index = 0; subpxl_index < LCD_PER_PIXEL; ++subpxl_index) {
   1.485 +                    fir[subpxl_index] += coefficients[subpxl_index][coeff_index] * sample_value;
   1.486 +                }
   1.487 +            }
   1.488 +            for (int subpxl_index = 0; subpxl_index < LCD_PER_PIXEL; ++subpxl_index) {
   1.489 +                fir[subpxl_index] /= 0x100;
   1.490 +                fir[subpxl_index] = SkMin32(fir[subpxl_index], 255);
   1.491 +            }
   1.492 +
   1.493 +            U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(fir[0], maskPreBlend.fR);
   1.494 +            U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(fir[1], maskPreBlend.fG);
   1.495 +            U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(fir[2], maskPreBlend.fB);
   1.496 +#if SK_SHOW_TEXT_BLIT_COVERAGE
   1.497 +            r = SkMax32(r, 10); g = SkMax32(g, 10); b = SkMax32(b, 10);
   1.498 +#endif
   1.499 +            dstP[pixel_x] = SkPack888ToRGB16(r, g, b);
   1.500 +        }
   1.501 +        dstP = (uint16_t*)((char*)dstP + dstRB);
   1.502 +    }
   1.503 +}
   1.504 +
   1.505 +template<bool APPLY_PREBLEND>
   1.506 +static void pack4xHToLCD32(const SkBitmap& src, const SkMask& dst,
   1.507 +                           const SkMaskGamma::PreBlend& maskPreBlend) {
   1.508 +    SkASSERT(kAlpha_8_SkColorType == src.colorType());
   1.509 +    SkASSERT(SkMask::kLCD32_Format == dst.fFormat);
   1.510 +
   1.511 +    const int width = dst.fBounds.width();
   1.512 +    const int height = dst.fBounds.height();
   1.513 +    SkPMColor* dstP = (SkPMColor*)dst.fImage;
   1.514 +    size_t dstRB = dst.fRowBytes;
   1.515 +
   1.516 +    for (int y = 0; y < height; ++y) {
   1.517 +        const uint8_t* srcP = src.getAddr8(0, y);
   1.518 +
   1.519 +        // TODO: need to use fir filter here as well.
   1.520 +        for (int x = 0; x < width; ++x) {
   1.521 +            U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlend.fR);
   1.522 +            U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlend.fG);
   1.523 +            U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlend.fB);
   1.524 +            dstP[x] = SkPackARGB32(0xFF, r, g, b);
   1.525 +        }
   1.526 +        dstP = (SkPMColor*)((char*)dstP + dstRB);
   1.527 +    }
   1.528 +}
   1.529 +
   1.530 +static inline int convert_8_to_1(unsigned byte) {
   1.531 +    SkASSERT(byte <= 0xFF);
   1.532 +    return byte >> 7;
   1.533 +}
   1.534 +
   1.535 +static uint8_t pack_8_to_1(const uint8_t alpha[8]) {
   1.536 +    unsigned bits = 0;
   1.537 +    for (int i = 0; i < 8; ++i) {
   1.538 +        bits <<= 1;
   1.539 +        bits |= convert_8_to_1(alpha[i]);
   1.540 +    }
   1.541 +    return SkToU8(bits);
   1.542 +}
   1.543 +
   1.544 +static void packA8ToA1(const SkMask& mask, const uint8_t* src, size_t srcRB) {
   1.545 +    const int height = mask.fBounds.height();
   1.546 +    const int width = mask.fBounds.width();
   1.547 +    const int octs = width >> 3;
   1.548 +    const int leftOverBits = width & 7;
   1.549 +
   1.550 +    uint8_t* dst = mask.fImage;
   1.551 +    const int dstPad = mask.fRowBytes - SkAlign8(width)/8;
   1.552 +    SkASSERT(dstPad >= 0);
   1.553 +
   1.554 +    const int srcPad = srcRB - width;
   1.555 +    SkASSERT(srcPad >= 0);
   1.556 +
   1.557 +    for (int y = 0; y < height; ++y) {
   1.558 +        for (int i = 0; i < octs; ++i) {
   1.559 +            *dst++ = pack_8_to_1(src);
   1.560 +            src += 8;
   1.561 +        }
   1.562 +        if (leftOverBits > 0) {
   1.563 +            unsigned bits = 0;
   1.564 +            int shift = 7;
   1.565 +            for (int i = 0; i < leftOverBits; ++i, --shift) {
   1.566 +                bits |= convert_8_to_1(*src++) << shift;
   1.567 +            }
   1.568 +            *dst++ = bits;
   1.569 +        }
   1.570 +        src += srcPad;
   1.571 +        dst += dstPad;
   1.572 +    }
   1.573 +}
   1.574 +
   1.575 +static void generateMask(const SkMask& mask, const SkPath& path,
   1.576 +                         const SkMaskGamma::PreBlend& maskPreBlend) {
   1.577 +    SkPaint paint;
   1.578 +
   1.579 +    int srcW = mask.fBounds.width();
   1.580 +    int srcH = mask.fBounds.height();
   1.581 +    int dstW = srcW;
   1.582 +    int dstH = srcH;
   1.583 +    int dstRB = mask.fRowBytes;
   1.584 +
   1.585 +    SkMatrix matrix;
   1.586 +    matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft),
   1.587 +                        -SkIntToScalar(mask.fBounds.fTop));
   1.588 +
   1.589 +    SkBitmap::Config config = SkBitmap::kA8_Config;
   1.590 +    paint.setAntiAlias(SkMask::kBW_Format != mask.fFormat);
   1.591 +    switch (mask.fFormat) {
   1.592 +        case SkMask::kBW_Format:
   1.593 +            dstRB = 0;  // signals we need a copy
   1.594 +            break;
   1.595 +        case SkMask::kA8_Format:
   1.596 +            break;
   1.597 +        case SkMask::kLCD16_Format:
   1.598 +        case SkMask::kLCD32_Format:
   1.599 +            // TODO: trigger off LCD orientation
   1.600 +            dstW = 4*dstW - 8;
   1.601 +            matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft + 1),
   1.602 +                                -SkIntToScalar(mask.fBounds.fTop));
   1.603 +            matrix.postScale(SkIntToScalar(4), SK_Scalar1);
   1.604 +            dstRB = 0;  // signals we need a copy
   1.605 +            break;
   1.606 +        default:
   1.607 +            SkDEBUGFAIL("unexpected mask format");
   1.608 +    }
   1.609 +
   1.610 +    SkRasterClip clip;
   1.611 +    clip.setRect(SkIRect::MakeWH(dstW, dstH));
   1.612 +
   1.613 +    SkBitmap bm;
   1.614 +    bm.setConfig(config, dstW, dstH, dstRB);
   1.615 +
   1.616 +    if (0 == dstRB) {
   1.617 +        if (!bm.allocPixels()) {
   1.618 +            // can't allocate offscreen, so empty the mask and return
   1.619 +            sk_bzero(mask.fImage, mask.computeImageSize());
   1.620 +            return;
   1.621 +        }
   1.622 +        bm.lockPixels();
   1.623 +    } else {
   1.624 +        bm.setPixels(mask.fImage);
   1.625 +    }
   1.626 +    sk_bzero(bm.getPixels(), bm.getSafeSize());
   1.627 +
   1.628 +    SkDraw  draw;
   1.629 +    draw.fRC    = &clip;
   1.630 +    draw.fClip  = &clip.bwRgn();
   1.631 +    draw.fMatrix = &matrix;
   1.632 +    draw.fBitmap = &bm;
   1.633 +    draw.drawPath(path, paint);
   1.634 +
   1.635 +    switch (mask.fFormat) {
   1.636 +        case SkMask::kBW_Format:
   1.637 +            packA8ToA1(mask, bm.getAddr8(0, 0), bm.rowBytes());
   1.638 +            break;
   1.639 +        case SkMask::kA8_Format:
   1.640 +            if (maskPreBlend.isApplicable()) {
   1.641 +                applyLUTToA8Mask(mask, maskPreBlend.fG);
   1.642 +            }
   1.643 +            break;
   1.644 +        case SkMask::kLCD16_Format:
   1.645 +            if (maskPreBlend.isApplicable()) {
   1.646 +                pack4xHToLCD16<true>(bm, mask, maskPreBlend);
   1.647 +            } else {
   1.648 +                pack4xHToLCD16<false>(bm, mask, maskPreBlend);
   1.649 +            }
   1.650 +            break;
   1.651 +        case SkMask::kLCD32_Format:
   1.652 +            if (maskPreBlend.isApplicable()) {
   1.653 +                pack4xHToLCD32<true>(bm, mask, maskPreBlend);
   1.654 +            } else {
   1.655 +                pack4xHToLCD32<false>(bm, mask, maskPreBlend);
   1.656 +            }
   1.657 +            break;
   1.658 +        default:
   1.659 +            break;
   1.660 +    }
   1.661 +}
   1.662 +
   1.663 +static void extract_alpha(const SkMask& dst,
   1.664 +                          const SkPMColor* srcRow, size_t srcRB) {
   1.665 +    int width = dst.fBounds.width();
   1.666 +    int height = dst.fBounds.height();
   1.667 +    int dstRB = dst.fRowBytes;
   1.668 +    uint8_t* dstRow = dst.fImage;
   1.669 +
   1.670 +    for (int y = 0; y < height; ++y) {
   1.671 +        for (int x = 0; x < width; ++x) {
   1.672 +            dstRow[x] = SkGetPackedA32(srcRow[x]);
   1.673 +        }
   1.674 +        // zero any padding on each row
   1.675 +        for (int x = width; x < dstRB; ++x) {
   1.676 +            dstRow[x] = 0;
   1.677 +        }
   1.678 +        dstRow += dstRB;
   1.679 +        srcRow = (const SkPMColor*)((const char*)srcRow + srcRB);
   1.680 +    }
   1.681 +}
   1.682 +
   1.683 +void SkScalerContext::getImage(const SkGlyph& origGlyph) {
   1.684 +    const SkGlyph*  glyph = &origGlyph;
   1.685 +    SkGlyph         tmpGlyph;
   1.686 +
   1.687 +    // in case we need to call generateImage on a mask-format that is different
   1.688 +    // (i.e. larger) than what our caller allocated by looking at origGlyph.
   1.689 +    SkAutoMalloc tmpGlyphImageStorage;
   1.690 +
   1.691 +    // If we are going to draw-from-path, then we cannot generate color, since
   1.692 +    // the path only makes a mask. This case should have been caught up in
   1.693 +    // generateMetrics().
   1.694 +    SkASSERT(!fGenerateImageFromPath ||
   1.695 +             SkMask::kARGB32_Format != origGlyph.fMaskFormat);
   1.696 +
   1.697 +    if (fMaskFilter) {   // restore the prefilter bounds
   1.698 +        tmpGlyph.init(origGlyph.fID);
   1.699 +
   1.700 +        // need the original bounds, sans our maskfilter
   1.701 +        SkMaskFilter* mf = fMaskFilter;
   1.702 +        fMaskFilter = NULL;             // temp disable
   1.703 +        this->getMetrics(&tmpGlyph);
   1.704 +        fMaskFilter = mf;               // restore
   1.705 +
   1.706 +        // we need the prefilter bounds to be <= filter bounds
   1.707 +        SkASSERT(tmpGlyph.fWidth <= origGlyph.fWidth);
   1.708 +        SkASSERT(tmpGlyph.fHeight <= origGlyph.fHeight);
   1.709 +
   1.710 +        if (tmpGlyph.fMaskFormat == origGlyph.fMaskFormat) {
   1.711 +            tmpGlyph.fImage = origGlyph.fImage;
   1.712 +        } else {
   1.713 +            tmpGlyphImageStorage.reset(tmpGlyph.computeImageSize());
   1.714 +            tmpGlyph.fImage = tmpGlyphImageStorage.get();
   1.715 +        }
   1.716 +        glyph = &tmpGlyph;
   1.717 +    }
   1.718 +
   1.719 +    if (fGenerateImageFromPath) {
   1.720 +        SkPath      devPath, fillPath;
   1.721 +        SkMatrix    fillToDevMatrix;
   1.722 +        SkMask      mask;
   1.723 +
   1.724 +        this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix);
   1.725 +        glyph->toMask(&mask);
   1.726 +
   1.727 +        if (fRasterizer) {
   1.728 +            mask.fFormat = SkMask::kA8_Format;
   1.729 +            sk_bzero(glyph->fImage, mask.computeImageSize());
   1.730 +
   1.731 +            if (!fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL,
   1.732 +                                        fMaskFilter, &mask,
   1.733 +                                        SkMask::kJustRenderImage_CreateMode)) {
   1.734 +                return;
   1.735 +            }
   1.736 +            if (fPreBlend.isApplicable()) {
   1.737 +                applyLUTToA8Mask(mask, fPreBlend.fG);
   1.738 +            }
   1.739 +        } else {
   1.740 +            SkASSERT(SkMask::kARGB32_Format != mask.fFormat);
   1.741 +            generateMask(mask, devPath, fPreBlend);
   1.742 +        }
   1.743 +    } else {
   1.744 +        this->getGlyphContext(*glyph)->generateImage(*glyph);
   1.745 +    }
   1.746 +
   1.747 +    if (fMaskFilter) {
   1.748 +        SkMask      srcM, dstM;
   1.749 +        SkMatrix    matrix;
   1.750 +
   1.751 +        // the src glyph image shouldn't be 3D
   1.752 +        SkASSERT(SkMask::k3D_Format != glyph->fMaskFormat);
   1.753 +
   1.754 +        SkAutoSMalloc<32*32> a8storage;
   1.755 +        glyph->toMask(&srcM);
   1.756 +        if (SkMask::kARGB32_Format == srcM.fFormat) {
   1.757 +            // now we need to extract the alpha-channel from the glyph's image
   1.758 +            // and copy it into a temp buffer, and then point srcM at that temp.
   1.759 +            srcM.fFormat = SkMask::kA8_Format;
   1.760 +            srcM.fRowBytes = SkAlign4(srcM.fBounds.width());
   1.761 +            size_t size = srcM.computeImageSize();
   1.762 +            a8storage.reset(size);
   1.763 +            srcM.fImage = (uint8_t*)a8storage.get();
   1.764 +            extract_alpha(srcM,
   1.765 +                          (const SkPMColor*)glyph->fImage, glyph->rowBytes());
   1.766 +        }
   1.767 +
   1.768 +        fRec.getMatrixFrom2x2(&matrix);
   1.769 +
   1.770 +        if (fMaskFilter->filterMask(&dstM, srcM, matrix, NULL)) {
   1.771 +            int width = SkFastMin32(origGlyph.fWidth, dstM.fBounds.width());
   1.772 +            int height = SkFastMin32(origGlyph.fHeight, dstM.fBounds.height());
   1.773 +            int dstRB = origGlyph.rowBytes();
   1.774 +            int srcRB = dstM.fRowBytes;
   1.775 +
   1.776 +            const uint8_t* src = (const uint8_t*)dstM.fImage;
   1.777 +            uint8_t* dst = (uint8_t*)origGlyph.fImage;
   1.778 +
   1.779 +            if (SkMask::k3D_Format == dstM.fFormat) {
   1.780 +                // we have to copy 3 times as much
   1.781 +                height *= 3;
   1.782 +            }
   1.783 +
   1.784 +            // clean out our glyph, since it may be larger than dstM
   1.785 +            //sk_bzero(dst, height * dstRB);
   1.786 +
   1.787 +            while (--height >= 0) {
   1.788 +                memcpy(dst, src, width);
   1.789 +                src += srcRB;
   1.790 +                dst += dstRB;
   1.791 +            }
   1.792 +            SkMask::FreeImage(dstM.fImage);
   1.793 +
   1.794 +            if (fPreBlendForFilter.isApplicable()) {
   1.795 +                applyLUTToA8Mask(srcM, fPreBlendForFilter.fG);
   1.796 +            }
   1.797 +        }
   1.798 +    }
   1.799 +}
   1.800 +
   1.801 +void SkScalerContext::getPath(const SkGlyph& glyph, SkPath* path) {
   1.802 +    this->internalGetPath(glyph, NULL, path, NULL);
   1.803 +}
   1.804 +
   1.805 +void SkScalerContext::getFontMetrics(SkPaint::FontMetrics* fm) {
   1.806 +    // All of this complexity should go away when we change generateFontMetrics
   1.807 +    // to just take one parameter (since it knows if it is vertical or not)
   1.808 +    SkPaint::FontMetrics* mx = NULL;
   1.809 +    SkPaint::FontMetrics* my = NULL;
   1.810 +    if (fRec.fFlags & kVertical_Flag) {
   1.811 +        mx = fm;
   1.812 +    } else {
   1.813 +        my = fm;
   1.814 +    }
   1.815 +    this->generateFontMetrics(mx, my);
   1.816 +}
   1.817 +
   1.818 +SkUnichar SkScalerContext::generateGlyphToChar(uint16_t glyph) {
   1.819 +    return 0;
   1.820 +}
   1.821 +
   1.822 +///////////////////////////////////////////////////////////////////////////////
   1.823 +
   1.824 +void SkScalerContext::internalGetPath(const SkGlyph& glyph, SkPath* fillPath,
   1.825 +                                  SkPath* devPath, SkMatrix* fillToDevMatrix) {
   1.826 +    SkPath  path;
   1.827 +
   1.828 +    this->getGlyphContext(glyph)->generatePath(glyph, &path);
   1.829 +
   1.830 +    if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) {
   1.831 +        SkFixed dx = glyph.getSubXFixed();
   1.832 +        SkFixed dy = glyph.getSubYFixed();
   1.833 +        if (dx | dy) {
   1.834 +            path.offset(SkFixedToScalar(dx), SkFixedToScalar(dy));
   1.835 +        }
   1.836 +    }
   1.837 +
   1.838 +    if (fRec.fFrameWidth > 0 || fPathEffect != NULL) {
   1.839 +        // need the path in user-space, with only the point-size applied
   1.840 +        // so that our stroking and effects will operate the same way they
   1.841 +        // would if the user had extracted the path themself, and then
   1.842 +        // called drawPath
   1.843 +        SkPath      localPath;
   1.844 +        SkMatrix    matrix, inverse;
   1.845 +
   1.846 +        fRec.getMatrixFrom2x2(&matrix);
   1.847 +        if (!matrix.invert(&inverse)) {
   1.848 +            // assume fillPath and devPath are already empty.
   1.849 +            return;
   1.850 +        }
   1.851 +        path.transform(inverse, &localPath);
   1.852 +        // now localPath is only affected by the paint settings, and not the canvas matrix
   1.853 +
   1.854 +        SkStrokeRec rec(SkStrokeRec::kFill_InitStyle);
   1.855 +
   1.856 +        if (fRec.fFrameWidth > 0) {
   1.857 +            rec.setStrokeStyle(fRec.fFrameWidth,
   1.858 +                               SkToBool(fRec.fFlags & kFrameAndFill_Flag));
   1.859 +            // glyphs are always closed contours, so cap type is ignored,
   1.860 +            // so we just pass something.
   1.861 +            rec.setStrokeParams(SkPaint::kButt_Cap,
   1.862 +                                (SkPaint::Join)fRec.fStrokeJoin,
   1.863 +                                fRec.fMiterLimit);
   1.864 +        }
   1.865 +
   1.866 +        if (fPathEffect) {
   1.867 +            SkPath effectPath;
   1.868 +            if (fPathEffect->filterPath(&effectPath, localPath, &rec, NULL)) {
   1.869 +                localPath.swap(effectPath);
   1.870 +            }
   1.871 +        }
   1.872 +
   1.873 +        if (rec.needToApply()) {
   1.874 +            SkPath strokePath;
   1.875 +            if (rec.applyToPath(&strokePath, localPath)) {
   1.876 +                localPath.swap(strokePath);
   1.877 +            }
   1.878 +        }
   1.879 +
   1.880 +        // now return stuff to the caller
   1.881 +        if (fillToDevMatrix) {
   1.882 +            *fillToDevMatrix = matrix;
   1.883 +        }
   1.884 +        if (devPath) {
   1.885 +            localPath.transform(matrix, devPath);
   1.886 +        }
   1.887 +        if (fillPath) {
   1.888 +            fillPath->swap(localPath);
   1.889 +        }
   1.890 +    } else {   // nothing tricky to do
   1.891 +        if (fillToDevMatrix) {
   1.892 +            fillToDevMatrix->reset();
   1.893 +        }
   1.894 +        if (devPath) {
   1.895 +            if (fillPath == NULL) {
   1.896 +                devPath->swap(path);
   1.897 +            } else {
   1.898 +                *devPath = path;
   1.899 +            }
   1.900 +        }
   1.901 +
   1.902 +        if (fillPath) {
   1.903 +            fillPath->swap(path);
   1.904 +        }
   1.905 +    }
   1.906 +
   1.907 +    if (devPath) {
   1.908 +        devPath->updateBoundsCache();
   1.909 +    }
   1.910 +    if (fillPath) {
   1.911 +        fillPath->updateBoundsCache();
   1.912 +    }
   1.913 +}
   1.914 +
   1.915 +
   1.916 +void SkScalerContextRec::getMatrixFrom2x2(SkMatrix* dst) const {
   1.917 +    dst->setAll(fPost2x2[0][0], fPost2x2[0][1], 0,
   1.918 +                fPost2x2[1][0], fPost2x2[1][1], 0,
   1.919 +                0,              0,              SkScalarToPersp(SK_Scalar1));
   1.920 +}
   1.921 +
   1.922 +void SkScalerContextRec::getLocalMatrix(SkMatrix* m) const {
   1.923 +    SkPaint::SetTextMatrix(m, fTextSize, fPreScaleX, fPreSkewX);
   1.924 +}
   1.925 +
   1.926 +void SkScalerContextRec::getSingleMatrix(SkMatrix* m) const {
   1.927 +    this->getLocalMatrix(m);
   1.928 +
   1.929 +    //  now concat the device matrix
   1.930 +    SkMatrix    deviceMatrix;
   1.931 +    this->getMatrixFrom2x2(&deviceMatrix);
   1.932 +    m->postConcat(deviceMatrix);
   1.933 +}
   1.934 +
   1.935 +SkAxisAlignment SkComputeAxisAlignmentForHText(const SkMatrix& matrix) {
   1.936 +    SkASSERT(!matrix.hasPerspective());
   1.937 +
   1.938 +    if (0 == matrix[SkMatrix::kMSkewY]) {
   1.939 +        return kX_SkAxisAlignment;
   1.940 +    }
   1.941 +    if (0 == matrix[SkMatrix::kMScaleX]) {
   1.942 +        return kY_SkAxisAlignment;
   1.943 +    }
   1.944 +    return kNone_SkAxisAlignment;
   1.945 +}
   1.946 +
   1.947 +///////////////////////////////////////////////////////////////////////////////
   1.948 +
   1.949 +#include "SkFontHost.h"
   1.950 +
   1.951 +class SkScalerContext_Empty : public SkScalerContext {
   1.952 +public:
   1.953 +    SkScalerContext_Empty(SkTypeface* face, const SkDescriptor* desc)
   1.954 +        : SkScalerContext(face, desc) {}
   1.955 +
   1.956 +protected:
   1.957 +    virtual unsigned generateGlyphCount() SK_OVERRIDE {
   1.958 +        return 0;
   1.959 +    }
   1.960 +    virtual uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE {
   1.961 +        return 0;
   1.962 +    }
   1.963 +    virtual void generateAdvance(SkGlyph* glyph) SK_OVERRIDE {
   1.964 +        glyph->zeroMetrics();
   1.965 +    }
   1.966 +    virtual void generateMetrics(SkGlyph* glyph) SK_OVERRIDE {
   1.967 +        glyph->zeroMetrics();
   1.968 +    }
   1.969 +    virtual void generateImage(const SkGlyph& glyph) SK_OVERRIDE {}
   1.970 +    virtual void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE {}
   1.971 +    virtual void generateFontMetrics(SkPaint::FontMetrics* mx,
   1.972 +                                     SkPaint::FontMetrics* my) SK_OVERRIDE {
   1.973 +        if (mx) {
   1.974 +            sk_bzero(mx, sizeof(*mx));
   1.975 +        }
   1.976 +        if (my) {
   1.977 +            sk_bzero(my, sizeof(*my));
   1.978 +        }
   1.979 +    }
   1.980 +};
   1.981 +
   1.982 +extern SkScalerContext* SkCreateColorScalerContext(const SkDescriptor* desc);
   1.983 +
   1.984 +SkScalerContext* SkTypeface::createScalerContext(const SkDescriptor* desc,
   1.985 +                                                 bool allowFailure) const {
   1.986 +    SkScalerContext* c = this->onCreateScalerContext(desc);
   1.987 +
   1.988 +    if (!c && !allowFailure) {
   1.989 +        c = SkNEW_ARGS(SkScalerContext_Empty,
   1.990 +                       (const_cast<SkTypeface*>(this), desc));
   1.991 +    }
   1.992 +    return c;
   1.993 +}

mercurial