LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/gpu - GrShape.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 330 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 13 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright 2016 Google Inc.
       3             :  *
       4             :  * Use of this source code is governed by a BSD-style license that can be
       5             :  * found in the LICENSE file.
       6             :  */
       7             : 
       8             : #include "GrShape.h"
       9             : 
      10           0 : GrShape& GrShape::operator=(const GrShape& that) {
      11           0 :     fStyle = that.fStyle;
      12           0 :     this->changeType(that.fType, Type::kPath == that.fType ? &that.path() : nullptr);
      13           0 :     switch (fType) {
      14             :         case Type::kEmpty:
      15           0 :             break;
      16             :         case Type::kRRect:
      17           0 :             fRRectData = that.fRRectData;
      18           0 :             break;
      19             :         case Type::kLine:
      20           0 :             fLineData = that.fLineData;
      21           0 :             break;
      22             :         case Type::kPath:
      23           0 :             fPathData.fGenID = that.fPathData.fGenID;
      24           0 :             break;
      25             :     }
      26           0 :     fInheritedKey.reset(that.fInheritedKey.count());
      27           0 :     sk_careful_memcpy(fInheritedKey.get(), that.fInheritedKey.get(),
      28           0 :                       sizeof(uint32_t) * fInheritedKey.count());
      29           0 :     return *this;
      30             : }
      31             : 
      32           0 : SkRect GrShape::bounds() const {
      33             :     // Bounds where left == bottom or top == right can indicate a line or point shape. We return
      34             :     // inverted bounds for a truly empty shape.
      35             :     static constexpr SkRect kInverted = SkRect::MakeLTRB(1, 1, -1, -1);
      36           0 :     switch (fType) {
      37             :         case Type::kEmpty:
      38           0 :             return kInverted;
      39             :         case Type::kLine: {
      40             :             SkRect bounds;
      41           0 :             if (fLineData.fPts[0].fX < fLineData.fPts[1].fX) {
      42           0 :                 bounds.fLeft = fLineData.fPts[0].fX;
      43           0 :                 bounds.fRight = fLineData.fPts[1].fX;
      44             :             } else {
      45           0 :                 bounds.fLeft = fLineData.fPts[1].fX;
      46           0 :                 bounds.fRight = fLineData.fPts[0].fX;
      47             :             }
      48           0 :             if (fLineData.fPts[0].fY < fLineData.fPts[1].fY) {
      49           0 :                 bounds.fTop = fLineData.fPts[0].fY;
      50           0 :                 bounds.fBottom = fLineData.fPts[1].fY;
      51             :             } else {
      52           0 :                 bounds.fTop = fLineData.fPts[1].fY;
      53           0 :                 bounds.fBottom = fLineData.fPts[0].fY;
      54             :             }
      55           0 :             return bounds;
      56             :         }
      57             :         case Type::kRRect:
      58           0 :             return fRRectData.fRRect.getBounds();
      59             :         case Type::kPath:
      60           0 :             return this->path().getBounds();
      61             :     }
      62           0 :     SkFAIL("Unknown shape type");
      63           0 :     return kInverted;
      64             : }
      65             : 
      66           0 : SkRect GrShape::styledBounds() const {
      67           0 :     if (Type::kEmpty == fType && !fStyle.hasNonDashPathEffect()) {
      68           0 :         return SkRect::MakeEmpty();
      69             :     }
      70             :     SkRect bounds;
      71           0 :     fStyle.adjustBounds(&bounds, this->bounds());
      72           0 :     return bounds;
      73             : }
      74             : 
      75             : // If the path is small enough to be keyed from its data this returns key length, otherwise -1.
      76           0 : static int path_key_from_data_size(const SkPath& path) {
      77           0 :     const int verbCnt = path.countVerbs();
      78           0 :     if (verbCnt > GrShape::kMaxKeyFromDataVerbCnt) {
      79           0 :         return -1;
      80             :     }
      81           0 :     const int pointCnt = path.countPoints();
      82           0 :     const int conicWeightCnt = SkPathPriv::ConicWeightCnt(path);
      83             : 
      84             :     GR_STATIC_ASSERT(sizeof(SkPoint) == 2 * sizeof(uint32_t));
      85             :     GR_STATIC_ASSERT(sizeof(SkScalar) == sizeof(uint32_t));
      86             :     // 2 is for the verb cnt and a fill type. Each verb is a byte but we'll pad the verb data out to
      87             :     // a uint32_t length.
      88           0 :     return 2 + (SkAlign4(verbCnt) >> 2) + 2 * pointCnt + conicWeightCnt;
      89             : }
      90             : 
      91             : // Writes the path data key into the passed pointer.
      92           0 : static void write_path_key_from_data(const SkPath& path, uint32_t* origKey) {
      93           0 :     uint32_t* key = origKey;
      94             :     // The check below should take care of negative values casted positive.
      95           0 :     const int verbCnt = path.countVerbs();
      96           0 :     const int pointCnt = path.countPoints();
      97           0 :     const int conicWeightCnt = SkPathPriv::ConicWeightCnt(path);
      98           0 :     SkASSERT(verbCnt <= GrShape::kMaxKeyFromDataVerbCnt);
      99           0 :     SkASSERT(pointCnt && verbCnt);
     100           0 :     *key++ = path.getFillType();
     101           0 :     *key++ = verbCnt;
     102           0 :     memcpy(key, SkPathPriv::VerbData(path), verbCnt * sizeof(uint8_t));
     103           0 :     int verbKeySize = SkAlign4(verbCnt);
     104             :     // pad out to uint32_t alignment using value that will stand out when debugging.
     105           0 :     uint8_t* pad = reinterpret_cast<uint8_t*>(key)+ verbCnt;
     106           0 :     memset(pad, 0xDE, verbKeySize - verbCnt);
     107           0 :     key += verbKeySize >> 2;
     108             : 
     109           0 :     memcpy(key, SkPathPriv::PointData(path), sizeof(SkPoint) * pointCnt);
     110             :     GR_STATIC_ASSERT(sizeof(SkPoint) == 2 * sizeof(uint32_t));
     111           0 :     key += 2 * pointCnt;
     112           0 :     sk_careful_memcpy(key, SkPathPriv::ConicWeightData(path), sizeof(SkScalar) * conicWeightCnt);
     113             :     GR_STATIC_ASSERT(sizeof(SkScalar) == sizeof(uint32_t));
     114           0 :     SkDEBUGCODE(key += conicWeightCnt);
     115           0 :     SkASSERT(key - origKey == path_key_from_data_size(path));
     116           0 : }
     117             : 
     118           0 : int GrShape::unstyledKeySize() const {
     119           0 :     if (fInheritedKey.count()) {
     120           0 :         return fInheritedKey.count();
     121             :     }
     122           0 :     switch (fType) {
     123             :         case Type::kEmpty:
     124           0 :             return 1;
     125             :         case Type::kRRect:
     126           0 :             SkASSERT(!fInheritedKey.count());
     127             :             SkASSERT(0 == SkRRect::kSizeInMemory % sizeof(uint32_t));
     128             :             // + 1 for the direction, start index, and inverseness.
     129           0 :             return SkRRect::kSizeInMemory / sizeof(uint32_t) + 1;
     130             :         case Type::kLine:
     131             :             GR_STATIC_ASSERT(2 * sizeof(uint32_t) == sizeof(SkPoint));
     132             :             // 4 for the end points and 1 for the inverseness
     133           0 :             return 5;
     134             :         case Type::kPath: {
     135           0 :             if (0 == fPathData.fGenID) {
     136           0 :                 return -1;
     137             :             }
     138           0 :             int dataKeySize = path_key_from_data_size(fPathData.fPath);
     139           0 :             if (dataKeySize >= 0) {
     140           0 :                 return dataKeySize;
     141             :             }
     142             :             // The key is the path ID and fill type.
     143           0 :             return 2;
     144             :         }
     145             :     }
     146           0 :     SkFAIL("Should never get here.");
     147           0 :     return 0;
     148             : }
     149             : 
     150           0 : void GrShape::writeUnstyledKey(uint32_t* key) const {
     151           0 :     SkASSERT(this->unstyledKeySize());
     152           0 :     SkDEBUGCODE(uint32_t* origKey = key;)
     153           0 :     if (fInheritedKey.count()) {
     154           0 :         memcpy(key, fInheritedKey.get(), sizeof(uint32_t) * fInheritedKey.count());
     155           0 :         SkDEBUGCODE(key += fInheritedKey.count();)
     156             :     } else {
     157           0 :         switch (fType) {
     158             :             case Type::kEmpty:
     159           0 :                 *key++ = 1;
     160           0 :                 break;
     161             :             case Type::kRRect:
     162           0 :                 fRRectData.fRRect.writeToMemory(key);
     163           0 :                 key += SkRRect::kSizeInMemory / sizeof(uint32_t);
     164           0 :                 *key = (fRRectData.fDir == SkPath::kCCW_Direction) ? (1 << 31) : 0;
     165           0 :                 *key |= fRRectData.fInverted ? (1 << 30) : 0;
     166           0 :                 *key++ |= fRRectData.fStart;
     167           0 :                 SkASSERT(fRRectData.fStart < 8);
     168           0 :                 break;
     169             :             case Type::kLine:
     170           0 :                 memcpy(key, fLineData.fPts, 2 * sizeof(SkPoint));
     171           0 :                 key += 4;
     172           0 :                 *key++ = fLineData.fInverted ? 1 : 0;
     173           0 :                 break;
     174             :             case Type::kPath: {
     175           0 :                 SkASSERT(fPathData.fGenID);
     176           0 :                 int dataKeySize = path_key_from_data_size(fPathData.fPath);
     177           0 :                 if (dataKeySize >= 0) {
     178           0 :                     write_path_key_from_data(fPathData.fPath, key);
     179           0 :                     return;
     180             :                 }
     181           0 :                 *key++ = fPathData.fGenID;
     182             :                 // We could canonicalize the fill rule for paths that don't differentiate between
     183             :                 // even/odd or winding fill (e.g. convex).
     184           0 :                 *key++ = this->path().getFillType();
     185           0 :                 break;
     186             :             }
     187             :         }
     188             :     }
     189           0 :     SkASSERT(key - origKey == this->unstyledKeySize());
     190             : }
     191             : 
     192           0 : void GrShape::setInheritedKey(const GrShape &parent, GrStyle::Apply apply, SkScalar scale) {
     193           0 :     SkASSERT(!fInheritedKey.count());
     194             :     // If the output shape turns out to be simple, then we will just use its geometric key
     195           0 :     if (Type::kPath == fType) {
     196             :         // We want ApplyFullStyle(ApplyPathEffect(shape)) to have the same key as
     197             :         // ApplyFullStyle(shape).
     198             :         // The full key is structured as (geo,path_effect,stroke).
     199             :         // If we do ApplyPathEffect we get get,path_effect as the inherited key. If we then
     200             :         // do ApplyFullStyle we'll memcpy geo,path_effect into the new inherited key
     201             :         // and then append the style key (which should now be stroke only) at the end.
     202           0 :         int parentCnt = parent.fInheritedKey.count();
     203           0 :         bool useParentGeoKey = !parentCnt;
     204           0 :         if (useParentGeoKey) {
     205           0 :             parentCnt = parent.unstyledKeySize();
     206           0 :             if (parentCnt < 0) {
     207             :                 // The parent's geometry has no key so we will have no key.
     208           0 :                 fPathData.fGenID = 0;
     209           0 :                 return;
     210             :             }
     211             :         }
     212           0 :         uint32_t styleKeyFlags = 0;
     213           0 :         if (parent.knownToBeClosed()) {
     214           0 :             styleKeyFlags |= GrStyle::kClosed_KeyFlag;
     215             :         }
     216           0 :         if (parent.asLine(nullptr, nullptr)) {
     217           0 :             styleKeyFlags |= GrStyle::kNoJoins_KeyFlag;
     218             :         }
     219           0 :         int styleCnt = GrStyle::KeySize(parent.fStyle, apply, styleKeyFlags);
     220           0 :         if (styleCnt < 0) {
     221             :             // The style doesn't allow a key, set the path gen ID to 0 so that we fail when
     222             :             // we try to get a key for the shape.
     223           0 :             fPathData.fGenID = 0;
     224           0 :             return;
     225             :         }
     226           0 :         fInheritedKey.reset(parentCnt + styleCnt);
     227           0 :         if (useParentGeoKey) {
     228             :             // This will be the geo key.
     229           0 :             parent.writeUnstyledKey(fInheritedKey.get());
     230             :         } else {
     231             :             // This should be (geo,path_effect).
     232           0 :             memcpy(fInheritedKey.get(), parent.fInheritedKey.get(),
     233           0 :                    parentCnt * sizeof(uint32_t));
     234             :         }
     235             :         // Now turn (geo,path_effect) or (geo) into (geo,path_effect,stroke)
     236           0 :         GrStyle::WriteKey(fInheritedKey.get() + parentCnt, parent.fStyle, apply, scale,
     237           0 :                           styleKeyFlags);
     238             :     }
     239             : }
     240             : 
     241           0 : GrShape::GrShape(const GrShape& that) : fStyle(that.fStyle) {
     242           0 :     const SkPath* thatPath = Type::kPath == that.fType ? &that.fPathData.fPath : nullptr;
     243           0 :     this->initType(that.fType, thatPath);
     244           0 :     switch (fType) {
     245             :         case Type::kEmpty:
     246           0 :             break;
     247             :         case Type::kRRect:
     248           0 :             fRRectData = that.fRRectData;
     249           0 :             break;
     250             :         case Type::kLine:
     251           0 :             fLineData = that.fLineData;
     252           0 :             break;
     253             :         case Type::kPath:
     254           0 :             fPathData.fGenID = that.fPathData.fGenID;
     255           0 :             break;
     256             :     }
     257           0 :     fInheritedKey.reset(that.fInheritedKey.count());
     258           0 :     sk_careful_memcpy(fInheritedKey.get(), that.fInheritedKey.get(),
     259           0 :                       sizeof(uint32_t) * fInheritedKey.count());
     260           0 : }
     261             : 
     262           0 : GrShape::GrShape(const GrShape& parent, GrStyle::Apply apply, SkScalar scale) {
     263             :     // TODO: Add some quantization of scale for better cache performance here or leave that up
     264             :     // to caller?
     265             :     // TODO: For certain shapes and stroke params we could ignore the scale. (e.g. miter or bevel
     266             :     // stroke of a rect).
     267           0 :     if (!parent.style().applies() ||
     268           0 :         (GrStyle::Apply::kPathEffectOnly == apply && !parent.style().pathEffect())) {
     269           0 :         this->initType(Type::kEmpty);
     270           0 :         *this = parent;
     271           0 :         return;
     272             :     }
     273             : 
     274           0 :     SkPathEffect* pe = parent.fStyle.pathEffect();
     275           0 :     SkTLazy<SkPath> tmpPath;
     276           0 :     const GrShape* parentForKey = &parent;
     277           0 :     SkTLazy<GrShape> tmpParent;
     278           0 :     this->initType(Type::kPath);
     279           0 :     fPathData.fGenID = 0;
     280           0 :     if (pe) {
     281             :         const SkPath* srcForPathEffect;
     282           0 :         if (parent.fType == Type::kPath) {
     283           0 :             srcForPathEffect = &parent.path();
     284             :         } else {
     285           0 :             srcForPathEffect = tmpPath.init();
     286           0 :             parent.asPath(tmpPath.get());
     287             :         }
     288             :         // Should we consider bounds? Would have to include in key, but it'd be nice to know
     289             :         // if the bounds actually modified anything before including in key.
     290           0 :         SkStrokeRec strokeRec = parent.fStyle.strokeRec();
     291           0 :         if (!parent.fStyle.applyPathEffectToPath(&this->path(), &strokeRec, *srcForPathEffect,
     292             :                                                  scale)) {
     293           0 :             tmpParent.init(*srcForPathEffect, GrStyle(strokeRec, nullptr));
     294           0 :             *this = tmpParent.get()->applyStyle(apply, scale);
     295           0 :             return;
     296             :         }
     297             :         // A path effect has access to change the res scale but we aren't expecting it to and it
     298             :         // would mess up our key computation.
     299           0 :         SkASSERT(scale == strokeRec.getResScale());
     300           0 :         if (GrStyle::Apply::kPathEffectAndStrokeRec == apply && strokeRec.needToApply()) {
     301             :             // The intermediate shape may not be a general path. If we we're just applying
     302             :             // the path effect then attemptToReduceFromPath would catch it. This means that
     303             :             // when we subsequently applied the remaining strokeRec we would have a non-path
     304             :             // parent shape that would be used to determine the the stroked path's key.
     305             :             // We detect that case here and change parentForKey to a temporary that represents
     306             :             // the simpler shape so that applying both path effect and the strokerec all at
     307             :             // once produces the same key.
     308           0 :             tmpParent.init(this->path(), GrStyle(strokeRec, nullptr));
     309           0 :             tmpParent.get()->setInheritedKey(parent, GrStyle::Apply::kPathEffectOnly, scale);
     310           0 :             if (!tmpPath.isValid()) {
     311           0 :                 tmpPath.init();
     312             :             }
     313           0 :             tmpParent.get()->asPath(tmpPath.get());
     314             :             SkStrokeRec::InitStyle fillOrHairline;
     315             :             // The parent shape may have simplified away the strokeRec, check for that here.
     316           0 :             if (tmpParent.get()->style().applies()) {
     317           0 :                 SkAssertResult(tmpParent.get()->style().applyToPath(&this->path(), &fillOrHairline,
     318             :                                                                     *tmpPath.get(), scale));
     319           0 :             } else if (tmpParent.get()->style().isSimpleFill()) {
     320           0 :                 fillOrHairline = SkStrokeRec::kFill_InitStyle;
     321             :             } else {
     322           0 :                 SkASSERT(tmpParent.get()->style().isSimpleHairline());
     323           0 :                 fillOrHairline = SkStrokeRec::kHairline_InitStyle;
     324             :             }
     325           0 :             fStyle.resetToInitStyle(fillOrHairline);
     326           0 :             parentForKey = tmpParent.get();
     327             :         } else {
     328           0 :             fStyle = GrStyle(strokeRec, nullptr);
     329             :         }
     330             :     } else {
     331             :         const SkPath* srcForParentStyle;
     332           0 :         if (parent.fType == Type::kPath) {
     333           0 :             srcForParentStyle = &parent.path();
     334             :         } else {
     335           0 :             srcForParentStyle = tmpPath.init();
     336           0 :             parent.asPath(tmpPath.get());
     337             :         }
     338             :         SkStrokeRec::InitStyle fillOrHairline;
     339           0 :         SkASSERT(parent.fStyle.applies());
     340           0 :         SkASSERT(!parent.fStyle.pathEffect());
     341           0 :         SkAssertResult(parent.fStyle.applyToPath(&this->path(), &fillOrHairline, *srcForParentStyle,
     342             :                                                  scale));
     343           0 :         fStyle.resetToInitStyle(fillOrHairline);
     344             :     }
     345           0 :     this->attemptToSimplifyPath();
     346           0 :     this->setInheritedKey(*parentForKey, apply, scale);
     347             : }
     348             : 
     349           0 : void GrShape::attemptToSimplifyPath() {
     350             :     SkRect rect;
     351           0 :     SkRRect rrect;
     352             :     SkPath::Direction rrectDir;
     353             :     unsigned rrectStart;
     354           0 :     bool inverted = this->path().isInverseFillType();
     355             :     SkPoint pts[2];
     356           0 :     if (this->path().isEmpty()) {
     357           0 :         this->changeType(Type::kEmpty);
     358           0 :     } else if (this->path().isLine(pts)) {
     359           0 :         this->changeType(Type::kLine);
     360           0 :         fLineData.fPts[0] = pts[0];
     361           0 :         fLineData.fPts[1] = pts[1];
     362           0 :         fLineData.fInverted = inverted;
     363           0 :     } else if (this->path().isRRect(&rrect, &rrectDir, &rrectStart)) {
     364           0 :         this->changeType(Type::kRRect);
     365           0 :         fRRectData.fRRect = rrect;
     366           0 :         fRRectData.fDir = rrectDir;
     367           0 :         fRRectData.fStart = rrectStart;
     368           0 :         fRRectData.fInverted = inverted;
     369             :         // Currently SkPath does not acknowledge that empty, rect, or oval subtypes as rrects.
     370           0 :         SkASSERT(!fRRectData.fRRect.isEmpty());
     371           0 :         SkASSERT(fRRectData.fRRect.getType() != SkRRect::kRect_Type);
     372           0 :         SkASSERT(fRRectData.fRRect.getType() != SkRRect::kOval_Type);
     373           0 :     } else if (this->path().isOval(&rect, &rrectDir, &rrectStart)) {
     374           0 :         this->changeType(Type::kRRect);
     375           0 :         fRRectData.fRRect.setOval(rect);
     376           0 :         fRRectData.fDir = rrectDir;
     377           0 :         fRRectData.fInverted = inverted;
     378             :         // convert from oval indexing to rrect indexiing.
     379           0 :         fRRectData.fStart = 2 * rrectStart;
     380           0 :     } else if (SkPathPriv::IsSimpleClosedRect(this->path(), &rect, &rrectDir, &rrectStart)) {
     381           0 :         this->changeType(Type::kRRect);
     382             :         // When there is a path effect we restrict rect detection to the narrower API that
     383             :         // gives us the starting position. Otherwise, we will retry with the more aggressive
     384             :         // isRect().
     385           0 :         fRRectData.fRRect.setRect(rect);
     386           0 :         fRRectData.fInverted = inverted;
     387           0 :         fRRectData.fDir = rrectDir;
     388             :         // convert from rect indexing to rrect indexiing.
     389           0 :         fRRectData.fStart = 2 * rrectStart;
     390           0 :     } else if (!this->style().hasPathEffect()) {
     391             :         bool closed;
     392           0 :         if (this->path().isRect(&rect, &closed, nullptr)) {
     393           0 :             if (closed || this->style().isSimpleFill()) {
     394           0 :                 this->changeType(Type::kRRect);
     395           0 :                 fRRectData.fRRect.setRect(rect);
     396             :                 // Since there is no path effect the dir and start index is immaterial.
     397           0 :                 fRRectData.fDir = kDefaultRRectDir;
     398           0 :                 fRRectData.fStart = kDefaultRRectStart;
     399             :                 // There isn't dashing so we will have to preserver inverseness.
     400           0 :                 fRRectData.fInverted = inverted;
     401             :             }
     402             :         }
     403             :     }
     404           0 :     if (Type::kPath != fType) {
     405           0 :         fInheritedKey.reset(0);
     406           0 :         if (Type::kRRect == fType) {
     407           0 :             this->attemptToSimplifyRRect();
     408           0 :         } else if (Type::kLine == fType) {
     409           0 :             this->attemptToSimplifyLine();
     410             :         }
     411             :     } else {
     412           0 :         if (fInheritedKey.count() || this->path().isVolatile()) {
     413           0 :             fPathData.fGenID = 0;
     414             :         } else {
     415           0 :             fPathData.fGenID = this->path().getGenerationID();
     416             :         }
     417           0 :         if (!this->style().hasNonDashPathEffect()) {
     418           0 :             if (this->style().strokeRec().getStyle() == SkStrokeRec::kStroke_Style ||
     419           0 :                 this->style().strokeRec().getStyle() == SkStrokeRec::kHairline_Style) {
     420             :                 // Stroke styles don't differentiate between winding and even/odd.
     421             :                 // Moreover, dashing ignores inverseness (skbug.com/5421)
     422           0 :                 bool inverse = !this->style().isDashed() && this->path().isInverseFillType();
     423           0 :                 if (inverse) {
     424           0 :                     this->path().setFillType(kDefaultPathInverseFillType);
     425             :                 } else {
     426           0 :                     this->path().setFillType(kDefaultPathFillType);
     427             :                 }
     428           0 :             } else if (this->path().isConvex()) {
     429             :                 // There is no distinction between even/odd and non-zero winding count for convex
     430             :                 // paths.
     431           0 :                 if (this->path().isInverseFillType()) {
     432           0 :                     this->path().setFillType(kDefaultPathInverseFillType);
     433             :                 } else {
     434           0 :                     this->path().setFillType(kDefaultPathFillType);
     435             :                 }
     436             :             }
     437             :         }
     438             :     }
     439           0 : }
     440             : 
     441           0 : void GrShape::attemptToSimplifyRRect() {
     442           0 :     SkASSERT(Type::kRRect == fType);
     443           0 :     SkASSERT(!fInheritedKey.count());
     444           0 :     if (fRRectData.fRRect.isEmpty()) {
     445           0 :         fType = Type::kEmpty;
     446           0 :         return;
     447             :     }
     448           0 :     if (!this->style().hasPathEffect()) {
     449           0 :         fRRectData.fDir = kDefaultRRectDir;
     450           0 :         fRRectData.fStart = kDefaultRRectStart;
     451           0 :     } else if (fStyle.isDashed()) {
     452             :         // Dashing ignores the inverseness (currently). skbug.com/5421
     453           0 :         fRRectData.fInverted = false;
     454             :     }
     455             :     // Turn a stroke-and-filled miter rect into a filled rect. TODO: more rrect stroke shortcuts.
     456           0 :     if (!fStyle.hasPathEffect() &&
     457           0 :         fStyle.strokeRec().getStyle() == SkStrokeRec::kStrokeAndFill_Style &&
     458           0 :         fStyle.strokeRec().getJoin() == SkPaint::kMiter_Join &&
     459           0 :         fStyle.strokeRec().getMiter() >= SK_ScalarSqrt2 &&
     460           0 :         fRRectData.fRRect.isRect()) {
     461           0 :         SkScalar r = fStyle.strokeRec().getWidth() / 2;
     462           0 :         fRRectData.fRRect = SkRRect::MakeRect(fRRectData.fRRect.rect().makeOutset(r, r));
     463           0 :         fStyle = GrStyle::SimpleFill();
     464             :     }
     465             : }
     466             : 
     467           0 : void GrShape::attemptToSimplifyLine() {
     468           0 :     SkASSERT(Type::kLine == fType);
     469           0 :     SkASSERT(!fInheritedKey.count());
     470           0 :     if (fStyle.isDashed()) {
     471             :         // Dashing ignores inverseness.
     472           0 :         fLineData.fInverted = false;
     473           0 :         return;
     474           0 :     } else if (fStyle.hasPathEffect()) {
     475           0 :         return;
     476             :     }
     477           0 :     if (fStyle.strokeRec().getStyle() == SkStrokeRec::kStrokeAndFill_Style) {
     478             :         // Make stroke + fill be stroke since the fill is empty.
     479           0 :         SkStrokeRec rec = fStyle.strokeRec();
     480           0 :         rec.setStrokeStyle(fStyle.strokeRec().getWidth(), false);
     481           0 :         fStyle = GrStyle(rec, nullptr);
     482             :     }
     483           0 :     if (fStyle.isSimpleFill() && !fLineData.fInverted) {
     484           0 :         this->changeType(Type::kEmpty);
     485           0 :         return;
     486             :     }
     487           0 :     SkPoint* pts = fLineData.fPts;
     488           0 :     if (fStyle.strokeRec().getStyle() == SkStrokeRec::kStroke_Style) {
     489             :         // If it is horizontal or vertical we will turn it into a filled rrect.
     490             :         SkRect rect;
     491           0 :         rect.fLeft = SkTMin(pts[0].fX, pts[1].fX);
     492           0 :         rect.fRight = SkTMax(pts[0].fX, pts[1].fX);
     493           0 :         rect.fTop = SkTMin(pts[0].fY, pts[1].fY);
     494           0 :         rect.fBottom = SkTMax(pts[0].fY, pts[1].fY);
     495           0 :         bool eqX = rect.fLeft == rect.fRight;
     496           0 :         bool eqY = rect.fTop == rect.fBottom;
     497           0 :         if (eqX || eqY) {
     498           0 :             SkScalar r = fStyle.strokeRec().getWidth() / 2;
     499           0 :             bool inverted = fLineData.fInverted;
     500           0 :             this->changeType(Type::kRRect);
     501           0 :             switch (fStyle.strokeRec().getCap()) {
     502             :                 case SkPaint::kButt_Cap:
     503           0 :                     if (eqX && eqY) {
     504           0 :                         this->changeType(Type::kEmpty);
     505           0 :                         return;
     506             :                     }
     507           0 :                     if (eqX) {
     508           0 :                         rect.outset(r, 0);
     509             :                     } else {
     510           0 :                         rect.outset(0, r);
     511             :                     }
     512           0 :                     fRRectData.fRRect = SkRRect::MakeRect(rect);
     513           0 :                     break;
     514             :                 case SkPaint::kSquare_Cap:
     515           0 :                     rect.outset(r, r);
     516           0 :                     fRRectData.fRRect = SkRRect::MakeRect(rect);
     517           0 :                     break;
     518             :                 case SkPaint::kRound_Cap:
     519           0 :                     rect.outset(r, r);
     520           0 :                     fRRectData.fRRect = SkRRect::MakeRectXY(rect, r, r);
     521           0 :                     break;
     522             :             }
     523           0 :             fRRectData.fInverted = inverted;
     524           0 :             fRRectData.fDir = kDefaultRRectDir;
     525           0 :             fRRectData.fStart = kDefaultRRectStart;
     526           0 :             if (fRRectData.fRRect.isEmpty()) {
     527             :                 // This can happen when r is very small relative to the rect edges.
     528           0 :                 this->changeType(Type::kEmpty);
     529           0 :                 return;
     530             :             }
     531           0 :             fStyle = GrStyle::SimpleFill();
     532           0 :             return;
     533             :         }
     534             :     }
     535             :     // Only path effects could care about the order of the points. Otherwise canonicalize
     536             :     // the point order.
     537           0 :     if (pts[1].fY < pts[0].fY || (pts[1].fY == pts[0].fY && pts[1].fX < pts[0].fX)) {
     538           0 :         SkTSwap(pts[0], pts[1]);
     539             :     }
     540             : }

Generated by: LCOV version 1.13