123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199 |
- /*
- * 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 "src/gpu/GrStyle.h"
- #include "src/utils/SkDashPathPriv.h"
- int GrStyle::KeySize(const GrStyle &style, Apply apply, uint32_t flags) {
- GR_STATIC_ASSERT(sizeof(uint32_t) == sizeof(SkScalar));
- int size = 0;
- if (style.isDashed()) {
- // One scalar for scale, one for dash phase, and one for each dash value.
- size += 2 + style.dashIntervalCnt();
- } else if (style.pathEffect()) {
- // No key for a generic path effect.
- return -1;
- }
- if (Apply::kPathEffectOnly == apply) {
- return size;
- }
- if (style.strokeRec().needToApply()) {
- // One for res scale, one for style/cap/join, one for miter limit, and one for width.
- size += 4;
- }
- return size;
- }
- void GrStyle::WriteKey(uint32_t *key, const GrStyle &style, Apply apply, SkScalar scale,
- uint32_t flags) {
- SkASSERT(key);
- SkASSERT(KeySize(style, apply) >= 0);
- GR_STATIC_ASSERT(sizeof(uint32_t) == sizeof(SkScalar));
- int i = 0;
- // The scale can influence both the path effect and stroking. We want to preserve the
- // property that the following two are equal:
- // 1. WriteKey with apply == kPathEffectAndStrokeRec
- // 2. WriteKey with apply == kPathEffectOnly followed by WriteKey of a GrStyle made
- // from SkStrokeRec output by the the path effect (and no additional path effect).
- // Since the scale can affect both parts of 2 we write it into the key twice.
- if (style.isDashed()) {
- GR_STATIC_ASSERT(sizeof(style.dashPhase()) == sizeof(uint32_t));
- SkScalar phase = style.dashPhase();
- memcpy(&key[i++], &scale, sizeof(SkScalar));
- 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);
- i += count;
- } else {
- SkASSERT(!style.pathEffect());
- }
- if (Apply::kPathEffectAndStrokeRec == apply && style.strokeRec().needToApply()) {
- memcpy(&key[i++], &scale, sizeof(SkScalar));
- enum {
- kStyleBits = 2,
- kJoinBits = 2,
- kCapBits = 32 - kStyleBits - kJoinBits,
- kJoinShift = kStyleBits,
- kCapShift = kJoinShift + kJoinBits,
- };
- GR_STATIC_ASSERT(SkStrokeRec::kStyleCount <= (1 << kStyleBits));
- GR_STATIC_ASSERT(SkPaint::kJoinCount <= (1 << kJoinBits));
- GR_STATIC_ASSERT(SkPaint::kCapCount <= (1 << kCapBits));
- // The cap type only matters for unclosed shapes. However, a path effect could unclose
- // the shape before it is stroked.
- SkPaint::Cap cap = SkPaint::kDefault_Cap;
- if (!(flags & kClosed_KeyFlag) || style.pathEffect()) {
- cap = style.strokeRec().getCap();
- }
- SkScalar miter = -1.f;
- SkPaint::Join join = SkPaint::kDefault_Join;
- // Dashing will not insert joins but other path effects may.
- if (!(flags & kNoJoins_KeyFlag) || style.hasNonDashPathEffect()) {
- join = style.strokeRec().getJoin();
- // Miter limit only affects miter joins
- if (SkPaint::kMiter_Join == join) {
- miter = style.strokeRec().getMiter();
- }
- }
- key[i++] = style.strokeRec().getStyle() |
- join << kJoinShift |
- cap << kCapShift;
- memcpy(&key[i++], &miter, sizeof(miter));
- SkScalar width = style.strokeRec().getWidth();
- memcpy(&key[i++], &width, sizeof(width));
- }
- SkASSERT(KeySize(style, apply) == i);
- }
- void GrStyle::initPathEffect(sk_sp<SkPathEffect> pe) {
- SkASSERT(!fPathEffect);
- SkASSERT(SkPathEffect::kNone_DashType == fDashInfo.fType);
- SkASSERT(0 == fDashInfo.fIntervals.count());
- if (!pe) {
- return;
- }
- SkPathEffect::DashInfo info;
- if (SkPathEffect::kDash_DashType == pe->asADash(&info)) {
- SkStrokeRec::Style recStyle = fStrokeRec.getStyle();
- if (recStyle != SkStrokeRec::kFill_Style && recStyle != SkStrokeRec::kStrokeAndFill_Style) {
- fDashInfo.fType = SkPathEffect::kDash_DashType;
- fDashInfo.fIntervals.reset(info.fCount);
- fDashInfo.fPhase = info.fPhase;
- info.fIntervals = fDashInfo.fIntervals.get();
- pe->asADash(&info);
- fPathEffect = std::move(pe);
- }
- } else {
- fPathEffect = std::move(pe);
- }
- }
- bool GrStyle::applyPathEffect(SkPath* dst, SkStrokeRec* strokeRec, const SkPath& src) const {
- if (!fPathEffect) {
- return false;
- }
- if (SkPathEffect::kDash_DashType == fDashInfo.fType) {
- // We apply the dash ourselves here rather than using the path effect. This is so that
- // we can control whether the dasher applies the strokeRec for special cases. Our keying
- // depends on the strokeRec being applied separately.
- SkScalar phase = fDashInfo.fPhase;
- const SkScalar* intervals = fDashInfo.fIntervals.get();
- int intervalCnt = fDashInfo.fIntervals.count();
- SkScalar initialLength;
- int initialIndex;
- SkScalar intervalLength;
- SkDashPath::CalcDashParameters(phase, intervals, intervalCnt, &initialLength,
- &initialIndex, &intervalLength);
- if (!SkDashPath::InternalFilter(dst, src, strokeRec,
- nullptr, intervals, intervalCnt,
- initialLength, initialIndex, intervalLength,
- SkDashPath::StrokeRecApplication::kDisallow)) {
- return false;
- }
- } else if (!fPathEffect->filterPath(dst, src, strokeRec, nullptr)) {
- return false;
- }
- dst->setIsVolatile(true);
- return true;
- }
- bool GrStyle::applyPathEffectToPath(SkPath *dst, SkStrokeRec *remainingStroke,
- const SkPath &src, SkScalar resScale) const {
- SkASSERT(dst);
- SkStrokeRec strokeRec = fStrokeRec;
- strokeRec.setResScale(resScale);
- if (!this->applyPathEffect(dst, &strokeRec, src)) {
- return false;
- }
- *remainingStroke = strokeRec;
- return true;
- }
- bool GrStyle::applyToPath(SkPath* dst, SkStrokeRec::InitStyle* style, const SkPath& src,
- SkScalar resScale) const {
- SkASSERT(style);
- SkASSERT(dst);
- SkStrokeRec strokeRec = fStrokeRec;
- strokeRec.setResScale(resScale);
- const SkPath* pathForStrokeRec = &src;
- if (this->applyPathEffect(dst, &strokeRec, src)) {
- pathForStrokeRec = dst;
- } else if (fPathEffect) {
- return false;
- }
- if (strokeRec.needToApply()) {
- if (!strokeRec.applyToPath(dst, *pathForStrokeRec)) {
- return false;
- }
- dst->setIsVolatile(true);
- *style = SkStrokeRec::kFill_InitStyle;
- } else if (!fPathEffect) {
- // Nothing to do for path effect or stroke, fail.
- return false;
- } else {
- SkASSERT(SkStrokeRec::kFill_Style == strokeRec.getStyle() ||
- SkStrokeRec::kHairline_Style == strokeRec.getStyle());
- *style = strokeRec.getStyle() == SkStrokeRec::kFill_Style
- ? SkStrokeRec::kFill_InitStyle
- : SkStrokeRec::kHairline_InitStyle;
- }
- return true;
- }
|