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