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