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 +}