147cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon/* 247cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon * Copyright 2016 Google Inc. 347cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon * 447cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon * Use of this source code is governed by a BSD-style license that can be 547cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon * found in the LICENSE file. 647cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon */ 747cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon 847cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon#ifndef GrShape_DEFINED 947cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon#define GrShape_DEFINED 1047cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon 1147cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon#include "GrStyle.h" 1247cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon#include "SkPath.h" 13ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon#include "SkPathPriv.h" 1447cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon#include "SkRRect.h" 1547cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon#include "SkTemplates.h" 1647cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon#include "SkTLazy.h" 1747cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon 1847cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon/** 1947cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon * Represents a geometric shape (rrect or path) and the GrStyle that it should be rendered with. 2047cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon * It is possible to apply the style to the GrShape to produce a new GrShape where the geometry 2147cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon * reflects the styling information (e.g. is stroked). It is also possible to apply just the 2247cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon * path effect from the style. In this case the resulting shape will include any remaining 2347cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon * stroking information that is to be applied after the path effect. 2447cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon * 2547cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon * Shapes can produce keys that represent only the geometry information, not the style. Note that 2647cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon * when styling information is applied to produce a new shape then the style has been converted 2747cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon * to geometric information and is included in the new shape's key. When the same style is applied 2847cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon * to two shapes that reflect the same underlying geometry the computed keys of the stylized shapes 2947cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon * will be the same. 3047cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon * 31ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon * Currently this can only be constructed from a path, rect, or rrect though it can become a path 32ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon * applying style to the geometry. The idea is to expand this to cover most or all of the geometries 334f40caf33e15c4e2e21742854dfd5cfd31812c3fBrian Salomon * that have fast paths in the GPU backend. 3447cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon */ 3547cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomonclass GrShape { 3647cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomonpublic: 3767fa4e31d885acf74514527a2cc3ed759c05d3c4bsalomon // Keys for paths may be extracted from the path data for small paths. Clients aren't supposed 3867fa4e31d885acf74514527a2cc3ed759c05d3c4bsalomon // to have to worry about this. This value is exposed for unit tests. 3967fa4e31d885acf74514527a2cc3ed759c05d3c4bsalomon static constexpr int kMaxKeyFromDataVerbCnt = 10; 4067fa4e31d885acf74514527a2cc3ed759c05d3c4bsalomon 41728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon GrShape() { this->initType(Type::kEmpty); } 425e410b4a68d11a06c331139905171952ef535cf8bsalomon 43728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon explicit GrShape(const SkPath& path) : GrShape(path, GrStyle::SimpleFill()) {} 4472dc51c288169f38177c71081090581c5ff415b1bsalomon 45728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon explicit GrShape(const SkRRect& rrect) : GrShape(rrect, GrStyle::SimpleFill()) {} 4647cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon 47728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon explicit GrShape(const SkRect& rect) : GrShape(rect, GrStyle::SimpleFill()) {} 4847cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon 49da6d0720300a29a4deb5dd4c433a92a3ec41286eBrian Salomon GrShape(const SkPath& path, const GrStyle& style) : fStyle(style) { 50728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon this->initType(Type::kPath, &path); 511b28c1adc1e156831d5332546e942b63fd29075bbsalomon this->attemptToSimplifyPath(); 5272dc51c288169f38177c71081090581c5ff415b1bsalomon } 5372dc51c288169f38177c71081090581c5ff415b1bsalomon 5447cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon GrShape(const SkRRect& rrect, const GrStyle& style) 55728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon : fStyle(style) { 56728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon this->initType(Type::kRRect); 57728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon fRRectData.fRRect = rrect; 58728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon fRRectData.fInverted = false; 59728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon fRRectData.fStart = DefaultRRectDirAndStartIndex(rrect, style.hasPathEffect(), 60728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon &fRRectData.fDir); 611b28c1adc1e156831d5332546e942b63fd29075bbsalomon this->attemptToSimplifyRRect(); 62ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon } 63ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon 647049396b65660907af5292d899053280430d929absalomon GrShape(const SkRRect& rrect, SkPath::Direction dir, unsigned start, bool inverted, 657049396b65660907af5292d899053280430d929absalomon const GrStyle& style) 66728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon : fStyle(style) { 67728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon this->initType(Type::kRRect); 68728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon fRRectData.fRRect = rrect; 69728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon fRRectData.fInverted = inverted; 70ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon if (style.pathEffect()) { 71728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon fRRectData.fDir = dir; 72728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon fRRectData.fStart = start; 73728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon if (fRRectData.fRRect.getType() == SkRRect::kRect_Type) { 74728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon fRRectData.fStart = (fRRectData.fStart + 1) & 0b110; 75728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon } else if (fRRectData.fRRect.getType() == SkRRect::kOval_Type) { 76728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon fRRectData.fStart &= 0b110; 777049396b65660907af5292d899053280430d929absalomon } 78ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon } else { 79728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon fRRectData.fStart = DefaultRRectDirAndStartIndex(rrect, false, &fRRectData.fDir); 80ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon } 811b28c1adc1e156831d5332546e942b63fd29075bbsalomon this->attemptToSimplifyRRect(); 825e410b4a68d11a06c331139905171952ef535cf8bsalomon } 8347cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon 8447cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon GrShape(const SkRect& rect, const GrStyle& style) 85728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon : fStyle(style) { 86728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon this->initType(Type::kRRect); 87728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon fRRectData.fRRect = SkRRect::MakeRect(rect); 88728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon fRRectData.fInverted = false; 89728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon fRRectData.fStart = DefaultRectDirAndStartIndex(rect, style.hasPathEffect(), 90728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon &fRRectData.fDir); 911b28c1adc1e156831d5332546e942b63fd29075bbsalomon this->attemptToSimplifyRRect(); 925e410b4a68d11a06c331139905171952ef535cf8bsalomon } 9347cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon 94da6d0720300a29a4deb5dd4c433a92a3ec41286eBrian Salomon GrShape(const SkPath& path, const SkPaint& paint) : fStyle(paint) { 95728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon this->initType(Type::kPath, &path); 961b28c1adc1e156831d5332546e942b63fd29075bbsalomon this->attemptToSimplifyPath(); 9772dc51c288169f38177c71081090581c5ff415b1bsalomon } 9872dc51c288169f38177c71081090581c5ff415b1bsalomon 9947cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon GrShape(const SkRRect& rrect, const SkPaint& paint) 100728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon : fStyle(paint) { 101728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon this->initType(Type::kRRect); 102728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon fRRectData.fRRect = rrect; 103728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon fRRectData.fInverted = false; 104728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon fRRectData.fStart = DefaultRRectDirAndStartIndex(rrect, fStyle.hasPathEffect(), 105728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon &fRRectData.fDir); 1061b28c1adc1e156831d5332546e942b63fd29075bbsalomon this->attemptToSimplifyRRect(); 1075e410b4a68d11a06c331139905171952ef535cf8bsalomon } 10847cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon 10947cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon GrShape(const SkRect& rect, const SkPaint& paint) 110728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon : fStyle(paint) { 111728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon this->initType(Type::kRRect); 112728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon fRRectData.fRRect = SkRRect::MakeRect(rect); 113728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon fRRectData.fInverted = false; 114728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon fRRectData.fStart = DefaultRectDirAndStartIndex(rect, fStyle.hasPathEffect(), 115728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon &fRRectData.fDir); 1161b28c1adc1e156831d5332546e942b63fd29075bbsalomon this->attemptToSimplifyRRect(); 1175e410b4a68d11a06c331139905171952ef535cf8bsalomon } 11847cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon 119a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon static GrShape MakeArc(const SkRect& oval, SkScalar startAngleDegrees, 120a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon SkScalar sweepAngleDegrees, bool useCenter, const GrStyle& style); 121a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon 12247cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon GrShape(const GrShape&); 12347cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon GrShape& operator=(const GrShape& that); 12447cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon 125728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon ~GrShape() { this->changeType(Type::kEmpty); } 12647cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon 1274f40caf33e15c4e2e21742854dfd5cfd31812c3fBrian Salomon /** 1284f40caf33e15c4e2e21742854dfd5cfd31812c3fBrian Salomon * Informs MakeFilled on how to modify that shape's fill rule when making a simple filled 1294f40caf33e15c4e2e21742854dfd5cfd31812c3fBrian Salomon * version of the shape. 1304f40caf33e15c4e2e21742854dfd5cfd31812c3fBrian Salomon */ 1314f40caf33e15c4e2e21742854dfd5cfd31812c3fBrian Salomon enum class FillInversion { 1324f40caf33e15c4e2e21742854dfd5cfd31812c3fBrian Salomon kPreserve, 1334f40caf33e15c4e2e21742854dfd5cfd31812c3fBrian Salomon kFlip, 1344f40caf33e15c4e2e21742854dfd5cfd31812c3fBrian Salomon kForceNoninverted, 1354f40caf33e15c4e2e21742854dfd5cfd31812c3fBrian Salomon kForceInverted 1364f40caf33e15c4e2e21742854dfd5cfd31812c3fBrian Salomon }; 1374f40caf33e15c4e2e21742854dfd5cfd31812c3fBrian Salomon /** 1384f40caf33e15c4e2e21742854dfd5cfd31812c3fBrian Salomon * Makes a filled shape from the pre-styled original shape and optionally modifies whether 1394f40caf33e15c4e2e21742854dfd5cfd31812c3fBrian Salomon * the fill is inverted or not. It's important to note that the original shape's geometry 1404f40caf33e15c4e2e21742854dfd5cfd31812c3fBrian Salomon * may already have been modified if doing so was neutral with respect to its style 1414f40caf33e15c4e2e21742854dfd5cfd31812c3fBrian Salomon * (e.g. filled paths are always closed when stored in a shape and dashed paths are always 1424f40caf33e15c4e2e21742854dfd5cfd31812c3fBrian Salomon * made non-inverted since dashing ignores inverseness). 1434f40caf33e15c4e2e21742854dfd5cfd31812c3fBrian Salomon */ 1444f40caf33e15c4e2e21742854dfd5cfd31812c3fBrian Salomon static GrShape MakeFilled(const GrShape& original, FillInversion = FillInversion::kPreserve); 1454f40caf33e15c4e2e21742854dfd5cfd31812c3fBrian Salomon 14647cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon const GrStyle& style() const { return fStyle; } 14747cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon 14897fd2d42b97104fa32a58d7e7a5b7255913f9c9dbsalomon /** 14997fd2d42b97104fa32a58d7e7a5b7255913f9c9dbsalomon * Returns a shape that has either applied the path effect or path effect and stroking 15097fd2d42b97104fa32a58d7e7a5b7255913f9c9dbsalomon * information from this shape's style to its geometry. Scale is used when approximating the 15197fd2d42b97104fa32a58d7e7a5b7255913f9c9dbsalomon * output geometry and typically is computed from the view matrix 15297fd2d42b97104fa32a58d7e7a5b7255913f9c9dbsalomon */ 153425c27fab9d82d19b0bce7c091533d546465bbaebsalomon GrShape applyStyle(GrStyle::Apply apply, SkScalar scale) const { 15497fd2d42b97104fa32a58d7e7a5b7255913f9c9dbsalomon return GrShape(*this, apply, scale); 15597fd2d42b97104fa32a58d7e7a5b7255913f9c9dbsalomon } 15647cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon 1577c73a53894927d222d4aceed96893daae8ea14f1bsalomon /** Returns the unstyled geometry as a rrect if possible. */ 1587049396b65660907af5292d899053280430d929absalomon bool asRRect(SkRRect* rrect, SkPath::Direction* dir, unsigned* start, bool* inverted) const { 15947cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon if (Type::kRRect != fType) { 16047cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon return false; 16147cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon } 16247cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon if (rrect) { 163728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon *rrect = fRRectData.fRRect; 16447cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon } 165ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon if (dir) { 166728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon *dir = fRRectData.fDir; 167ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon } 168ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon if (start) { 169728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon *start = fRRectData.fStart; 170ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon } 1717049396b65660907af5292d899053280430d929absalomon if (inverted) { 172728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon *inverted = fRRectData.fInverted; 1737049396b65660907af5292d899053280430d929absalomon } 17447cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon return true; 17547cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon } 17647cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon 177398e3f4b9f67e0c7f635e68cae1ff7f42213bbfcbsalomon /** 178398e3f4b9f67e0c7f635e68cae1ff7f42213bbfcbsalomon * If the unstyled shape is a straight line segment, returns true and sets pts to the endpoints. 179398e3f4b9f67e0c7f635e68cae1ff7f42213bbfcbsalomon * An inverse filled line path is still considered a line. 180398e3f4b9f67e0c7f635e68cae1ff7f42213bbfcbsalomon */ 1810a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon bool asLine(SkPoint pts[2], bool* inverted) const { 1820a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon if (fType != Type::kLine) { 1830a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon return false; 1840a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon } 1850a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon if (pts) { 1860a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon pts[0] = fLineData.fPts[0]; 1870a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon pts[1] = fLineData.fPts[1]; 1880a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon } 1890a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon if (inverted) { 1900a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon *inverted = fLineData.fInverted; 1910a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon } 1920a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon return true; 1930a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon } 194398e3f4b9f67e0c7f635e68cae1ff7f42213bbfcbsalomon 1957c73a53894927d222d4aceed96893daae8ea14f1bsalomon /** Returns the unstyled geometry as a path. */ 19647cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon void asPath(SkPath* out) const { 19747cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon switch (fType) { 19806077565b18714ff3fc0db9118e2c21f6f25243fbsalomon case Type::kEmpty: 19906077565b18714ff3fc0db9118e2c21f6f25243fbsalomon out->reset(); 20006077565b18714ff3fc0db9118e2c21f6f25243fbsalomon break; 201085c0862f674337c5a60f8c46da4c12f0d12511aBrian Salomon case Type::kInvertedEmpty: 202085c0862f674337c5a60f8c46da4c12f0d12511aBrian Salomon out->reset(); 203085c0862f674337c5a60f8c46da4c12f0d12511aBrian Salomon out->setFillType(kDefaultPathInverseFillType); 204085c0862f674337c5a60f8c46da4c12f0d12511aBrian Salomon break; 20547cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon case Type::kRRect: 20647cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon out->reset(); 207728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon out->addRRect(fRRectData.fRRect, fRRectData.fDir, fRRectData.fStart); 20893f66bc3af522fdd2a5315407ba6d3f65c13fd1cbsalomon // Below matches the fill type that attemptToSimplifyPath uses. 209728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon if (fRRectData.fInverted) { 210a4817afe5095b67a68c907ff2e48e3e07907140cbsalomon out->setFillType(kDefaultPathInverseFillType); 21193f66bc3af522fdd2a5315407ba6d3f65c13fd1cbsalomon } else { 212a4817afe5095b67a68c907ff2e48e3e07907140cbsalomon out->setFillType(kDefaultPathFillType); 2137049396b65660907af5292d899053280430d929absalomon } 21447cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon break; 215a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon case Type::kArc: 216a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon SkPathPriv::CreateDrawArcPath(out, fArcData.fOval, fArcData.fStartAngleDegrees, 217a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon fArcData.fSweepAngleDegrees, fArcData.fUseCenter, 218a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon fStyle.isSimpleFill()); 219a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon if (fArcData.fInverted) { 220a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon out->setFillType(kDefaultPathInverseFillType); 221a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon } else { 222a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon out->setFillType(kDefaultPathFillType); 223a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon } 224a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon break; 2250a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon case Type::kLine: 2260a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon out->reset(); 2270a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon out->moveTo(fLineData.fPts[0]); 2280a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon out->lineTo(fLineData.fPts[1]); 2290a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon if (fLineData.fInverted) { 2300a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon out->setFillType(kDefaultPathInverseFillType); 2310a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon } else { 2320a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon out->setFillType(kDefaultPathFillType); 2330a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon } 2340a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon break; 23547cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon case Type::kPath: 236728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon *out = this->path(); 23747cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon break; 23806077565b18714ff3fc0db9118e2c21f6f25243fbsalomon } 23906077565b18714ff3fc0db9118e2c21f6f25243fbsalomon } 24006077565b18714ff3fc0db9118e2c21f6f25243fbsalomon 24106077565b18714ff3fc0db9118e2c21f6f25243fbsalomon /** 2427c73a53894927d222d4aceed96893daae8ea14f1bsalomon * Returns whether the geometry is empty. Note that applying the style could produce a 243085c0862f674337c5a60f8c46da4c12f0d12511aBrian Salomon * non-empty shape. It also may have an inverse fill. 2447c73a53894927d222d4aceed96893daae8ea14f1bsalomon */ 245085c0862f674337c5a60f8c46da4c12f0d12511aBrian Salomon bool isEmpty() const { return Type::kEmpty == fType || Type::kInvertedEmpty == fType; } 2467c73a53894927d222d4aceed96893daae8ea14f1bsalomon 2477049396b65660907af5292d899053280430d929absalomon /** 2487049396b65660907af5292d899053280430d929absalomon * Gets the bounds of the geometry without reflecting the shape's styling. This ignores 2497049396b65660907af5292d899053280430d929absalomon * the inverse fill nature of the geometry. 2507049396b65660907af5292d899053280430d929absalomon */ 2510a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon SkRect bounds() const; 2529fb420393ee1c24fc3282b7155985fa8fa7bcad4bsalomon 2537049396b65660907af5292d899053280430d929absalomon /** 2547049396b65660907af5292d899053280430d929absalomon * Gets the bounds of the geometry reflecting the shape's styling (ignoring inverse fill 2557049396b65660907af5292d899053280430d929absalomon * status). 2567049396b65660907af5292d899053280430d929absalomon */ 2570a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon SkRect styledBounds() const; 2589fb420393ee1c24fc3282b7155985fa8fa7bcad4bsalomon 2597c73a53894927d222d4aceed96893daae8ea14f1bsalomon /** 260425c27fab9d82d19b0bce7c091533d546465bbaebsalomon * Is this shape known to be convex, before styling is applied. An unclosed but otherwise 261425c27fab9d82d19b0bce7c091533d546465bbaebsalomon * convex path is considered to be closed if they styling reflects a fill and not otherwise. 262425c27fab9d82d19b0bce7c091533d546465bbaebsalomon * This is because filling closes all contours in the path. 263425c27fab9d82d19b0bce7c091533d546465bbaebsalomon */ 264425c27fab9d82d19b0bce7c091533d546465bbaebsalomon bool knownToBeConvex() const { 265425c27fab9d82d19b0bce7c091533d546465bbaebsalomon switch (fType) { 266425c27fab9d82d19b0bce7c091533d546465bbaebsalomon case Type::kEmpty: 267425c27fab9d82d19b0bce7c091533d546465bbaebsalomon return true; 268085c0862f674337c5a60f8c46da4c12f0d12511aBrian Salomon case Type::kInvertedEmpty: 269085c0862f674337c5a60f8c46da4c12f0d12511aBrian Salomon return true; 270425c27fab9d82d19b0bce7c091533d546465bbaebsalomon case Type::kRRect: 271425c27fab9d82d19b0bce7c091533d546465bbaebsalomon return true; 272a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon case Type::kArc: 273a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon return SkPathPriv::DrawArcIsConvex(fArcData.fSweepAngleDegrees, 274a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon SkToBool(fArcData.fUseCenter), 275a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon fStyle.isSimpleFill()); 2760a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon case Type::kLine: 2770a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon return true; 278425c27fab9d82d19b0bce7c091533d546465bbaebsalomon case Type::kPath: 279425c27fab9d82d19b0bce7c091533d546465bbaebsalomon // SkPath.isConvex() really means "is this path convex were it to be closed" and 280425c27fab9d82d19b0bce7c091533d546465bbaebsalomon // thus doesn't give the correct answer for stroked paths, hence we also check 281425c27fab9d82d19b0bce7c091533d546465bbaebsalomon // whether the path is either filled or closed. Convex paths may only have one 282425c27fab9d82d19b0bce7c091533d546465bbaebsalomon // contour hence isLastContourClosed() is a sufficient for a convex path. 283728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon return (this->style().isSimpleFill() || this->path().isLastContourClosed()) && 284728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon this->path().isConvex(); 285425c27fab9d82d19b0bce7c091533d546465bbaebsalomon } 286425c27fab9d82d19b0bce7c091533d546465bbaebsalomon return false; 287425c27fab9d82d19b0bce7c091533d546465bbaebsalomon } 288425c27fab9d82d19b0bce7c091533d546465bbaebsalomon 289425c27fab9d82d19b0bce7c091533d546465bbaebsalomon /** Is the pre-styled geometry inverse filled? */ 290425c27fab9d82d19b0bce7c091533d546465bbaebsalomon bool inverseFilled() const { 291425c27fab9d82d19b0bce7c091533d546465bbaebsalomon bool ret = false; 292425c27fab9d82d19b0bce7c091533d546465bbaebsalomon switch (fType) { 293425c27fab9d82d19b0bce7c091533d546465bbaebsalomon case Type::kEmpty: 294425c27fab9d82d19b0bce7c091533d546465bbaebsalomon ret = false; 295425c27fab9d82d19b0bce7c091533d546465bbaebsalomon break; 296085c0862f674337c5a60f8c46da4c12f0d12511aBrian Salomon case Type::kInvertedEmpty: 297085c0862f674337c5a60f8c46da4c12f0d12511aBrian Salomon ret = true; 298085c0862f674337c5a60f8c46da4c12f0d12511aBrian Salomon break; 299425c27fab9d82d19b0bce7c091533d546465bbaebsalomon case Type::kRRect: 300728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon ret = fRRectData.fInverted; 301425c27fab9d82d19b0bce7c091533d546465bbaebsalomon break; 302a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon case Type::kArc: 303a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon ret = fArcData.fInverted; 304a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon break; 3050a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon case Type::kLine: 3060a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon ret = fLineData.fInverted; 3070a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon break; 308425c27fab9d82d19b0bce7c091533d546465bbaebsalomon case Type::kPath: 309728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon ret = this->path().isInverseFillType(); 310425c27fab9d82d19b0bce7c091533d546465bbaebsalomon break; 311425c27fab9d82d19b0bce7c091533d546465bbaebsalomon } 312425c27fab9d82d19b0bce7c091533d546465bbaebsalomon // Dashing ignores inverseness. We should have caught this earlier. skbug.com/5421 313425c27fab9d82d19b0bce7c091533d546465bbaebsalomon SkASSERT(!(ret && this->style().isDashed())); 314425c27fab9d82d19b0bce7c091533d546465bbaebsalomon return ret; 315425c27fab9d82d19b0bce7c091533d546465bbaebsalomon } 316425c27fab9d82d19b0bce7c091533d546465bbaebsalomon 317425c27fab9d82d19b0bce7c091533d546465bbaebsalomon /** 318425c27fab9d82d19b0bce7c091533d546465bbaebsalomon * Might applying the styling to the geometry produce an inverse fill. The "may" part comes in 319425c27fab9d82d19b0bce7c091533d546465bbaebsalomon * because an arbitrary path effect could produce an inverse filled path. In other cases this 320425c27fab9d82d19b0bce7c091533d546465bbaebsalomon * can be thought of as "inverseFilledAfterStyling()". 321425c27fab9d82d19b0bce7c091533d546465bbaebsalomon */ 322425c27fab9d82d19b0bce7c091533d546465bbaebsalomon bool mayBeInverseFilledAfterStyling() const { 323425c27fab9d82d19b0bce7c091533d546465bbaebsalomon // An arbitrary path effect can produce an arbitrary output path, which may be inverse 324425c27fab9d82d19b0bce7c091533d546465bbaebsalomon // filled. 325425c27fab9d82d19b0bce7c091533d546465bbaebsalomon if (this->style().hasNonDashPathEffect()) { 326425c27fab9d82d19b0bce7c091533d546465bbaebsalomon return true; 327425c27fab9d82d19b0bce7c091533d546465bbaebsalomon } 328425c27fab9d82d19b0bce7c091533d546465bbaebsalomon return this->inverseFilled(); 329425c27fab9d82d19b0bce7c091533d546465bbaebsalomon } 330425c27fab9d82d19b0bce7c091533d546465bbaebsalomon 331425c27fab9d82d19b0bce7c091533d546465bbaebsalomon /** 3327c73a53894927d222d4aceed96893daae8ea14f1bsalomon * Is it known that the unstyled geometry has no unclosed contours. This means that it will 3337c73a53894927d222d4aceed96893daae8ea14f1bsalomon * not have any caps if stroked (modulo the effect of any path effect). 33406077565b18714ff3fc0db9118e2c21f6f25243fbsalomon */ 33506077565b18714ff3fc0db9118e2c21f6f25243fbsalomon bool knownToBeClosed() const { 33606077565b18714ff3fc0db9118e2c21f6f25243fbsalomon switch (fType) { 33747cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon case Type::kEmpty: 33806077565b18714ff3fc0db9118e2c21f6f25243fbsalomon return true; 339085c0862f674337c5a60f8c46da4c12f0d12511aBrian Salomon case Type::kInvertedEmpty: 340085c0862f674337c5a60f8c46da4c12f0d12511aBrian Salomon return true; 34106077565b18714ff3fc0db9118e2c21f6f25243fbsalomon case Type::kRRect: 34206077565b18714ff3fc0db9118e2c21f6f25243fbsalomon return true; 343a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon case Type::kArc: 344a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon return fArcData.fUseCenter; 3450a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon case Type::kLine: 3460a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon return false; 34706077565b18714ff3fc0db9118e2c21f6f25243fbsalomon case Type::kPath: 348425c27fab9d82d19b0bce7c091533d546465bbaebsalomon // SkPath doesn't keep track of the closed status of each contour. 349728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon return SkPathPriv::IsClosedSingleContour(this->path()); 35047cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon } 35106077565b18714ff3fc0db9118e2c21f6f25243fbsalomon return false; 35247cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon } 35347cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon 35406115ee4300ef6756729dfbcb3e2fc70ebf0413absalomon uint32_t segmentMask() const { 35506115ee4300ef6756729dfbcb3e2fc70ebf0413absalomon switch (fType) { 35606115ee4300ef6756729dfbcb3e2fc70ebf0413absalomon case Type::kEmpty: 35706115ee4300ef6756729dfbcb3e2fc70ebf0413absalomon return 0; 358085c0862f674337c5a60f8c46da4c12f0d12511aBrian Salomon case Type::kInvertedEmpty: 359085c0862f674337c5a60f8c46da4c12f0d12511aBrian Salomon return 0; 36006115ee4300ef6756729dfbcb3e2fc70ebf0413absalomon case Type::kRRect: 361728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon if (fRRectData.fRRect.getType() == SkRRect::kOval_Type) { 36206115ee4300ef6756729dfbcb3e2fc70ebf0413absalomon return SkPath::kConic_SegmentMask; 3632fad74a0fdc5eb3f505a052849c3cbeffa6e2d17Brian Salomon } else if (fRRectData.fRRect.getType() == SkRRect::kRect_Type || 3642fad74a0fdc5eb3f505a052849c3cbeffa6e2d17Brian Salomon fRRectData.fRRect.getType() == SkRRect::kEmpty_Type) { 36506115ee4300ef6756729dfbcb3e2fc70ebf0413absalomon return SkPath::kLine_SegmentMask; 36606115ee4300ef6756729dfbcb3e2fc70ebf0413absalomon } 36706115ee4300ef6756729dfbcb3e2fc70ebf0413absalomon return SkPath::kLine_SegmentMask | SkPath::kConic_SegmentMask; 368a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon case Type::kArc: 369a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon if (fArcData.fUseCenter) { 370a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon return SkPath::kConic_SegmentMask | SkPath::kLine_SegmentMask; 371a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon } 372a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon return SkPath::kConic_SegmentMask; 3730a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon case Type::kLine: 3740a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon return SkPath::kLine_SegmentMask; 37506115ee4300ef6756729dfbcb3e2fc70ebf0413absalomon case Type::kPath: 376728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon return this->path().getSegmentMasks(); 37706115ee4300ef6756729dfbcb3e2fc70ebf0413absalomon } 37806115ee4300ef6756729dfbcb3e2fc70ebf0413absalomon return 0; 37906115ee4300ef6756729dfbcb3e2fc70ebf0413absalomon } 38006115ee4300ef6756729dfbcb3e2fc70ebf0413absalomon 38147cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon /** 38247cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon * Gets the size of the key for the shape represented by this GrShape (ignoring its styling). 38347cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon * A negative value is returned if the shape has no key (shouldn't be cached). 38447cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon */ 38547cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon int unstyledKeySize() const; 38647cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon 387425c27fab9d82d19b0bce7c091533d546465bbaebsalomon bool hasUnstyledKey() const { return this->unstyledKeySize() >= 0; } 388425c27fab9d82d19b0bce7c091533d546465bbaebsalomon 38947cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon /** 39047cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon * Writes unstyledKeySize() bytes into the provided pointer. Assumes that there is enough 39147cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon * space allocated for the key and that unstyledKeySize() does not return a negative value 39247cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon * for this shape. 39347cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon */ 39447cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon void writeUnstyledKey(uint32_t* key) const; 39547cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon 396f6f7cf60985d8e109cc136f25e2a3c3383ca05eaBrian Osman /** 397f6f7cf60985d8e109cc136f25e2a3c3383ca05eaBrian Osman * Adds a listener to the *original* path. Typically used to invalidate cached resources when 398f6f7cf60985d8e109cc136f25e2a3c3383ca05eaBrian Osman * a path is no longer in-use. If the shape started out as something other than a path, this 399f6f7cf60985d8e109cc136f25e2a3c3383ca05eaBrian Osman * does nothing (but will delete the listener). 400f6f7cf60985d8e109cc136f25e2a3c3383ca05eaBrian Osman */ 401f6f7cf60985d8e109cc136f25e2a3c3383ca05eaBrian Osman void addGenIDChangeListener(SkPathRef::GenIDChangeListener* listener) const; 402f6f7cf60985d8e109cc136f25e2a3c3383ca05eaBrian Osman 403f6f7cf60985d8e109cc136f25e2a3c3383ca05eaBrian Osman /** 404b379dcd64eb69140f4393ac922d0774cc7d15596Brian Osman * Helpers that are only exposed for unit tests, to determine if the shape is a path, and get 405da6d0720300a29a4deb5dd4c433a92a3ec41286eBrian Salomon * the generation ID of the *original* path. This is the path that will receive 406da6d0720300a29a4deb5dd4c433a92a3ec41286eBrian Salomon * GenIDChangeListeners added to this shape. 407f6f7cf60985d8e109cc136f25e2a3c3383ca05eaBrian Osman */ 408f6f7cf60985d8e109cc136f25e2a3c3383ca05eaBrian Osman uint32_t testingOnly_getOriginalGenerationID() const; 409b379dcd64eb69140f4393ac922d0774cc7d15596Brian Osman bool testingOnly_isPath() const; 410da6d0720300a29a4deb5dd4c433a92a3ec41286eBrian Salomon bool testingOnly_isNonVolatilePath() const; 411f6f7cf60985d8e109cc136f25e2a3c3383ca05eaBrian Osman 41247cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomonprivate: 41372dc51c288169f38177c71081090581c5ff415b1bsalomon enum class Type { 41472dc51c288169f38177c71081090581c5ff415b1bsalomon kEmpty, 415085c0862f674337c5a60f8c46da4c12f0d12511aBrian Salomon kInvertedEmpty, 41672dc51c288169f38177c71081090581c5ff415b1bsalomon kRRect, 417a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon kArc, 4180a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon kLine, 41972dc51c288169f38177c71081090581c5ff415b1bsalomon kPath, 42072dc51c288169f38177c71081090581c5ff415b1bsalomon }; 42172dc51c288169f38177c71081090581c5ff415b1bsalomon 422728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon void initType(Type type, const SkPath* path = nullptr) { 423728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon fType = Type::kEmpty; 424728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon this->changeType(type, path); 425728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon } 426728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon 427728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon void changeType(Type type, const SkPath* path = nullptr) { 428728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon bool wasPath = Type::kPath == fType; 429728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon fType = type; 430728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon bool isPath = Type::kPath == type; 431728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon SkASSERT(!path || isPath); 432728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon if (wasPath && !isPath) { 433728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon fPathData.fPath.~SkPath(); 434728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon } else if (!wasPath && isPath) { 435728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon if (path) { 436728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon new (&fPathData.fPath) SkPath(*path); 437728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon } else { 438728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon new (&fPathData.fPath) SkPath(); 439728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon } 440728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon } else if (isPath && path) { 441728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon fPathData.fPath = *path; 442728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon } 443728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon // Whether or not we use the path's gen ID is decided in attemptToSimplifyPath. 444728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon fPathData.fGenID = 0; 445728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon } 446728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon 447728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon SkPath& path() { 448728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon SkASSERT(Type::kPath == fType); 449728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon return fPathData.fPath; 450728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon } 451728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon 452728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon const SkPath& path() const { 453728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon SkASSERT(Type::kPath == fType); 454728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon return fPathData.fPath; 455728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon } 456728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon 45797fd2d42b97104fa32a58d7e7a5b7255913f9c9dbsalomon /** Constructor used by the applyStyle() function */ 45897fd2d42b97104fa32a58d7e7a5b7255913f9c9dbsalomon GrShape(const GrShape& parentShape, GrStyle::Apply, SkScalar scale); 45947cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon 46047cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon /** 46147cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon * Determines the key we should inherit from the input shape's geometry and style when 46247cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon * we are applying the style to create a new shape. 46347cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon */ 46497fd2d42b97104fa32a58d7e7a5b7255913f9c9dbsalomon void setInheritedKey(const GrShape& parentShape, GrStyle::Apply, SkScalar scale); 46547cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon 4661b28c1adc1e156831d5332546e942b63fd29075bbsalomon void attemptToSimplifyPath(); 4671b28c1adc1e156831d5332546e942b63fd29075bbsalomon void attemptToSimplifyRRect(); 4680a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon void attemptToSimplifyLine(); 469a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon void attemptToSimplifyArc(); 470ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon 47172f78c37010eb2bf20be4884d4f376d122830dfdBrian Salomon bool attemptToSimplifyStrokedLineToRRect(); 47272f78c37010eb2bf20be4884d4f376d122830dfdBrian Salomon 473da6d0720300a29a4deb5dd4c433a92a3ec41286eBrian Salomon /** Gets the path that gen id listeners should be added to. */ 474da6d0720300a29a4deb5dd4c433a92a3ec41286eBrian Salomon const SkPath* originalPathForListeners() const; 475da6d0720300a29a4deb5dd4c433a92a3ec41286eBrian Salomon 476a4817afe5095b67a68c907ff2e48e3e07907140cbsalomon // Defaults to use when there is no distinction between even/odd and winding fills. 477a4817afe5095b67a68c907ff2e48e3e07907140cbsalomon static constexpr SkPath::FillType kDefaultPathFillType = SkPath::kEvenOdd_FillType; 478a4817afe5095b67a68c907ff2e48e3e07907140cbsalomon static constexpr SkPath::FillType kDefaultPathInverseFillType = 479a4817afe5095b67a68c907ff2e48e3e07907140cbsalomon SkPath::kInverseEvenOdd_FillType; 480a4817afe5095b67a68c907ff2e48e3e07907140cbsalomon 481ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon static constexpr SkPath::Direction kDefaultRRectDir = SkPath::kCW_Direction; 482ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon static constexpr unsigned kDefaultRRectStart = 0; 483ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon 484ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon static unsigned DefaultRectDirAndStartIndex(const SkRect& rect, bool hasPathEffect, 485ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon SkPath::Direction* dir) { 486ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon *dir = kDefaultRRectDir; 487ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon // This comes from SkPath's interface. The default for adding a SkRect is counter clockwise 488ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon // beginning at index 0 (which happens to correspond to rrect index 0 or 7). 489ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon if (!hasPathEffect) { 490ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon // It doesn't matter what start we use, just be consistent to avoid redundant keys. 491ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon return kDefaultRRectStart; 49272dc51c288169f38177c71081090581c5ff415b1bsalomon } 493ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon // In SkPath a rect starts at index 0 by default. This is the top left corner. However, 494ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon // we store rects as rrects. RRects don't preserve the invertedness, but rather sort the 495ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon // rect edges. Thus, we may need to modify the rrect's start index to account for the sort. 496ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon bool swapX = rect.fLeft > rect.fRight; 497ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon bool swapY = rect.fTop > rect.fBottom; 498ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon if (swapX && swapY) { 499ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon // 0 becomes start index 2 and times 2 to convert from rect the rrect indices. 500ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon return 2 * 2; 501ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon } else if (swapX) { 502ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon *dir = SkPath::kCCW_Direction; 503ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon // 0 becomes start index 1 and times 2 to convert from rect the rrect indices. 504ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon return 2 * 1; 505ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon } else if (swapY) { 506ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon *dir = SkPath::kCCW_Direction; 507ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon // 0 becomes start index 3 and times 2 to convert from rect the rrect indices. 508ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon return 2 * 3; 50972dc51c288169f38177c71081090581c5ff415b1bsalomon } 510ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon return 0; 511ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon } 512ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon 513ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon static unsigned DefaultRRectDirAndStartIndex(const SkRRect& rrect, bool hasPathEffect, 514ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon SkPath::Direction* dir) { 515ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon // This comes from SkPath's interface. The default for adding a SkRRect to a path is 516ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon // clockwise beginning at starting index 6. 517ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon static constexpr unsigned kPathRRectStartIdx = 6; 518ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon *dir = kDefaultRRectDir; 519ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon if (!hasPathEffect) { 520ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon // It doesn't matter what start we use, just be consistent to avoid redundant keys. 521ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon return kDefaultRRectStart; 52272dc51c288169f38177c71081090581c5ff415b1bsalomon } 523ee295645bd91fcbe1714847c5fe5341759037cc5bsalomon return kPathRRectStartIdx; 52472dc51c288169f38177c71081090581c5ff415b1bsalomon } 52547cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon 526728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon union { 527728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon struct { 528a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon SkRRect fRRect; 529a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon SkPath::Direction fDir; 530a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon unsigned fStart; 531a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon bool fInverted; 532728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon } fRRectData; 533728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon struct { 534a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon SkRect fOval; 535a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon SkScalar fStartAngleDegrees; 536a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon SkScalar fSweepAngleDegrees; 537a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon int16_t fUseCenter; 538a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon int16_t fInverted; 539a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon } fArcData; 540a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon struct { 541a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon SkPath fPath; 542728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon // Gen ID of the original path (fPath may be modified) 543a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon int32_t fGenID; 544728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon } fPathData; 5450a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon struct { 546a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon SkPoint fPts[2]; 547a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon bool fInverted; 5480a0f67ececbdf1a7f81296ed0d2cb9e3bc00e4dcbsalomon } fLineData; 549728b0f750570ada198bde4c5b4605bc1902de1d4bsalomon }; 550a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon GrStyle fStyle; 551a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon SkTLazy<SkPath> fInheritedPathForListeners; 55247cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon SkAutoSTArray<8, uint32_t> fInheritedKey; 553a0657609f1f9304b1de63871ef91fc6cbca0d0f7Brian Salomon Type fType; 55447cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon}; 55547cc7691181e3c9d74f7d66d5bc3c0b7ac7855d5bsalomon#endif 556