1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2016 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "src/gpu/GrStyle.h" 9cb93a386Sopenharmony_ci#include "src/utils/SkDashPathPriv.h" 10cb93a386Sopenharmony_ci 11cb93a386Sopenharmony_ciint GrStyle::KeySize(const GrStyle &style, Apply apply, uint32_t flags) { 12cb93a386Sopenharmony_ci static_assert(sizeof(uint32_t) == sizeof(SkScalar)); 13cb93a386Sopenharmony_ci int size = 0; 14cb93a386Sopenharmony_ci if (style.isDashed()) { 15cb93a386Sopenharmony_ci // One scalar for scale, one for dash phase, and one for each dash value. 16cb93a386Sopenharmony_ci size += 2 + style.dashIntervalCnt(); 17cb93a386Sopenharmony_ci } else if (style.pathEffect()) { 18cb93a386Sopenharmony_ci // No key for a generic path effect. 19cb93a386Sopenharmony_ci return -1; 20cb93a386Sopenharmony_ci } 21cb93a386Sopenharmony_ci 22cb93a386Sopenharmony_ci if (Apply::kPathEffectOnly == apply) { 23cb93a386Sopenharmony_ci return size; 24cb93a386Sopenharmony_ci } 25cb93a386Sopenharmony_ci 26cb93a386Sopenharmony_ci if (style.strokeRec().needToApply()) { 27cb93a386Sopenharmony_ci // One for res scale, one for style/cap/join, one for miter limit, and one for width. 28cb93a386Sopenharmony_ci size += 4; 29cb93a386Sopenharmony_ci } 30cb93a386Sopenharmony_ci return size; 31cb93a386Sopenharmony_ci} 32cb93a386Sopenharmony_ci 33cb93a386Sopenharmony_civoid GrStyle::WriteKey(uint32_t *key, const GrStyle &style, Apply apply, SkScalar scale, 34cb93a386Sopenharmony_ci uint32_t flags) { 35cb93a386Sopenharmony_ci SkASSERT(key); 36cb93a386Sopenharmony_ci SkASSERT(KeySize(style, apply) >= 0); 37cb93a386Sopenharmony_ci static_assert(sizeof(uint32_t) == sizeof(SkScalar)); 38cb93a386Sopenharmony_ci 39cb93a386Sopenharmony_ci int i = 0; 40cb93a386Sopenharmony_ci // The scale can influence both the path effect and stroking. We want to preserve the 41cb93a386Sopenharmony_ci // property that the following two are equal: 42cb93a386Sopenharmony_ci // 1. WriteKey with apply == kPathEffectAndStrokeRec 43cb93a386Sopenharmony_ci // 2. WriteKey with apply == kPathEffectOnly followed by WriteKey of a GrStyle made 44cb93a386Sopenharmony_ci // from SkStrokeRec output by the the path effect (and no additional path effect). 45cb93a386Sopenharmony_ci // Since the scale can affect both parts of 2 we write it into the key twice. 46cb93a386Sopenharmony_ci if (style.isDashed()) { 47cb93a386Sopenharmony_ci static_assert(sizeof(style.dashPhase()) == sizeof(uint32_t)); 48cb93a386Sopenharmony_ci SkScalar phase = style.dashPhase(); 49cb93a386Sopenharmony_ci memcpy(&key[i++], &scale, sizeof(SkScalar)); 50cb93a386Sopenharmony_ci memcpy(&key[i++], &phase, sizeof(SkScalar)); 51cb93a386Sopenharmony_ci 52cb93a386Sopenharmony_ci int32_t count = style.dashIntervalCnt(); 53cb93a386Sopenharmony_ci // Dash count should always be even. 54cb93a386Sopenharmony_ci SkASSERT(0 == (count & 0x1)); 55cb93a386Sopenharmony_ci const SkScalar *intervals = style.dashIntervals(); 56cb93a386Sopenharmony_ci int intervalByteCnt = count * sizeof(SkScalar); 57cb93a386Sopenharmony_ci memcpy(&key[i], intervals, intervalByteCnt); 58cb93a386Sopenharmony_ci i += count; 59cb93a386Sopenharmony_ci } else { 60cb93a386Sopenharmony_ci SkASSERT(!style.pathEffect()); 61cb93a386Sopenharmony_ci } 62cb93a386Sopenharmony_ci 63cb93a386Sopenharmony_ci if (Apply::kPathEffectAndStrokeRec == apply && style.strokeRec().needToApply()) { 64cb93a386Sopenharmony_ci memcpy(&key[i++], &scale, sizeof(SkScalar)); 65cb93a386Sopenharmony_ci enum { 66cb93a386Sopenharmony_ci kStyleBits = 2, 67cb93a386Sopenharmony_ci kJoinBits = 2, 68cb93a386Sopenharmony_ci kCapBits = 32 - kStyleBits - kJoinBits, 69cb93a386Sopenharmony_ci 70cb93a386Sopenharmony_ci kJoinShift = kStyleBits, 71cb93a386Sopenharmony_ci kCapShift = kJoinShift + kJoinBits, 72cb93a386Sopenharmony_ci }; 73cb93a386Sopenharmony_ci static_assert(SkStrokeRec::kStyleCount <= (1 << kStyleBits)); 74cb93a386Sopenharmony_ci static_assert(SkPaint::kJoinCount <= (1 << kJoinBits)); 75cb93a386Sopenharmony_ci static_assert(SkPaint::kCapCount <= (1 << kCapBits)); 76cb93a386Sopenharmony_ci // The cap type only matters for unclosed shapes. However, a path effect could unclose 77cb93a386Sopenharmony_ci // the shape before it is stroked. 78cb93a386Sopenharmony_ci SkPaint::Cap cap = SkPaint::kDefault_Cap; 79cb93a386Sopenharmony_ci if (!(flags & kClosed_KeyFlag) || style.pathEffect()) { 80cb93a386Sopenharmony_ci cap = style.strokeRec().getCap(); 81cb93a386Sopenharmony_ci } 82cb93a386Sopenharmony_ci SkScalar miter = -1.f; 83cb93a386Sopenharmony_ci SkPaint::Join join = SkPaint::kDefault_Join; 84cb93a386Sopenharmony_ci 85cb93a386Sopenharmony_ci // Dashing will not insert joins but other path effects may. 86cb93a386Sopenharmony_ci if (!(flags & kNoJoins_KeyFlag) || style.hasNonDashPathEffect()) { 87cb93a386Sopenharmony_ci join = style.strokeRec().getJoin(); 88cb93a386Sopenharmony_ci // Miter limit only affects miter joins 89cb93a386Sopenharmony_ci if (SkPaint::kMiter_Join == join) { 90cb93a386Sopenharmony_ci miter = style.strokeRec().getMiter(); 91cb93a386Sopenharmony_ci } 92cb93a386Sopenharmony_ci } 93cb93a386Sopenharmony_ci 94cb93a386Sopenharmony_ci key[i++] = style.strokeRec().getStyle() | 95cb93a386Sopenharmony_ci join << kJoinShift | 96cb93a386Sopenharmony_ci cap << kCapShift; 97cb93a386Sopenharmony_ci 98cb93a386Sopenharmony_ci memcpy(&key[i++], &miter, sizeof(miter)); 99cb93a386Sopenharmony_ci 100cb93a386Sopenharmony_ci SkScalar width = style.strokeRec().getWidth(); 101cb93a386Sopenharmony_ci memcpy(&key[i++], &width, sizeof(width)); 102cb93a386Sopenharmony_ci } 103cb93a386Sopenharmony_ci SkASSERT(KeySize(style, apply) == i); 104cb93a386Sopenharmony_ci} 105cb93a386Sopenharmony_ci 106cb93a386Sopenharmony_civoid GrStyle::initPathEffect(sk_sp<SkPathEffect> pe) { 107cb93a386Sopenharmony_ci SkASSERT(!fPathEffect); 108cb93a386Sopenharmony_ci SkASSERT(SkPathEffect::kNone_DashType == fDashInfo.fType); 109cb93a386Sopenharmony_ci SkASSERT(0 == fDashInfo.fIntervals.count()); 110cb93a386Sopenharmony_ci if (!pe) { 111cb93a386Sopenharmony_ci return; 112cb93a386Sopenharmony_ci } 113cb93a386Sopenharmony_ci SkPathEffect::DashInfo info; 114cb93a386Sopenharmony_ci if (SkPathEffect::kDash_DashType == pe->asADash(&info)) { 115cb93a386Sopenharmony_ci SkStrokeRec::Style recStyle = fStrokeRec.getStyle(); 116cb93a386Sopenharmony_ci if (recStyle != SkStrokeRec::kFill_Style && recStyle != SkStrokeRec::kStrokeAndFill_Style) { 117cb93a386Sopenharmony_ci fDashInfo.fType = SkPathEffect::kDash_DashType; 118cb93a386Sopenharmony_ci fDashInfo.fIntervals.reset(info.fCount); 119cb93a386Sopenharmony_ci fDashInfo.fPhase = info.fPhase; 120cb93a386Sopenharmony_ci info.fIntervals = fDashInfo.fIntervals.get(); 121cb93a386Sopenharmony_ci pe->asADash(&info); 122cb93a386Sopenharmony_ci fPathEffect = std::move(pe); 123cb93a386Sopenharmony_ci } 124cb93a386Sopenharmony_ci } else { 125cb93a386Sopenharmony_ci fPathEffect = std::move(pe); 126cb93a386Sopenharmony_ci } 127cb93a386Sopenharmony_ci} 128cb93a386Sopenharmony_ci 129cb93a386Sopenharmony_cibool GrStyle::applyPathEffect(SkPath* dst, SkStrokeRec* strokeRec, const SkPath& src) const { 130cb93a386Sopenharmony_ci if (!fPathEffect) { 131cb93a386Sopenharmony_ci return false; 132cb93a386Sopenharmony_ci } 133cb93a386Sopenharmony_ci 134cb93a386Sopenharmony_ci // TODO: [skbug.com/11957] Plumb CTM callers and pass it to filterPath(). 135cb93a386Sopenharmony_ci SkASSERT(!fPathEffect->needsCTM()); 136cb93a386Sopenharmony_ci 137cb93a386Sopenharmony_ci if (SkPathEffect::kDash_DashType == fDashInfo.fType) { 138cb93a386Sopenharmony_ci // We apply the dash ourselves here rather than using the path effect. This is so that 139cb93a386Sopenharmony_ci // we can control whether the dasher applies the strokeRec for special cases. Our keying 140cb93a386Sopenharmony_ci // depends on the strokeRec being applied separately. 141cb93a386Sopenharmony_ci SkASSERT(!fPathEffect->needsCTM()); // Make sure specified PE doesn't need CTM 142cb93a386Sopenharmony_ci SkScalar phase = fDashInfo.fPhase; 143cb93a386Sopenharmony_ci const SkScalar* intervals = fDashInfo.fIntervals.get(); 144cb93a386Sopenharmony_ci int intervalCnt = fDashInfo.fIntervals.count(); 145cb93a386Sopenharmony_ci SkScalar initialLength; 146cb93a386Sopenharmony_ci int initialIndex; 147cb93a386Sopenharmony_ci SkScalar intervalLength; 148cb93a386Sopenharmony_ci SkDashPath::CalcDashParameters(phase, intervals, intervalCnt, &initialLength, 149cb93a386Sopenharmony_ci &initialIndex, &intervalLength); 150cb93a386Sopenharmony_ci if (!SkDashPath::InternalFilter(dst, src, strokeRec, 151cb93a386Sopenharmony_ci nullptr, intervals, intervalCnt, 152cb93a386Sopenharmony_ci initialLength, initialIndex, intervalLength, 153cb93a386Sopenharmony_ci SkDashPath::StrokeRecApplication::kDisallow)) { 154cb93a386Sopenharmony_ci return false; 155cb93a386Sopenharmony_ci } 156cb93a386Sopenharmony_ci } else if (!fPathEffect->filterPath(dst, src, strokeRec, nullptr)) { 157cb93a386Sopenharmony_ci return false; 158cb93a386Sopenharmony_ci } 159cb93a386Sopenharmony_ci dst->setIsVolatile(true); 160cb93a386Sopenharmony_ci return true; 161cb93a386Sopenharmony_ci} 162cb93a386Sopenharmony_ci 163cb93a386Sopenharmony_cibool GrStyle::applyPathEffectToPath(SkPath *dst, SkStrokeRec *remainingStroke, 164cb93a386Sopenharmony_ci const SkPath &src, SkScalar resScale) const { 165cb93a386Sopenharmony_ci SkASSERT(dst); 166cb93a386Sopenharmony_ci SkStrokeRec strokeRec = fStrokeRec; 167cb93a386Sopenharmony_ci strokeRec.setResScale(resScale); 168cb93a386Sopenharmony_ci if (!this->applyPathEffect(dst, &strokeRec, src)) { 169cb93a386Sopenharmony_ci return false; 170cb93a386Sopenharmony_ci } 171cb93a386Sopenharmony_ci *remainingStroke = strokeRec; 172cb93a386Sopenharmony_ci return true; 173cb93a386Sopenharmony_ci} 174cb93a386Sopenharmony_ci 175cb93a386Sopenharmony_cibool GrStyle::applyToPath(SkPath* dst, SkStrokeRec::InitStyle* style, const SkPath& src, 176cb93a386Sopenharmony_ci SkScalar resScale) const { 177cb93a386Sopenharmony_ci SkASSERT(style); 178cb93a386Sopenharmony_ci SkASSERT(dst); 179cb93a386Sopenharmony_ci SkStrokeRec strokeRec = fStrokeRec; 180cb93a386Sopenharmony_ci strokeRec.setResScale(resScale); 181cb93a386Sopenharmony_ci const SkPath* pathForStrokeRec = &src; 182cb93a386Sopenharmony_ci if (this->applyPathEffect(dst, &strokeRec, src)) { 183cb93a386Sopenharmony_ci pathForStrokeRec = dst; 184cb93a386Sopenharmony_ci } else if (fPathEffect) { 185cb93a386Sopenharmony_ci return false; 186cb93a386Sopenharmony_ci } 187cb93a386Sopenharmony_ci if (strokeRec.needToApply()) { 188cb93a386Sopenharmony_ci if (!strokeRec.applyToPath(dst, *pathForStrokeRec)) { 189cb93a386Sopenharmony_ci return false; 190cb93a386Sopenharmony_ci } 191cb93a386Sopenharmony_ci dst->setIsVolatile(true); 192cb93a386Sopenharmony_ci *style = SkStrokeRec::kFill_InitStyle; 193cb93a386Sopenharmony_ci } else if (!fPathEffect) { 194cb93a386Sopenharmony_ci // Nothing to do for path effect or stroke, fail. 195cb93a386Sopenharmony_ci return false; 196cb93a386Sopenharmony_ci } else { 197cb93a386Sopenharmony_ci SkASSERT(SkStrokeRec::kFill_Style == strokeRec.getStyle() || 198cb93a386Sopenharmony_ci SkStrokeRec::kHairline_Style == strokeRec.getStyle()); 199cb93a386Sopenharmony_ci *style = strokeRec.getStyle() == SkStrokeRec::kFill_Style 200cb93a386Sopenharmony_ci ? SkStrokeRec::kFill_InitStyle 201cb93a386Sopenharmony_ci : SkStrokeRec::kHairline_InitStyle; 202cb93a386Sopenharmony_ci } 203cb93a386Sopenharmony_ci return true; 204cb93a386Sopenharmony_ci} 205