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