michael@0: michael@0: michael@0: /* michael@0: * Copyright 2006 The Android Open Source Project michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: michael@0: #ifndef SkPaint_DEFINED michael@0: #define SkPaint_DEFINED michael@0: michael@0: #include "SkColor.h" michael@0: #include "SkDrawLooper.h" michael@0: #include "SkMatrix.h" michael@0: #include "SkXfermode.h" michael@0: #ifdef SK_BUILD_FOR_ANDROID michael@0: #include "SkPaintOptionsAndroid.h" michael@0: #endif michael@0: michael@0: class SkAnnotation; michael@0: class SkAutoGlyphCache; michael@0: class SkColorFilter; michael@0: class SkDescriptor; michael@0: struct SkDeviceProperties; michael@0: class SkReadBuffer; michael@0: class SkWriteBuffer; michael@0: struct SkGlyph; michael@0: struct SkRect; michael@0: class SkGlyphCache; michael@0: class SkImageFilter; michael@0: class SkMaskFilter; michael@0: class SkPath; michael@0: class SkPathEffect; michael@0: struct SkPoint; michael@0: class SkRasterizer; michael@0: class SkShader; michael@0: class SkTypeface; michael@0: michael@0: typedef const SkGlyph& (*SkDrawCacheProc)(SkGlyphCache*, const char**, michael@0: SkFixed x, SkFixed y); michael@0: michael@0: typedef const SkGlyph& (*SkMeasureCacheProc)(SkGlyphCache*, const char**); michael@0: michael@0: #define kBicubicFilterBitmap_Flag kHighQualityFilterBitmap_Flag michael@0: michael@0: /** \class SkPaint michael@0: michael@0: The SkPaint class holds the style and color information about how to draw michael@0: geometries, text and bitmaps. michael@0: */ michael@0: michael@0: class SK_API SkPaint { michael@0: enum { michael@0: // DEPRECATED -- use setFilterLevel instead michael@0: kFilterBitmap_Flag = 0x02, // temporary flag michael@0: // DEPRECATED -- use setFilterLevel instead michael@0: kHighQualityFilterBitmap_Flag = 0x4000, // temporary flag michael@0: // DEPRECATED -- use setFilterLevel instead michael@0: kHighQualityDownsampleBitmap_Flag = 0x8000, // temporary flag michael@0: }; michael@0: public: michael@0: SkPaint(); michael@0: SkPaint(const SkPaint& paint); michael@0: ~SkPaint(); michael@0: michael@0: SkPaint& operator=(const SkPaint&); michael@0: michael@0: SK_API friend bool operator==(const SkPaint& a, const SkPaint& b); michael@0: friend bool operator!=(const SkPaint& a, const SkPaint& b) { michael@0: return !(a == b); michael@0: } michael@0: michael@0: void flatten(SkWriteBuffer&) const; michael@0: void unflatten(SkReadBuffer&); michael@0: michael@0: /** Restores the paint to its initial settings. michael@0: */ michael@0: void reset(); michael@0: michael@0: /** Specifies the level of hinting to be performed. These names are taken michael@0: from the Gnome/Cairo names for the same. They are translated into michael@0: Freetype concepts the same as in cairo-ft-font.c: michael@0: kNo_Hinting -> FT_LOAD_NO_HINTING michael@0: kSlight_Hinting -> FT_LOAD_TARGET_LIGHT michael@0: kNormal_Hinting -> michael@0: kFull_Hinting -> michael@0: */ michael@0: enum Hinting { michael@0: kNo_Hinting = 0, michael@0: kSlight_Hinting = 1, michael@0: kNormal_Hinting = 2, //!< this is the default michael@0: kFull_Hinting = 3 michael@0: }; michael@0: michael@0: Hinting getHinting() const { michael@0: return static_cast(fHinting); michael@0: } michael@0: michael@0: void setHinting(Hinting hintingLevel); michael@0: michael@0: /** Specifies the bit values that are stored in the paint's flags. michael@0: */ michael@0: enum Flags { michael@0: kAntiAlias_Flag = 0x01, //!< mask to enable antialiasing michael@0: kDither_Flag = 0x04, //!< mask to enable dithering michael@0: kUnderlineText_Flag = 0x08, //!< mask to enable underline text michael@0: kStrikeThruText_Flag = 0x10, //!< mask to enable strike-thru text michael@0: kFakeBoldText_Flag = 0x20, //!< mask to enable fake-bold text michael@0: kLinearText_Flag = 0x40, //!< mask to enable linear-text michael@0: kSubpixelText_Flag = 0x80, //!< mask to enable subpixel text positioning michael@0: kDevKernText_Flag = 0x100, //!< mask to enable device kerning text michael@0: kLCDRenderText_Flag = 0x200, //!< mask to enable subpixel glyph renderering michael@0: kEmbeddedBitmapText_Flag = 0x400, //!< mask to enable embedded bitmap strikes michael@0: kAutoHinting_Flag = 0x800, //!< mask to force Freetype's autohinter michael@0: kVerticalText_Flag = 0x1000, michael@0: kGenA8FromLCD_Flag = 0x2000, // hack for GDI -- do not use if you can help it michael@0: kDistanceFieldTextTEMP_Flag = 0x4000, //!< TEMPORARY mask to enable distance fields michael@0: // currently overrides LCD and subpixel rendering michael@0: // when adding extra flags, note that the fFlags member is specified michael@0: // with a bit-width and you'll have to expand it. michael@0: michael@0: kAllFlags = 0xFFFF michael@0: }; michael@0: michael@0: /** Return the paint's flags. Use the Flag enum to test flag values. michael@0: @return the paint's flags (see enums ending in _Flag for bit masks) michael@0: */ michael@0: uint32_t getFlags() const { return fFlags; } michael@0: michael@0: /** Set the paint's flags. Use the Flag enum to specific flag values. michael@0: @param flags The new flag bits for the paint (see Flags enum) michael@0: */ michael@0: void setFlags(uint32_t flags); michael@0: michael@0: /** Helper for getFlags(), returning true if kAntiAlias_Flag bit is set michael@0: @return true if the antialias bit is set in the paint's flags. michael@0: */ michael@0: bool isAntiAlias() const { michael@0: return SkToBool(this->getFlags() & kAntiAlias_Flag); michael@0: } michael@0: michael@0: /** Helper for setFlags(), setting or clearing the kAntiAlias_Flag bit michael@0: @param aa true to enable antialiasing, false to disable it michael@0: */ michael@0: void setAntiAlias(bool aa); michael@0: michael@0: /** Helper for getFlags(), returning true if kDither_Flag bit is set michael@0: @return true if the dithering bit is set in the paint's flags. michael@0: */ michael@0: bool isDither() const { michael@0: return SkToBool(this->getFlags() & kDither_Flag); michael@0: } michael@0: michael@0: /** Helper for setFlags(), setting or clearing the kDither_Flag bit michael@0: @param dither true to enable dithering, false to disable it michael@0: */ michael@0: void setDither(bool dither); michael@0: michael@0: /** Helper for getFlags(), returning true if kLinearText_Flag bit is set michael@0: @return true if the lineartext bit is set in the paint's flags michael@0: */ michael@0: bool isLinearText() const { michael@0: return SkToBool(this->getFlags() & kLinearText_Flag); michael@0: } michael@0: michael@0: /** Helper for setFlags(), setting or clearing the kLinearText_Flag bit michael@0: @param linearText true to set the linearText bit in the paint's flags, michael@0: false to clear it. michael@0: */ michael@0: void setLinearText(bool linearText); michael@0: michael@0: /** Helper for getFlags(), returning true if kSubpixelText_Flag bit is set michael@0: @return true if the lineartext bit is set in the paint's flags michael@0: */ michael@0: bool isSubpixelText() const { michael@0: return SkToBool(this->getFlags() & kSubpixelText_Flag); michael@0: } michael@0: michael@0: /** michael@0: * Helper for setFlags(), setting or clearing the kSubpixelText_Flag. michael@0: * @param subpixelText true to set the subpixelText bit in the paint's michael@0: * flags, false to clear it. michael@0: */ michael@0: void setSubpixelText(bool subpixelText); michael@0: michael@0: bool isLCDRenderText() const { michael@0: return SkToBool(this->getFlags() & kLCDRenderText_Flag); michael@0: } michael@0: michael@0: /** michael@0: * Helper for setFlags(), setting or clearing the kLCDRenderText_Flag. michael@0: * Note: antialiasing must also be on for lcd rendering michael@0: * @param lcdText true to set the LCDRenderText bit in the paint's flags, michael@0: * false to clear it. michael@0: */ michael@0: void setLCDRenderText(bool lcdText); michael@0: michael@0: bool isEmbeddedBitmapText() const { michael@0: return SkToBool(this->getFlags() & kEmbeddedBitmapText_Flag); michael@0: } michael@0: michael@0: /** Helper for setFlags(), setting or clearing the kEmbeddedBitmapText_Flag bit michael@0: @param useEmbeddedBitmapText true to set the kEmbeddedBitmapText bit in the paint's flags, michael@0: false to clear it. michael@0: */ michael@0: void setEmbeddedBitmapText(bool useEmbeddedBitmapText); michael@0: michael@0: bool isAutohinted() const { michael@0: return SkToBool(this->getFlags() & kAutoHinting_Flag); michael@0: } michael@0: michael@0: /** Helper for setFlags(), setting or clearing the kAutoHinting_Flag bit michael@0: @param useAutohinter true to set the kEmbeddedBitmapText bit in the michael@0: paint's flags, michael@0: false to clear it. michael@0: */ michael@0: void setAutohinted(bool useAutohinter); michael@0: michael@0: bool isVerticalText() const { michael@0: return SkToBool(this->getFlags() & kVerticalText_Flag); michael@0: } michael@0: michael@0: /** michael@0: * Helper for setting or clearing the kVerticalText_Flag bit in michael@0: * setFlags(...). michael@0: * michael@0: * If this bit is set, then advances are treated as Y values rather than michael@0: * X values, and drawText will places its glyphs vertically rather than michael@0: * horizontally. michael@0: */ michael@0: void setVerticalText(bool); michael@0: michael@0: /** Helper for getFlags(), returning true if kUnderlineText_Flag bit is set michael@0: @return true if the underlineText bit is set in the paint's flags. michael@0: */ michael@0: bool isUnderlineText() const { michael@0: return SkToBool(this->getFlags() & kUnderlineText_Flag); michael@0: } michael@0: michael@0: /** Helper for setFlags(), setting or clearing the kUnderlineText_Flag bit michael@0: @param underlineText true to set the underlineText bit in the paint's michael@0: flags, false to clear it. michael@0: */ michael@0: void setUnderlineText(bool underlineText); michael@0: michael@0: /** Helper for getFlags(), returns true if kStrikeThruText_Flag bit is set michael@0: @return true if the strikeThruText bit is set in the paint's flags. michael@0: */ michael@0: bool isStrikeThruText() const { michael@0: return SkToBool(this->getFlags() & kStrikeThruText_Flag); michael@0: } michael@0: michael@0: /** Helper for setFlags(), setting or clearing the kStrikeThruText_Flag bit michael@0: @param strikeThruText true to set the strikeThruText bit in the michael@0: paint's flags, false to clear it. michael@0: */ michael@0: void setStrikeThruText(bool strikeThruText); michael@0: michael@0: /** Helper for getFlags(), returns true if kFakeBoldText_Flag bit is set michael@0: @return true if the kFakeBoldText_Flag bit is set in the paint's flags. michael@0: */ michael@0: bool isFakeBoldText() const { michael@0: return SkToBool(this->getFlags() & kFakeBoldText_Flag); michael@0: } michael@0: michael@0: /** Helper for setFlags(), setting or clearing the kFakeBoldText_Flag bit michael@0: @param fakeBoldText true to set the kFakeBoldText_Flag bit in the paint's michael@0: flags, false to clear it. michael@0: */ michael@0: void setFakeBoldText(bool fakeBoldText); michael@0: michael@0: /** Helper for getFlags(), returns true if kDevKernText_Flag bit is set michael@0: @return true if the kernText bit is set in the paint's flags. michael@0: */ michael@0: bool isDevKernText() const { michael@0: return SkToBool(this->getFlags() & kDevKernText_Flag); michael@0: } michael@0: michael@0: /** Helper for setFlags(), setting or clearing the kKernText_Flag bit michael@0: @param kernText true to set the kKernText_Flag bit in the paint's michael@0: flags, false to clear it. michael@0: */ michael@0: void setDevKernText(bool devKernText); michael@0: michael@0: /** Helper for getFlags(), returns true if kDistanceFieldTextTEMP_Flag bit is set michael@0: @return true if the distanceFieldText bit is set in the paint's flags. michael@0: */ michael@0: bool isDistanceFieldTextTEMP() const { michael@0: return SkToBool(this->getFlags() & kDistanceFieldTextTEMP_Flag); michael@0: } michael@0: michael@0: /** Helper for setFlags(), setting or clearing the kDistanceFieldTextTEMP_Flag bit michael@0: @param distanceFieldText true to set the kDistanceFieldTextTEMP_Flag bit in the paint's michael@0: flags, false to clear it. michael@0: */ michael@0: void setDistanceFieldTextTEMP(bool distanceFieldText); michael@0: michael@0: enum FilterLevel { michael@0: kNone_FilterLevel, michael@0: kLow_FilterLevel, michael@0: kMedium_FilterLevel, michael@0: kHigh_FilterLevel michael@0: }; michael@0: michael@0: /** michael@0: * Return the filter level. This affects the quality (and performance) of michael@0: * drawing scaled images. michael@0: */ michael@0: FilterLevel getFilterLevel() const; michael@0: michael@0: /** michael@0: * Set the filter level. This affects the quality (and performance) of michael@0: * drawing scaled images. michael@0: */ michael@0: void setFilterLevel(FilterLevel); michael@0: michael@0: /** michael@0: * If the predicate is true, set the filterLevel to Low, else set it to michael@0: * None. michael@0: */ michael@0: SK_ATTR_DEPRECATED("use setFilterLevel") michael@0: void setFilterBitmap(bool doFilter) { michael@0: this->setFilterLevel(doFilter ? kLow_FilterLevel : kNone_FilterLevel); michael@0: } michael@0: michael@0: /** michael@0: * Returns true if getFilterLevel() returns anything other than None. michael@0: */ michael@0: SK_ATTR_DEPRECATED("use getFilterLevel") michael@0: bool isFilterBitmap() const { michael@0: return kNone_FilterLevel != this->getFilterLevel(); michael@0: } michael@0: michael@0: /** Styles apply to rect, oval, path, and text. michael@0: Bitmaps are always drawn in "fill", and lines are always drawn in michael@0: "stroke". michael@0: michael@0: Note: strokeandfill implicitly draws the result with michael@0: SkPath::kWinding_FillType, so if the original path is even-odd, the michael@0: results may not appear the same as if it was drawn twice, filled and michael@0: then stroked. michael@0: */ michael@0: enum Style { michael@0: kFill_Style, //!< fill the geometry michael@0: kStroke_Style, //!< stroke the geometry michael@0: kStrokeAndFill_Style, //!< fill and stroke the geometry michael@0: }; michael@0: enum { michael@0: kStyleCount = kStrokeAndFill_Style + 1 michael@0: }; michael@0: michael@0: /** Return the paint's style, used for controlling how primitives' michael@0: geometries are interpreted (except for drawBitmap, which always assumes michael@0: kFill_Style). michael@0: @return the paint's Style michael@0: */ michael@0: Style getStyle() const { return (Style)fStyle; } michael@0: michael@0: /** Set the paint's style, used for controlling how primitives' michael@0: geometries are interpreted (except for drawBitmap, which always assumes michael@0: Fill). michael@0: @param style The new style to set in the paint michael@0: */ michael@0: void setStyle(Style style); michael@0: michael@0: /** Return the paint's color. Note that the color is a 32bit value michael@0: containing alpha as well as r,g,b. This 32bit value is not michael@0: premultiplied, meaning that its alpha can be any value, regardless of michael@0: the values of r,g,b. michael@0: @return the paint's color (and alpha). michael@0: */ michael@0: SkColor getColor() const { return fColor; } michael@0: michael@0: /** Set the paint's color. Note that the color is a 32bit value containing michael@0: alpha as well as r,g,b. This 32bit value is not premultiplied, meaning michael@0: that its alpha can be any value, regardless of the values of r,g,b. michael@0: @param color The new color (including alpha) to set in the paint. michael@0: */ michael@0: void setColor(SkColor color); michael@0: michael@0: /** Helper to getColor() that just returns the color's alpha value. michael@0: @return the alpha component of the paint's color. michael@0: */ michael@0: uint8_t getAlpha() const { return SkToU8(SkColorGetA(fColor)); } michael@0: michael@0: /** Helper to setColor(), that only assigns the color's alpha value, michael@0: leaving its r,g,b values unchanged. michael@0: @param a set the alpha component (0..255) of the paint's color. michael@0: */ michael@0: void setAlpha(U8CPU a); michael@0: michael@0: /** Helper to setColor(), that takes a,r,g,b and constructs the color value michael@0: using SkColorSetARGB() michael@0: @param a The new alpha component (0..255) of the paint's color. michael@0: @param r The new red component (0..255) of the paint's color. michael@0: @param g The new green component (0..255) of the paint's color. michael@0: @param b The new blue component (0..255) of the paint's color. michael@0: */ michael@0: void setARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b); michael@0: michael@0: /** Return the width for stroking. michael@0:

michael@0: A value of 0 strokes in hairline mode. michael@0: Hairlines always draw 1-pixel wide, regardless of the matrix. michael@0: @return the paint's stroke width, used whenever the paint's style is michael@0: Stroke or StrokeAndFill. michael@0: */ michael@0: SkScalar getStrokeWidth() const { return fWidth; } michael@0: michael@0: /** Set the width for stroking. michael@0: Pass 0 to stroke in hairline mode. michael@0: Hairlines always draw 1-pixel wide, regardless of the matrix. michael@0: @param width set the paint's stroke width, used whenever the paint's michael@0: style is Stroke or StrokeAndFill. michael@0: */ michael@0: void setStrokeWidth(SkScalar width); michael@0: michael@0: /** Return the paint's stroke miter value. This is used to control the michael@0: behavior of miter joins when the joins angle is sharp. michael@0: @return the paint's miter limit, used whenever the paint's style is michael@0: Stroke or StrokeAndFill. michael@0: */ michael@0: SkScalar getStrokeMiter() const { return fMiterLimit; } michael@0: michael@0: /** Set the paint's stroke miter value. This is used to control the michael@0: behavior of miter joins when the joins angle is sharp. This value must michael@0: be >= 0. michael@0: @param miter set the miter limit on the paint, used whenever the michael@0: paint's style is Stroke or StrokeAndFill. michael@0: */ michael@0: void setStrokeMiter(SkScalar miter); michael@0: michael@0: /** Cap enum specifies the settings for the paint's strokecap. This is the michael@0: treatment that is applied to the beginning and end of each non-closed michael@0: contour (e.g. lines). michael@0: */ michael@0: enum Cap { michael@0: kButt_Cap, //!< begin/end contours with no extension michael@0: kRound_Cap, //!< begin/end contours with a semi-circle extension michael@0: kSquare_Cap, //!< begin/end contours with a half square extension michael@0: michael@0: kCapCount, michael@0: kDefault_Cap = kButt_Cap michael@0: }; michael@0: michael@0: /** Join enum specifies the settings for the paint's strokejoin. This is michael@0: the treatment that is applied to corners in paths and rectangles. michael@0: */ michael@0: enum Join { michael@0: kMiter_Join, //!< connect path segments with a sharp join michael@0: kRound_Join, //!< connect path segments with a round join michael@0: kBevel_Join, //!< connect path segments with a flat bevel join michael@0: michael@0: kJoinCount, michael@0: kDefault_Join = kMiter_Join michael@0: }; michael@0: michael@0: /** Return the paint's stroke cap type, controlling how the start and end michael@0: of stroked lines and paths are treated. michael@0: @return the line cap style for the paint, used whenever the paint's michael@0: style is Stroke or StrokeAndFill. michael@0: */ michael@0: Cap getStrokeCap() const { return (Cap)fCapType; } michael@0: michael@0: /** Set the paint's stroke cap type. michael@0: @param cap set the paint's line cap style, used whenever the paint's michael@0: style is Stroke or StrokeAndFill. michael@0: */ michael@0: void setStrokeCap(Cap cap); michael@0: michael@0: /** Return the paint's stroke join type. michael@0: @return the paint's line join style, used whenever the paint's style is michael@0: Stroke or StrokeAndFill. michael@0: */ michael@0: Join getStrokeJoin() const { return (Join)fJoinType; } michael@0: michael@0: /** Set the paint's stroke join type. michael@0: @param join set the paint's line join style, used whenever the paint's michael@0: style is Stroke or StrokeAndFill. michael@0: */ michael@0: void setStrokeJoin(Join join); michael@0: michael@0: /** michael@0: * Applies any/all effects (patheffect, stroking) to src, returning the michael@0: * result in dst. The result is that drawing src with this paint will be michael@0: * the same as drawing dst with a default paint (at least from the michael@0: * geometric perspective). michael@0: * michael@0: * @param src input path michael@0: * @param dst output path (may be the same as src) michael@0: * @param cullRect If not null, the dst path may be culled to this rect. michael@0: * @return true if the path should be filled, or false if it should be michael@0: * drawn with a hairline (width == 0) michael@0: */ michael@0: bool getFillPath(const SkPath& src, SkPath* dst, michael@0: const SkRect* cullRect = NULL) const; michael@0: michael@0: /** Get the paint's shader object. michael@0:

michael@0: The shader's reference count is not affected. michael@0: @return the paint's shader (or NULL) michael@0: */ michael@0: SkShader* getShader() const { return fShader; } michael@0: michael@0: /** Set or clear the shader object. michael@0: * Shaders specify the source color(s) for what is being drawn. If a paint michael@0: * has no shader, then the paint's color is used. If the paint has a michael@0: * shader, then the shader's color(s) are use instead, but they are michael@0: * modulated by the paint's alpha. This makes it easy to create a shader michael@0: * once (e.g. bitmap tiling or gradient) and then change its transparency michael@0: * w/o having to modify the original shader... only the paint's alpha needs michael@0: * to be modified. michael@0: *

michael@0: * Pass NULL to clear any previous shader. michael@0: * As a convenience, the parameter passed is also returned. michael@0: * If a previous shader exists, its reference count is decremented. michael@0: * If shader is not NULL, its reference count is incremented. michael@0: * @param shader May be NULL. The shader to be installed in the paint michael@0: * @return shader michael@0: */ michael@0: SkShader* setShader(SkShader* shader); michael@0: michael@0: /** Get the paint's colorfilter. If there is a colorfilter, its reference michael@0: count is not changed. michael@0: @return the paint's colorfilter (or NULL) michael@0: */ michael@0: SkColorFilter* getColorFilter() const { return fColorFilter; } michael@0: michael@0: /** Set or clear the paint's colorfilter, returning the parameter. michael@0:

michael@0: If the paint already has a filter, its reference count is decremented. michael@0: If filter is not NULL, its reference count is incremented. michael@0: @param filter May be NULL. The filter to be installed in the paint michael@0: @return filter michael@0: */ michael@0: SkColorFilter* setColorFilter(SkColorFilter* filter); michael@0: michael@0: /** Get the paint's xfermode object. michael@0:

michael@0: The xfermode's reference count is not affected. michael@0: @return the paint's xfermode (or NULL) michael@0: */ michael@0: SkXfermode* getXfermode() const { return fXfermode; } michael@0: michael@0: /** Set or clear the xfermode object. michael@0:

michael@0: Pass NULL to clear any previous xfermode. michael@0: As a convenience, the parameter passed is also returned. michael@0: If a previous xfermode exists, its reference count is decremented. michael@0: If xfermode is not NULL, its reference count is incremented. michael@0: @param xfermode May be NULL. The new xfermode to be installed in the michael@0: paint michael@0: @return xfermode michael@0: */ michael@0: SkXfermode* setXfermode(SkXfermode* xfermode); michael@0: michael@0: /** Create an xfermode based on the specified Mode, and assign it into the michael@0: paint, returning the mode that was set. If the Mode is SrcOver, then michael@0: the paint's xfermode is set to null. michael@0: */ michael@0: SkXfermode* setXfermodeMode(SkXfermode::Mode); michael@0: michael@0: /** Get the paint's patheffect object. michael@0:

michael@0: The patheffect reference count is not affected. michael@0: @return the paint's patheffect (or NULL) michael@0: */ michael@0: SkPathEffect* getPathEffect() const { return fPathEffect; } michael@0: michael@0: /** Set or clear the patheffect object. michael@0:

michael@0: Pass NULL to clear any previous patheffect. michael@0: As a convenience, the parameter passed is also returned. michael@0: If a previous patheffect exists, its reference count is decremented. michael@0: If patheffect is not NULL, its reference count is incremented. michael@0: @param effect May be NULL. The new patheffect to be installed in the michael@0: paint michael@0: @return effect michael@0: */ michael@0: SkPathEffect* setPathEffect(SkPathEffect* effect); michael@0: michael@0: /** Get the paint's maskfilter object. michael@0:

michael@0: The maskfilter reference count is not affected. michael@0: @return the paint's maskfilter (or NULL) michael@0: */ michael@0: SkMaskFilter* getMaskFilter() const { return fMaskFilter; } michael@0: michael@0: /** Set or clear the maskfilter object. michael@0:

michael@0: Pass NULL to clear any previous maskfilter. michael@0: As a convenience, the parameter passed is also returned. michael@0: If a previous maskfilter exists, its reference count is decremented. michael@0: If maskfilter is not NULL, its reference count is incremented. michael@0: @param maskfilter May be NULL. The new maskfilter to be installed in michael@0: the paint michael@0: @return maskfilter michael@0: */ michael@0: SkMaskFilter* setMaskFilter(SkMaskFilter* maskfilter); michael@0: michael@0: // These attributes are for text/fonts michael@0: michael@0: /** Get the paint's typeface object. michael@0:

michael@0: The typeface object identifies which font to use when drawing or michael@0: measuring text. The typeface reference count is not affected. michael@0: @return the paint's typeface (or NULL) michael@0: */ michael@0: SkTypeface* getTypeface() const { return fTypeface; } michael@0: michael@0: /** Set or clear the typeface object. michael@0:

michael@0: Pass NULL to clear any previous typeface. michael@0: As a convenience, the parameter passed is also returned. michael@0: If a previous typeface exists, its reference count is decremented. michael@0: If typeface is not NULL, its reference count is incremented. michael@0: @param typeface May be NULL. The new typeface to be installed in the michael@0: paint michael@0: @return typeface michael@0: */ michael@0: SkTypeface* setTypeface(SkTypeface* typeface); michael@0: michael@0: /** Get the paint's rasterizer (or NULL). michael@0:

michael@0: The raster controls how paths/text are turned into alpha masks. michael@0: @return the paint's rasterizer (or NULL) michael@0: */ michael@0: SkRasterizer* getRasterizer() const { return fRasterizer; } michael@0: michael@0: /** Set or clear the rasterizer object. michael@0:

michael@0: Pass NULL to clear any previous rasterizer. michael@0: As a convenience, the parameter passed is also returned. michael@0: If a previous rasterizer exists in the paint, its reference count is michael@0: decremented. If rasterizer is not NULL, its reference count is michael@0: incremented. michael@0: @param rasterizer May be NULL. The new rasterizer to be installed in michael@0: the paint. michael@0: @return rasterizer michael@0: */ michael@0: SkRasterizer* setRasterizer(SkRasterizer* rasterizer); michael@0: michael@0: SkImageFilter* getImageFilter() const { return fImageFilter; } michael@0: SkImageFilter* setImageFilter(SkImageFilter*); michael@0: michael@0: SkAnnotation* getAnnotation() const { return fAnnotation; } michael@0: SkAnnotation* setAnnotation(SkAnnotation*); michael@0: michael@0: /** michael@0: * Returns true if there is an annotation installed on this paint, and michael@0: * the annotation specifics no-drawing. michael@0: */ michael@0: SK_ATTR_DEPRECATED("use getAnnotation and check for non-null") michael@0: bool isNoDrawAnnotation() const { return this->getAnnotation() != NULL; } michael@0: michael@0: /** michael@0: * Return the paint's SkDrawLooper (if any). Does not affect the looper's michael@0: * reference count. michael@0: */ michael@0: SkDrawLooper* getLooper() const { return fLooper; } michael@0: michael@0: /** michael@0: * Set or clear the looper object. michael@0: *

michael@0: * Pass NULL to clear any previous looper. michael@0: * As a convenience, the parameter passed is also returned. michael@0: * If a previous looper exists in the paint, its reference count is michael@0: * decremented. If looper is not NULL, its reference count is michael@0: * incremented. michael@0: * @param looper May be NULL. The new looper to be installed in the paint. michael@0: * @return looper michael@0: */ michael@0: SkDrawLooper* setLooper(SkDrawLooper* looper); michael@0: michael@0: enum Align { michael@0: kLeft_Align, michael@0: kCenter_Align, michael@0: kRight_Align, michael@0: }; michael@0: enum { michael@0: kAlignCount = 3 michael@0: }; michael@0: michael@0: /** Return the paint's Align value for drawing text. michael@0: @return the paint's Align value for drawing text. michael@0: */ michael@0: Align getTextAlign() const { return (Align)fTextAlign; } michael@0: michael@0: /** Set the paint's text alignment. michael@0: @param align set the paint's Align value for drawing text. michael@0: */ michael@0: void setTextAlign(Align align); michael@0: michael@0: /** Return the paint's text size. michael@0: @return the paint's text size. michael@0: */ michael@0: SkScalar getTextSize() const { return fTextSize; } michael@0: michael@0: /** Set the paint's text size. This value must be > 0 michael@0: @param textSize set the paint's text size. michael@0: */ michael@0: void setTextSize(SkScalar textSize); michael@0: michael@0: /** Return the paint's horizontal scale factor for text. The default value michael@0: is 1.0. michael@0: @return the paint's scale factor in X for drawing/measuring text michael@0: */ michael@0: SkScalar getTextScaleX() const { return fTextScaleX; } michael@0: michael@0: /** Set the paint's horizontal scale factor for text. The default value michael@0: is 1.0. Values > 1.0 will stretch the text wider. Values < 1.0 will michael@0: stretch the text narrower. michael@0: @param scaleX set the paint's scale factor in X for drawing/measuring michael@0: text. michael@0: */ michael@0: void setTextScaleX(SkScalar scaleX); michael@0: michael@0: /** Return the paint's horizontal skew factor for text. The default value michael@0: is 0. michael@0: @return the paint's skew factor in X for drawing text. michael@0: */ michael@0: SkScalar getTextSkewX() const { return fTextSkewX; } michael@0: michael@0: /** Set the paint's horizontal skew factor for text. The default value michael@0: is 0. For approximating oblique text, use values around -0.25. michael@0: @param skewX set the paint's skew factor in X for drawing text. michael@0: */ michael@0: void setTextSkewX(SkScalar skewX); michael@0: michael@0: /** Describes how to interpret the text parameters that are passed to paint michael@0: methods like measureText() and getTextWidths(). michael@0: */ michael@0: enum TextEncoding { michael@0: kUTF8_TextEncoding, //!< the text parameters are UTF8 michael@0: kUTF16_TextEncoding, //!< the text parameters are UTF16 michael@0: kUTF32_TextEncoding, //!< the text parameters are UTF32 michael@0: kGlyphID_TextEncoding //!< the text parameters are glyph indices michael@0: }; michael@0: michael@0: TextEncoding getTextEncoding() const { return (TextEncoding)fTextEncoding; } michael@0: michael@0: void setTextEncoding(TextEncoding encoding); michael@0: michael@0: struct FontMetrics { michael@0: /** Flags which indicate the confidence level of various metrics. michael@0: A set flag indicates that the metric may be trusted. michael@0: */ michael@0: enum FontMetricsFlags { michael@0: kUnderlineThinknessIsValid_Flag = 1 << 0, michael@0: kUnderlinePositionIsValid_Flag = 1 << 1, michael@0: }; michael@0: michael@0: uint32_t fFlags; //!< Bit field to identify which values are unknown michael@0: SkScalar fTop; //!< The greatest distance above the baseline for any glyph (will be <= 0) michael@0: SkScalar fAscent; //!< The recommended distance above the baseline (will be <= 0) michael@0: SkScalar fDescent; //!< The recommended distance below the baseline (will be >= 0) michael@0: SkScalar fBottom; //!< The greatest distance below the baseline for any glyph (will be >= 0) michael@0: SkScalar fLeading; //!< The recommended distance to add between lines of text (will be >= 0) michael@0: SkScalar fAvgCharWidth; //!< the average character width (>= 0) michael@0: SkScalar fMaxCharWidth; //!< the max character width (>= 0) michael@0: SkScalar fXMin; //!< The minimum bounding box x value for all glyphs michael@0: SkScalar fXMax; //!< The maximum bounding box x value for all glyphs michael@0: SkScalar fXHeight; //!< The height of an 'x' in px, or 0 if no 'x' in face michael@0: SkScalar fCapHeight; //!< The cap height (> 0), or 0 if cannot be determined. michael@0: SkScalar fUnderlineThickness; //!< underline thickness, or 0 if cannot be determined michael@0: michael@0: /** Underline Position - position of the top of the Underline stroke michael@0: relative to the baseline, this can have following values michael@0: - Negative - means underline should be drawn above baseline. michael@0: - Positive - means below baseline. michael@0: - Zero - mean underline should be drawn on baseline. michael@0: */ michael@0: SkScalar fUnderlinePosition; //!< underline position, or 0 if cannot be determined michael@0: michael@0: /** If the fontmetrics has a valid underlinethickness, return true, and set the michael@0: thickness param to that value. If it doesn't return false and ignore the michael@0: thickness param. michael@0: */ michael@0: bool hasUnderlineThickness(SkScalar* thickness) const { michael@0: if (SkToBool(fFlags & kUnderlineThinknessIsValid_Flag)) { michael@0: *thickness = fUnderlineThickness; michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: /** If the fontmetrics has a valid underlineposition, return true, and set the michael@0: thickness param to that value. If it doesn't return false and ignore the michael@0: thickness param. michael@0: */ michael@0: bool hasUnderlinePosition(SkScalar* position) const { michael@0: if (SkToBool(fFlags & kUnderlinePositionIsValid_Flag)) { michael@0: *position = fUnderlinePosition; michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: }; michael@0: michael@0: /** Return the recommend spacing between lines (which will be michael@0: fDescent - fAscent + fLeading). michael@0: If metrics is not null, return in it the font metrics for the michael@0: typeface/pointsize/etc. currently set in the paint. michael@0: @param metrics If not null, returns the font metrics for the michael@0: current typeface/pointsize/etc setting in this michael@0: paint. michael@0: @param scale If not 0, return width as if the canvas were scaled michael@0: by this value michael@0: @param return the recommended spacing between lines michael@0: */ michael@0: SkScalar getFontMetrics(FontMetrics* metrics, SkScalar scale = 0) const; michael@0: michael@0: /** Return the recommend line spacing. This will be michael@0: fDescent - fAscent + fLeading michael@0: */ michael@0: SkScalar getFontSpacing() const { return this->getFontMetrics(NULL, 0); } michael@0: michael@0: /** Convert the specified text into glyph IDs, returning the number of michael@0: glyphs ID written. If glyphs is NULL, it is ignore and only the count michael@0: is returned. michael@0: */ michael@0: int textToGlyphs(const void* text, size_t byteLength, michael@0: uint16_t glyphs[]) const; michael@0: michael@0: /** Return true if all of the specified text has a corresponding non-zero michael@0: glyph ID. If any of the code-points in the text are not supported in michael@0: the typeface (i.e. the glyph ID would be zero), then return false. michael@0: michael@0: If the text encoding for the paint is kGlyph_TextEncoding, then this michael@0: returns true if all of the specified glyph IDs are non-zero. michael@0: */ michael@0: bool containsText(const void* text, size_t byteLength) const; michael@0: michael@0: /** Convert the glyph array into Unichars. Unconvertable glyphs are mapped michael@0: to zero. Note: this does not look at the text-encoding setting in the michael@0: paint, only at the typeface. michael@0: */ michael@0: void glyphsToUnichars(const uint16_t glyphs[], int count, michael@0: SkUnichar text[]) const; michael@0: michael@0: /** Return the number of drawable units in the specified text buffer. michael@0: This looks at the current TextEncoding field of the paint. If you also michael@0: want to have the text converted into glyph IDs, call textToGlyphs michael@0: instead. michael@0: */ michael@0: int countText(const void* text, size_t byteLength) const { michael@0: return this->textToGlyphs(text, byteLength, NULL); michael@0: } michael@0: michael@0: /** Return the width of the text. This will return the vertical measure michael@0: * if isVerticalText() is true, in which case the returned value should michael@0: * be treated has a height instead of a width. michael@0: * michael@0: * @param text The text to be measured michael@0: * @param length Number of bytes of text to measure michael@0: * @param bounds If not NULL, returns the bounds of the text, michael@0: * relative to (0, 0). michael@0: * @param scale If not 0, return width as if the canvas were scaled michael@0: * by this value michael@0: * @return The advance width of the text michael@0: */ michael@0: SkScalar measureText(const void* text, size_t length, michael@0: SkRect* bounds, SkScalar scale = 0) const; michael@0: michael@0: /** Return the width of the text. This will return the vertical measure michael@0: * if isVerticalText() is true, in which case the returned value should michael@0: * be treated has a height instead of a width. michael@0: * michael@0: * @param text Address of the text michael@0: * @param length Number of bytes of text to measure michael@0: * @return The advance width of the text michael@0: */ michael@0: SkScalar measureText(const void* text, size_t length) const { michael@0: return this->measureText(text, length, NULL, 0); michael@0: } michael@0: michael@0: /** Specify the direction the text buffer should be processed in breakText() michael@0: */ michael@0: enum TextBufferDirection { michael@0: /** When measuring text for breakText(), begin at the start of the text michael@0: buffer and proceed forward through the data. This is the default. michael@0: */ michael@0: kForward_TextBufferDirection, michael@0: /** When measuring text for breakText(), begin at the end of the text michael@0: buffer and proceed backwards through the data. michael@0: */ michael@0: kBackward_TextBufferDirection michael@0: }; michael@0: michael@0: /** Return the number of bytes of text that were measured. If michael@0: * isVerticalText() is true, then the vertical advances are used for michael@0: * the measurement. michael@0: * michael@0: * @param text The text to be measured michael@0: * @param length Number of bytes of text to measure michael@0: * @param maxWidth Maximum width. Only the subset of text whose accumulated michael@0: * widths are <= maxWidth are measured. michael@0: * @param measuredWidth Optional. If non-null, this returns the actual michael@0: * width of the measured text. michael@0: * @param tbd Optional. The direction the text buffer should be michael@0: * traversed during measuring. michael@0: * @return The number of bytes of text that were measured. Will be michael@0: * <= length. michael@0: */ michael@0: size_t breakText(const void* text, size_t length, SkScalar maxWidth, michael@0: SkScalar* measuredWidth = NULL, michael@0: TextBufferDirection tbd = kForward_TextBufferDirection) michael@0: const; michael@0: michael@0: /** Return the advances for the text. These will be vertical advances if michael@0: * isVerticalText() returns true. michael@0: * michael@0: * @param text the text michael@0: * @param byteLength number of bytes to of text michael@0: * @param widths If not null, returns the array of advances for michael@0: * the glyphs. If not NULL, must be at least a large michael@0: * as the number of unichars in the specified text. michael@0: * @param bounds If not null, returns the bounds for each of michael@0: * character, relative to (0, 0) michael@0: * @return the number of unichars in the specified text. michael@0: */ michael@0: int getTextWidths(const void* text, size_t byteLength, SkScalar widths[], michael@0: SkRect bounds[] = NULL) const; michael@0: michael@0: /** Return the path (outline) for the specified text. michael@0: Note: just like SkCanvas::drawText, this will respect the Align setting michael@0: in the paint. michael@0: */ michael@0: void getTextPath(const void* text, size_t length, SkScalar x, SkScalar y, michael@0: SkPath* path) const; michael@0: michael@0: void getPosTextPath(const void* text, size_t length, michael@0: const SkPoint pos[], SkPath* path) const; michael@0: michael@0: #ifdef SK_BUILD_FOR_ANDROID michael@0: uint32_t getGenerationID() const; michael@0: void setGenerationID(uint32_t generationID); michael@0: michael@0: /** Returns the base glyph count for the strike associated with this paint michael@0: */ michael@0: unsigned getBaseGlyphCount(SkUnichar text) const; michael@0: michael@0: const SkPaintOptionsAndroid& getPaintOptionsAndroid() const { michael@0: return fPaintOptionsAndroid; michael@0: } michael@0: void setPaintOptionsAndroid(const SkPaintOptionsAndroid& options); michael@0: #endif michael@0: michael@0: // returns true if the paint's settings (e.g. xfermode + alpha) resolve to michael@0: // mean that we need not draw at all (e.g. SrcOver + 0-alpha) michael@0: bool nothingToDraw() const; michael@0: michael@0: /////////////////////////////////////////////////////////////////////////// michael@0: // would prefer to make these private... michael@0: michael@0: /** Returns true if the current paint settings allow for fast computation of michael@0: bounds (i.e. there is nothing complex like a patheffect that would make michael@0: the bounds computation expensive. michael@0: */ michael@0: bool canComputeFastBounds() const { michael@0: if (this->getLooper()) { michael@0: return this->getLooper()->canComputeFastBounds(*this); michael@0: } michael@0: return !this->getRasterizer(); michael@0: } michael@0: michael@0: /** Only call this if canComputeFastBounds() returned true. This takes a michael@0: raw rectangle (the raw bounds of a shape), and adjusts it for stylistic michael@0: effects in the paint (e.g. stroking). If needed, it uses the storage michael@0: rect parameter. It returns the adjusted bounds that can then be used michael@0: for quickReject tests. michael@0: michael@0: The returned rect will either be orig or storage, thus the caller michael@0: should not rely on storage being set to the result, but should always michael@0: use the retured value. It is legal for orig and storage to be the same michael@0: rect. michael@0: michael@0: e.g. michael@0: if (paint.canComputeFastBounds()) { michael@0: SkRect r, storage; michael@0: path.computeBounds(&r, SkPath::kFast_BoundsType); michael@0: const SkRect& fastR = paint.computeFastBounds(r, &storage); michael@0: if (canvas->quickReject(fastR, ...)) { michael@0: // don't draw the path michael@0: } michael@0: } michael@0: */ michael@0: const SkRect& computeFastBounds(const SkRect& orig, SkRect* storage) const { michael@0: SkPaint::Style style = this->getStyle(); michael@0: // ultra fast-case: filling with no effects that affect geometry michael@0: if (kFill_Style == style) { michael@0: uintptr_t effects = reinterpret_cast(this->getLooper()); michael@0: effects |= reinterpret_cast(this->getMaskFilter()); michael@0: effects |= reinterpret_cast(this->getPathEffect()); michael@0: effects |= reinterpret_cast(this->getImageFilter()); michael@0: if (!effects) { michael@0: return orig; michael@0: } michael@0: } michael@0: michael@0: return this->doComputeFastBounds(orig, storage, style); michael@0: } michael@0: michael@0: const SkRect& computeFastStrokeBounds(const SkRect& orig, michael@0: SkRect* storage) const { michael@0: return this->doComputeFastBounds(orig, storage, kStroke_Style); michael@0: } michael@0: michael@0: // Take the style explicitly, so the caller can force us to be stroked michael@0: // without having to make a copy of the paint just to change that field. michael@0: const SkRect& doComputeFastBounds(const SkRect& orig, SkRect* storage, michael@0: Style) const; michael@0: michael@0: /** michael@0: * Return a matrix that applies the paint's text values: size, scale, skew michael@0: */ michael@0: static SkMatrix* SetTextMatrix(SkMatrix* matrix, SkScalar size, michael@0: SkScalar scaleX, SkScalar skewX) { michael@0: matrix->setScale(size * scaleX, size); michael@0: if (skewX) { michael@0: matrix->postSkew(skewX, 0); michael@0: } michael@0: return matrix; michael@0: } michael@0: michael@0: SkMatrix* setTextMatrix(SkMatrix* matrix) const { michael@0: return SetTextMatrix(matrix, fTextSize, fTextScaleX, fTextSkewX); michael@0: } michael@0: michael@0: SK_TO_STRING_NONVIRT() michael@0: michael@0: struct FlatteningTraits { michael@0: static void Flatten(SkWriteBuffer& buffer, const SkPaint& paint); michael@0: static void Unflatten(SkReadBuffer& buffer, SkPaint* paint); michael@0: }; michael@0: michael@0: private: michael@0: SkTypeface* fTypeface; michael@0: SkScalar fTextSize; michael@0: SkScalar fTextScaleX; michael@0: SkScalar fTextSkewX; michael@0: michael@0: SkPathEffect* fPathEffect; michael@0: SkShader* fShader; michael@0: SkXfermode* fXfermode; michael@0: SkMaskFilter* fMaskFilter; michael@0: SkColorFilter* fColorFilter; michael@0: SkRasterizer* fRasterizer; michael@0: SkDrawLooper* fLooper; michael@0: SkImageFilter* fImageFilter; michael@0: SkAnnotation* fAnnotation; michael@0: michael@0: SkColor fColor; michael@0: SkScalar fWidth; michael@0: SkScalar fMiterLimit; michael@0: michael@0: union { michael@0: struct { michael@0: // all of these bitfields should add up to 32 michael@0: unsigned fFlags : 16; michael@0: unsigned fTextAlign : 2; michael@0: unsigned fCapType : 2; michael@0: unsigned fJoinType : 2; michael@0: unsigned fStyle : 2; michael@0: unsigned fTextEncoding : 2; // 3 values michael@0: unsigned fHinting : 2; michael@0: //unsigned fFreeBits : 4; michael@0: }; michael@0: uint32_t fBitfields; michael@0: }; michael@0: uint32_t getBitfields() const { return fBitfields; } michael@0: void setBitfields(uint32_t bitfields); michael@0: michael@0: uint32_t fDirtyBits; michael@0: michael@0: SkDrawCacheProc getDrawCacheProc() const; michael@0: SkMeasureCacheProc getMeasureCacheProc(TextBufferDirection dir, michael@0: bool needFullMetrics) const; michael@0: michael@0: SkScalar measure_text(SkGlyphCache*, const char* text, size_t length, michael@0: int* count, SkRect* bounds) const; michael@0: michael@0: SkGlyphCache* detachCache(const SkDeviceProperties* deviceProperties, const SkMatrix*) const; michael@0: michael@0: void descriptorProc(const SkDeviceProperties* deviceProperties, const SkMatrix* deviceMatrix, michael@0: void (*proc)(SkTypeface*, const SkDescriptor*, void*), michael@0: void* context, bool ignoreGamma = false) const; michael@0: michael@0: static void Term(); michael@0: michael@0: enum { michael@0: /* This is the size we use when we ask for a glyph's path. We then michael@0: * post-transform it as we draw to match the request. michael@0: * This is done to try to re-use cache entries for the path. michael@0: * michael@0: * This value is somewhat arbitrary. In theory, it could be 1, since michael@0: * we store paths as floats. However, we get the path from the font michael@0: * scaler, and it may represent its paths as fixed-point (or 26.6), michael@0: * so we shouldn't ask for something too big (might overflow 16.16) michael@0: * or too small (underflow 26.6). michael@0: * michael@0: * This value could track kMaxSizeForGlyphCache, assuming the above michael@0: * constraints, but since we ask for unhinted paths, the two values michael@0: * need not match per-se. michael@0: */ michael@0: kCanonicalTextSizeForPaths = 64, michael@0: michael@0: /* michael@0: * Above this size (taking into account CTM and textSize), we never use michael@0: * the cache for bits or metrics (we might overflow), so we just ask michael@0: * for a caononical size and post-transform that. michael@0: */ michael@0: kMaxSizeForGlyphCache = 256, michael@0: }; michael@0: michael@0: static bool TooBigToUseCache(const SkMatrix& ctm, const SkMatrix& textM); michael@0: michael@0: bool tooBigToUseCache() const; michael@0: bool tooBigToUseCache(const SkMatrix& ctm) const; michael@0: michael@0: // Set flags/hinting/textSize up to use for drawing text as paths. michael@0: // Returns scale factor to restore the original textSize, since will will michael@0: // have change it to kCanonicalTextSizeForPaths. michael@0: SkScalar setupForAsPaths(); michael@0: michael@0: static SkScalar MaxCacheSize2() { michael@0: static const SkScalar kMaxSize = SkIntToScalar(kMaxSizeForGlyphCache); michael@0: static const SkScalar kMag2Max = kMaxSize * kMaxSize; michael@0: return kMag2Max; michael@0: } michael@0: michael@0: friend class SkAutoGlyphCache; michael@0: friend class SkCanvas; michael@0: friend class SkDraw; michael@0: friend class SkGraphics; // So Term() can be called. michael@0: friend class SkPDFDevice; michael@0: friend class GrBitmapTextContext; michael@0: friend class GrDistanceFieldTextContext; michael@0: friend class SkTextToPathIter; michael@0: friend class SkCanonicalizePaint; michael@0: michael@0: #ifdef SK_BUILD_FOR_ANDROID michael@0: SkPaintOptionsAndroid fPaintOptionsAndroid; michael@0: michael@0: // In order for the == operator to work properly this must be the last field michael@0: // in the struct so that we can do a memcmp to this field's offset. michael@0: uint32_t fGenerationID; michael@0: #endif michael@0: }; michael@0: michael@0: #endif