1 /* 2 * Copyright 2006 The Android Open Source Project 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #ifndef SkScalerContext_DEFINED 9 #define SkScalerContext_DEFINED 10 11 #include "SkGlyph.h" 12 #include "SkMask.h" 13 #include "SkMaskGamma.h" 14 #include "SkMatrix.h" 15 #include "SkPaint.h" 16 #include "SkTypeface.h" 17 18 class SkDescriptor; 19 class SkMaskFilter; 20 class SkPathEffect; 21 class SkRasterizer; 22 23 struct SkScalerContextEffects { 24 SkScalerContextEffects() : fPathEffect(nullptr), fMaskFilter(nullptr), fRasterizer(nullptr) {} 25 SkScalerContextEffects(SkPathEffect* pe, SkMaskFilter* mf, SkRasterizer* ra) 26 : fPathEffect(pe), fMaskFilter(mf), fRasterizer(ra) {} 27 28 SkPathEffect* fPathEffect; 29 SkMaskFilter* fMaskFilter; 30 SkRasterizer* fRasterizer; 31 }; 32 33 enum SkAxisAlignment { 34 kNone_SkAxisAlignment, 35 kX_SkAxisAlignment, 36 kY_SkAxisAlignment 37 }; 38 39 /* 40 * To allow this to be forward-declared, it must be its own typename, rather 41 * than a nested struct inside SkScalerContext (where it started). 42 */ 43 struct SkScalerContextRec { 44 uint32_t fFontID; 45 SkScalar fTextSize, fPreScaleX, fPreSkewX; 46 SkScalar fPost2x2[2][2]; 47 SkScalar fFrameWidth, fMiterLimit; 48 49 //These describe the parameters to create (uniquely identify) the pre-blend. 50 uint32_t fLumBits; 51 uint8_t fDeviceGamma; //2.6, (0.0, 4.0) gamma, 0.0 for sRGB 52 uint8_t fPaintGamma; //2.6, (0.0, 4.0) gamma, 0.0 for sRGB 53 uint8_t fContrast; //0.8+1, [0.0, 1.0] artificial contrast 54 uint8_t fReservedAlign; 55 56 SkScalar getDeviceGamma() const { 57 return SkIntToScalar(fDeviceGamma) / (1 << 6); 58 } 59 void setDeviceGamma(SkScalar dg) { 60 SkASSERT(0 <= dg && dg < SkIntToScalar(4)); 61 fDeviceGamma = SkScalarFloorToInt(dg * (1 << 6)); 62 } 63 64 SkScalar getPaintGamma() const { 65 return SkIntToScalar(fPaintGamma) / (1 << 6); 66 } 67 void setPaintGamma(SkScalar pg) { 68 SkASSERT(0 <= pg && pg < SkIntToScalar(4)); 69 fPaintGamma = SkScalarFloorToInt(pg * (1 << 6)); 70 } 71 72 SkScalar getContrast() const { 73 return SkIntToScalar(fContrast) / ((1 << 8) - 1); 74 } 75 void setContrast(SkScalar c) { 76 SkASSERT(0 <= c && c <= SK_Scalar1); 77 fContrast = SkScalarRoundToInt(c * ((1 << 8) - 1)); 78 } 79 80 /** 81 * Causes the luminance color to be ignored, and the paint and device 82 * gamma to be effectively 1.0 83 */ 84 void ignoreGamma() { 85 setLuminanceColor(SK_ColorTRANSPARENT); 86 setPaintGamma(SK_Scalar1); 87 setDeviceGamma(SK_Scalar1); 88 } 89 90 /** 91 * Causes the luminance color and contrast to be ignored, and the 92 * paint and device gamma to be effectively 1.0. 93 */ 94 void ignorePreBlend() { 95 ignoreGamma(); 96 setContrast(0); 97 } 98 99 uint8_t fMaskFormat; 100 uint8_t fStrokeJoin : 4; 101 uint8_t fStrokeCap : 4; 102 uint16_t fFlags; 103 // Warning: when adding members note that the size of this structure 104 // must be a multiple of 4. SkDescriptor requires that its arguments be 105 // multiples of four and this structure is put in an SkDescriptor in 106 // SkPaint::MakeRec. 107 108 void getMatrixFrom2x2(SkMatrix*) const; 109 void getLocalMatrix(SkMatrix*) const; 110 void getSingleMatrix(SkMatrix*) const; 111 112 /** The kind of scale which will be applied by the underlying port (pre-matrix). */ 113 enum PreMatrixScale { 114 kFull_PreMatrixScale, // The underlying port can apply both x and y scale. 115 kVertical_PreMatrixScale, // The underlying port can only apply a y scale. 116 kVerticalInteger_PreMatrixScale // The underlying port can only apply an integer y scale. 117 }; 118 /** 119 * Compute useful matrices for use with sizing in underlying libraries. 120 * 121 * There are two kinds of text size, a 'requested/logical size' which is like asking for size 122 * '12' and a 'real' size which is the size after the matrix is applied. The matrices produced 123 * by this method are based on the 'real' size. This method effectively finds the total device 124 * matrix and decomposes it in various ways. 125 * 126 * The most useful decomposition is into 'scale' and 'remaining'. The 'scale' is applied first 127 * and then the 'remaining' to fully apply the total matrix. This decomposition is useful when 128 * the text size ('scale') may have meaning apart from the total matrix. This is true when 129 * hinting, and sometimes true for other properties as well. 130 * 131 * The second (optional) decomposition is of 'remaining' into a non-rotational part 132 * 'remainingWithoutRotation' and a rotational part 'remainingRotation'. The 'scale' is applied 133 * first, then 'remainingWithoutRotation', then 'remainingRotation' to fully apply the total 134 * matrix. This decomposition is helpful when only horizontal metrics can be trusted, so the 135 * 'scale' and 'remainingWithoutRotation' will be handled by the underlying library, but 136 * the final rotation 'remainingRotation' will be handled manually. 137 * 138 * The 'total' matrix is also (optionally) available. This is useful in cases where the 139 * underlying library will not be used, often when working directly with font data. 140 * 141 * The parameters 'scale' and 'remaining' are required, the other pointers may be nullptr. 142 * 143 * @param preMatrixScale the kind of scale to extract from the total matrix. 144 * @param scale the scale extracted from the total matrix (both values positive). 145 * @param remaining apply after scale to apply the total matrix. 146 * @param remainingWithoutRotation apply after scale to apply the total matrix sans rotation. 147 * @param remainingRotation apply after remainingWithoutRotation to apply the total matrix. 148 * @param total the total matrix. 149 * @return false if the matrix was singular. The output will be valid but not invertible. 150 */ 151 bool computeMatrices(PreMatrixScale preMatrixScale, 152 SkVector* scale, SkMatrix* remaining, 153 SkMatrix* remainingWithoutRotation = nullptr, 154 SkMatrix* remainingRotation = nullptr, 155 SkMatrix* total = nullptr); 156 157 inline SkPaint::Hinting getHinting() const; 158 inline void setHinting(SkPaint::Hinting); 159 160 SkMask::Format getFormat() const { 161 return static_cast<SkMask::Format>(fMaskFormat); 162 } 163 164 SkColor getLuminanceColor() const { 165 return fLumBits; 166 } 167 168 void setLuminanceColor(SkColor c) { 169 fLumBits = c; 170 } 171 }; 172 173 //The following typedef hides from the rest of the implementation the number of 174 //most significant bits to consider when creating mask gamma tables. Two bits 175 //per channel was chosen as a balance between fidelity (more bits) and cache 176 //sizes (fewer bits). Three bits per channel was chosen when #303942; (used by 177 //the Chrome UI) turned out too green. 178 typedef SkTMaskGamma<3, 3, 3> SkMaskGamma; 179 180 class SkScalerContext { 181 public: 182 typedef SkScalerContextRec Rec; 183 184 enum Flags { 185 kFrameAndFill_Flag = 0x0001, 186 kDevKernText_Flag = 0x0002, 187 kEmbeddedBitmapText_Flag = 0x0004, 188 kEmbolden_Flag = 0x0008, 189 kSubpixelPositioning_Flag = 0x0010, 190 kForceAutohinting_Flag = 0x0020, // Use auto instead of bytcode hinting if hinting. 191 kVertical_Flag = 0x0040, 192 193 // together, these two flags resulting in a two bit value which matches 194 // up with the SkPaint::Hinting enum. 195 kHinting_Shift = 7, // to shift into the other flags above 196 kHintingBit1_Flag = 0x0080, 197 kHintingBit2_Flag = 0x0100, 198 199 // Pixel geometry information. 200 // only meaningful if fMaskFormat is kLCD16 201 kLCD_Vertical_Flag = 0x0200, // else Horizontal 202 kLCD_BGROrder_Flag = 0x0400, // else RGB order 203 204 // Generate A8 from LCD source (for GDI and CoreGraphics). 205 // only meaningful if fMaskFormat is kA8 206 kGenA8FromLCD_Flag = 0x0800, // could be 0x200 (bit meaning dependent on fMaskFormat) 207 }; 208 209 // computed values 210 enum { 211 kHinting_Mask = kHintingBit1_Flag | kHintingBit2_Flag, 212 }; 213 214 SkScalerContext(sk_sp<SkTypeface>, const SkScalerContextEffects&, const SkDescriptor*); 215 virtual ~SkScalerContext(); 216 217 SkTypeface* getTypeface() const { return fTypeface.get(); } 218 219 SkMask::Format getMaskFormat() const { 220 return (SkMask::Format)fRec.fMaskFormat; 221 } 222 223 bool isSubpixel() const { 224 return SkToBool(fRec.fFlags & kSubpixelPositioning_Flag); 225 } 226 227 bool isVertical() const { 228 return SkToBool(fRec.fFlags & kVertical_Flag); 229 } 230 231 /** Return the corresponding glyph for the specified unichar. Since contexts 232 may be chained (under the hood), the glyphID that is returned may in 233 fact correspond to a different font/context. In that case, we use the 234 base-glyph-count to know how to translate back into local glyph space. 235 */ 236 uint16_t charToGlyphID(SkUnichar uni) { 237 return generateCharToGlyph(uni); 238 } 239 240 /** Map the glyphID to its glyph index, and then to its char code. Unmapped 241 glyphs return zero. 242 */ 243 SkUnichar glyphIDToChar(uint16_t glyphID) { 244 return (glyphID < getGlyphCount()) ? generateGlyphToChar(glyphID) : 0; 245 } 246 247 unsigned getGlyphCount() { return this->generateGlyphCount(); } 248 void getAdvance(SkGlyph*); 249 void getMetrics(SkGlyph*); 250 void getImage(const SkGlyph&); 251 void getPath(SkPackedGlyphID, SkPath*); 252 void getFontMetrics(SkPaint::FontMetrics*); 253 254 /** Return the size in bytes of the associated gamma lookup table 255 */ 256 static size_t GetGammaLUTSize(SkScalar contrast, SkScalar paintGamma, SkScalar deviceGamma, 257 int* width, int* height); 258 259 /** Get the associated gamma lookup table. The 'data' pointer must point to pre-allocated 260 memory, with size in bytes greater than or equal to the return value of getGammaLUTSize(). 261 */ 262 static void GetGammaLUTData(SkScalar contrast, SkScalar paintGamma, SkScalar deviceGamma, 263 void* data); 264 265 static void MakeRec(const SkPaint&, const SkSurfaceProps* surfaceProps, 266 const SkMatrix*, Rec* rec); 267 static inline void PostMakeRec(const SkPaint&, Rec*); 268 269 static SkMaskGamma::PreBlend GetMaskPreBlend(const Rec& rec); 270 271 const Rec& getRec() const { return fRec; } 272 273 SkScalerContextEffects getEffects() const { 274 return { fPathEffect.get(), fMaskFilter.get(), fRasterizer.get() }; 275 } 276 277 /** 278 * Return the axis (if any) that the baseline for horizontal text should land on. 279 * As an example, the identity matrix will return kX_SkAxisAlignment 280 */ 281 SkAxisAlignment computeAxisAlignmentForHText(); 282 283 protected: 284 Rec fRec; 285 286 /** Generates the contents of glyph.fAdvanceX and glyph.fAdvanceY. 287 * May call getMetrics if that would be just as fast. 288 */ 289 virtual void generateAdvance(SkGlyph* glyph) = 0; 290 291 /** Generates the contents of glyph.fWidth, fHeight, fTop, fLeft, 292 * as well as fAdvanceX and fAdvanceY if not already set. 293 * 294 * TODO: fMaskFormat is set by getMetrics later; cannot be set here. 295 */ 296 virtual void generateMetrics(SkGlyph* glyph) = 0; 297 298 /** Generates the contents of glyph.fImage. 299 * When called, glyph.fImage will be pointing to a pre-allocated, 300 * uninitialized region of memory of size glyph.computeImageSize(). 301 * This method may change glyph.fMaskFormat if the new image size is 302 * less than or equal to the old image size. 303 * 304 * Because glyph.computeImageSize() will determine the size of fImage, 305 * generateMetrics will be called before generateImage. 306 */ 307 virtual void generateImage(const SkGlyph& glyph) = 0; 308 309 /** Sets the passed path to the glyph outline. 310 * If this cannot be done the path is set to empty; 311 * this is indistinguishable from a glyph with an empty path. 312 */ 313 virtual void generatePath(SkGlyphID glyphId, SkPath* path) = 0; 314 315 /** Retrieves font metrics. */ 316 virtual void generateFontMetrics(SkPaint::FontMetrics*) = 0; 317 318 /** Returns the number of glyphs in the font. */ 319 virtual unsigned generateGlyphCount() = 0; 320 321 /** Returns the glyph id for the given unichar. 322 * If there is no 1:1 mapping from the unichar to a glyph id, returns 0. 323 */ 324 virtual uint16_t generateCharToGlyph(SkUnichar unichar) = 0; 325 326 /** Returns the unichar for the given glyph id. 327 * If there is no 1:1 mapping from the glyph id to a unichar, returns 0. 328 * The default implementation always returns 0, indicating failure. 329 */ 330 virtual SkUnichar generateGlyphToChar(uint16_t glyphId); 331 332 void forceGenerateImageFromPath() { fGenerateImageFromPath = true; } 333 void forceOffGenerateImageFromPath() { fGenerateImageFromPath = false; } 334 335 private: 336 friend class SkRandomScalerContext; // For debug purposes 337 338 // never null 339 sk_sp<SkTypeface> fTypeface; 340 341 // optional objects, which may be null 342 sk_sp<SkPathEffect> fPathEffect; 343 sk_sp<SkMaskFilter> fMaskFilter; 344 sk_sp<SkRasterizer> fRasterizer; 345 346 // if this is set, we draw the image from a path, rather than 347 // calling generateImage. 348 bool fGenerateImageFromPath; 349 350 void internalGetPath(SkPackedGlyphID id, SkPath* fillPath, 351 SkPath* devPath, SkMatrix* fillToDevMatrix); 352 353 // SkMaskGamma::PreBlend converts linear masks to gamma correcting masks. 354 protected: 355 // Visible to subclasses so that generateImage can apply the pre-blend directly. 356 const SkMaskGamma::PreBlend fPreBlend; 357 private: 358 // When there is a filter, previous steps must create a linear mask 359 // and the pre-blend applied as a final step. 360 const SkMaskGamma::PreBlend fPreBlendForFilter; 361 }; 362 363 #define kRec_SkDescriptorTag SkSetFourByteTag('s', 'r', 'e', 'c') 364 #define kPathEffect_SkDescriptorTag SkSetFourByteTag('p', 't', 'h', 'e') 365 #define kMaskFilter_SkDescriptorTag SkSetFourByteTag('m', 's', 'k', 'f') 366 #define kRasterizer_SkDescriptorTag SkSetFourByteTag('r', 'a', 's', 't') 367 368 /////////////////////////////////////////////////////////////////////////////// 369 370 SkPaint::Hinting SkScalerContextRec::getHinting() const { 371 unsigned hint = (fFlags & SkScalerContext::kHinting_Mask) >> 372 SkScalerContext::kHinting_Shift; 373 return static_cast<SkPaint::Hinting>(hint); 374 } 375 376 void SkScalerContextRec::setHinting(SkPaint::Hinting hinting) { 377 fFlags = (fFlags & ~SkScalerContext::kHinting_Mask) | 378 (hinting << SkScalerContext::kHinting_Shift); 379 } 380 381 382 #endif 383