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 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