1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2006 The Android Open Source Project 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "include/core/SkPaint.h" 9cb93a386Sopenharmony_ci#include "src/core/SkScalerContext.h" 10cb93a386Sopenharmony_ci 11cb93a386Sopenharmony_ci#include "include/core/SkFontMetrics.h" 12cb93a386Sopenharmony_ci#include "include/core/SkMaskFilter.h" 13cb93a386Sopenharmony_ci#include "include/core/SkPathEffect.h" 14cb93a386Sopenharmony_ci#include "include/core/SkStrokeRec.h" 15cb93a386Sopenharmony_ci#include "include/private/SkColorData.h" 16cb93a386Sopenharmony_ci#include "include/private/SkTo.h" 17cb93a386Sopenharmony_ci#include "src/core/SkAutoMalloc.h" 18cb93a386Sopenharmony_ci#include "src/core/SkAutoPixmapStorage.h" 19cb93a386Sopenharmony_ci#include "src/core/SkDescriptor.h" 20cb93a386Sopenharmony_ci#include "src/core/SkDraw.h" 21cb93a386Sopenharmony_ci#include "src/core/SkFontPriv.h" 22cb93a386Sopenharmony_ci#include "src/core/SkGlyph.h" 23cb93a386Sopenharmony_ci#include "src/core/SkMaskGamma.h" 24cb93a386Sopenharmony_ci#include "src/core/SkMatrixProvider.h" 25cb93a386Sopenharmony_ci#include "src/core/SkPaintPriv.h" 26cb93a386Sopenharmony_ci#include "src/core/SkPathPriv.h" 27cb93a386Sopenharmony_ci#include "src/core/SkRasterClip.h" 28cb93a386Sopenharmony_ci#include "src/core/SkReadBuffer.h" 29cb93a386Sopenharmony_ci#include "src/core/SkRectPriv.h" 30cb93a386Sopenharmony_ci#include "src/core/SkStroke.h" 31cb93a386Sopenharmony_ci#include "src/core/SkSurfacePriv.h" 32cb93a386Sopenharmony_ci#include "src/core/SkTextFormatParams.h" 33cb93a386Sopenharmony_ci#include "src/core/SkWriteBuffer.h" 34cb93a386Sopenharmony_ci#include "src/utils/SkMatrix22.h" 35cb93a386Sopenharmony_ci#include <new> 36cb93a386Sopenharmony_ci 37cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 38cb93a386Sopenharmony_ci 39cb93a386Sopenharmony_ci#ifdef SK_DEBUG 40cb93a386Sopenharmony_ci #define DUMP_RECx 41cb93a386Sopenharmony_ci#endif 42cb93a386Sopenharmony_ci 43cb93a386Sopenharmony_ciSkScalerContextRec SkScalerContext::PreprocessRec(const SkTypeface& typeface, 44cb93a386Sopenharmony_ci const SkScalerContextEffects& effects, 45cb93a386Sopenharmony_ci const SkDescriptor& desc) { 46cb93a386Sopenharmony_ci SkScalerContextRec rec = 47cb93a386Sopenharmony_ci *static_cast<const SkScalerContextRec*>(desc.findEntry(kRec_SkDescriptorTag, nullptr)); 48cb93a386Sopenharmony_ci 49cb93a386Sopenharmony_ci // Allow the typeface to adjust the rec. 50cb93a386Sopenharmony_ci typeface.onFilterRec(&rec); 51cb93a386Sopenharmony_ci 52cb93a386Sopenharmony_ci if (effects.fMaskFilter) { 53cb93a386Sopenharmony_ci // Pre-blend is not currently applied to filtered text. 54cb93a386Sopenharmony_ci // The primary filter is blur, for which contrast makes no sense, 55cb93a386Sopenharmony_ci // and for which the destination guess error is more visible. 56cb93a386Sopenharmony_ci // Also, all existing users of blur have calibrated for linear. 57cb93a386Sopenharmony_ci rec.ignorePreBlend(); 58cb93a386Sopenharmony_ci } 59cb93a386Sopenharmony_ci 60cb93a386Sopenharmony_ci SkColor lumColor = rec.getLuminanceColor(); 61cb93a386Sopenharmony_ci 62cb93a386Sopenharmony_ci if (rec.fMaskFormat == SkMask::kA8_Format) { 63cb93a386Sopenharmony_ci U8CPU lum = SkComputeLuminance(SkColorGetR(lumColor), 64cb93a386Sopenharmony_ci SkColorGetG(lumColor), 65cb93a386Sopenharmony_ci SkColorGetB(lumColor)); 66cb93a386Sopenharmony_ci lumColor = SkColorSetRGB(lum, lum, lum); 67cb93a386Sopenharmony_ci } 68cb93a386Sopenharmony_ci 69cb93a386Sopenharmony_ci // TODO: remove CanonicalColor when we to fix up Chrome layout tests. 70cb93a386Sopenharmony_ci rec.setLuminanceColor(lumColor); 71cb93a386Sopenharmony_ci 72cb93a386Sopenharmony_ci return rec; 73cb93a386Sopenharmony_ci} 74cb93a386Sopenharmony_ci 75cb93a386Sopenharmony_ciSkScalerContext::SkScalerContext(sk_sp<SkTypeface> typeface, const SkScalerContextEffects& effects, 76cb93a386Sopenharmony_ci const SkDescriptor* desc) 77cb93a386Sopenharmony_ci : fRec(PreprocessRec(*typeface, effects, *desc)) 78cb93a386Sopenharmony_ci , fTypeface(std::move(typeface)) 79cb93a386Sopenharmony_ci , fPathEffect(sk_ref_sp(effects.fPathEffect)) 80cb93a386Sopenharmony_ci , fMaskFilter(sk_ref_sp(effects.fMaskFilter)) 81cb93a386Sopenharmony_ci // Initialize based on our settings. Subclasses can also force this. 82cb93a386Sopenharmony_ci , fGenerateImageFromPath(fRec.fFrameWidth >= 0 || fPathEffect != nullptr) 83cb93a386Sopenharmony_ci 84cb93a386Sopenharmony_ci , fPreBlend(fMaskFilter ? SkMaskGamma::PreBlend() : SkScalerContext::GetMaskPreBlend(fRec)) 85cb93a386Sopenharmony_ci{ 86cb93a386Sopenharmony_ci#ifdef DUMP_REC 87cb93a386Sopenharmony_ci SkDebugf("SkScalerContext checksum %x count %d length %d\n", 88cb93a386Sopenharmony_ci desc->getChecksum(), desc->getCount(), desc->getLength()); 89cb93a386Sopenharmony_ci SkDebugf("%s", fRec.dump().c_str()); 90cb93a386Sopenharmony_ci SkDebugf(" effects %x\n", desc->findEntry(kEffects_SkDescriptorTag, nullptr)); 91cb93a386Sopenharmony_ci#endif 92cb93a386Sopenharmony_ci} 93cb93a386Sopenharmony_ci 94cb93a386Sopenharmony_ciSkScalerContext::~SkScalerContext() {} 95cb93a386Sopenharmony_ci 96cb93a386Sopenharmony_ci/** 97cb93a386Sopenharmony_ci * In order to call cachedDeviceLuminance, cachedPaintLuminance, or 98cb93a386Sopenharmony_ci * cachedMaskGamma the caller must hold the mask_gamma_cache_mutex and continue 99cb93a386Sopenharmony_ci * to hold it until the returned pointer is refed or forgotten. 100cb93a386Sopenharmony_ci */ 101cb93a386Sopenharmony_cistatic SkMutex& mask_gamma_cache_mutex() { 102cb93a386Sopenharmony_ci static SkMutex& mutex = *(new SkMutex); 103cb93a386Sopenharmony_ci return mutex; 104cb93a386Sopenharmony_ci} 105cb93a386Sopenharmony_ci 106cb93a386Sopenharmony_cistatic SkMaskGamma* gLinearMaskGamma = nullptr; 107cb93a386Sopenharmony_cistatic SkMaskGamma* gMaskGamma = nullptr; 108cb93a386Sopenharmony_cistatic SkScalar gContrast = SK_ScalarMin; 109cb93a386Sopenharmony_cistatic SkScalar gPaintGamma = SK_ScalarMin; 110cb93a386Sopenharmony_cistatic SkScalar gDeviceGamma = SK_ScalarMin; 111cb93a386Sopenharmony_ci 112cb93a386Sopenharmony_ci/** 113cb93a386Sopenharmony_ci * The caller must hold the mask_gamma_cache_mutex() and continue to hold it until 114cb93a386Sopenharmony_ci * the returned SkMaskGamma pointer is refed or forgotten. 115cb93a386Sopenharmony_ci */ 116cb93a386Sopenharmony_cistatic const SkMaskGamma& cached_mask_gamma(SkScalar contrast, SkScalar paintGamma, 117cb93a386Sopenharmony_ci SkScalar deviceGamma) { 118cb93a386Sopenharmony_ci mask_gamma_cache_mutex().assertHeld(); 119cb93a386Sopenharmony_ci if (0 == contrast && SK_Scalar1 == paintGamma && SK_Scalar1 == deviceGamma) { 120cb93a386Sopenharmony_ci if (nullptr == gLinearMaskGamma) { 121cb93a386Sopenharmony_ci gLinearMaskGamma = new SkMaskGamma; 122cb93a386Sopenharmony_ci } 123cb93a386Sopenharmony_ci return *gLinearMaskGamma; 124cb93a386Sopenharmony_ci } 125cb93a386Sopenharmony_ci if (gContrast != contrast || gPaintGamma != paintGamma || gDeviceGamma != deviceGamma) { 126cb93a386Sopenharmony_ci SkSafeUnref(gMaskGamma); 127cb93a386Sopenharmony_ci gMaskGamma = new SkMaskGamma(contrast, paintGamma, deviceGamma); 128cb93a386Sopenharmony_ci gContrast = contrast; 129cb93a386Sopenharmony_ci gPaintGamma = paintGamma; 130cb93a386Sopenharmony_ci gDeviceGamma = deviceGamma; 131cb93a386Sopenharmony_ci } 132cb93a386Sopenharmony_ci return *gMaskGamma; 133cb93a386Sopenharmony_ci} 134cb93a386Sopenharmony_ci 135cb93a386Sopenharmony_ci/** 136cb93a386Sopenharmony_ci * Expands fDeviceGamma, fPaintGamma, fContrast, and fLumBits into a mask pre-blend. 137cb93a386Sopenharmony_ci */ 138cb93a386Sopenharmony_ciSkMaskGamma::PreBlend SkScalerContext::GetMaskPreBlend(const SkScalerContextRec& rec) { 139cb93a386Sopenharmony_ci SkAutoMutexExclusive ama(mask_gamma_cache_mutex()); 140cb93a386Sopenharmony_ci 141cb93a386Sopenharmony_ci const SkMaskGamma& maskGamma = cached_mask_gamma(rec.getContrast(), 142cb93a386Sopenharmony_ci rec.getPaintGamma(), 143cb93a386Sopenharmony_ci rec.getDeviceGamma()); 144cb93a386Sopenharmony_ci 145cb93a386Sopenharmony_ci // TODO: remove CanonicalColor when we to fix up Chrome layout tests. 146cb93a386Sopenharmony_ci return maskGamma.preBlend(rec.getLuminanceColor()); 147cb93a386Sopenharmony_ci} 148cb93a386Sopenharmony_ci 149cb93a386Sopenharmony_cisize_t SkScalerContext::GetGammaLUTSize(SkScalar contrast, SkScalar paintGamma, 150cb93a386Sopenharmony_ci SkScalar deviceGamma, int* width, int* height) { 151cb93a386Sopenharmony_ci SkAutoMutexExclusive ama(mask_gamma_cache_mutex()); 152cb93a386Sopenharmony_ci const SkMaskGamma& maskGamma = cached_mask_gamma(contrast, 153cb93a386Sopenharmony_ci paintGamma, 154cb93a386Sopenharmony_ci deviceGamma); 155cb93a386Sopenharmony_ci 156cb93a386Sopenharmony_ci maskGamma.getGammaTableDimensions(width, height); 157cb93a386Sopenharmony_ci size_t size = (*width)*(*height)*sizeof(uint8_t); 158cb93a386Sopenharmony_ci 159cb93a386Sopenharmony_ci return size; 160cb93a386Sopenharmony_ci} 161cb93a386Sopenharmony_ci 162cb93a386Sopenharmony_cibool SkScalerContext::GetGammaLUTData(SkScalar contrast, SkScalar paintGamma, SkScalar deviceGamma, 163cb93a386Sopenharmony_ci uint8_t* data) { 164cb93a386Sopenharmony_ci SkAutoMutexExclusive ama(mask_gamma_cache_mutex()); 165cb93a386Sopenharmony_ci const SkMaskGamma& maskGamma = cached_mask_gamma(contrast, 166cb93a386Sopenharmony_ci paintGamma, 167cb93a386Sopenharmony_ci deviceGamma); 168cb93a386Sopenharmony_ci const uint8_t* gammaTables = maskGamma.getGammaTables(); 169cb93a386Sopenharmony_ci if (!gammaTables) { 170cb93a386Sopenharmony_ci return false; 171cb93a386Sopenharmony_ci } 172cb93a386Sopenharmony_ci 173cb93a386Sopenharmony_ci int width, height; 174cb93a386Sopenharmony_ci maskGamma.getGammaTableDimensions(&width, &height); 175cb93a386Sopenharmony_ci size_t size = width*height * sizeof(uint8_t); 176cb93a386Sopenharmony_ci memcpy(data, gammaTables, size); 177cb93a386Sopenharmony_ci return true; 178cb93a386Sopenharmony_ci} 179cb93a386Sopenharmony_ci 180cb93a386Sopenharmony_ciSkGlyph SkScalerContext::makeGlyph(SkPackedGlyphID packedID) { 181cb93a386Sopenharmony_ci return internalMakeGlyph(packedID, fRec.fMaskFormat); 182cb93a386Sopenharmony_ci} 183cb93a386Sopenharmony_ci 184cb93a386Sopenharmony_ciSkGlyph SkScalerContext::internalMakeGlyph(SkPackedGlyphID packedID, SkMask::Format format) { 185cb93a386Sopenharmony_ci SkGlyph glyph{packedID}; 186cb93a386Sopenharmony_ci glyph.fMaskFormat = format; 187cb93a386Sopenharmony_ci bool generatingImageFromPath = fGenerateImageFromPath; 188cb93a386Sopenharmony_ci if (!generatingImageFromPath) { 189cb93a386Sopenharmony_ci generateMetrics(&glyph); 190cb93a386Sopenharmony_ci } else { 191cb93a386Sopenharmony_ci SkPath devPath; 192cb93a386Sopenharmony_ci bool hairline; 193cb93a386Sopenharmony_ci generatingImageFromPath = this->internalGetPath(glyph.getPackedID(), &devPath, &hairline); 194cb93a386Sopenharmony_ci if (!generatingImageFromPath) { 195cb93a386Sopenharmony_ci generateMetrics(&glyph); 196cb93a386Sopenharmony_ci } else { 197cb93a386Sopenharmony_ci if (!generateAdvance(&glyph)) { 198cb93a386Sopenharmony_ci generateMetrics(&glyph); 199cb93a386Sopenharmony_ci } 200cb93a386Sopenharmony_ci 201cb93a386Sopenharmony_ci // If we are going to create the mask, then we cannot keep the color 202cb93a386Sopenharmony_ci if (SkMask::kARGB32_Format == glyph.fMaskFormat) { 203cb93a386Sopenharmony_ci glyph.fMaskFormat = SkMask::kA8_Format; 204cb93a386Sopenharmony_ci } 205cb93a386Sopenharmony_ci 206cb93a386Sopenharmony_ci const SkIRect ir = devPath.getBounds().roundOut(); 207cb93a386Sopenharmony_ci if (ir.isEmpty() || !SkRectPriv::Is16Bit(ir)) { 208cb93a386Sopenharmony_ci goto SK_ERROR; 209cb93a386Sopenharmony_ci } 210cb93a386Sopenharmony_ci glyph.fLeft = ir.fLeft; 211cb93a386Sopenharmony_ci glyph.fTop = ir.fTop; 212cb93a386Sopenharmony_ci glyph.fWidth = SkToU16(ir.width()); 213cb93a386Sopenharmony_ci glyph.fHeight = SkToU16(ir.height()); 214cb93a386Sopenharmony_ci 215cb93a386Sopenharmony_ci const bool a8FromLCD = fRec.fFlags & SkScalerContext::kGenA8FromLCD_Flag; 216cb93a386Sopenharmony_ci const bool fromLCD = (glyph.fMaskFormat == SkMask::kLCD16_Format) || 217cb93a386Sopenharmony_ci (glyph.fMaskFormat == SkMask::kA8_Format && a8FromLCD); 218cb93a386Sopenharmony_ci const bool notEmptyAndFromLCD = 0 < glyph.fWidth && fromLCD; 219cb93a386Sopenharmony_ci const bool verticalLCD = fRec.fFlags & SkScalerContext::kLCD_Vertical_Flag; 220cb93a386Sopenharmony_ci 221cb93a386Sopenharmony_ci const bool needExtraWidth = (notEmptyAndFromLCD && !verticalLCD) || hairline; 222cb93a386Sopenharmony_ci const bool needExtraHeight = (notEmptyAndFromLCD && verticalLCD) || hairline; 223cb93a386Sopenharmony_ci if (needExtraWidth) { 224cb93a386Sopenharmony_ci glyph.fWidth += 2; 225cb93a386Sopenharmony_ci glyph.fLeft -= 1; 226cb93a386Sopenharmony_ci } 227cb93a386Sopenharmony_ci if (needExtraHeight) { 228cb93a386Sopenharmony_ci glyph.fHeight += 2; 229cb93a386Sopenharmony_ci glyph.fTop -= 1; 230cb93a386Sopenharmony_ci } 231cb93a386Sopenharmony_ci } 232cb93a386Sopenharmony_ci } 233cb93a386Sopenharmony_ci 234cb93a386Sopenharmony_ci // if either dimension is empty, zap the image bounds of the glyph 235cb93a386Sopenharmony_ci if (0 == glyph.fWidth || 0 == glyph.fHeight) { 236cb93a386Sopenharmony_ci glyph.fWidth = 0; 237cb93a386Sopenharmony_ci glyph.fHeight = 0; 238cb93a386Sopenharmony_ci glyph.fTop = 0; 239cb93a386Sopenharmony_ci glyph.fLeft = 0; 240cb93a386Sopenharmony_ci glyph.fMaskFormat = SkMask::kBW_Format; 241cb93a386Sopenharmony_ci return glyph; 242cb93a386Sopenharmony_ci } 243cb93a386Sopenharmony_ci 244cb93a386Sopenharmony_ci if (fMaskFilter) { 245cb93a386Sopenharmony_ci SkMask src = glyph.mask(), 246cb93a386Sopenharmony_ci dst; 247cb93a386Sopenharmony_ci SkMatrix matrix; 248cb93a386Sopenharmony_ci 249cb93a386Sopenharmony_ci fRec.getMatrixFrom2x2(&matrix); 250cb93a386Sopenharmony_ci 251cb93a386Sopenharmony_ci src.fImage = nullptr; // only want the bounds from the filter 252cb93a386Sopenharmony_ci if (as_MFB(fMaskFilter)->filterMask(&dst, src, matrix, nullptr)) { 253cb93a386Sopenharmony_ci if (dst.fBounds.isEmpty() || !SkRectPriv::Is16Bit(dst.fBounds)) { 254cb93a386Sopenharmony_ci goto SK_ERROR; 255cb93a386Sopenharmony_ci } 256cb93a386Sopenharmony_ci SkASSERT(dst.fImage == nullptr); 257cb93a386Sopenharmony_ci glyph.fLeft = dst.fBounds.fLeft; 258cb93a386Sopenharmony_ci glyph.fTop = dst.fBounds.fTop; 259cb93a386Sopenharmony_ci glyph.fWidth = SkToU16(dst.fBounds.width()); 260cb93a386Sopenharmony_ci glyph.fHeight = SkToU16(dst.fBounds.height()); 261cb93a386Sopenharmony_ci glyph.fMaskFormat = dst.fFormat; 262cb93a386Sopenharmony_ci } 263cb93a386Sopenharmony_ci } 264cb93a386Sopenharmony_ci return glyph; 265cb93a386Sopenharmony_ci 266cb93a386Sopenharmony_ciSK_ERROR: 267cb93a386Sopenharmony_ci // draw nothing 'cause we failed 268cb93a386Sopenharmony_ci glyph.fLeft = 0; 269cb93a386Sopenharmony_ci glyph.fTop = 0; 270cb93a386Sopenharmony_ci glyph.fWidth = 0; 271cb93a386Sopenharmony_ci glyph.fHeight = 0; 272cb93a386Sopenharmony_ci glyph.fMaskFormat = fRec.fMaskFormat; 273cb93a386Sopenharmony_ci return glyph; 274cb93a386Sopenharmony_ci} 275cb93a386Sopenharmony_ci 276cb93a386Sopenharmony_ci#define SK_SHOW_TEXT_BLIT_COVERAGE 0 277cb93a386Sopenharmony_ci 278cb93a386Sopenharmony_cistatic void applyLUTToA8Mask(const SkMask& mask, const uint8_t* lut) { 279cb93a386Sopenharmony_ci uint8_t* SK_RESTRICT dst = (uint8_t*)mask.fImage; 280cb93a386Sopenharmony_ci unsigned rowBytes = mask.fRowBytes; 281cb93a386Sopenharmony_ci 282cb93a386Sopenharmony_ci for (int y = mask.fBounds.height() - 1; y >= 0; --y) { 283cb93a386Sopenharmony_ci for (int x = mask.fBounds.width() - 1; x >= 0; --x) { 284cb93a386Sopenharmony_ci dst[x] = lut[dst[x]]; 285cb93a386Sopenharmony_ci } 286cb93a386Sopenharmony_ci dst += rowBytes; 287cb93a386Sopenharmony_ci } 288cb93a386Sopenharmony_ci} 289cb93a386Sopenharmony_ci 290cb93a386Sopenharmony_cistatic void pack4xHToMask(const SkPixmap& src, const SkMask& dst, 291cb93a386Sopenharmony_ci const SkMaskGamma::PreBlend& maskPreBlend, 292cb93a386Sopenharmony_ci const bool doBGR, const bool doVert) { 293cb93a386Sopenharmony_ci#define SAMPLES_PER_PIXEL 4 294cb93a386Sopenharmony_ci#define LCD_PER_PIXEL 3 295cb93a386Sopenharmony_ci SkASSERT(kAlpha_8_SkColorType == src.colorType()); 296cb93a386Sopenharmony_ci 297cb93a386Sopenharmony_ci const bool toA8 = SkMask::kA8_Format == dst.fFormat; 298cb93a386Sopenharmony_ci SkASSERT(SkMask::kLCD16_Format == dst.fFormat || toA8); 299cb93a386Sopenharmony_ci 300cb93a386Sopenharmony_ci // doVert in this function means swap x and y when writing to dst. 301cb93a386Sopenharmony_ci if (doVert) { 302cb93a386Sopenharmony_ci SkASSERT(src.width() == (dst.fBounds.height() - 2) * 4); 303cb93a386Sopenharmony_ci SkASSERT(src.height() == dst.fBounds.width()); 304cb93a386Sopenharmony_ci } else { 305cb93a386Sopenharmony_ci SkASSERT(src.width() == (dst.fBounds.width() - 2) * 4); 306cb93a386Sopenharmony_ci SkASSERT(src.height() == dst.fBounds.height()); 307cb93a386Sopenharmony_ci } 308cb93a386Sopenharmony_ci 309cb93a386Sopenharmony_ci const int sample_width = src.width(); 310cb93a386Sopenharmony_ci const int height = src.height(); 311cb93a386Sopenharmony_ci 312cb93a386Sopenharmony_ci uint8_t* dstImage = dst.fImage; 313cb93a386Sopenharmony_ci size_t dstRB = dst.fRowBytes; 314cb93a386Sopenharmony_ci // An N tap FIR is defined by 315cb93a386Sopenharmony_ci // out[n] = coeff[0]*x[n] + coeff[1]*x[n-1] + ... + coeff[N]*x[n-N] 316cb93a386Sopenharmony_ci // or 317cb93a386Sopenharmony_ci // out[n] = sum(i, 0, N, coeff[i]*x[n-i]) 318cb93a386Sopenharmony_ci 319cb93a386Sopenharmony_ci // The strategy is to use one FIR (different coefficients) for each of r, g, and b. 320cb93a386Sopenharmony_ci // This means using every 4th FIR output value of each FIR and discarding the rest. 321cb93a386Sopenharmony_ci // The FIRs are aligned, and the coefficients reach 5 samples to each side of their 'center'. 322cb93a386Sopenharmony_ci // (For r and b this is technically incorrect, but the coeffs outside round to zero anyway.) 323cb93a386Sopenharmony_ci 324cb93a386Sopenharmony_ci // These are in some fixed point repesentation. 325cb93a386Sopenharmony_ci // Adding up to more than one simulates ink spread. 326cb93a386Sopenharmony_ci // For implementation reasons, these should never add up to more than two. 327cb93a386Sopenharmony_ci 328cb93a386Sopenharmony_ci // Coefficients determined by a gausian where 5 samples = 3 std deviations (0x110 'contrast'). 329cb93a386Sopenharmony_ci // Calculated using tools/generate_fir_coeff.py 330cb93a386Sopenharmony_ci // With this one almost no fringing is ever seen, but it is imperceptibly blurry. 331cb93a386Sopenharmony_ci // The lcd smoothed text is almost imperceptibly different from gray, 332cb93a386Sopenharmony_ci // but is still sharper on small stems and small rounded corners than gray. 333cb93a386Sopenharmony_ci // This also seems to be about as wide as one can get and only have a three pixel kernel. 334cb93a386Sopenharmony_ci // TODO: calculate these at runtime so parameters can be adjusted (esp contrast). 335cb93a386Sopenharmony_ci static const unsigned int coefficients[LCD_PER_PIXEL][SAMPLES_PER_PIXEL*3] = { 336cb93a386Sopenharmony_ci //The red subpixel is centered inside the first sample (at 1/6 pixel), and is shifted. 337cb93a386Sopenharmony_ci { 0x03, 0x0b, 0x1c, 0x33, 0x40, 0x39, 0x24, 0x10, 0x05, 0x01, 0x00, 0x00, }, 338cb93a386Sopenharmony_ci //The green subpixel is centered between two samples (at 1/2 pixel), so is symetric 339cb93a386Sopenharmony_ci { 0x00, 0x02, 0x08, 0x16, 0x2b, 0x3d, 0x3d, 0x2b, 0x16, 0x08, 0x02, 0x00, }, 340cb93a386Sopenharmony_ci //The blue subpixel is centered inside the last sample (at 5/6 pixel), and is shifted. 341cb93a386Sopenharmony_ci { 0x00, 0x00, 0x01, 0x05, 0x10, 0x24, 0x39, 0x40, 0x33, 0x1c, 0x0b, 0x03, }, 342cb93a386Sopenharmony_ci }; 343cb93a386Sopenharmony_ci 344cb93a386Sopenharmony_ci size_t dstPB = toA8 ? sizeof(uint8_t) : sizeof(uint16_t); 345cb93a386Sopenharmony_ci for (int y = 0; y < height; ++y) { 346cb93a386Sopenharmony_ci uint8_t* dstP; 347cb93a386Sopenharmony_ci size_t dstPDelta; 348cb93a386Sopenharmony_ci if (doVert) { 349cb93a386Sopenharmony_ci dstP = SkTAddOffset<uint8_t>(dstImage, y * dstPB); 350cb93a386Sopenharmony_ci dstPDelta = dstRB; 351cb93a386Sopenharmony_ci } else { 352cb93a386Sopenharmony_ci dstP = SkTAddOffset<uint8_t>(dstImage, y * dstRB); 353cb93a386Sopenharmony_ci dstPDelta = dstPB; 354cb93a386Sopenharmony_ci } 355cb93a386Sopenharmony_ci 356cb93a386Sopenharmony_ci const uint8_t* srcP = src.addr8(0, y); 357cb93a386Sopenharmony_ci 358cb93a386Sopenharmony_ci // TODO: this fir filter implementation is straight forward, but slow. 359cb93a386Sopenharmony_ci // It should be possible to make it much faster. 360cb93a386Sopenharmony_ci for (int sample_x = -4; sample_x < sample_width + 4; sample_x += 4) { 361cb93a386Sopenharmony_ci int fir[LCD_PER_PIXEL] = { 0 }; 362cb93a386Sopenharmony_ci for (int sample_index = std::max(0, sample_x - 4), coeff_index = sample_index - (sample_x - 4) 363cb93a386Sopenharmony_ci ; sample_index < std::min(sample_x + 8, sample_width) 364cb93a386Sopenharmony_ci ; ++sample_index, ++coeff_index) 365cb93a386Sopenharmony_ci { 366cb93a386Sopenharmony_ci int sample_value = srcP[sample_index]; 367cb93a386Sopenharmony_ci for (int subpxl_index = 0; subpxl_index < LCD_PER_PIXEL; ++subpxl_index) { 368cb93a386Sopenharmony_ci fir[subpxl_index] += coefficients[subpxl_index][coeff_index] * sample_value; 369cb93a386Sopenharmony_ci } 370cb93a386Sopenharmony_ci } 371cb93a386Sopenharmony_ci for (int subpxl_index = 0; subpxl_index < LCD_PER_PIXEL; ++subpxl_index) { 372cb93a386Sopenharmony_ci fir[subpxl_index] /= 0x100; 373cb93a386Sopenharmony_ci fir[subpxl_index] = std::min(fir[subpxl_index], 255); 374cb93a386Sopenharmony_ci } 375cb93a386Sopenharmony_ci 376cb93a386Sopenharmony_ci U8CPU r, g, b; 377cb93a386Sopenharmony_ci if (doBGR) { 378cb93a386Sopenharmony_ci r = fir[2]; 379cb93a386Sopenharmony_ci g = fir[1]; 380cb93a386Sopenharmony_ci b = fir[0]; 381cb93a386Sopenharmony_ci } else { 382cb93a386Sopenharmony_ci r = fir[0]; 383cb93a386Sopenharmony_ci g = fir[1]; 384cb93a386Sopenharmony_ci b = fir[2]; 385cb93a386Sopenharmony_ci } 386cb93a386Sopenharmony_ci#if SK_SHOW_TEXT_BLIT_COVERAGE 387cb93a386Sopenharmony_ci r = std::max(r, 10); g = std::max(g, 10); b = std::max(b, 10); 388cb93a386Sopenharmony_ci#endif 389cb93a386Sopenharmony_ci if (toA8) { 390cb93a386Sopenharmony_ci U8CPU a = (r + g + b) / 3; 391cb93a386Sopenharmony_ci if (maskPreBlend.isApplicable()) { 392cb93a386Sopenharmony_ci a = maskPreBlend.fG[a]; 393cb93a386Sopenharmony_ci } 394cb93a386Sopenharmony_ci *dstP = a; 395cb93a386Sopenharmony_ci } else { 396cb93a386Sopenharmony_ci if (maskPreBlend.isApplicable()) { 397cb93a386Sopenharmony_ci r = maskPreBlend.fR[r]; 398cb93a386Sopenharmony_ci g = maskPreBlend.fG[g]; 399cb93a386Sopenharmony_ci b = maskPreBlend.fB[b]; 400cb93a386Sopenharmony_ci } 401cb93a386Sopenharmony_ci *(uint16_t*)dstP = SkPack888ToRGB16(r, g, b); 402cb93a386Sopenharmony_ci } 403cb93a386Sopenharmony_ci dstP = SkTAddOffset<uint8_t>(dstP, dstPDelta); 404cb93a386Sopenharmony_ci } 405cb93a386Sopenharmony_ci } 406cb93a386Sopenharmony_ci} 407cb93a386Sopenharmony_ci 408cb93a386Sopenharmony_cistatic inline int convert_8_to_1(unsigned byte) { 409cb93a386Sopenharmony_ci SkASSERT(byte <= 0xFF); 410cb93a386Sopenharmony_ci return byte >> 7; 411cb93a386Sopenharmony_ci} 412cb93a386Sopenharmony_ci 413cb93a386Sopenharmony_cistatic uint8_t pack_8_to_1(const uint8_t alpha[8]) { 414cb93a386Sopenharmony_ci unsigned bits = 0; 415cb93a386Sopenharmony_ci for (int i = 0; i < 8; ++i) { 416cb93a386Sopenharmony_ci bits <<= 1; 417cb93a386Sopenharmony_ci bits |= convert_8_to_1(alpha[i]); 418cb93a386Sopenharmony_ci } 419cb93a386Sopenharmony_ci return SkToU8(bits); 420cb93a386Sopenharmony_ci} 421cb93a386Sopenharmony_ci 422cb93a386Sopenharmony_cistatic void packA8ToA1(const SkMask& mask, const uint8_t* src, size_t srcRB) { 423cb93a386Sopenharmony_ci const int height = mask.fBounds.height(); 424cb93a386Sopenharmony_ci const int width = mask.fBounds.width(); 425cb93a386Sopenharmony_ci const int octs = width >> 3; 426cb93a386Sopenharmony_ci const int leftOverBits = width & 7; 427cb93a386Sopenharmony_ci 428cb93a386Sopenharmony_ci uint8_t* dst = mask.fImage; 429cb93a386Sopenharmony_ci const int dstPad = mask.fRowBytes - SkAlign8(width)/8; 430cb93a386Sopenharmony_ci SkASSERT(dstPad >= 0); 431cb93a386Sopenharmony_ci 432cb93a386Sopenharmony_ci SkASSERT(width >= 0); 433cb93a386Sopenharmony_ci SkASSERT(srcRB >= (size_t)width); 434cb93a386Sopenharmony_ci const size_t srcPad = srcRB - width; 435cb93a386Sopenharmony_ci 436cb93a386Sopenharmony_ci for (int y = 0; y < height; ++y) { 437cb93a386Sopenharmony_ci for (int i = 0; i < octs; ++i) { 438cb93a386Sopenharmony_ci *dst++ = pack_8_to_1(src); 439cb93a386Sopenharmony_ci src += 8; 440cb93a386Sopenharmony_ci } 441cb93a386Sopenharmony_ci if (leftOverBits > 0) { 442cb93a386Sopenharmony_ci unsigned bits = 0; 443cb93a386Sopenharmony_ci int shift = 7; 444cb93a386Sopenharmony_ci for (int i = 0; i < leftOverBits; ++i, --shift) { 445cb93a386Sopenharmony_ci bits |= convert_8_to_1(*src++) << shift; 446cb93a386Sopenharmony_ci } 447cb93a386Sopenharmony_ci *dst++ = bits; 448cb93a386Sopenharmony_ci } 449cb93a386Sopenharmony_ci src += srcPad; 450cb93a386Sopenharmony_ci dst += dstPad; 451cb93a386Sopenharmony_ci } 452cb93a386Sopenharmony_ci} 453cb93a386Sopenharmony_ci 454cb93a386Sopenharmony_cistatic void generateMask(const SkMask& mask, const SkPath& path, 455cb93a386Sopenharmony_ci const SkMaskGamma::PreBlend& maskPreBlend, 456cb93a386Sopenharmony_ci const bool doBGR, const bool doVert, const bool a8FromLCD, 457cb93a386Sopenharmony_ci const bool hairline) { 458cb93a386Sopenharmony_ci SkASSERT(mask.fFormat == SkMask::kBW_Format || 459cb93a386Sopenharmony_ci mask.fFormat == SkMask::kA8_Format || 460cb93a386Sopenharmony_ci mask.fFormat == SkMask::kLCD16_Format); 461cb93a386Sopenharmony_ci 462cb93a386Sopenharmony_ci SkPaint paint; 463cb93a386Sopenharmony_ci SkPath strokePath; 464cb93a386Sopenharmony_ci const SkPath* pathToUse = &path; 465cb93a386Sopenharmony_ci 466cb93a386Sopenharmony_ci int srcW = mask.fBounds.width(); 467cb93a386Sopenharmony_ci int srcH = mask.fBounds.height(); 468cb93a386Sopenharmony_ci int dstW = srcW; 469cb93a386Sopenharmony_ci int dstH = srcH; 470cb93a386Sopenharmony_ci 471cb93a386Sopenharmony_ci SkMatrix matrix; 472cb93a386Sopenharmony_ci matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft), 473cb93a386Sopenharmony_ci -SkIntToScalar(mask.fBounds.fTop)); 474cb93a386Sopenharmony_ci 475cb93a386Sopenharmony_ci paint.setStroke(hairline); 476cb93a386Sopenharmony_ci paint.setAntiAlias(SkMask::kBW_Format != mask.fFormat); 477cb93a386Sopenharmony_ci 478cb93a386Sopenharmony_ci const bool fromLCD = (mask.fFormat == SkMask::kLCD16_Format) || 479cb93a386Sopenharmony_ci (mask.fFormat == SkMask::kA8_Format && a8FromLCD); 480cb93a386Sopenharmony_ci const bool intermediateDst = fromLCD || mask.fFormat == SkMask::kBW_Format; 481cb93a386Sopenharmony_ci if (fromLCD) { 482cb93a386Sopenharmony_ci if (doVert) { 483cb93a386Sopenharmony_ci dstW = 4*dstH - 8; 484cb93a386Sopenharmony_ci dstH = srcW; 485cb93a386Sopenharmony_ci matrix.setAll(0, 4, -SkIntToScalar(mask.fBounds.fTop + 1) * 4, 486cb93a386Sopenharmony_ci 1, 0, -SkIntToScalar(mask.fBounds.fLeft), 487cb93a386Sopenharmony_ci 0, 0, 1); 488cb93a386Sopenharmony_ci } else { 489cb93a386Sopenharmony_ci dstW = 4*dstW - 8; 490cb93a386Sopenharmony_ci matrix.setAll(4, 0, -SkIntToScalar(mask.fBounds.fLeft + 1) * 4, 491cb93a386Sopenharmony_ci 0, 1, -SkIntToScalar(mask.fBounds.fTop), 492cb93a386Sopenharmony_ci 0, 0, 1); 493cb93a386Sopenharmony_ci } 494cb93a386Sopenharmony_ci 495cb93a386Sopenharmony_ci // LCD hairline doesn't line up with the pixels, so do it the expensive way. 496cb93a386Sopenharmony_ci SkStrokeRec rec(SkStrokeRec::kFill_InitStyle); 497cb93a386Sopenharmony_ci if (hairline) { 498cb93a386Sopenharmony_ci rec.setStrokeStyle(1.0f, false); 499cb93a386Sopenharmony_ci rec.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kRound_Join, 0.0f); 500cb93a386Sopenharmony_ci } 501cb93a386Sopenharmony_ci if (rec.needToApply() && rec.applyToPath(&strokePath, path)) { 502cb93a386Sopenharmony_ci pathToUse = &strokePath; 503cb93a386Sopenharmony_ci paint.setStyle(SkPaint::kFill_Style); 504cb93a386Sopenharmony_ci } 505cb93a386Sopenharmony_ci } 506cb93a386Sopenharmony_ci 507cb93a386Sopenharmony_ci SkRasterClip clip; 508cb93a386Sopenharmony_ci clip.setRect(SkIRect::MakeWH(dstW, dstH)); 509cb93a386Sopenharmony_ci 510cb93a386Sopenharmony_ci const SkImageInfo info = SkImageInfo::MakeA8(dstW, dstH); 511cb93a386Sopenharmony_ci SkAutoPixmapStorage dst; 512cb93a386Sopenharmony_ci 513cb93a386Sopenharmony_ci if (intermediateDst) { 514cb93a386Sopenharmony_ci if (!dst.tryAlloc(info)) { 515cb93a386Sopenharmony_ci // can't allocate offscreen, so empty the mask and return 516cb93a386Sopenharmony_ci sk_bzero(mask.fImage, mask.computeImageSize()); 517cb93a386Sopenharmony_ci return; 518cb93a386Sopenharmony_ci } 519cb93a386Sopenharmony_ci } else { 520cb93a386Sopenharmony_ci dst.reset(info, mask.fImage, mask.fRowBytes); 521cb93a386Sopenharmony_ci } 522cb93a386Sopenharmony_ci sk_bzero(dst.writable_addr(), dst.computeByteSize()); 523cb93a386Sopenharmony_ci 524cb93a386Sopenharmony_ci SkDraw draw; 525cb93a386Sopenharmony_ci SkSimpleMatrixProvider matrixProvider(matrix); 526cb93a386Sopenharmony_ci draw.fDst = dst; 527cb93a386Sopenharmony_ci draw.fRC = &clip; 528cb93a386Sopenharmony_ci draw.fMatrixProvider = &matrixProvider; 529cb93a386Sopenharmony_ci draw.drawPath(*pathToUse, paint); 530cb93a386Sopenharmony_ci 531cb93a386Sopenharmony_ci switch (mask.fFormat) { 532cb93a386Sopenharmony_ci case SkMask::kBW_Format: 533cb93a386Sopenharmony_ci packA8ToA1(mask, dst.addr8(0, 0), dst.rowBytes()); 534cb93a386Sopenharmony_ci break; 535cb93a386Sopenharmony_ci case SkMask::kA8_Format: 536cb93a386Sopenharmony_ci if (fromLCD) { 537cb93a386Sopenharmony_ci pack4xHToMask(dst, mask, maskPreBlend, doBGR, doVert); 538cb93a386Sopenharmony_ci } else if (maskPreBlend.isApplicable()) { 539cb93a386Sopenharmony_ci applyLUTToA8Mask(mask, maskPreBlend.fG); 540cb93a386Sopenharmony_ci } 541cb93a386Sopenharmony_ci break; 542cb93a386Sopenharmony_ci case SkMask::kLCD16_Format: 543cb93a386Sopenharmony_ci pack4xHToMask(dst, mask, maskPreBlend, doBGR, doVert); 544cb93a386Sopenharmony_ci break; 545cb93a386Sopenharmony_ci default: 546cb93a386Sopenharmony_ci break; 547cb93a386Sopenharmony_ci } 548cb93a386Sopenharmony_ci} 549cb93a386Sopenharmony_ci 550cb93a386Sopenharmony_civoid SkScalerContext::getImage(const SkGlyph& origGlyph) { 551cb93a386Sopenharmony_ci const SkGlyph* unfilteredGlyph = &origGlyph; 552cb93a386Sopenharmony_ci // in case we need to call generateImage on a mask-format that is different 553cb93a386Sopenharmony_ci // (i.e. larger) than what our caller allocated by looking at origGlyph. 554cb93a386Sopenharmony_ci SkAutoMalloc tmpGlyphImageStorage; 555cb93a386Sopenharmony_ci SkGlyph tmpGlyph; 556cb93a386Sopenharmony_ci if (fMaskFilter) { 557cb93a386Sopenharmony_ci // need the original bounds, sans our maskfilter 558cb93a386Sopenharmony_ci sk_sp<SkMaskFilter> mf = std::move(fMaskFilter); 559cb93a386Sopenharmony_ci tmpGlyph = this->internalMakeGlyph(origGlyph.getPackedID(), fRec.fMaskFormat); 560cb93a386Sopenharmony_ci fMaskFilter = std::move(mf); 561cb93a386Sopenharmony_ci 562cb93a386Sopenharmony_ci // Use the origGlyph storage for the temporary unfiltered mask if it will fit. 563cb93a386Sopenharmony_ci if (tmpGlyph.fMaskFormat == origGlyph.fMaskFormat && 564cb93a386Sopenharmony_ci tmpGlyph.imageSize() <= origGlyph.imageSize()) 565cb93a386Sopenharmony_ci { 566cb93a386Sopenharmony_ci tmpGlyph.fImage = origGlyph.fImage; 567cb93a386Sopenharmony_ci } else { 568cb93a386Sopenharmony_ci tmpGlyphImageStorage.reset(tmpGlyph.imageSize()); 569cb93a386Sopenharmony_ci tmpGlyph.fImage = tmpGlyphImageStorage.get(); 570cb93a386Sopenharmony_ci } 571cb93a386Sopenharmony_ci unfilteredGlyph = &tmpGlyph; 572cb93a386Sopenharmony_ci } 573cb93a386Sopenharmony_ci 574cb93a386Sopenharmony_ci if (!fGenerateImageFromPath) { 575cb93a386Sopenharmony_ci generateImage(*unfilteredGlyph); 576cb93a386Sopenharmony_ci } else { 577cb93a386Sopenharmony_ci SkPath devPath; 578cb93a386Sopenharmony_ci SkMask mask = unfilteredGlyph->mask(); 579cb93a386Sopenharmony_ci bool hairline; 580cb93a386Sopenharmony_ci 581cb93a386Sopenharmony_ci if (!this->internalGetPath(unfilteredGlyph->getPackedID(), &devPath, &hairline)) { 582cb93a386Sopenharmony_ci generateImage(*unfilteredGlyph); 583cb93a386Sopenharmony_ci } else { 584cb93a386Sopenharmony_ci SkASSERT(SkMask::kARGB32_Format != origGlyph.fMaskFormat); 585cb93a386Sopenharmony_ci SkASSERT(SkMask::kARGB32_Format != mask.fFormat); 586cb93a386Sopenharmony_ci const bool doBGR = SkToBool(fRec.fFlags & SkScalerContext::kLCD_BGROrder_Flag); 587cb93a386Sopenharmony_ci const bool doVert = SkToBool(fRec.fFlags & SkScalerContext::kLCD_Vertical_Flag); 588cb93a386Sopenharmony_ci const bool a8LCD = SkToBool(fRec.fFlags & SkScalerContext::kGenA8FromLCD_Flag); 589cb93a386Sopenharmony_ci generateMask(mask, devPath, fPreBlend, doBGR, doVert, a8LCD, hairline); 590cb93a386Sopenharmony_ci } 591cb93a386Sopenharmony_ci } 592cb93a386Sopenharmony_ci 593cb93a386Sopenharmony_ci if (fMaskFilter) { 594cb93a386Sopenharmony_ci // k3D_Format should not be mask filtered. 595cb93a386Sopenharmony_ci SkASSERT(SkMask::k3D_Format != unfilteredGlyph->fMaskFormat); 596cb93a386Sopenharmony_ci 597cb93a386Sopenharmony_ci SkMask filteredMask; 598cb93a386Sopenharmony_ci SkMask srcMask; 599cb93a386Sopenharmony_ci SkMatrix m; 600cb93a386Sopenharmony_ci fRec.getMatrixFrom2x2(&m); 601cb93a386Sopenharmony_ci 602cb93a386Sopenharmony_ci if (as_MFB(fMaskFilter)->filterMask(&filteredMask, unfilteredGlyph->mask(), m, nullptr)) { 603cb93a386Sopenharmony_ci // Filter succeeded; filteredMask.fImage was allocated. 604cb93a386Sopenharmony_ci srcMask = filteredMask; 605cb93a386Sopenharmony_ci } else if (unfilteredGlyph->fImage == tmpGlyphImageStorage.get()) { 606cb93a386Sopenharmony_ci // Filter did nothing; unfiltered mask is independent of origGlyph.fImage. 607cb93a386Sopenharmony_ci srcMask = unfilteredGlyph->mask(); 608cb93a386Sopenharmony_ci } else if (origGlyph.iRect() == unfilteredGlyph->iRect()) { 609cb93a386Sopenharmony_ci // Filter did nothing; the unfiltered mask is in origGlyph.fImage and matches. 610cb93a386Sopenharmony_ci return; 611cb93a386Sopenharmony_ci } else { 612cb93a386Sopenharmony_ci // Filter did nothing; the unfiltered mask is in origGlyph.fImage and conflicts. 613cb93a386Sopenharmony_ci srcMask = unfilteredGlyph->mask(); 614cb93a386Sopenharmony_ci size_t imageSize = unfilteredGlyph->imageSize(); 615cb93a386Sopenharmony_ci tmpGlyphImageStorage.reset(imageSize); 616cb93a386Sopenharmony_ci srcMask.fImage = static_cast<uint8_t*>(tmpGlyphImageStorage.get()); 617cb93a386Sopenharmony_ci memcpy(srcMask.fImage, unfilteredGlyph->fImage, imageSize); 618cb93a386Sopenharmony_ci } 619cb93a386Sopenharmony_ci 620cb93a386Sopenharmony_ci SkASSERT_RELEASE(srcMask.fFormat == origGlyph.fMaskFormat); 621cb93a386Sopenharmony_ci SkMask dstMask = origGlyph.mask(); 622cb93a386Sopenharmony_ci SkIRect origBounds = dstMask.fBounds; 623cb93a386Sopenharmony_ci 624cb93a386Sopenharmony_ci // Find the intersection of src and dst while updating the fImages. 625cb93a386Sopenharmony_ci if (srcMask.fBounds.fTop < dstMask.fBounds.fTop) { 626cb93a386Sopenharmony_ci int32_t topDiff = dstMask.fBounds.fTop - srcMask.fBounds.fTop; 627cb93a386Sopenharmony_ci srcMask.fImage += srcMask.fRowBytes * topDiff; 628cb93a386Sopenharmony_ci srcMask.fBounds.fTop = dstMask.fBounds.fTop; 629cb93a386Sopenharmony_ci } 630cb93a386Sopenharmony_ci if (dstMask.fBounds.fTop < srcMask.fBounds.fTop) { 631cb93a386Sopenharmony_ci int32_t topDiff = srcMask.fBounds.fTop - dstMask.fBounds.fTop; 632cb93a386Sopenharmony_ci dstMask.fImage += dstMask.fRowBytes * topDiff; 633cb93a386Sopenharmony_ci dstMask.fBounds.fTop = srcMask.fBounds.fTop; 634cb93a386Sopenharmony_ci } 635cb93a386Sopenharmony_ci 636cb93a386Sopenharmony_ci if (srcMask.fBounds.fLeft < dstMask.fBounds.fLeft) { 637cb93a386Sopenharmony_ci int32_t leftDiff = dstMask.fBounds.fLeft - srcMask.fBounds.fLeft; 638cb93a386Sopenharmony_ci srcMask.fImage += leftDiff; 639cb93a386Sopenharmony_ci srcMask.fBounds.fLeft = dstMask.fBounds.fLeft; 640cb93a386Sopenharmony_ci } 641cb93a386Sopenharmony_ci if (dstMask.fBounds.fLeft < srcMask.fBounds.fLeft) { 642cb93a386Sopenharmony_ci int32_t leftDiff = srcMask.fBounds.fLeft - dstMask.fBounds.fLeft; 643cb93a386Sopenharmony_ci dstMask.fImage += leftDiff; 644cb93a386Sopenharmony_ci dstMask.fBounds.fLeft = srcMask.fBounds.fLeft; 645cb93a386Sopenharmony_ci } 646cb93a386Sopenharmony_ci 647cb93a386Sopenharmony_ci if (srcMask.fBounds.fBottom < dstMask.fBounds.fBottom) { 648cb93a386Sopenharmony_ci dstMask.fBounds.fBottom = srcMask.fBounds.fBottom; 649cb93a386Sopenharmony_ci } 650cb93a386Sopenharmony_ci if (dstMask.fBounds.fBottom < srcMask.fBounds.fBottom) { 651cb93a386Sopenharmony_ci srcMask.fBounds.fBottom = dstMask.fBounds.fBottom; 652cb93a386Sopenharmony_ci } 653cb93a386Sopenharmony_ci 654cb93a386Sopenharmony_ci if (srcMask.fBounds.fRight < dstMask.fBounds.fRight) { 655cb93a386Sopenharmony_ci dstMask.fBounds.fRight = srcMask.fBounds.fRight; 656cb93a386Sopenharmony_ci } 657cb93a386Sopenharmony_ci if (dstMask.fBounds.fRight < srcMask.fBounds.fRight) { 658cb93a386Sopenharmony_ci srcMask.fBounds.fRight = dstMask.fBounds.fRight; 659cb93a386Sopenharmony_ci } 660cb93a386Sopenharmony_ci 661cb93a386Sopenharmony_ci SkASSERT(srcMask.fBounds == dstMask.fBounds); 662cb93a386Sopenharmony_ci int width = srcMask.fBounds.width(); 663cb93a386Sopenharmony_ci int height = srcMask.fBounds.height(); 664cb93a386Sopenharmony_ci int dstRB = dstMask.fRowBytes; 665cb93a386Sopenharmony_ci int srcRB = srcMask.fRowBytes; 666cb93a386Sopenharmony_ci 667cb93a386Sopenharmony_ci const uint8_t* src = srcMask.fImage; 668cb93a386Sopenharmony_ci uint8_t* dst = dstMask.fImage; 669cb93a386Sopenharmony_ci 670cb93a386Sopenharmony_ci if (SkMask::k3D_Format == filteredMask.fFormat) { 671cb93a386Sopenharmony_ci // we have to copy 3 times as much 672cb93a386Sopenharmony_ci height *= 3; 673cb93a386Sopenharmony_ci } 674cb93a386Sopenharmony_ci 675cb93a386Sopenharmony_ci // If not filling the full original glyph, clear it out first. 676cb93a386Sopenharmony_ci if (dstMask.fBounds != origBounds) { 677cb93a386Sopenharmony_ci sk_bzero(origGlyph.fImage, origGlyph.fHeight * origGlyph.rowBytes()); 678cb93a386Sopenharmony_ci } 679cb93a386Sopenharmony_ci 680cb93a386Sopenharmony_ci while (--height >= 0) { 681cb93a386Sopenharmony_ci memcpy(dst, src, width); 682cb93a386Sopenharmony_ci src += srcRB; 683cb93a386Sopenharmony_ci dst += dstRB; 684cb93a386Sopenharmony_ci } 685cb93a386Sopenharmony_ci SkMask::FreeImage(filteredMask.fImage); 686cb93a386Sopenharmony_ci } 687cb93a386Sopenharmony_ci} 688cb93a386Sopenharmony_ci 689cb93a386Sopenharmony_cibool SkScalerContext::getPath(SkPackedGlyphID glyphID, SkPath* path) { 690cb93a386Sopenharmony_ci // TODO: return hairline so user knows to stroke. 691cb93a386Sopenharmony_ci // Most users get the fill path without path effect and then draw that, so don't need this. 692cb93a386Sopenharmony_ci return this->internalGetPath(glyphID, path, nullptr); 693cb93a386Sopenharmony_ci} 694cb93a386Sopenharmony_ci 695cb93a386Sopenharmony_civoid SkScalerContext::getFontMetrics(SkFontMetrics* fm) { 696cb93a386Sopenharmony_ci SkASSERT(fm); 697cb93a386Sopenharmony_ci this->generateFontMetrics(fm); 698cb93a386Sopenharmony_ci} 699cb93a386Sopenharmony_ci 700cb93a386Sopenharmony_ci/////////////////////////////////////////////////////////////////////////////// 701cb93a386Sopenharmony_ci 702cb93a386Sopenharmony_cibool SkScalerContext::internalGetPath(SkPackedGlyphID glyphID, SkPath* devPath, bool* hairline) { 703cb93a386Sopenharmony_ci SkPath path; 704cb93a386Sopenharmony_ci if (!generatePath(glyphID.glyphID(), &path)) { 705cb93a386Sopenharmony_ci return false; 706cb93a386Sopenharmony_ci } 707cb93a386Sopenharmony_ci 708cb93a386Sopenharmony_ci if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) { 709cb93a386Sopenharmony_ci SkFixed dx = glyphID.getSubXFixed(); 710cb93a386Sopenharmony_ci SkFixed dy = glyphID.getSubYFixed(); 711cb93a386Sopenharmony_ci if (dx | dy) { 712cb93a386Sopenharmony_ci path.offset(SkFixedToScalar(dx), SkFixedToScalar(dy)); 713cb93a386Sopenharmony_ci } 714cb93a386Sopenharmony_ci } 715cb93a386Sopenharmony_ci 716cb93a386Sopenharmony_ci if (hairline) { 717cb93a386Sopenharmony_ci *hairline = false; 718cb93a386Sopenharmony_ci } 719cb93a386Sopenharmony_ci 720cb93a386Sopenharmony_ci if (fRec.fFrameWidth >= 0 || fPathEffect != nullptr) { 721cb93a386Sopenharmony_ci // need the path in user-space, with only the point-size applied 722cb93a386Sopenharmony_ci // so that our stroking and effects will operate the same way they 723cb93a386Sopenharmony_ci // would if the user had extracted the path themself, and then 724cb93a386Sopenharmony_ci // called drawPath 725cb93a386Sopenharmony_ci SkPath localPath; 726cb93a386Sopenharmony_ci SkMatrix matrix, inverse; 727cb93a386Sopenharmony_ci 728cb93a386Sopenharmony_ci fRec.getMatrixFrom2x2(&matrix); 729cb93a386Sopenharmony_ci if (!matrix.invert(&inverse)) { 730cb93a386Sopenharmony_ci // assume devPath is already empty. 731cb93a386Sopenharmony_ci return true; 732cb93a386Sopenharmony_ci } 733cb93a386Sopenharmony_ci path.transform(inverse, &localPath); 734cb93a386Sopenharmony_ci // now localPath is only affected by the paint settings, and not the canvas matrix 735cb93a386Sopenharmony_ci 736cb93a386Sopenharmony_ci SkStrokeRec rec(SkStrokeRec::kFill_InitStyle); 737cb93a386Sopenharmony_ci 738cb93a386Sopenharmony_ci if (fRec.fFrameWidth > 0) { 739cb93a386Sopenharmony_ci rec.setStrokeStyle(fRec.fFrameWidth, 740cb93a386Sopenharmony_ci SkToBool(fRec.fFlags & kFrameAndFill_Flag)); 741cb93a386Sopenharmony_ci // glyphs are always closed contours, so cap type is ignored, 742cb93a386Sopenharmony_ci // so we just pass something. 743cb93a386Sopenharmony_ci rec.setStrokeParams((SkPaint::Cap)fRec.fStrokeCap, 744cb93a386Sopenharmony_ci (SkPaint::Join)fRec.fStrokeJoin, 745cb93a386Sopenharmony_ci fRec.fMiterLimit); 746cb93a386Sopenharmony_ci } 747cb93a386Sopenharmony_ci 748cb93a386Sopenharmony_ci if (fPathEffect) { 749cb93a386Sopenharmony_ci SkPath effectPath; 750cb93a386Sopenharmony_ci if (fPathEffect->filterPath(&effectPath, localPath, &rec, nullptr, matrix)) { 751cb93a386Sopenharmony_ci localPath.swap(effectPath); 752cb93a386Sopenharmony_ci } 753cb93a386Sopenharmony_ci } 754cb93a386Sopenharmony_ci 755cb93a386Sopenharmony_ci if (rec.needToApply()) { 756cb93a386Sopenharmony_ci SkPath strokePath; 757cb93a386Sopenharmony_ci if (rec.applyToPath(&strokePath, localPath)) { 758cb93a386Sopenharmony_ci localPath.swap(strokePath); 759cb93a386Sopenharmony_ci } 760cb93a386Sopenharmony_ci } 761cb93a386Sopenharmony_ci 762cb93a386Sopenharmony_ci // The path effect may have modified 'rec', so wait to here to check hairline status. 763cb93a386Sopenharmony_ci if (hairline && rec.isHairlineStyle()) { 764cb93a386Sopenharmony_ci *hairline = true; 765cb93a386Sopenharmony_ci } 766cb93a386Sopenharmony_ci 767cb93a386Sopenharmony_ci // now return stuff to the caller 768cb93a386Sopenharmony_ci if (devPath) { 769cb93a386Sopenharmony_ci localPath.transform(matrix, devPath); 770cb93a386Sopenharmony_ci } 771cb93a386Sopenharmony_ci } else { // nothing tricky to do 772cb93a386Sopenharmony_ci if (devPath) { 773cb93a386Sopenharmony_ci devPath->swap(path); 774cb93a386Sopenharmony_ci } 775cb93a386Sopenharmony_ci } 776cb93a386Sopenharmony_ci 777cb93a386Sopenharmony_ci if (devPath) { 778cb93a386Sopenharmony_ci devPath->updateBoundsCache(); 779cb93a386Sopenharmony_ci } 780cb93a386Sopenharmony_ci return true; 781cb93a386Sopenharmony_ci} 782cb93a386Sopenharmony_ci 783cb93a386Sopenharmony_ci 784cb93a386Sopenharmony_civoid SkScalerContextRec::getMatrixFrom2x2(SkMatrix* dst) const { 785cb93a386Sopenharmony_ci dst->setAll(fPost2x2[0][0], fPost2x2[0][1], 0, 786cb93a386Sopenharmony_ci fPost2x2[1][0], fPost2x2[1][1], 0, 787cb93a386Sopenharmony_ci 0, 0, 1); 788cb93a386Sopenharmony_ci} 789cb93a386Sopenharmony_ci 790cb93a386Sopenharmony_civoid SkScalerContextRec::getLocalMatrix(SkMatrix* m) const { 791cb93a386Sopenharmony_ci *m = SkFontPriv::MakeTextMatrix(fTextSize, fPreScaleX, fPreSkewX); 792cb93a386Sopenharmony_ci} 793cb93a386Sopenharmony_ci 794cb93a386Sopenharmony_civoid SkScalerContextRec::getSingleMatrix(SkMatrix* m) const { 795cb93a386Sopenharmony_ci this->getLocalMatrix(m); 796cb93a386Sopenharmony_ci 797cb93a386Sopenharmony_ci // now concat the device matrix 798cb93a386Sopenharmony_ci SkMatrix deviceMatrix; 799cb93a386Sopenharmony_ci this->getMatrixFrom2x2(&deviceMatrix); 800cb93a386Sopenharmony_ci m->postConcat(deviceMatrix); 801cb93a386Sopenharmony_ci} 802cb93a386Sopenharmony_ci 803cb93a386Sopenharmony_cibool SkScalerContextRec::computeMatrices(PreMatrixScale preMatrixScale, SkVector* s, SkMatrix* sA, 804cb93a386Sopenharmony_ci SkMatrix* GsA, SkMatrix* G_inv, SkMatrix* A_out) 805cb93a386Sopenharmony_ci{ 806cb93a386Sopenharmony_ci // A is the 'total' matrix. 807cb93a386Sopenharmony_ci SkMatrix A; 808cb93a386Sopenharmony_ci this->getSingleMatrix(&A); 809cb93a386Sopenharmony_ci 810cb93a386Sopenharmony_ci // The caller may find the 'total' matrix useful when dealing directly with EM sizes. 811cb93a386Sopenharmony_ci if (A_out) { 812cb93a386Sopenharmony_ci *A_out = A; 813cb93a386Sopenharmony_ci } 814cb93a386Sopenharmony_ci 815cb93a386Sopenharmony_ci // GA is the matrix A with rotation removed. 816cb93a386Sopenharmony_ci SkMatrix GA; 817cb93a386Sopenharmony_ci bool skewedOrFlipped = A.getSkewX() || A.getSkewY() || A.getScaleX() < 0 || A.getScaleY() < 0; 818cb93a386Sopenharmony_ci if (skewedOrFlipped) { 819cb93a386Sopenharmony_ci // QR by Givens rotations. G is Q^T and GA is R. G is rotational (no reflections). 820cb93a386Sopenharmony_ci // h is where A maps the horizontal baseline. 821cb93a386Sopenharmony_ci SkPoint h = SkPoint::Make(SK_Scalar1, 0); 822cb93a386Sopenharmony_ci A.mapPoints(&h, 1); 823cb93a386Sopenharmony_ci 824cb93a386Sopenharmony_ci // G is the Givens Matrix for A (rotational matrix where GA[0][1] == 0). 825cb93a386Sopenharmony_ci SkMatrix G; 826cb93a386Sopenharmony_ci SkComputeGivensRotation(h, &G); 827cb93a386Sopenharmony_ci 828cb93a386Sopenharmony_ci GA = G; 829cb93a386Sopenharmony_ci GA.preConcat(A); 830cb93a386Sopenharmony_ci 831cb93a386Sopenharmony_ci // The 'remainingRotation' is G inverse, which is fairly simple since G is 2x2 rotational. 832cb93a386Sopenharmony_ci if (G_inv) { 833cb93a386Sopenharmony_ci G_inv->setAll( 834cb93a386Sopenharmony_ci G.get(SkMatrix::kMScaleX), -G.get(SkMatrix::kMSkewX), G.get(SkMatrix::kMTransX), 835cb93a386Sopenharmony_ci -G.get(SkMatrix::kMSkewY), G.get(SkMatrix::kMScaleY), G.get(SkMatrix::kMTransY), 836cb93a386Sopenharmony_ci G.get(SkMatrix::kMPersp0), G.get(SkMatrix::kMPersp1), G.get(SkMatrix::kMPersp2)); 837cb93a386Sopenharmony_ci } 838cb93a386Sopenharmony_ci } else { 839cb93a386Sopenharmony_ci GA = A; 840cb93a386Sopenharmony_ci if (G_inv) { 841cb93a386Sopenharmony_ci G_inv->reset(); 842cb93a386Sopenharmony_ci } 843cb93a386Sopenharmony_ci } 844cb93a386Sopenharmony_ci 845cb93a386Sopenharmony_ci // If the 'total' matrix is singular, set the 'scale' to something finite and zero the matrices. 846cb93a386Sopenharmony_ci // All underlying ports have issues with zero text size, so use the matricies to zero. 847cb93a386Sopenharmony_ci // If one of the scale factors is less than 1/256 then an EM filling square will 848cb93a386Sopenharmony_ci // never affect any pixels. 849cb93a386Sopenharmony_ci // If there are any nonfinite numbers in the matrix, bail out and set the matrices to zero. 850cb93a386Sopenharmony_ci if (SkScalarAbs(GA.get(SkMatrix::kMScaleX)) <= SK_ScalarNearlyZero || 851cb93a386Sopenharmony_ci SkScalarAbs(GA.get(SkMatrix::kMScaleY)) <= SK_ScalarNearlyZero || 852cb93a386Sopenharmony_ci !GA.isFinite()) 853cb93a386Sopenharmony_ci { 854cb93a386Sopenharmony_ci s->fX = SK_Scalar1; 855cb93a386Sopenharmony_ci s->fY = SK_Scalar1; 856cb93a386Sopenharmony_ci sA->setScale(0, 0); 857cb93a386Sopenharmony_ci if (GsA) { 858cb93a386Sopenharmony_ci GsA->setScale(0, 0); 859cb93a386Sopenharmony_ci } 860cb93a386Sopenharmony_ci if (G_inv) { 861cb93a386Sopenharmony_ci G_inv->reset(); 862cb93a386Sopenharmony_ci } 863cb93a386Sopenharmony_ci return false; 864cb93a386Sopenharmony_ci } 865cb93a386Sopenharmony_ci 866cb93a386Sopenharmony_ci // At this point, given GA, create s. 867cb93a386Sopenharmony_ci switch (preMatrixScale) { 868cb93a386Sopenharmony_ci case kFull_PreMatrixScale: 869cb93a386Sopenharmony_ci s->fX = SkScalarAbs(GA.get(SkMatrix::kMScaleX)); 870cb93a386Sopenharmony_ci s->fY = SkScalarAbs(GA.get(SkMatrix::kMScaleY)); 871cb93a386Sopenharmony_ci break; 872cb93a386Sopenharmony_ci case kVertical_PreMatrixScale: { 873cb93a386Sopenharmony_ci SkScalar yScale = SkScalarAbs(GA.get(SkMatrix::kMScaleY)); 874cb93a386Sopenharmony_ci s->fX = yScale; 875cb93a386Sopenharmony_ci s->fY = yScale; 876cb93a386Sopenharmony_ci break; 877cb93a386Sopenharmony_ci } 878cb93a386Sopenharmony_ci case kVerticalInteger_PreMatrixScale: { 879cb93a386Sopenharmony_ci SkScalar realYScale = SkScalarAbs(GA.get(SkMatrix::kMScaleY)); 880cb93a386Sopenharmony_ci SkScalar intYScale = SkScalarRoundToScalar(realYScale); 881cb93a386Sopenharmony_ci if (intYScale == 0) { 882cb93a386Sopenharmony_ci intYScale = SK_Scalar1; 883cb93a386Sopenharmony_ci } 884cb93a386Sopenharmony_ci s->fX = intYScale; 885cb93a386Sopenharmony_ci s->fY = intYScale; 886cb93a386Sopenharmony_ci break; 887cb93a386Sopenharmony_ci } 888cb93a386Sopenharmony_ci } 889cb93a386Sopenharmony_ci 890cb93a386Sopenharmony_ci // The 'remaining' matrix sA is the total matrix A without the scale. 891cb93a386Sopenharmony_ci if (!skewedOrFlipped && ( 892cb93a386Sopenharmony_ci (kFull_PreMatrixScale == preMatrixScale) || 893cb93a386Sopenharmony_ci (kVertical_PreMatrixScale == preMatrixScale && A.getScaleX() == A.getScaleY()))) 894cb93a386Sopenharmony_ci { 895cb93a386Sopenharmony_ci // If GA == A and kFull_PreMatrixScale, sA is identity. 896cb93a386Sopenharmony_ci // If GA == A and kVertical_PreMatrixScale and A.scaleX == A.scaleY, sA is identity. 897cb93a386Sopenharmony_ci sA->reset(); 898cb93a386Sopenharmony_ci } else if (!skewedOrFlipped && kVertical_PreMatrixScale == preMatrixScale) { 899cb93a386Sopenharmony_ci // If GA == A and kVertical_PreMatrixScale, sA.scaleY is SK_Scalar1. 900cb93a386Sopenharmony_ci sA->reset(); 901cb93a386Sopenharmony_ci sA->setScaleX(A.getScaleX() / s->fY); 902cb93a386Sopenharmony_ci } else { 903cb93a386Sopenharmony_ci // TODO: like kVertical_PreMatrixScale, kVerticalInteger_PreMatrixScale with int scales. 904cb93a386Sopenharmony_ci *sA = A; 905cb93a386Sopenharmony_ci sA->preScale(SkScalarInvert(s->fX), SkScalarInvert(s->fY)); 906cb93a386Sopenharmony_ci } 907cb93a386Sopenharmony_ci 908cb93a386Sopenharmony_ci // The 'remainingWithoutRotation' matrix GsA is the non-rotational part of A without the scale. 909cb93a386Sopenharmony_ci if (GsA) { 910cb93a386Sopenharmony_ci *GsA = GA; 911cb93a386Sopenharmony_ci // G is rotational so reorders with the scale. 912cb93a386Sopenharmony_ci GsA->preScale(SkScalarInvert(s->fX), SkScalarInvert(s->fY)); 913cb93a386Sopenharmony_ci } 914cb93a386Sopenharmony_ci 915cb93a386Sopenharmony_ci return true; 916cb93a386Sopenharmony_ci} 917cb93a386Sopenharmony_ci 918cb93a386Sopenharmony_ciSkAxisAlignment SkScalerContext::computeAxisAlignmentForHText() const { 919cb93a386Sopenharmony_ci return fRec.computeAxisAlignmentForHText(); 920cb93a386Sopenharmony_ci} 921cb93a386Sopenharmony_ci 922cb93a386Sopenharmony_ciSkAxisAlignment SkScalerContextRec::computeAxisAlignmentForHText() const { 923cb93a386Sopenharmony_ci // Why fPost2x2 can be used here. 924cb93a386Sopenharmony_ci // getSingleMatrix multiplies in getLocalMatrix, which consists of 925cb93a386Sopenharmony_ci // * fTextSize (a scale, which has no effect) 926cb93a386Sopenharmony_ci // * fPreScaleX (a scale in x, which has no effect) 927cb93a386Sopenharmony_ci // * fPreSkewX (has no effect, but would on vertical text alignment). 928cb93a386Sopenharmony_ci // In other words, making the text bigger, stretching it along the 929cb93a386Sopenharmony_ci // horizontal axis, or fake italicizing it does not move the baseline. 930cb93a386Sopenharmony_ci if (!SkToBool(fFlags & SkScalerContext::kBaselineSnap_Flag)) { 931cb93a386Sopenharmony_ci return kNone_SkAxisAlignment; 932cb93a386Sopenharmony_ci } 933cb93a386Sopenharmony_ci 934cb93a386Sopenharmony_ci if (0 == fPost2x2[1][0]) { 935cb93a386Sopenharmony_ci // The x axis is mapped onto the x axis. 936cb93a386Sopenharmony_ci return kX_SkAxisAlignment; 937cb93a386Sopenharmony_ci } 938cb93a386Sopenharmony_ci if (0 == fPost2x2[0][0]) { 939cb93a386Sopenharmony_ci // The x axis is mapped onto the y axis. 940cb93a386Sopenharmony_ci return kY_SkAxisAlignment; 941cb93a386Sopenharmony_ci } 942cb93a386Sopenharmony_ci return kNone_SkAxisAlignment; 943cb93a386Sopenharmony_ci} 944cb93a386Sopenharmony_ci 945cb93a386Sopenharmony_civoid SkScalerContextRec::setLuminanceColor(SkColor c) { 946cb93a386Sopenharmony_ci fLumBits = SkMaskGamma::CanonicalColor( 947cb93a386Sopenharmony_ci SkColorSetRGB(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c))); 948cb93a386Sopenharmony_ci} 949cb93a386Sopenharmony_ci 950cb93a386Sopenharmony_ci/* 951cb93a386Sopenharmony_ci * Return the scalar with only limited fractional precision. Used to consolidate matrices 952cb93a386Sopenharmony_ci * that vary only slightly when we create our key into the font cache, since the font scaler 953cb93a386Sopenharmony_ci * typically returns the same looking resuts for tiny changes in the matrix. 954cb93a386Sopenharmony_ci */ 955cb93a386Sopenharmony_cistatic SkScalar sk_relax(SkScalar x) { 956cb93a386Sopenharmony_ci SkScalar n = SkScalarRoundToScalar(x * 1024); 957cb93a386Sopenharmony_ci return n / 1024.0f; 958cb93a386Sopenharmony_ci} 959cb93a386Sopenharmony_ci 960cb93a386Sopenharmony_cistatic SkMask::Format compute_mask_format(const SkFont& font) { 961cb93a386Sopenharmony_ci switch (font.getEdging()) { 962cb93a386Sopenharmony_ci case SkFont::Edging::kAlias: 963cb93a386Sopenharmony_ci return SkMask::kBW_Format; 964cb93a386Sopenharmony_ci case SkFont::Edging::kAntiAlias: 965cb93a386Sopenharmony_ci return SkMask::kA8_Format; 966cb93a386Sopenharmony_ci case SkFont::Edging::kSubpixelAntiAlias: 967cb93a386Sopenharmony_ci return SkMask::kLCD16_Format; 968cb93a386Sopenharmony_ci } 969cb93a386Sopenharmony_ci SkASSERT(false); 970cb93a386Sopenharmony_ci return SkMask::kA8_Format; 971cb93a386Sopenharmony_ci} 972cb93a386Sopenharmony_ci 973cb93a386Sopenharmony_ci// Beyond this size, LCD doesn't appreciably improve quality, but it always 974cb93a386Sopenharmony_ci// cost more RAM and draws slower, so we set a cap. 975cb93a386Sopenharmony_ci#ifndef SK_MAX_SIZE_FOR_LCDTEXT 976cb93a386Sopenharmony_ci #define SK_MAX_SIZE_FOR_LCDTEXT 48 977cb93a386Sopenharmony_ci#endif 978cb93a386Sopenharmony_ci 979cb93a386Sopenharmony_ciconst SkScalar gMaxSize2ForLCDText = SK_MAX_SIZE_FOR_LCDTEXT * SK_MAX_SIZE_FOR_LCDTEXT; 980cb93a386Sopenharmony_ci 981cb93a386Sopenharmony_cistatic bool too_big_for_lcd(const SkScalerContextRec& rec, bool checkPost2x2) { 982cb93a386Sopenharmony_ci if (checkPost2x2) { 983cb93a386Sopenharmony_ci SkScalar area = rec.fPost2x2[0][0] * rec.fPost2x2[1][1] - 984cb93a386Sopenharmony_ci rec.fPost2x2[1][0] * rec.fPost2x2[0][1]; 985cb93a386Sopenharmony_ci area *= rec.fTextSize * rec.fTextSize; 986cb93a386Sopenharmony_ci return area > gMaxSize2ForLCDText; 987cb93a386Sopenharmony_ci } else { 988cb93a386Sopenharmony_ci return rec.fTextSize > SK_MAX_SIZE_FOR_LCDTEXT; 989cb93a386Sopenharmony_ci } 990cb93a386Sopenharmony_ci} 991cb93a386Sopenharmony_ci 992cb93a386Sopenharmony_ci// The only reason this is not file static is because it needs the context of SkScalerContext to 993cb93a386Sopenharmony_ci// access SkPaint::computeLuminanceColor. 994cb93a386Sopenharmony_civoid SkScalerContext::MakeRecAndEffects(const SkFont& font, const SkPaint& paint, 995cb93a386Sopenharmony_ci const SkSurfaceProps& surfaceProps, 996cb93a386Sopenharmony_ci SkScalerContextFlags scalerContextFlags, 997cb93a386Sopenharmony_ci const SkMatrix& deviceMatrix, 998cb93a386Sopenharmony_ci SkScalerContextRec* rec, 999cb93a386Sopenharmony_ci SkScalerContextEffects* effects) { 1000cb93a386Sopenharmony_ci SkASSERT(!deviceMatrix.hasPerspective()); 1001cb93a386Sopenharmony_ci 1002cb93a386Sopenharmony_ci sk_bzero(rec, sizeof(SkScalerContextRec)); 1003cb93a386Sopenharmony_ci 1004cb93a386Sopenharmony_ci SkTypeface* typeface = font.getTypefaceOrDefault(); 1005cb93a386Sopenharmony_ci 1006cb93a386Sopenharmony_ci rec->fFontID = typeface->uniqueID(); 1007cb93a386Sopenharmony_ci rec->fTextSize = font.getSize(); 1008cb93a386Sopenharmony_ci rec->fPreScaleX = font.getScaleX(); 1009cb93a386Sopenharmony_ci rec->fPreSkewX = font.getSkewX(); 1010cb93a386Sopenharmony_ci 1011cb93a386Sopenharmony_ci bool checkPost2x2 = false; 1012cb93a386Sopenharmony_ci 1013cb93a386Sopenharmony_ci const SkMatrix::TypeMask mask = deviceMatrix.getType(); 1014cb93a386Sopenharmony_ci if (mask & SkMatrix::kScale_Mask) { 1015cb93a386Sopenharmony_ci rec->fPost2x2[0][0] = sk_relax(deviceMatrix.getScaleX()); 1016cb93a386Sopenharmony_ci rec->fPost2x2[1][1] = sk_relax(deviceMatrix.getScaleY()); 1017cb93a386Sopenharmony_ci checkPost2x2 = true; 1018cb93a386Sopenharmony_ci } else { 1019cb93a386Sopenharmony_ci rec->fPost2x2[0][0] = rec->fPost2x2[1][1] = SK_Scalar1; 1020cb93a386Sopenharmony_ci } 1021cb93a386Sopenharmony_ci if (mask & SkMatrix::kAffine_Mask) { 1022cb93a386Sopenharmony_ci rec->fPost2x2[0][1] = sk_relax(deviceMatrix.getSkewX()); 1023cb93a386Sopenharmony_ci rec->fPost2x2[1][0] = sk_relax(deviceMatrix.getSkewY()); 1024cb93a386Sopenharmony_ci checkPost2x2 = true; 1025cb93a386Sopenharmony_ci } else { 1026cb93a386Sopenharmony_ci rec->fPost2x2[0][1] = rec->fPost2x2[1][0] = 0; 1027cb93a386Sopenharmony_ci } 1028cb93a386Sopenharmony_ci 1029cb93a386Sopenharmony_ci SkPaint::Style style = paint.getStyle(); 1030cb93a386Sopenharmony_ci SkScalar strokeWidth = paint.getStrokeWidth(); 1031cb93a386Sopenharmony_ci 1032cb93a386Sopenharmony_ci unsigned flags = 0; 1033cb93a386Sopenharmony_ci 1034cb93a386Sopenharmony_ci if (font.isEmbolden()) { 1035cb93a386Sopenharmony_ci#ifdef SK_USE_FREETYPE_EMBOLDEN 1036cb93a386Sopenharmony_ci flags |= SkScalerContext::kEmbolden_Flag; 1037cb93a386Sopenharmony_ci#else 1038cb93a386Sopenharmony_ci SkScalar fakeBoldScale = SkScalarInterpFunc(font.getSize(), 1039cb93a386Sopenharmony_ci kStdFakeBoldInterpKeys, 1040cb93a386Sopenharmony_ci kStdFakeBoldInterpValues, 1041cb93a386Sopenharmony_ci kStdFakeBoldInterpLength); 1042cb93a386Sopenharmony_ci SkScalar extra = font.getSize() * fakeBoldScale; 1043cb93a386Sopenharmony_ci 1044cb93a386Sopenharmony_ci if (style == SkPaint::kFill_Style) { 1045cb93a386Sopenharmony_ci style = SkPaint::kStrokeAndFill_Style; 1046cb93a386Sopenharmony_ci strokeWidth = extra; // ignore paint's strokeWidth if it was "fill" 1047cb93a386Sopenharmony_ci } else { 1048cb93a386Sopenharmony_ci strokeWidth += extra; 1049cb93a386Sopenharmony_ci } 1050cb93a386Sopenharmony_ci#endif 1051cb93a386Sopenharmony_ci } 1052cb93a386Sopenharmony_ci 1053cb93a386Sopenharmony_ci if (style != SkPaint::kFill_Style && strokeWidth >= 0) { 1054cb93a386Sopenharmony_ci rec->fFrameWidth = strokeWidth; 1055cb93a386Sopenharmony_ci rec->fMiterLimit = paint.getStrokeMiter(); 1056cb93a386Sopenharmony_ci rec->fStrokeJoin = SkToU8(paint.getStrokeJoin()); 1057cb93a386Sopenharmony_ci rec->fStrokeCap = SkToU8(paint.getStrokeCap()); 1058cb93a386Sopenharmony_ci 1059cb93a386Sopenharmony_ci if (style == SkPaint::kStrokeAndFill_Style) { 1060cb93a386Sopenharmony_ci flags |= SkScalerContext::kFrameAndFill_Flag; 1061cb93a386Sopenharmony_ci } 1062cb93a386Sopenharmony_ci } else { 1063cb93a386Sopenharmony_ci rec->fFrameWidth = -1; 1064cb93a386Sopenharmony_ci rec->fMiterLimit = 0; 1065cb93a386Sopenharmony_ci rec->fStrokeJoin = 0; 1066cb93a386Sopenharmony_ci rec->fStrokeCap = 0; 1067cb93a386Sopenharmony_ci } 1068cb93a386Sopenharmony_ci 1069cb93a386Sopenharmony_ci rec->fMaskFormat = compute_mask_format(font); 1070cb93a386Sopenharmony_ci 1071cb93a386Sopenharmony_ci if (SkMask::kLCD16_Format == rec->fMaskFormat) { 1072cb93a386Sopenharmony_ci if (too_big_for_lcd(*rec, checkPost2x2)) { 1073cb93a386Sopenharmony_ci rec->fMaskFormat = SkMask::kA8_Format; 1074cb93a386Sopenharmony_ci flags |= SkScalerContext::kGenA8FromLCD_Flag; 1075cb93a386Sopenharmony_ci } else { 1076cb93a386Sopenharmony_ci SkPixelGeometry geometry = surfaceProps.pixelGeometry(); 1077cb93a386Sopenharmony_ci 1078cb93a386Sopenharmony_ci switch (geometry) { 1079cb93a386Sopenharmony_ci case kUnknown_SkPixelGeometry: 1080cb93a386Sopenharmony_ci // eeek, can't support LCD 1081cb93a386Sopenharmony_ci rec->fMaskFormat = SkMask::kA8_Format; 1082cb93a386Sopenharmony_ci flags |= SkScalerContext::kGenA8FromLCD_Flag; 1083cb93a386Sopenharmony_ci break; 1084cb93a386Sopenharmony_ci case kRGB_H_SkPixelGeometry: 1085cb93a386Sopenharmony_ci // our default, do nothing. 1086cb93a386Sopenharmony_ci break; 1087cb93a386Sopenharmony_ci case kBGR_H_SkPixelGeometry: 1088cb93a386Sopenharmony_ci flags |= SkScalerContext::kLCD_BGROrder_Flag; 1089cb93a386Sopenharmony_ci break; 1090cb93a386Sopenharmony_ci case kRGB_V_SkPixelGeometry: 1091cb93a386Sopenharmony_ci flags |= SkScalerContext::kLCD_Vertical_Flag; 1092cb93a386Sopenharmony_ci break; 1093cb93a386Sopenharmony_ci case kBGR_V_SkPixelGeometry: 1094cb93a386Sopenharmony_ci flags |= SkScalerContext::kLCD_Vertical_Flag; 1095cb93a386Sopenharmony_ci flags |= SkScalerContext::kLCD_BGROrder_Flag; 1096cb93a386Sopenharmony_ci break; 1097cb93a386Sopenharmony_ci } 1098cb93a386Sopenharmony_ci } 1099cb93a386Sopenharmony_ci } 1100cb93a386Sopenharmony_ci 1101cb93a386Sopenharmony_ci if (font.isEmbeddedBitmaps()) { 1102cb93a386Sopenharmony_ci flags |= SkScalerContext::kEmbeddedBitmapText_Flag; 1103cb93a386Sopenharmony_ci } 1104cb93a386Sopenharmony_ci if (font.isSubpixel()) { 1105cb93a386Sopenharmony_ci flags |= SkScalerContext::kSubpixelPositioning_Flag; 1106cb93a386Sopenharmony_ci } 1107cb93a386Sopenharmony_ci if (font.isForceAutoHinting()) { 1108cb93a386Sopenharmony_ci flags |= SkScalerContext::kForceAutohinting_Flag; 1109cb93a386Sopenharmony_ci } 1110cb93a386Sopenharmony_ci if (font.isLinearMetrics()) { 1111cb93a386Sopenharmony_ci flags |= SkScalerContext::kLinearMetrics_Flag; 1112cb93a386Sopenharmony_ci } 1113cb93a386Sopenharmony_ci if (font.isBaselineSnap()) { 1114cb93a386Sopenharmony_ci flags |= SkScalerContext::kBaselineSnap_Flag; 1115cb93a386Sopenharmony_ci } 1116cb93a386Sopenharmony_ci if (typeface->glyphMaskNeedsCurrentColor()) { 1117cb93a386Sopenharmony_ci flags |= SkScalerContext::kNeedsForegroundColor_Flag; 1118cb93a386Sopenharmony_ci rec->fForegroundColor = paint.getColor(); 1119cb93a386Sopenharmony_ci } 1120cb93a386Sopenharmony_ci rec->fFlags = SkToU16(flags); 1121cb93a386Sopenharmony_ci 1122cb93a386Sopenharmony_ci // these modify fFlags, so do them after assigning fFlags 1123cb93a386Sopenharmony_ci rec->setHinting(font.getHinting()); 1124cb93a386Sopenharmony_ci rec->setLuminanceColor(SkPaintPriv::ComputeLuminanceColor(paint)); 1125cb93a386Sopenharmony_ci 1126cb93a386Sopenharmony_ci // For now always set the paint gamma equal to the device gamma. 1127cb93a386Sopenharmony_ci // The math in SkMaskGamma can handle them being different, 1128cb93a386Sopenharmony_ci // but it requires superluminous masks when 1129cb93a386Sopenharmony_ci // Ex : deviceGamma(x) < paintGamma(x) and x is sufficiently large. 1130cb93a386Sopenharmony_ci rec->setDeviceGamma(SK_GAMMA_EXPONENT); 1131cb93a386Sopenharmony_ci rec->setPaintGamma(SK_GAMMA_EXPONENT); 1132cb93a386Sopenharmony_ci 1133cb93a386Sopenharmony_ci#ifdef SK_GAMMA_CONTRAST 1134cb93a386Sopenharmony_ci rec->setContrast(SK_GAMMA_CONTRAST); 1135cb93a386Sopenharmony_ci#else 1136cb93a386Sopenharmony_ci // A value of 0.5 for SK_GAMMA_CONTRAST appears to be a good compromise. 1137cb93a386Sopenharmony_ci // With lower values small text appears washed out (though correctly so). 1138cb93a386Sopenharmony_ci // With higher values lcd fringing is worse and the smoothing effect of 1139cb93a386Sopenharmony_ci // partial coverage is diminished. 1140cb93a386Sopenharmony_ci rec->setContrast(0.5f); 1141cb93a386Sopenharmony_ci#endif 1142cb93a386Sopenharmony_ci 1143cb93a386Sopenharmony_ci if (!SkToBool(scalerContextFlags & SkScalerContextFlags::kFakeGamma)) { 1144cb93a386Sopenharmony_ci rec->ignoreGamma(); 1145cb93a386Sopenharmony_ci } 1146cb93a386Sopenharmony_ci if (!SkToBool(scalerContextFlags & SkScalerContextFlags::kBoostContrast)) { 1147cb93a386Sopenharmony_ci rec->setContrast(0); 1148cb93a386Sopenharmony_ci } 1149cb93a386Sopenharmony_ci 1150cb93a386Sopenharmony_ci new (effects) SkScalerContextEffects{paint}; 1151cb93a386Sopenharmony_ci} 1152cb93a386Sopenharmony_ci 1153cb93a386Sopenharmony_ciSkDescriptor* SkScalerContext::CreateDescriptorAndEffectsUsingPaint( 1154cb93a386Sopenharmony_ci const SkFont& font, const SkPaint& paint, const SkSurfaceProps& surfaceProps, 1155cb93a386Sopenharmony_ci SkScalerContextFlags scalerContextFlags, const SkMatrix& deviceMatrix, SkAutoDescriptor* ad, 1156cb93a386Sopenharmony_ci SkScalerContextEffects* effects) 1157cb93a386Sopenharmony_ci{ 1158cb93a386Sopenharmony_ci SkScalerContextRec rec; 1159cb93a386Sopenharmony_ci MakeRecAndEffects(font, paint, surfaceProps, scalerContextFlags, deviceMatrix, &rec, effects); 1160cb93a386Sopenharmony_ci return AutoDescriptorGivenRecAndEffects(rec, *effects, ad); 1161cb93a386Sopenharmony_ci} 1162cb93a386Sopenharmony_ci 1163cb93a386Sopenharmony_cistatic size_t calculate_size_and_flatten(const SkScalerContextRec& rec, 1164cb93a386Sopenharmony_ci const SkScalerContextEffects& effects, 1165cb93a386Sopenharmony_ci SkBinaryWriteBuffer* effectBuffer) { 1166cb93a386Sopenharmony_ci size_t descSize = sizeof(rec); 1167cb93a386Sopenharmony_ci int entryCount = 1; 1168cb93a386Sopenharmony_ci 1169cb93a386Sopenharmony_ci if (effects.fPathEffect || effects.fMaskFilter) { 1170cb93a386Sopenharmony_ci if (effects.fPathEffect) { effectBuffer->writeFlattenable(effects.fPathEffect); } 1171cb93a386Sopenharmony_ci if (effects.fMaskFilter) { effectBuffer->writeFlattenable(effects.fMaskFilter); } 1172cb93a386Sopenharmony_ci entryCount += 1; 1173cb93a386Sopenharmony_ci descSize += effectBuffer->bytesWritten(); 1174cb93a386Sopenharmony_ci } 1175cb93a386Sopenharmony_ci 1176cb93a386Sopenharmony_ci descSize += SkDescriptor::ComputeOverhead(entryCount); 1177cb93a386Sopenharmony_ci return descSize; 1178cb93a386Sopenharmony_ci} 1179cb93a386Sopenharmony_ci 1180cb93a386Sopenharmony_cistatic void generate_descriptor(const SkScalerContextRec& rec, 1181cb93a386Sopenharmony_ci const SkBinaryWriteBuffer& effectBuffer, 1182cb93a386Sopenharmony_ci SkDescriptor* desc) { 1183cb93a386Sopenharmony_ci desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec); 1184cb93a386Sopenharmony_ci 1185cb93a386Sopenharmony_ci if (effectBuffer.bytesWritten() > 0) { 1186cb93a386Sopenharmony_ci effectBuffer.writeToMemory(desc->addEntry(kEffects_SkDescriptorTag, 1187cb93a386Sopenharmony_ci effectBuffer.bytesWritten(), 1188cb93a386Sopenharmony_ci nullptr)); 1189cb93a386Sopenharmony_ci } 1190cb93a386Sopenharmony_ci 1191cb93a386Sopenharmony_ci desc->computeChecksum(); 1192cb93a386Sopenharmony_ci} 1193cb93a386Sopenharmony_ci 1194cb93a386Sopenharmony_ciSkDescriptor* SkScalerContext::AutoDescriptorGivenRecAndEffects( 1195cb93a386Sopenharmony_ci const SkScalerContextRec& rec, 1196cb93a386Sopenharmony_ci const SkScalerContextEffects& effects, 1197cb93a386Sopenharmony_ci SkAutoDescriptor* ad) 1198cb93a386Sopenharmony_ci{ 1199cb93a386Sopenharmony_ci SkBinaryWriteBuffer buf; 1200cb93a386Sopenharmony_ci 1201cb93a386Sopenharmony_ci ad->reset(calculate_size_and_flatten(rec, effects, &buf)); 1202cb93a386Sopenharmony_ci generate_descriptor(rec, buf, ad->getDesc()); 1203cb93a386Sopenharmony_ci 1204cb93a386Sopenharmony_ci return ad->getDesc(); 1205cb93a386Sopenharmony_ci} 1206cb93a386Sopenharmony_ci 1207cb93a386Sopenharmony_cistd::unique_ptr<SkDescriptor> SkScalerContext::DescriptorGivenRecAndEffects( 1208cb93a386Sopenharmony_ci const SkScalerContextRec& rec, 1209cb93a386Sopenharmony_ci const SkScalerContextEffects& effects) 1210cb93a386Sopenharmony_ci{ 1211cb93a386Sopenharmony_ci SkBinaryWriteBuffer buf; 1212cb93a386Sopenharmony_ci 1213cb93a386Sopenharmony_ci auto desc = SkDescriptor::Alloc(calculate_size_and_flatten(rec, effects, &buf)); 1214cb93a386Sopenharmony_ci generate_descriptor(rec, buf, desc.get()); 1215cb93a386Sopenharmony_ci 1216cb93a386Sopenharmony_ci return desc; 1217cb93a386Sopenharmony_ci} 1218cb93a386Sopenharmony_ci 1219cb93a386Sopenharmony_civoid SkScalerContext::DescriptorBufferGiveRec(const SkScalerContextRec& rec, void* buffer) { 1220cb93a386Sopenharmony_ci generate_descriptor(rec, SkBinaryWriteBuffer{}, (SkDescriptor*)buffer); 1221cb93a386Sopenharmony_ci} 1222cb93a386Sopenharmony_ci 1223cb93a386Sopenharmony_cibool SkScalerContext::CheckBufferSizeForRec(const SkScalerContextRec& rec, 1224cb93a386Sopenharmony_ci const SkScalerContextEffects& effects, 1225cb93a386Sopenharmony_ci size_t size) { 1226cb93a386Sopenharmony_ci SkBinaryWriteBuffer buf; 1227cb93a386Sopenharmony_ci return size >= calculate_size_and_flatten(rec, effects, &buf); 1228cb93a386Sopenharmony_ci} 1229cb93a386Sopenharmony_ci 1230cb93a386Sopenharmony_cistd::unique_ptr<SkScalerContext> SkScalerContext::MakeEmpty( 1231cb93a386Sopenharmony_ci sk_sp<SkTypeface> typeface, const SkScalerContextEffects& effects, 1232cb93a386Sopenharmony_ci const SkDescriptor* desc) { 1233cb93a386Sopenharmony_ci class SkScalerContext_Empty : public SkScalerContext { 1234cb93a386Sopenharmony_ci public: 1235cb93a386Sopenharmony_ci SkScalerContext_Empty(sk_sp<SkTypeface> typeface, const SkScalerContextEffects& effects, 1236cb93a386Sopenharmony_ci const SkDescriptor* desc) 1237cb93a386Sopenharmony_ci : SkScalerContext(std::move(typeface), effects, desc) {} 1238cb93a386Sopenharmony_ci 1239cb93a386Sopenharmony_ci protected: 1240cb93a386Sopenharmony_ci bool generateAdvance(SkGlyph* glyph) override { 1241cb93a386Sopenharmony_ci glyph->zeroMetrics(); 1242cb93a386Sopenharmony_ci return true; 1243cb93a386Sopenharmony_ci } 1244cb93a386Sopenharmony_ci void generateMetrics(SkGlyph* glyph) override { 1245cb93a386Sopenharmony_ci glyph->fMaskFormat = fRec.fMaskFormat; 1246cb93a386Sopenharmony_ci glyph->zeroMetrics(); 1247cb93a386Sopenharmony_ci } 1248cb93a386Sopenharmony_ci void generateImage(const SkGlyph& glyph) override {} 1249cb93a386Sopenharmony_ci bool generatePath(SkGlyphID glyph, SkPath* path) override { 1250cb93a386Sopenharmony_ci path->reset(); 1251cb93a386Sopenharmony_ci return false; 1252cb93a386Sopenharmony_ci } 1253cb93a386Sopenharmony_ci void generateFontMetrics(SkFontMetrics* metrics) override { 1254cb93a386Sopenharmony_ci if (metrics) { 1255cb93a386Sopenharmony_ci sk_bzero(metrics, sizeof(*metrics)); 1256cb93a386Sopenharmony_ci } 1257cb93a386Sopenharmony_ci } 1258cb93a386Sopenharmony_ci }; 1259cb93a386Sopenharmony_ci 1260cb93a386Sopenharmony_ci return std::make_unique<SkScalerContext_Empty>(std::move(typeface), effects, desc); 1261cb93a386Sopenharmony_ci} 1262cb93a386Sopenharmony_ci 1263cb93a386Sopenharmony_ci 1264cb93a386Sopenharmony_ci 1265cb93a386Sopenharmony_ci 1266