Merge tomhudson and mtklein SkPaint shrinking approaches.
I think this is cherry picking the best parts of both our CLs. We've got dirty bit tracking from Tom's, picture format stability from Mike's, etc. Paints are typically 1/3 their original size when flattened in the dictionary. bench_record on my desktop looks promising. Generally, looks faster. (Best in monospace.) a/b skp before after 0.83 desk_techcrunch.skp 0.29 0.24 0.83 tabl_gamedeksiam.skp 0.52 0.43 0.87 desk_carsvg.skp 0.4 0.35 0.87 desk_googlehome.skp 0.038 0.033 0.87 desk_pokemonwiki.skp 3.9 3.4 0.88 desk_fontwipe.skp 0.0089 0.0078 0.88 desk_googlespreadsheet.skp 0.16 0.14 0.89 desk_jsfiddlebigcar.skp 0.027 0.024 0.89 desk_tigersvg.skp 0.038 0.034 0.89 desk_weather.skp 0.19 0.17 0.89 tabl_engadget.skp 0.37 0.33 0.89 tabl_googleblog.skp 0.28 0.25 0.9 desk_facebook.skp 0.2 0.18 0.91 desk_mapsvg.skp 0.45 0.41 0.91 desk_youtube.skp 0.22 0.2 0.92 desk_forecastio.skp 0.12 0.11 0.92 desk_googlespreadsheetdashed.skp 0.49 0.45 0.92 desk_gws.skp 0.13 0.12 0.92 desk_pinterest.skp 0.037 0.034 0.92 desk_twitter.skp 0.25 0.23 0.92 tabl_culturalsolutions.skp 0.26 0.24 0.92 tabl_gspro.skp 0.072 0.066 0.92 tabl_mercurynews.skp 0.26 0.24 0.93 desk_booking.skp 0.46 0.43 0.93 desk_chalkboard.skp 0.28 0.26 0.93 desk_linkedin.skp 0.14 0.13 0.93 desk_mobilenews.skp 0.28 0.26 0.93 tabl_cuteoverload.skp 0.46 0.43 0.93 tabl_deviantart.skp 0.15 0.14 0.93 tabl_gmail.skp 0.029 0.027 0.93 tabl_googlecalendar.skp 0.15 0.14 0.93 tabl_mlb.skp 0.15 0.14 0.94 desk_blogger.skp 0.18 0.17 0.94 desk_jsfiddlehumperclip.skp 0.034 0.032 0.94 desk_wordpress.skp 0.33 0.31 0.94 desk_wowwiki.skp 0.94 0.88 0.94 desk_yahooanswers.skp 0.17 0.16 0.94 desk_youtubetvvideo.skp 0.017 0.016 0.94 tabl_sahadan.skp 0.093 0.087 0.94 tabl_worldjournal.skp 0.35 0.33 0.95 desk_css3gradients.skp 0.21 0.2 0.95 desk_gmailthread.skp 0.19 0.18 0.95 tabl_cnet.skp 0.42 0.4 0.95 tabl_mozilla.skp 1.9 1.8 0.95 tabl_pravda.skp 0.19 0.18 0.96 mobi_wikipedia.skp 0.55 0.53 0.96 tabl_cnn.skp 0.48 0.46 0.96 tabl_nofolo.skp 0.05 0.048 0.97 desk_googleplus.skp 0.29 0.28 0.97 tabl_frantzen.skp 0.059 0.057 0.97 tabl_onlinewsj.skp 0.38 0.37 0.97 tabl_slashdot.skp 0.1 0.097 0.97 tabl_vnexpress.skp 0.29 0.28 0.99 desk_amazon.skp 0.088 0.087 1 desk_baidu.skp 0.097 0.099 1 desk_ebay.skp 0.18 0.18 1 desk_espn.skp 0.24 0.24 1 desk_oldinboxapp.skp 0.026 0.026 1 desk_rectangletransition.skp 0.014 0.014 1 desk_samoasvg.skp 0.23 0.24 1 desk_yahoogames.skp 0.029 0.029 1 desk_yahoosports.skp 0.0033 0.0033 1 desk_youtubetvbrowse.skp 0.01 0.01 1 tabl_androidpolice.skp 0.65 0.65 1 tabl_digg.skp 0.33 0.33 1 tabl_hsfi.skp 0.32 0.32 1 tabl_nytimes.skp 0.22 0.22 1 tabl_techmeme.skp 0.069 0.072 1 tabl_ukwsj.skp 0.35 0.35 1.1 desk_sfgate.skp 0.25 0.28 BUG=skia:2190,skia:2194 Committed: http://code.google.com/p/skia/source/detail?r=13487 Committed: http://code.google.com/p/skia/source/detail?r=13496 R=tomhudson@google.com, reed@google.com, mtklein@google.com, robertphillips@google.com Author: mtklein@chromium.org Review URL: https://codereview.chromium.org/158913005 git-svn-id: http://skia.googlecode.com/svn/trunk@13536 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
e5280893f8
commit
aca1c01f3b
@ -980,6 +980,11 @@ public:
|
|||||||
|
|
||||||
SkDEVCODE(void toString(SkString*) const;)
|
SkDEVCODE(void toString(SkString*) const;)
|
||||||
|
|
||||||
|
struct FlatteningTraits {
|
||||||
|
static void Flatten(SkWriteBuffer& buffer, const SkPaint& paint);
|
||||||
|
static void Unflatten(SkReadBuffer& buffer, SkPaint* paint);
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SkTypeface* fTypeface;
|
SkTypeface* fTypeface;
|
||||||
SkScalar fTextSize;
|
SkScalar fTextSize;
|
||||||
@ -999,15 +1004,25 @@ private:
|
|||||||
SkColor fColor;
|
SkColor fColor;
|
||||||
SkScalar fWidth;
|
SkScalar fWidth;
|
||||||
SkScalar fMiterLimit;
|
SkScalar fMiterLimit;
|
||||||
// all of these bitfields should add up to 32
|
|
||||||
unsigned fFlags : 16;
|
union {
|
||||||
unsigned fTextAlign : 2;
|
struct {
|
||||||
unsigned fCapType : 2;
|
// all of these bitfields should add up to 32
|
||||||
unsigned fJoinType : 2;
|
unsigned fFlags : 16;
|
||||||
unsigned fStyle : 2;
|
unsigned fTextAlign : 2;
|
||||||
unsigned fTextEncoding : 2; // 3 values
|
unsigned fCapType : 2;
|
||||||
unsigned fHinting : 2;
|
unsigned fJoinType : 2;
|
||||||
//unsigned fFreeBits : 4;
|
unsigned fStyle : 2;
|
||||||
|
unsigned fTextEncoding : 2; // 3 values
|
||||||
|
unsigned fHinting : 2;
|
||||||
|
//unsigned fFreeBits : 4;
|
||||||
|
};
|
||||||
|
uint32_t fBitfields;
|
||||||
|
};
|
||||||
|
uint32_t getBitfields() const { return fBitfields; }
|
||||||
|
void setBitfields(uint32_t bitfields);
|
||||||
|
|
||||||
|
uint32_t fDirtyBits;
|
||||||
|
|
||||||
|
|
||||||
SkDrawCacheProc getDrawCacheProc() const;
|
SkDrawCacheProc getDrawCacheProc() const;
|
||||||
|
@ -35,6 +35,26 @@
|
|||||||
#include "SkTypeface.h"
|
#include "SkTypeface.h"
|
||||||
#include "SkXfermode.h"
|
#include "SkXfermode.h"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
kColor_DirtyBit = 1 << 0,
|
||||||
|
kBitfields_DirtyBit = 1 << 1,
|
||||||
|
kTextSize_DirtyBit = 1 << 2,
|
||||||
|
kTextScaleX_DirtyBit = 1 << 3,
|
||||||
|
kTextSkewX_DirtyBit = 1 << 4,
|
||||||
|
kStrokeWidth_DirtyBit = 1 << 5,
|
||||||
|
kStrokeMiter_DirtyBit = 1 << 6,
|
||||||
|
kPathEffect_DirtyBit = 1 << 7,
|
||||||
|
kShader_DirtyBit = 1 << 8,
|
||||||
|
kXfermode_DirtyBit = 1 << 9,
|
||||||
|
kMaskFilter_DirtyBit = 1 << 10,
|
||||||
|
kColorFilter_DirtyBit = 1 << 11,
|
||||||
|
kRasterizer_DirtyBit = 1 << 12,
|
||||||
|
kLooper_DirtyBit = 1 << 13,
|
||||||
|
kImageFilter_DirtyBit = 1 << 14,
|
||||||
|
kTypeface_DirtyBit = 1 << 15,
|
||||||
|
kAnnotation_DirtyBit = 1 << 16,
|
||||||
|
kPaintOptionsAndroid_DirtyBit = 1 << 17,
|
||||||
|
};
|
||||||
|
|
||||||
// define this to get a printf for out-of-range parameter in setters
|
// define this to get a printf for out-of-range parameter in setters
|
||||||
// e.g. setTextSize(-1)
|
// e.g. setTextSize(-1)
|
||||||
@ -55,8 +75,8 @@ SkPaint::SkPaint() {
|
|||||||
sk_bzero(this, sizeof(*this));
|
sk_bzero(this, sizeof(*this));
|
||||||
|
|
||||||
#if 0 // not needed with the bzero call above
|
#if 0 // not needed with the bzero call above
|
||||||
fTypeface = NULL;
|
fTypeface = NULL;
|
||||||
fTextSkewX = 0;
|
fTextSkewX = 0;
|
||||||
fPathEffect = NULL;
|
fPathEffect = NULL;
|
||||||
fShader = NULL;
|
fShader = NULL;
|
||||||
fXfermode = NULL;
|
fXfermode = NULL;
|
||||||
@ -66,7 +86,8 @@ SkPaint::SkPaint() {
|
|||||||
fLooper = NULL;
|
fLooper = NULL;
|
||||||
fImageFilter = NULL;
|
fImageFilter = NULL;
|
||||||
fAnnotation = NULL;
|
fAnnotation = NULL;
|
||||||
fWidth = 0;
|
fWidth = 0;
|
||||||
|
fDirtyBits = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
fTextSize = SkPaintDefaults_TextSize;
|
fTextSize = SkPaintDefaults_TextSize;
|
||||||
@ -198,6 +219,7 @@ void SkPaint::setPaintOptionsAndroid(const SkPaintOptionsAndroid& options) {
|
|||||||
if (options != fPaintOptionsAndroid) {
|
if (options != fPaintOptionsAndroid) {
|
||||||
fPaintOptionsAndroid = options;
|
fPaintOptionsAndroid = options;
|
||||||
GEN_ID_INC;
|
GEN_ID_INC;
|
||||||
|
fDirtyBits |= kPaintOptionsAndroid_DirtyBit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -228,11 +250,13 @@ void SkPaint::setFilterLevel(FilterLevel level) {
|
|||||||
void SkPaint::setHinting(Hinting hintingLevel) {
|
void SkPaint::setHinting(Hinting hintingLevel) {
|
||||||
GEN_ID_INC_EVAL((unsigned) hintingLevel != fHinting);
|
GEN_ID_INC_EVAL((unsigned) hintingLevel != fHinting);
|
||||||
fHinting = hintingLevel;
|
fHinting = hintingLevel;
|
||||||
|
fDirtyBits |= kBitfields_DirtyBit;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkPaint::setFlags(uint32_t flags) {
|
void SkPaint::setFlags(uint32_t flags) {
|
||||||
GEN_ID_INC_EVAL(fFlags != flags);
|
GEN_ID_INC_EVAL(fFlags != flags);
|
||||||
fFlags = flags;
|
fFlags = flags;
|
||||||
|
fDirtyBits |= kBitfields_DirtyBit;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkPaint::setAntiAlias(bool doAA) {
|
void SkPaint::setAntiAlias(bool doAA) {
|
||||||
@ -287,6 +311,7 @@ void SkPaint::setStyle(Style style) {
|
|||||||
if ((unsigned)style < kStyleCount) {
|
if ((unsigned)style < kStyleCount) {
|
||||||
GEN_ID_INC_EVAL((unsigned)style != fStyle);
|
GEN_ID_INC_EVAL((unsigned)style != fStyle);
|
||||||
fStyle = style;
|
fStyle = style;
|
||||||
|
fDirtyBits |= kBitfields_DirtyBit;
|
||||||
} else {
|
} else {
|
||||||
#ifdef SK_REPORT_API_RANGE_CHECK
|
#ifdef SK_REPORT_API_RANGE_CHECK
|
||||||
SkDebugf("SkPaint::setStyle(%d) out of range\n", style);
|
SkDebugf("SkPaint::setStyle(%d) out of range\n", style);
|
||||||
@ -297,6 +322,7 @@ void SkPaint::setStyle(Style style) {
|
|||||||
void SkPaint::setColor(SkColor color) {
|
void SkPaint::setColor(SkColor color) {
|
||||||
GEN_ID_INC_EVAL(color != fColor);
|
GEN_ID_INC_EVAL(color != fColor);
|
||||||
fColor = color;
|
fColor = color;
|
||||||
|
fDirtyBits |= kColor_DirtyBit;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkPaint::setAlpha(U8CPU a) {
|
void SkPaint::setAlpha(U8CPU a) {
|
||||||
@ -312,6 +338,7 @@ void SkPaint::setStrokeWidth(SkScalar width) {
|
|||||||
if (width >= 0) {
|
if (width >= 0) {
|
||||||
GEN_ID_INC_EVAL(width != fWidth);
|
GEN_ID_INC_EVAL(width != fWidth);
|
||||||
fWidth = width;
|
fWidth = width;
|
||||||
|
fDirtyBits |= kStrokeWidth_DirtyBit;
|
||||||
} else {
|
} else {
|
||||||
#ifdef SK_REPORT_API_RANGE_CHECK
|
#ifdef SK_REPORT_API_RANGE_CHECK
|
||||||
SkDebugf("SkPaint::setStrokeWidth() called with negative value\n");
|
SkDebugf("SkPaint::setStrokeWidth() called with negative value\n");
|
||||||
@ -323,6 +350,7 @@ void SkPaint::setStrokeMiter(SkScalar limit) {
|
|||||||
if (limit >= 0) {
|
if (limit >= 0) {
|
||||||
GEN_ID_INC_EVAL(limit != fMiterLimit);
|
GEN_ID_INC_EVAL(limit != fMiterLimit);
|
||||||
fMiterLimit = limit;
|
fMiterLimit = limit;
|
||||||
|
fDirtyBits |= kStrokeMiter_DirtyBit;
|
||||||
} else {
|
} else {
|
||||||
#ifdef SK_REPORT_API_RANGE_CHECK
|
#ifdef SK_REPORT_API_RANGE_CHECK
|
||||||
SkDebugf("SkPaint::setStrokeMiter() called with negative value\n");
|
SkDebugf("SkPaint::setStrokeMiter() called with negative value\n");
|
||||||
@ -334,6 +362,7 @@ void SkPaint::setStrokeCap(Cap ct) {
|
|||||||
if ((unsigned)ct < kCapCount) {
|
if ((unsigned)ct < kCapCount) {
|
||||||
GEN_ID_INC_EVAL((unsigned)ct != fCapType);
|
GEN_ID_INC_EVAL((unsigned)ct != fCapType);
|
||||||
fCapType = SkToU8(ct);
|
fCapType = SkToU8(ct);
|
||||||
|
fDirtyBits |= kBitfields_DirtyBit;
|
||||||
} else {
|
} else {
|
||||||
#ifdef SK_REPORT_API_RANGE_CHECK
|
#ifdef SK_REPORT_API_RANGE_CHECK
|
||||||
SkDebugf("SkPaint::setStrokeCap(%d) out of range\n", ct);
|
SkDebugf("SkPaint::setStrokeCap(%d) out of range\n", ct);
|
||||||
@ -345,6 +374,7 @@ void SkPaint::setStrokeJoin(Join jt) {
|
|||||||
if ((unsigned)jt < kJoinCount) {
|
if ((unsigned)jt < kJoinCount) {
|
||||||
GEN_ID_INC_EVAL((unsigned)jt != fJoinType);
|
GEN_ID_INC_EVAL((unsigned)jt != fJoinType);
|
||||||
fJoinType = SkToU8(jt);
|
fJoinType = SkToU8(jt);
|
||||||
|
fDirtyBits |= kBitfields_DirtyBit;
|
||||||
} else {
|
} else {
|
||||||
#ifdef SK_REPORT_API_RANGE_CHECK
|
#ifdef SK_REPORT_API_RANGE_CHECK
|
||||||
SkDebugf("SkPaint::setStrokeJoin(%d) out of range\n", jt);
|
SkDebugf("SkPaint::setStrokeJoin(%d) out of range\n", jt);
|
||||||
@ -358,6 +388,7 @@ void SkPaint::setTextAlign(Align align) {
|
|||||||
if ((unsigned)align < kAlignCount) {
|
if ((unsigned)align < kAlignCount) {
|
||||||
GEN_ID_INC_EVAL((unsigned)align != fTextAlign);
|
GEN_ID_INC_EVAL((unsigned)align != fTextAlign);
|
||||||
fTextAlign = SkToU8(align);
|
fTextAlign = SkToU8(align);
|
||||||
|
fDirtyBits |= kBitfields_DirtyBit;
|
||||||
} else {
|
} else {
|
||||||
#ifdef SK_REPORT_API_RANGE_CHECK
|
#ifdef SK_REPORT_API_RANGE_CHECK
|
||||||
SkDebugf("SkPaint::setTextAlign(%d) out of range\n", align);
|
SkDebugf("SkPaint::setTextAlign(%d) out of range\n", align);
|
||||||
@ -369,6 +400,7 @@ void SkPaint::setTextSize(SkScalar ts) {
|
|||||||
if (ts >= 0) {
|
if (ts >= 0) {
|
||||||
GEN_ID_INC_EVAL(ts != fTextSize);
|
GEN_ID_INC_EVAL(ts != fTextSize);
|
||||||
fTextSize = ts;
|
fTextSize = ts;
|
||||||
|
fDirtyBits |= kTextSize_DirtyBit;
|
||||||
} else {
|
} else {
|
||||||
#ifdef SK_REPORT_API_RANGE_CHECK
|
#ifdef SK_REPORT_API_RANGE_CHECK
|
||||||
SkDebugf("SkPaint::setTextSize() called with negative value\n");
|
SkDebugf("SkPaint::setTextSize() called with negative value\n");
|
||||||
@ -379,17 +411,20 @@ void SkPaint::setTextSize(SkScalar ts) {
|
|||||||
void SkPaint::setTextScaleX(SkScalar scaleX) {
|
void SkPaint::setTextScaleX(SkScalar scaleX) {
|
||||||
GEN_ID_INC_EVAL(scaleX != fTextScaleX);
|
GEN_ID_INC_EVAL(scaleX != fTextScaleX);
|
||||||
fTextScaleX = scaleX;
|
fTextScaleX = scaleX;
|
||||||
|
fDirtyBits |= kTextScaleX_DirtyBit;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkPaint::setTextSkewX(SkScalar skewX) {
|
void SkPaint::setTextSkewX(SkScalar skewX) {
|
||||||
GEN_ID_INC_EVAL(skewX != fTextSkewX);
|
GEN_ID_INC_EVAL(skewX != fTextSkewX);
|
||||||
fTextSkewX = skewX;
|
fTextSkewX = skewX;
|
||||||
|
fDirtyBits |= kTextSkewX_DirtyBit;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkPaint::setTextEncoding(TextEncoding encoding) {
|
void SkPaint::setTextEncoding(TextEncoding encoding) {
|
||||||
if ((unsigned)encoding <= kGlyphID_TextEncoding) {
|
if ((unsigned)encoding <= kGlyphID_TextEncoding) {
|
||||||
GEN_ID_INC_EVAL((unsigned)encoding != fTextEncoding);
|
GEN_ID_INC_EVAL((unsigned)encoding != fTextEncoding);
|
||||||
fTextEncoding = encoding;
|
fTextEncoding = encoding;
|
||||||
|
fDirtyBits |= kBitfields_DirtyBit;
|
||||||
} else {
|
} else {
|
||||||
#ifdef SK_REPORT_API_RANGE_CHECK
|
#ifdef SK_REPORT_API_RANGE_CHECK
|
||||||
SkDebugf("SkPaint::setTextEncoding(%d) out of range\n", encoding);
|
SkDebugf("SkPaint::setTextEncoding(%d) out of range\n", encoding);
|
||||||
@ -399,33 +434,43 @@ void SkPaint::setTextEncoding(TextEncoding encoding) {
|
|||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Returns dst with the given bitmask enabled or disabled, depending on value.
|
||||||
|
inline static uint32_t set_mask(uint32_t dst, uint32_t bitmask, bool value) {
|
||||||
|
return value ? (dst | bitmask) : (dst & ~bitmask);
|
||||||
|
}
|
||||||
|
|
||||||
SkTypeface* SkPaint::setTypeface(SkTypeface* font) {
|
SkTypeface* SkPaint::setTypeface(SkTypeface* font) {
|
||||||
SkRefCnt_SafeAssign(fTypeface, font);
|
SkRefCnt_SafeAssign(fTypeface, font);
|
||||||
GEN_ID_INC;
|
GEN_ID_INC;
|
||||||
|
fDirtyBits = set_mask(fDirtyBits, kTypeface_DirtyBit, font != NULL);
|
||||||
return font;
|
return font;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkRasterizer* SkPaint::setRasterizer(SkRasterizer* r) {
|
SkRasterizer* SkPaint::setRasterizer(SkRasterizer* r) {
|
||||||
SkRefCnt_SafeAssign(fRasterizer, r);
|
SkRefCnt_SafeAssign(fRasterizer, r);
|
||||||
GEN_ID_INC;
|
GEN_ID_INC;
|
||||||
|
fDirtyBits = set_mask(fDirtyBits, kRasterizer_DirtyBit, r != NULL);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkDrawLooper* SkPaint::setLooper(SkDrawLooper* looper) {
|
SkDrawLooper* SkPaint::setLooper(SkDrawLooper* looper) {
|
||||||
SkRefCnt_SafeAssign(fLooper, looper);
|
SkRefCnt_SafeAssign(fLooper, looper);
|
||||||
GEN_ID_INC;
|
GEN_ID_INC;
|
||||||
|
fDirtyBits = set_mask(fDirtyBits, kLooper_DirtyBit, looper != NULL);
|
||||||
return looper;
|
return looper;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkImageFilter* SkPaint::setImageFilter(SkImageFilter* imageFilter) {
|
SkImageFilter* SkPaint::setImageFilter(SkImageFilter* imageFilter) {
|
||||||
SkRefCnt_SafeAssign(fImageFilter, imageFilter);
|
SkRefCnt_SafeAssign(fImageFilter, imageFilter);
|
||||||
GEN_ID_INC;
|
GEN_ID_INC;
|
||||||
|
fDirtyBits = set_mask(fDirtyBits, kImageFilter_DirtyBit, imageFilter != NULL);
|
||||||
return imageFilter;
|
return imageFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkAnnotation* SkPaint::setAnnotation(SkAnnotation* annotation) {
|
SkAnnotation* SkPaint::setAnnotation(SkAnnotation* annotation) {
|
||||||
SkRefCnt_SafeAssign(fAnnotation, annotation);
|
SkRefCnt_SafeAssign(fAnnotation, annotation);
|
||||||
GEN_ID_INC;
|
GEN_ID_INC;
|
||||||
|
fDirtyBits = set_mask(fDirtyBits, kAnnotation_DirtyBit, annotation != NULL);
|
||||||
return annotation;
|
return annotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2149,18 +2194,21 @@ void SkPaint::unflatten(SkReadBuffer& buffer) {
|
|||||||
SkShader* SkPaint::setShader(SkShader* shader) {
|
SkShader* SkPaint::setShader(SkShader* shader) {
|
||||||
GEN_ID_INC_EVAL(shader != fShader);
|
GEN_ID_INC_EVAL(shader != fShader);
|
||||||
SkRefCnt_SafeAssign(fShader, shader);
|
SkRefCnt_SafeAssign(fShader, shader);
|
||||||
|
fDirtyBits = set_mask(fDirtyBits, kShader_DirtyBit, shader != NULL);
|
||||||
return shader;
|
return shader;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkColorFilter* SkPaint::setColorFilter(SkColorFilter* filter) {
|
SkColorFilter* SkPaint::setColorFilter(SkColorFilter* filter) {
|
||||||
GEN_ID_INC_EVAL(filter != fColorFilter);
|
GEN_ID_INC_EVAL(filter != fColorFilter);
|
||||||
SkRefCnt_SafeAssign(fColorFilter, filter);
|
SkRefCnt_SafeAssign(fColorFilter, filter);
|
||||||
|
fDirtyBits = set_mask(fDirtyBits, kColorFilter_DirtyBit, filter != NULL);
|
||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkXfermode* SkPaint::setXfermode(SkXfermode* mode) {
|
SkXfermode* SkPaint::setXfermode(SkXfermode* mode) {
|
||||||
GEN_ID_INC_EVAL(mode != fXfermode);
|
GEN_ID_INC_EVAL(mode != fXfermode);
|
||||||
SkRefCnt_SafeAssign(fXfermode, mode);
|
SkRefCnt_SafeAssign(fXfermode, mode);
|
||||||
|
fDirtyBits = set_mask(fDirtyBits, kXfermode_DirtyBit, mode != NULL);
|
||||||
return mode;
|
return mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2168,18 +2216,21 @@ SkXfermode* SkPaint::setXfermodeMode(SkXfermode::Mode mode) {
|
|||||||
SkSafeUnref(fXfermode);
|
SkSafeUnref(fXfermode);
|
||||||
fXfermode = SkXfermode::Create(mode);
|
fXfermode = SkXfermode::Create(mode);
|
||||||
GEN_ID_INC;
|
GEN_ID_INC;
|
||||||
|
fDirtyBits = set_mask(fDirtyBits, kXfermode_DirtyBit, fXfermode != NULL);
|
||||||
return fXfermode;
|
return fXfermode;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkPathEffect* SkPaint::setPathEffect(SkPathEffect* effect) {
|
SkPathEffect* SkPaint::setPathEffect(SkPathEffect* effect) {
|
||||||
GEN_ID_INC_EVAL(effect != fPathEffect);
|
GEN_ID_INC_EVAL(effect != fPathEffect);
|
||||||
SkRefCnt_SafeAssign(fPathEffect, effect);
|
SkRefCnt_SafeAssign(fPathEffect, effect);
|
||||||
|
fDirtyBits = set_mask(fDirtyBits, kPathEffect_DirtyBit, effect != NULL);
|
||||||
return effect;
|
return effect;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkMaskFilter* SkPaint::setMaskFilter(SkMaskFilter* filter) {
|
SkMaskFilter* SkPaint::setMaskFilter(SkMaskFilter* filter) {
|
||||||
GEN_ID_INC_EVAL(filter != fMaskFilter);
|
GEN_ID_INC_EVAL(filter != fMaskFilter);
|
||||||
SkRefCnt_SafeAssign(fMaskFilter, filter);
|
SkRefCnt_SafeAssign(fMaskFilter, filter);
|
||||||
|
fDirtyBits = set_mask(fDirtyBits, kMaskFilter_DirtyBit, filter != NULL);
|
||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2550,3 +2601,97 @@ bool SkPaint::nothingToDraw() const {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SkPaint::setBitfields(uint32_t bitfields) {
|
||||||
|
fBitfields = bitfields;
|
||||||
|
fDirtyBits |= kBitfields_DirtyBit;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static unsigned popcount(uint8_t x) {
|
||||||
|
// As in Hacker's delight, adapted for just 8 bits.
|
||||||
|
x = (x & 0x55) + ((x >> 1) & 0x55); // a b c d w x y z -> a+b c+d w+x y+z
|
||||||
|
x = (x & 0x33) + ((x >> 2) & 0x33); // a+b c+d w+x y+z -> a+b+c+d w+x+y+z
|
||||||
|
x = (x & 0x0F) + ((x >> 4) & 0x0F); // a+b+c+d w+x+y+z -> a+b+c+d+w+x+y+z
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SkPaint::FlatteningTraits::Flatten(SkWriteBuffer& buffer, const SkPaint& paint) {
|
||||||
|
const uint32_t dirty = paint.fDirtyBits;
|
||||||
|
|
||||||
|
// Each of the low 7 dirty bits corresponds to a 4-byte flat value, plus one for the dirty bits.
|
||||||
|
const size_t flatBytes = 4 * (popcount(dirty & 127) + 1);
|
||||||
|
SkASSERT(flatBytes <= 32);
|
||||||
|
uint32_t* u32 = buffer.reserve(flatBytes);
|
||||||
|
*u32++ = dirty;
|
||||||
|
if (dirty == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define F(dst, field) if (dirty & k##field##_DirtyBit) *dst++ = paint.get##field()
|
||||||
|
F(u32, Color);
|
||||||
|
F(u32, Bitfields);
|
||||||
|
SkScalar* f32 = reinterpret_cast<SkScalar*>(u32);
|
||||||
|
F(f32, TextSize);
|
||||||
|
F(f32, TextScaleX);
|
||||||
|
F(f32, TextSkewX);
|
||||||
|
F(f32, StrokeWidth);
|
||||||
|
F(f32, StrokeMiter);
|
||||||
|
#undef F
|
||||||
|
#define F(field) if (dirty & k##field##_DirtyBit) buffer.writeFlattenable(paint.get##field())
|
||||||
|
F(PathEffect);
|
||||||
|
F(Shader);
|
||||||
|
F(Xfermode);
|
||||||
|
F(MaskFilter);
|
||||||
|
F(ColorFilter);
|
||||||
|
F(Rasterizer);
|
||||||
|
F(Looper);
|
||||||
|
F(ImageFilter);
|
||||||
|
#undef F
|
||||||
|
if (dirty & kTypeface_DirtyBit) buffer.writeTypeface(paint.getTypeface());
|
||||||
|
if (dirty & kAnnotation_DirtyBit) paint.getAnnotation()->writeToBuffer(buffer);
|
||||||
|
#ifdef SK_BUILD_FOR_ANDROID
|
||||||
|
if (dirty & kPaintOptionsAndroid_DirtyBit) paint.getPaintOptionsAndroid().flatten(buffer);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void SkPaint::FlatteningTraits::Unflatten(SkReadBuffer& buffer, SkPaint* paint) {
|
||||||
|
const uint32_t dirty = buffer.readUInt();
|
||||||
|
if (dirty == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#define F(field, reader) if (dirty & k##field##_DirtyBit) paint->set##field(buffer.reader())
|
||||||
|
// Same function, except it unrefs the object newly set on the paint:
|
||||||
|
#define F_UNREF(field, reader) \
|
||||||
|
if (dirty & k##field##_DirtyBit) \
|
||||||
|
paint->set##field(buffer.reader())->unref()
|
||||||
|
|
||||||
|
F(Color, readUInt);
|
||||||
|
F(Bitfields, readUInt);
|
||||||
|
F(TextSize, readScalar);
|
||||||
|
F(TextScaleX, readScalar);
|
||||||
|
F(TextSkewX, readScalar);
|
||||||
|
F(StrokeWidth, readScalar);
|
||||||
|
F(StrokeMiter, readScalar);
|
||||||
|
F_UNREF(PathEffect, readPathEffect);
|
||||||
|
F_UNREF(Shader, readShader);
|
||||||
|
F_UNREF(Xfermode, readXfermode);
|
||||||
|
F_UNREF(MaskFilter, readMaskFilter);
|
||||||
|
F_UNREF(ColorFilter, readColorFilter);
|
||||||
|
F_UNREF(Rasterizer, readRasterizer);
|
||||||
|
F_UNREF(Looper, readDrawLooper);
|
||||||
|
F_UNREF(ImageFilter, readImageFilter);
|
||||||
|
F(Typeface, readTypeface);
|
||||||
|
#undef F
|
||||||
|
#undef F_UNREF
|
||||||
|
if (dirty & kAnnotation_DirtyBit) {
|
||||||
|
paint->setAnnotation(SkNEW_ARGS(SkAnnotation, (buffer)))->unref();
|
||||||
|
}
|
||||||
|
#ifdef SK_BUILD_FOR_ANDROID
|
||||||
|
if (dirty & kPaintOptionsAndroid_DirtyBit) {
|
||||||
|
SkPaintOptionsAndroid options;
|
||||||
|
options.unflatten(buffer);
|
||||||
|
paint->setPaintOptionsAndroid(options);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
SkASSERT(dirty == paint->fDirtyBits);
|
||||||
|
}
|
||||||
|
@ -564,15 +564,7 @@ private:
|
|||||||
SkFlatData::Identity, SkFlatData::Hash, SkFlatData::Equal> fHash;
|
SkFlatData::Identity, SkFlatData::Hash, SkFlatData::Equal> fHash;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SkPaintTraits {
|
typedef SkFlatDictionary<SkPaint, SkPaint::FlatteningTraits> SkPaintDictionary;
|
||||||
static void Flatten(SkWriteBuffer& buffer, const SkPaint& paint) {
|
|
||||||
paint.flatten(buffer);
|
|
||||||
}
|
|
||||||
static void Unflatten(SkReadBuffer& buffer, SkPaint* paint) {
|
|
||||||
paint->unflatten(buffer);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
typedef SkFlatDictionary<SkPaint, SkPaintTraits> SkPaintDictionary;
|
|
||||||
|
|
||||||
class SkChunkFlatController : public SkFlatController {
|
class SkChunkFlatController : public SkFlatController {
|
||||||
public:
|
public:
|
||||||
|
@ -209,7 +209,7 @@ SkPicturePlayback::SkPicturePlayback(const SkPicturePlayback& src, SkPictCopyInf
|
|||||||
for (int i = 0; i < paintCount; i++) {
|
for (int i = 0; i < paintCount; i++) {
|
||||||
if (needs_deep_copy(src.fPaints->at(i))) {
|
if (needs_deep_copy(src.fPaints->at(i))) {
|
||||||
deepCopyInfo->paintData[i] =
|
deepCopyInfo->paintData[i] =
|
||||||
SkFlatData::Create<SkPaintTraits>(&deepCopyInfo->controller,
|
SkFlatData::Create<SkPaint::FlatteningTraits>(&deepCopyInfo->controller,
|
||||||
src.fPaints->at(i), 0);
|
src.fPaints->at(i), 0);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@ -230,8 +230,8 @@ SkPicturePlayback::SkPicturePlayback(const SkPicturePlayback& src, SkPictCopyInf
|
|||||||
SkTypefacePlayback* tfPlayback = deepCopyInfo->controller.getTypefacePlayback();
|
SkTypefacePlayback* tfPlayback = deepCopyInfo->controller.getTypefacePlayback();
|
||||||
for (int i = 0; i < paintCount; i++) {
|
for (int i = 0; i < paintCount; i++) {
|
||||||
if (deepCopyInfo->paintData[i]) {
|
if (deepCopyInfo->paintData[i]) {
|
||||||
deepCopyInfo->paintData[i]->unflatten<SkPaintTraits>(&fPaints->writableAt(i),
|
deepCopyInfo->paintData[i]->unflatten<SkPaint::FlatteningTraits>(
|
||||||
bmHeap, tfPlayback);
|
&fPaints->writableAt(i), bmHeap, tfPlayback);
|
||||||
} else {
|
} else {
|
||||||
// needs_deep_copy was false, so just need to assign
|
// needs_deep_copy was false, so just need to assign
|
||||||
fPaints->writableAt(i) = src.fPaints->at(i);
|
fPaints->writableAt(i) = src.fPaints->at(i);
|
||||||
|
@ -11,8 +11,11 @@
|
|||||||
#include "SkPaint.h"
|
#include "SkPaint.h"
|
||||||
#include "SkPath.h"
|
#include "SkPath.h"
|
||||||
#include "SkRandom.h"
|
#include "SkRandom.h"
|
||||||
|
#include "SkReadBuffer.h"
|
||||||
#include "SkTypeface.h"
|
#include "SkTypeface.h"
|
||||||
#include "SkUtils.h"
|
#include "SkUtils.h"
|
||||||
|
#include "SkWriteBuffer.h"
|
||||||
|
#include "SkXfermode.h"
|
||||||
#include "Test.h"
|
#include "Test.h"
|
||||||
|
|
||||||
static size_t uni_to_utf8(const SkUnichar src[], void* dst, int count) {
|
static size_t uni_to_utf8(const SkUnichar src[], void* dst, int count) {
|
||||||
@ -251,3 +254,40 @@ DEF_TEST(Paint, reporter) {
|
|||||||
test_cmap(reporter);
|
test_cmap(reporter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define ASSERT(expr) REPORTER_ASSERT(r, expr)
|
||||||
|
|
||||||
|
DEF_TEST(Paint_FlatteningTraits, r) {
|
||||||
|
SkPaint paint;
|
||||||
|
paint.setColor(0x00AABBCC);
|
||||||
|
paint.setTextScaleX(1.0f); // Encoded despite being the default value.
|
||||||
|
paint.setTextSize(19);
|
||||||
|
paint.setXfermode(SkXfermode::Create(SkXfermode::kModulate_Mode))->unref();
|
||||||
|
paint.setLooper(NULL); // Ignored.
|
||||||
|
|
||||||
|
SkWriteBuffer writer;
|
||||||
|
SkPaint::FlatteningTraits::Flatten(writer, paint);
|
||||||
|
const size_t expectedBytesWritten = sizeof(void*) == 8 ? 48 : 40;
|
||||||
|
ASSERT(expectedBytesWritten == writer.bytesWritten());
|
||||||
|
|
||||||
|
const uint32_t* written = writer.getWriter32()->contiguousArray();
|
||||||
|
SkASSERT(written != NULL);
|
||||||
|
ASSERT(*written == ((1<<0) | (1<<2) | (1<<3) | (1<<9))); // Dirty bits for our 4.
|
||||||
|
|
||||||
|
SkReadBuffer reader(written, writer.bytesWritten());
|
||||||
|
SkPaint other;
|
||||||
|
SkPaint::FlatteningTraits::Unflatten(reader, &other);
|
||||||
|
ASSERT(reader.offset() == writer.bytesWritten());
|
||||||
|
|
||||||
|
// No matter the encoding, these must always hold.
|
||||||
|
ASSERT(other.getColor() == paint.getColor());
|
||||||
|
ASSERT(other.getTextScaleX() == paint.getTextScaleX());
|
||||||
|
ASSERT(other.getTextSize() == paint.getTextSize());
|
||||||
|
ASSERT(other.getLooper() == paint.getLooper());
|
||||||
|
|
||||||
|
// We have to be a little looser and compare just the modes. Pointers might not be the same.
|
||||||
|
SkXfermode::Mode otherMode, paintMode;
|
||||||
|
ASSERT(other.getXfermode()->asMode(&otherMode));
|
||||||
|
ASSERT(paint.getXfermode()->asMode(&paintMode));
|
||||||
|
ASSERT(otherMode == paintMode);
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user