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