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