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 10bool 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 SkSTArenaAlloc<4096> allocator; // FIXME: constant-ize, tune 51 SkOpContour contour; 52 SkOpContourHead* contourList = static_cast<SkOpContourHead*>(&contour); 53 SkOpGlobalState globalState(contourList, &allocator SkDEBUGPARAMS(false) 54 SkDEBUGPARAMS(nullptr)); 55 // turn path into list of segments 56 SkScalar scaleFactor = ScaleFactor(path); 57 SkPath scaledPath; 58 const SkPath* workingPath; 59 if (scaleFactor > SK_Scalar1) { 60 ScalePath(path, 1.f / scaleFactor, &scaledPath); 61 workingPath = &scaledPath; 62 } else { 63 workingPath = &path; 64 } 65 SkOpEdgeBuilder builder(*workingPath, contourList, &globalState); 66 if (!builder.finish()) { 67 return false; 68 } 69 if (!SortContourList(&contourList, false, false)) { 70 *result = moveBounds; 71 return true; 72 } 73 SkOpContour* current = contourList; 74 SkPathOpsBounds bounds = current->bounds(); 75 while ((current = current->next())) { 76 bounds.add(current->bounds()); 77 } 78 if (scaleFactor > SK_Scalar1) { 79 bounds.set(bounds.left() * scaleFactor, bounds.top() * scaleFactor, 80 bounds.right() * scaleFactor, bounds.bottom() * scaleFactor); 81 } 82 *result = bounds; 83 if (!moveBounds.isEmpty()) { 84 result->join(moveBounds); 85 } 86 return true; 87} 88