Chromium Code Reviews| Index: src/gpu/GrShape.cpp |
| diff --git a/src/gpu/GrShape.cpp b/src/gpu/GrShape.cpp |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..23c6a3b36bd357301c60c0f3009a3c1a95f01ea7 |
| --- /dev/null |
| +++ b/src/gpu/GrShape.cpp |
| @@ -0,0 +1,255 @@ |
| +/* |
| + * Copyright 2016 Google Inc. |
| + * |
| + * Use of this source code is governed by a BSD-style license that can be |
| + * found in the LICENSE file. |
| + */ |
| + |
| +#include "GrShape.h" |
| + |
| +GrShape& GrShape::operator=(const GrShape& that) { |
| + bool wasPath = Type::kPath == fType; |
| + fStyle = that.fStyle; |
| + fType = that.fType; |
| + switch (fType) { |
| + case Type::kEmpty: |
| + if (wasPath) { |
| + fPath.~SkPath(); |
| + } |
| + break; |
| + case Type::kRRect: |
| + if (wasPath) { |
| + fPath.~SkPath(); |
| + } |
| + fRRect = that.fRRect; |
| + break; |
| + case Type::kPath: |
| + if (wasPath) { |
| + fPath = that.fPath; |
| + } else { |
| + new (&fPath) SkPath(that.fPath); |
| + } |
| + break; |
| + } |
| + fInheritedKey.reset(that.fInheritedKey.count()); |
| + memcpy(fInheritedKey.get(), that.fInheritedKey.get(), |
| + sizeof(uint32_t) * fInheritedKey.count()); |
| + return *this; |
| +} |
| + |
| +int GrShape::unstyledKeySize() const { |
| + if (fInheritedKey.count()) { |
| + return fInheritedKey.count(); |
| + } |
| + switch (fType) { |
| + case Type::kEmpty: |
| + return 1; |
| + case Type::kRRect: |
| + SkASSERT(!fInheritedKey.count()); |
| + SkASSERT(0 == SkRRect::kSizeInMemory % sizeof(uint32_t)); |
| + return SkRRect::kSizeInMemory / sizeof(uint32_t); |
| + case Type::kPath: |
| + if (fPath.isVolatile()) { |
| + return -1; |
| + } else { |
| + return 1; |
| + } |
| + } |
| + SkFAIL(); |
| + return 0; |
| +} |
| + |
| +void GrShape::writeUnstyledKey(uint32_t* key) const { |
| + SkASSERT(this->unstyledKeySize()); |
| + SkDEBUGCODE(uint32_t* origKey = key;) |
| + if (fInheritedKey.count()) { |
| + memcpy(key, fInheritedKey.get(), sizeof(uint32_t) * fInheritedKey.count()); |
| + SkDEBUGCODE(key += fInheritedKey.count();) |
| + } else { |
| + switch (fType) { |
| + case Type::kEmpty: |
| + *key++ = 1; |
| + break; |
| + case Type::kRRect: |
| + fRRect.writeToMemory(key); |
| + key += SkRRect::kSizeInMemory / sizeof(uint32_t); |
| + break; |
| + case Type::kPath: |
| + SkASSERT(!fPath.isVolatile()); |
| + *key++ = fPath.getGenerationID(); |
| + break; |
| + } |
| + } |
| + SkASSERT(key - origKey == this->unstyledKeySize()); |
| +} |
| + |
| +int GrShape::StyleKeySize(const GrStyle& style, bool stopAfterPE) { |
| + GR_STATIC_ASSERT(sizeof(uint32_t) == sizeof(SkScalar)); |
| + int size = 0; |
| + if (style.isDashed()) { |
| + // One scalar for dash phase and one for each dash value. |
| + size += 1 + style.dashIntervalCnt(); |
| + } else if (style.pathEffect()) { |
| + // No key for a generic path effect. |
| + return -1; |
| + } |
| + |
| + if (stopAfterPE) { |
| + return size; |
| + } |
| + |
| + if (style.strokeRec().needToApply()) { |
| + // One for style/cap/join, 2 for miter and width. |
| + size += 3; |
| + } |
| + return size; |
| +} |
| + |
| +void GrShape::StyleKey(uint32_t* key, const GrStyle& style, bool stopAfterPE) { |
| + SkASSERT(key); |
| + SkASSERT(StyleKeySize(style, stopAfterPE) >= 0); |
| + GR_STATIC_ASSERT(sizeof(uint32_t) == sizeof(SkScalar)); |
| + |
| + int i = 0; |
| + if (style.isDashed()) { |
| + GR_STATIC_ASSERT(sizeof(style.dashPhase()) == sizeof(uint32_t)); |
| + SkScalar phase = style.dashPhase(); |
| + memcpy(&key[i++], &phase, sizeof(SkScalar)); |
| + |
| + int32_t count = style.dashIntervalCnt(); |
| + // Dash count should always be even. |
| + SkASSERT(0 == (count & 0x1)); |
| + const SkScalar* intervals = style.dashIntervals(); |
| + int intervalByteCnt = count * sizeof(SkScalar); |
| + memcpy(&key[i], intervals, intervalByteCnt); |
|
robertphillips
2016/04/24 23:00:44
I'm not sure what this comment is saying
bsalomon
2016/04/25 13:32:26
I'll just rm it. I think it came in when I lifted
|
| + // Enable the line below if fields are added after dashing. |
| + SkDEBUGCODE(i += count); |
| + } else { |
| + SkASSERT(!style.pathEffect()); |
| + } |
| + |
| + if (!stopAfterPE && style.strokeRec().needToApply()) { |
| + enum { |
| + kStyleBits = 2, |
| + kJoinBits = 2, |
| + kCapBits = 32 - kStyleBits - kJoinBits, |
| + |
| + kJoinShift = kStyleBits, |
| + kCapShift = kJoinShift + kJoinBits, |
| + |
|
robertphillips
2016/04/24 23:00:44
rm this space ?
bsalomon
2016/04/25 13:32:26
Done.
|
| + }; |
| + GR_STATIC_ASSERT(SkStrokeRec::kStyleCount <= (1 << kStyleBits)); |
| + GR_STATIC_ASSERT(SkPaint::kJoinCount <= (1 << kJoinBits)); |
| + GR_STATIC_ASSERT(SkPaint::kCapCount <= (1 << kCapBits)); |
| + key[i++] = style.strokeRec().getStyle() | |
| + style.strokeRec().getJoin() << kJoinShift | |
| + style.strokeRec().getCap() << kCapShift; |
| + |
| + SkScalar scalar; |
| + // Miter limit only affects miter joins |
| + scalar = SkPaint::kMiter_Join == style.strokeRec().getJoin() |
| + ? style.strokeRec().getMiter() |
| + : -1.f; |
| + memcpy(&key[i++], &scalar, sizeof(scalar)); |
| + |
| + scalar = style.strokeRec().getWidth(); |
| + memcpy(&key[i++], &scalar, sizeof(scalar)); |
| + } |
| + SkASSERT(StyleKeySize(style, stopAfterPE) == i); |
| +} |
| + |
| +void GrShape::setInheritedKey(const GrShape &parent, bool stopAfterPE){ |
| + SkASSERT(!fInheritedKey.count()); |
| + // If the output shape turns out to be simple, then we will just use its geometric key |
| + if (Type::kPath == fType) { |
| + // We want ApplyFullStyle(ApplyPathEffect(shape)) to have the same key as |
| + // ApplyFullStyle(shape). |
| + // The full key is structured as geo,path_effect,stroke. |
|
robertphillips
2016/04/25 12:07:06
get get, -> get geo, ?
Maybe a paren or "" delimi
bsalomon
2016/04/25 13:32:26
Done.
|
| + // If we do ApplyPathEffect we get get,path_effect as the inherited key. If we then |
|
robertphillips
2016/04/25 12:07:06
as into -> into ?
bsalomon
2016/04/25 13:32:26
Done.
|
| + // do ApplyFullStyle we'll memcpy geo,path_effect as into the new inherited key |
| + // and then append the style (which should now be stroke only) key at the end. |
| + int parentCnt = parent.fInheritedKey.count(); |
|
robertphillips
2016/04/25 12:07:06
rm extra ' ' ?
bsalomon
2016/04/25 13:32:26
Done.
|
| + bool useParentGeoKey = !parentCnt ; |
| + if (useParentGeoKey) { |
| + parentCnt = parent.unstyledKeySize(); |
| + } |
| + int styleCnt = StyleKeySize(parent.fStyle, stopAfterPE); |
| + if (styleCnt < 0) { |
| + // The style doesn't allow a key, set the path to volatile so that we fail when |
| + // we try to get a key for the shape. |
| + fPath.setIsVolatile(true); |
| + } else { |
| + fInheritedKey.reset(parentCnt + styleCnt); |
| + if (useParentGeoKey) { |
| + // This will be the geo key. |
| + parent.writeUnstyledKey(fInheritedKey.get()); |
| + } else { |
| + // This should be geo,path_effect |
| + memcpy(fInheritedKey.get(), parent.fInheritedKey.get(), |
| + parentCnt * sizeof(uint32_t)); |
| + } |
| + // Now turn (geo,path_effect) or (geo) into (geo,path_effect,stroke) |
| + StyleKey(fInheritedKey.get() + parentCnt, parent.fStyle, stopAfterPE); |
| + } |
| + } |
| +} |
| + |
| +GrShape::GrShape(const GrShape& that) : fType(that.fType), fStyle(that.fStyle) { |
| + switch (fType) { |
| + case Type::kEmpty: |
| + return; |
| + case Type::kRRect: |
| + fRRect = that.fRRect; |
| + return; |
| + case Type::kPath: |
| + new (&fPath)SkPath(that.fPath); |
| + return; |
| + } |
| + fInheritedKey.reset(that.fInheritedKey.count()); |
| + memcpy(fInheritedKey.get(), that.fInheritedKey.get(), |
| + sizeof(uint32_t) * fInheritedKey.count()); |
| +} |
| + |
| +GrShape::GrShape(const GrShape& parent, bool stopAfterPE) { |
| + fType = Type::kEmpty; |
| + SkPathEffect* pe = parent.fStyle.pathEffect(); |
| + const SkPath* inPath; |
| + SkStrokeRec strokeRec = parent.fStyle.strokeRec(); |
| + if (pe) { |
| + fType = Type::kPath; |
| + new (&fPath) SkPath(); |
| + if (parent.fType == Type::kPath) { |
| + inPath = &parent.fPath; |
| + } else { |
| + inPath = &fPath; |
| + parent.asPath(&fPath); |
| + } |
| + // Should we consider bounds? Would have to include in key, but it'd be nice to know |
| + // if the bounds actually modified anything before including in key. |
| + if (!pe->filterPath(&fPath, *inPath, &strokeRec, nullptr)) { |
| + // Make an empty unstyled shape if filtering fails. |
| + fType = Type::kEmpty; |
| + fStyle = GrStyle(); |
| + fPath.~SkPath(); |
|
robertphillips
2016/04/25 12:07:06
won't falling through here be bad ?
bsalomon
2016/04/25 13:32:26
Yes, added return. I'll add a unit test for this i
|
| + } |
| + inPath = &fPath; |
| + } else if (stopAfterPE || !strokeRec.needToApply()) { |
| + *this = parent; |
| + return; |
| + } else { |
| + fType = Type::kPath; |
| + new (&fPath) SkPath(); |
| + if (parent.fType == Type::kPath) { |
| + inPath = &parent.fPath; |
| + } else { |
| + inPath = &fPath; |
| + parent.asPath(&fPath); |
| + } |
| + } |
| + if (!stopAfterPE) { |
| + strokeRec.applyToPath(&fPath, *inPath); |
| + } else { |
| + fStyle = GrStyle(strokeRec, nullptr); |
| + } |
| + this->setInheritedKey(parent, stopAfterPE); |
| +} |