1 /* 2 * Copyright 2014 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 #include "SkOpEdgeBuilder.h" 8 #include "SkPathOpsCommon.h" 9 10 bool TightBounds(const SkPath& path, SkRect* result) { 11 SkPath::RawIter iter(path); 12 SkRect moveBounds = { SK_ScalarMax, SK_ScalarMax, SK_ScalarMin, SK_ScalarMin }; 13 bool wellBehaved = true; 14 SkPath::Verb verb; 15 do { 16 SkPoint pts[4]; 17 verb = iter.next(pts); 18 switch (verb) { 19 case SkPath::kMove_Verb: 20 moveBounds.fLeft = SkTMin(moveBounds.fLeft, pts[0].fX); 21 moveBounds.fTop = SkTMin(moveBounds.fTop, pts[0].fY); 22 moveBounds.fRight = SkTMax(moveBounds.fRight, pts[0].fX); 23 moveBounds.fBottom = SkTMax(moveBounds.fBottom, pts[0].fY); 24 break; 25 case SkPath::kQuad_Verb: 26 case SkPath::kConic_Verb: 27 if (!wellBehaved) { 28 break; 29 } 30 wellBehaved &= between(pts[0].fX, pts[1].fX, pts[2].fX); 31 wellBehaved &= between(pts[0].fY, pts[1].fY, pts[2].fY); 32 break; 33 case SkPath::kCubic_Verb: 34 if (!wellBehaved) { 35 break; 36 } 37 wellBehaved &= between(pts[0].fX, pts[1].fX, pts[3].fX); 38 wellBehaved &= between(pts[0].fY, pts[1].fY, pts[3].fY); 39 wellBehaved &= between(pts[0].fX, pts[2].fX, pts[3].fX); 40 wellBehaved &= between(pts[0].fY, pts[2].fY, pts[3].fY); 41 break; 42 default: 43 break; 44 } 45 } while (verb != SkPath::kDone_Verb); 46 if (wellBehaved) { 47 *result = path.getBounds(); 48 return true; 49 } 50 char storage[4096]; 51 SkArenaAlloc allocator(storage); // FIXME: constant-ize, tune 52 SkOpContour contour; 53 SkOpContourHead* contourList = static_cast<SkOpContourHead*>(&contour); 54 SkOpGlobalState globalState(contourList, &allocator SkDEBUGPARAMS(false) 55 SkDEBUGPARAMS(nullptr)); 56 // turn path into list of segments 57 SkScalar scaleFactor = ScaleFactor(path); 58 SkPath scaledPath; 59 const SkPath* workingPath; 60 if (scaleFactor > SK_Scalar1) { 61 ScalePath(path, 1.f / scaleFactor, &scaledPath); 62 workingPath = &scaledPath; 63 } else { 64 workingPath = &path; 65 } 66 SkOpEdgeBuilder builder(*workingPath, contourList, &globalState); 67 if (!builder.finish()) { 68 return false; 69 } 70 if (!SortContourList(&contourList, false, false)) { 71 *result = moveBounds; 72 return true; 73 } 74 SkOpContour* current = contourList; 75 SkPathOpsBounds bounds = current->bounds(); 76 while ((current = current->next())) { 77 bounds.add(current->bounds()); 78 } 79 if (scaleFactor > SK_Scalar1) { 80 bounds.set(bounds.left() * scaleFactor, bounds.top() * scaleFactor, 81 bounds.right() * scaleFactor, bounds.bottom() * scaleFactor); 82 } 83 *result = bounds; 84 if (!moveBounds.isEmpty()) { 85 result->join(moveBounds); 86 } 87 return true; 88 } 89