1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/* 2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2006 The Android Open Source Project 3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * 4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be 5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file. 6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */ 7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com 81978ce22eb488e3f05670189ea35d9dfae6a6784bsalomon#include <cmath> 994e75ee46a569cbcdf61fb7f04ee3a69d3ca0896djsollen@google.com#include "SkBuffer.h" 109aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark#include "SkCubicClipper.h" 11220f926d9d4b38a9018c922c095847bbd261f583reed#include "SkGeometry.h" 128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkMath.h" 13026beb52a29a620290fcfb24f1e7e9e75547b80freed#include "SkPathPriv.h" 141dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com#include "SkPathRef.h" 154ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com#include "SkRRect.h" 168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 17a99b6ceff92183b424634f2e7276b9ea1d59e69dMike Reedstatic float poly_eval(float A, float B, float C, float t) { 18a99b6ceff92183b424634f2e7276b9ea1d59e69dMike Reed return (A * t + B) * t + C; 19a99b6ceff92183b424634f2e7276b9ea1d59e69dMike Reed} 20a99b6ceff92183b424634f2e7276b9ea1d59e69dMike Reed 21a99b6ceff92183b424634f2e7276b9ea1d59e69dMike Reedstatic float poly_eval(float A, float B, float C, float D, float t) { 22a99b6ceff92183b424634f2e7276b9ea1d59e69dMike Reed return ((A * t + B) * t + C) * t + D; 23a99b6ceff92183b424634f2e7276b9ea1d59e69dMike Reed} 24a99b6ceff92183b424634f2e7276b9ea1d59e69dMike Reed 258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//////////////////////////////////////////////////////////////////////////// 268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 273563c9ee527f524d421964b54d9b09e12ec0bf6breed@google.com/** 283563c9ee527f524d421964b54d9b09e12ec0bf6breed@google.com * Path.bounds is defined to be the bounds of all the control points. 293563c9ee527f524d421964b54d9b09e12ec0bf6breed@google.com * If we called bounds.join(r) we would skip r if r was empty, which breaks 303563c9ee527f524d421964b54d9b09e12ec0bf6breed@google.com * our promise. Hence we have a custom joiner that doesn't look at emptiness 313563c9ee527f524d421964b54d9b09e12ec0bf6breed@google.com */ 323563c9ee527f524d421964b54d9b09e12ec0bf6breed@google.comstatic void joinNoEmptyChecks(SkRect* dst, const SkRect& src) { 333563c9ee527f524d421964b54d9b09e12ec0bf6breed@google.com dst->fLeft = SkMinScalar(dst->fLeft, src.fLeft); 343563c9ee527f524d421964b54d9b09e12ec0bf6breed@google.com dst->fTop = SkMinScalar(dst->fTop, src.fTop); 353563c9ee527f524d421964b54d9b09e12ec0bf6breed@google.com dst->fRight = SkMaxScalar(dst->fRight, src.fRight); 363563c9ee527f524d421964b54d9b09e12ec0bf6breed@google.com dst->fBottom = SkMaxScalar(dst->fBottom, src.fBottom); 373563c9ee527f524d421964b54d9b09e12ec0bf6breed@google.com} 383563c9ee527f524d421964b54d9b09e12ec0bf6breed@google.com 39fb6f0f6f18cd515af85bb71e688e8530edd92827bsalomon@google.comstatic bool is_degenerate(const SkPath& path) { 40fb6f0f6f18cd515af85bb71e688e8530edd92827bsalomon@google.com SkPath::Iter iter(path, false); 41fb6f0f6f18cd515af85bb71e688e8530edd92827bsalomon@google.com SkPoint pts[4]; 42fb6f0f6f18cd515af85bb71e688e8530edd92827bsalomon@google.com return SkPath::kDone_Verb == iter.next(pts); 43fb6f0f6f18cd515af85bb71e688e8530edd92827bsalomon@google.com} 44fb6f0f6f18cd515af85bb71e688e8530edd92827bsalomon@google.com 4530c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.comclass SkAutoDisableDirectionCheck { 4630c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.compublic: 4730c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com SkAutoDisableDirectionCheck(SkPath* path) : fPath(path) { 489f4dbca3290cfaca7dd17b71eb6b5b3a0ba5323eherb fSaved = static_cast<SkPathPriv::FirstDirection>(fPath->fFirstDirection.load()); 4930c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com } 5030c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com 5130c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com ~SkAutoDisableDirectionCheck() { 52026beb52a29a620290fcfb24f1e7e9e75547b80freed fPath->fFirstDirection = fSaved; 5330c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com } 5430c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com 5530c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.comprivate: 56026beb52a29a620290fcfb24f1e7e9e75547b80freed SkPath* fPath; 57026beb52a29a620290fcfb24f1e7e9e75547b80freed SkPathPriv::FirstDirection fSaved; 5830c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com}; 59e61a86cfa00ea393ecc4a71fca94e1d476a37ecccommit-bot@chromium.org#define SkAutoDisableDirectionCheck(...) SK_REQUIRE_LOCAL_VAR(SkAutoDisableDirectionCheck) 6030c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com 618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/* This guy's constructor/destructor bracket a path editing operation. It is 628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com used when we know the bounds of the amount we are going to add to the path 638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com (usually a new contour, but not required). 64abf15c189b6333aa77a6c3f566cc67f4634ba338reed@google.com 658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com It captures some state about the path up front (i.e. if it already has a 66ca0c8389e2fd1c7f528869beb77a6c8587d59f29robertphillips@google.com cached bounds), and then if it can, it updates the cache bounds explicitly, 67d252db03d9650013b545ef9781fe993c07f8f314reed@android.com avoiding the need to revisit all of the points in getBounds(). 68abf15c189b6333aa77a6c3f566cc67f4634ba338reed@google.com 69fb6f0f6f18cd515af85bb71e688e8530edd92827bsalomon@google.com It also notes if the path was originally degenerate, and if so, sets 70fb6f0f6f18cd515af85bb71e688e8530edd92827bsalomon@google.com isConvex to true. Thus it can only be used if the contour being added is 71466310dbd3073add2ec934e336c30deaaf702eaerobertphillips@google.com convex. 728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com */ 738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass SkAutoPathBoundsUpdate { 748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic: 758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkAutoPathBoundsUpdate(SkPath* path, const SkRect& r) : fRect(r) { 768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com this->init(path); 778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkAutoPathBoundsUpdate(SkPath* path, SkScalar left, SkScalar top, 808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar right, SkScalar bottom) { 818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fRect.set(left, top, right, bottom); 828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com this->init(path); 838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 84abf15c189b6333aa77a6c3f566cc67f4634ba338reed@google.com 858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com ~SkAutoPathBoundsUpdate() { 864469938e92d779dff05e745559e67907bbf21e78reed@google.com fPath->setConvexity(fDegenerate ? SkPath::kConvex_Convexity 874469938e92d779dff05e745559e67907bbf21e78reed@google.com : SkPath::kUnknown_Convexity); 88ca0c8389e2fd1c7f528869beb77a6c8587d59f29robertphillips@google.com if (fEmpty || fHasValidBounds) { 89ca0c8389e2fd1c7f528869beb77a6c8587d59f29robertphillips@google.com fPath->setBounds(fRect); 908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 92abf15c189b6333aa77a6c3f566cc67f4634ba338reed@google.com 938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprivate: 946b82d1adc6a4726e36674e468ff1157e0b75373freed@android.com SkPath* fPath; 956b82d1adc6a4726e36674e468ff1157e0b75373freed@android.com SkRect fRect; 96ca0c8389e2fd1c7f528869beb77a6c8587d59f29robertphillips@google.com bool fHasValidBounds; 97fb6f0f6f18cd515af85bb71e688e8530edd92827bsalomon@google.com bool fDegenerate; 986b82d1adc6a4726e36674e468ff1157e0b75373freed@android.com bool fEmpty; 99abf15c189b6333aa77a6c3f566cc67f4634ba338reed@google.com 1006b82d1adc6a4726e36674e468ff1157e0b75373freed@android.com void init(SkPath* path) { 101ca0c8389e2fd1c7f528869beb77a6c8587d59f29robertphillips@google.com // Cannot use fRect for our bounds unless we know it is sorted 102ca0c8389e2fd1c7f528869beb77a6c8587d59f29robertphillips@google.com fRect.sort(); 1038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fPath = path; 104a8790debaab6c5e3b6a4a51d2cc91ae5aea9b2ddreed@google.com // Mark the path's bounds as dirty if (1) they are, or (2) the path 105a8790debaab6c5e3b6a4a51d2cc91ae5aea9b2ddreed@google.com // is non-finite, and therefore its bounds are not meaningful 106ca0c8389e2fd1c7f528869beb77a6c8587d59f29robertphillips@google.com fHasValidBounds = path->hasComputedBounds() && path->isFinite(); 1078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fEmpty = path->isEmpty(); 108ca0c8389e2fd1c7f528869beb77a6c8587d59f29robertphillips@google.com if (fHasValidBounds && !fEmpty) { 109ca0c8389e2fd1c7f528869beb77a6c8587d59f29robertphillips@google.com joinNoEmptyChecks(&fRect, fPath->getBounds()); 110ca0c8389e2fd1c7f528869beb77a6c8587d59f29robertphillips@google.com } 111ca0c8389e2fd1c7f528869beb77a6c8587d59f29robertphillips@google.com fDegenerate = is_degenerate(*path); 1128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}; 114e61a86cfa00ea393ecc4a71fca94e1d476a37ecccommit-bot@chromium.org#define SkAutoPathBoundsUpdate(...) SK_REQUIRE_LOCAL_VAR(SkAutoPathBoundsUpdate) 1158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//////////////////////////////////////////////////////////////////////////// 1178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/* 1198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com Stores the verbs and points as they are given to us, with exceptions: 1204da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org - we only record "Close" if it was immediately preceeded by Move | Line | Quad | Cubic 1218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com - we insert a Move(0,0) if Line | Quad | Cubic is our first command 1228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com The iterator does more cleanup, especially if forceClose == true 1244da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org 1. If we encounter degenerate segments, remove them 1254da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org 2. if we encounter Close, return a cons'd up Line() first (if the curr-pt != start-pt) 1264da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org 3. if we encounter Move without a preceeding Close, and forceClose is true, goto #2 1274da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org 4. if we encounter Line | Quad | Cubic after Close, cons up a Move 1288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com*/ 1298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com//////////////////////////////////////////////////////////////////////////// 1318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1325e1a7f2cc621d357da5c62a7bc4ef750d94b96f3commit-bot@chromium.org// flag to require a moveTo if we begin with something else, like lineTo etc. 1335e1a7f2cc621d357da5c62a7bc4ef750d94b96f3commit-bot@chromium.org#define INITIAL_LASTMOVETOINDEX_VALUE ~0 1345e1a7f2cc621d357da5c62a7bc4ef750d94b96f3commit-bot@chromium.org 135fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.comSkPath::SkPath() 136523cda39435256bcb3e5665f47612d661d3c6bf9djsollen : fPathRef(SkPathRef::CreateEmpty()) { 137a5809a3e4cb356387c5201ab9c0a10edf11a01bebungeman@google.com this->resetFields(); 138b3eb687f8a89eb1eacd1afb4016401eb392f66abjvanverth fIsVolatile = false; 139a5809a3e4cb356387c5201ab9c0a10edf11a01bebungeman@google.com} 140a5809a3e4cb356387c5201ab9c0a10edf11a01bebungeman@google.com 141a5809a3e4cb356387c5201ab9c0a10edf11a01bebungeman@google.comvoid SkPath::resetFields() { 142a5809a3e4cb356387c5201ab9c0a10edf11a01bebungeman@google.com //fPathRef is assumed to have been emptied by the caller. 1435e1a7f2cc621d357da5c62a7bc4ef750d94b96f3commit-bot@chromium.org fLastMoveToIndex = INITIAL_LASTMOVETOINDEX_VALUE; 144a5809a3e4cb356387c5201ab9c0a10edf11a01bebungeman@google.com fFillType = kWinding_FillType; 14504863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com fConvexity = kUnknown_Convexity; 146026beb52a29a620290fcfb24f1e7e9e75547b80freed fFirstDirection = SkPathPriv::kUnknown_FirstDirection; 1471ab9f737f000e530f0c7713c8fad282f39e26efecommit-bot@chromium.org 1481ab9f737f000e530f0c7713c8fad282f39e26efecommit-bot@chromium.org // We don't touch Android's fSourcePath. It's used to track texture garbage collection, so we 14996fcdcc219d2a0d3579719b84b28bede76efba64halcanary // don't want to muck with it if it's been set to something non-nullptr. 1506b82d1adc6a4726e36674e468ff1157e0b75373freed@android.com} 1518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 152a5809a3e4cb356387c5201ab9c0a10edf11a01bebungeman@google.comSkPath::SkPath(const SkPath& that) 1539c9d4a70028ef8dc33a46cfc0b22e254443effe3mtklein@google.com : fPathRef(SkRef(that.fPathRef.get())) { 1549c9d4a70028ef8dc33a46cfc0b22e254443effe3mtklein@google.com this->copyFields(that); 155a5809a3e4cb356387c5201ab9c0a10edf11a01bebungeman@google.com SkDEBUGCODE(that.validate();) 1568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkPath::~SkPath() { 1598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDEBUGCODE(this->validate();) 1608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 162a5809a3e4cb356387c5201ab9c0a10edf11a01bebungeman@google.comSkPath& SkPath::operator=(const SkPath& that) { 163a5809a3e4cb356387c5201ab9c0a10edf11a01bebungeman@google.com SkDEBUGCODE(that.validate();) 164a5809a3e4cb356387c5201ab9c0a10edf11a01bebungeman@google.com 165a5809a3e4cb356387c5201ab9c0a10edf11a01bebungeman@google.com if (this != &that) { 166a5809a3e4cb356387c5201ab9c0a10edf11a01bebungeman@google.com fPathRef.reset(SkRef(that.fPathRef.get())); 167a5809a3e4cb356387c5201ab9c0a10edf11a01bebungeman@google.com this->copyFields(that); 1688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDEBUGCODE(this->validate();) 1708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return *this; 1718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 173a5809a3e4cb356387c5201ab9c0a10edf11a01bebungeman@google.comvoid SkPath::copyFields(const SkPath& that) { 174a5809a3e4cb356387c5201ab9c0a10edf11a01bebungeman@google.com //fPathRef is assumed to have been set by the caller. 1755e1a7f2cc621d357da5c62a7bc4ef750d94b96f3commit-bot@chromium.org fLastMoveToIndex = that.fLastMoveToIndex; 176a5809a3e4cb356387c5201ab9c0a10edf11a01bebungeman@google.com fFillType = that.fFillType; 177a5809a3e4cb356387c5201ab9c0a10edf11a01bebungeman@google.com fConvexity = that.fConvexity; 1789f4dbca3290cfaca7dd17b71eb6b5b3a0ba5323eherb // Simulate fFirstDirection = that.fFirstDirection; 1799f4dbca3290cfaca7dd17b71eb6b5b3a0ba5323eherb fFirstDirection.store(that.fFirstDirection.load()); 180b3eb687f8a89eb1eacd1afb4016401eb392f66abjvanverth fIsVolatile = that.fIsVolatile; 181a5809a3e4cb356387c5201ab9c0a10edf11a01bebungeman@google.com} 182a5809a3e4cb356387c5201ab9c0a10edf11a01bebungeman@google.com 1839c1a967967e385a2c4c1607b8f997e72a18205bedjsollen@google.combool operator==(const SkPath& a, const SkPath& b) { 1846b82d1adc6a4726e36674e468ff1157e0b75373freed@android.com // note: don't need to look at isConvex or bounds, since just comparing the 1856b82d1adc6a4726e36674e468ff1157e0b75373freed@android.com // raw data is sufficient. 1863abec1d7c38e9bd786fc6057f9608f3eeec98c86reed@android.com return &a == &b || 1876b8dbb668f1f069270d35a47cfe98decd059c625robertphillips@google.com (a.fFillType == b.fFillType && *a.fPathRef.get() == *b.fPathRef.get()); 1883abec1d7c38e9bd786fc6057f9608f3eeec98c86reed@android.com} 1893abec1d7c38e9bd786fc6057f9608f3eeec98c86reed@android.com 190a5809a3e4cb356387c5201ab9c0a10edf11a01bebungeman@google.comvoid SkPath::swap(SkPath& that) { 191a5809a3e4cb356387c5201ab9c0a10edf11a01bebungeman@google.com if (this != &that) { 19277a53de20d723ca21cc824fd97e68aaa60e022eabungeman fPathRef.swap(that.fPathRef); 1935e1a7f2cc621d357da5c62a7bc4ef750d94b96f3commit-bot@chromium.org SkTSwap<int>(fLastMoveToIndex, that.fLastMoveToIndex); 194a5809a3e4cb356387c5201ab9c0a10edf11a01bebungeman@google.com SkTSwap<uint8_t>(fFillType, that.fFillType); 195a5809a3e4cb356387c5201ab9c0a10edf11a01bebungeman@google.com SkTSwap<uint8_t>(fConvexity, that.fConvexity); 1969f4dbca3290cfaca7dd17b71eb6b5b3a0ba5323eherb // Simulate SkTSwap<uint8_t>(fFirstDirection, that.fFirstDirection); 1979f4dbca3290cfaca7dd17b71eb6b5b3a0ba5323eherb uint8_t temp = fFirstDirection; 1989f4dbca3290cfaca7dd17b71eb6b5b3a0ba5323eherb fFirstDirection.store(that.fFirstDirection.load()); 1999f4dbca3290cfaca7dd17b71eb6b5b3a0ba5323eherb that.fFirstDirection.store(temp); 200b3eb687f8a89eb1eacd1afb4016401eb392f66abjvanverth SkTSwap<SkBool8>(fIsVolatile, that.fIsVolatile); 2018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 2028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 2039bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com 2048e7b19d0f04f286ec283747ec128e9696c842858caryclarkbool SkPath::isInterpolatable(const SkPath& compare) const { 2058e7b19d0f04f286ec283747ec128e9696c842858caryclark int count = fPathRef->countVerbs(); 2068e7b19d0f04f286ec283747ec128e9696c842858caryclark if (count != compare.fPathRef->countVerbs()) { 2078e7b19d0f04f286ec283747ec128e9696c842858caryclark return false; 2088e7b19d0f04f286ec283747ec128e9696c842858caryclark } 2098e7b19d0f04f286ec283747ec128e9696c842858caryclark if (!count) { 2108e7b19d0f04f286ec283747ec128e9696c842858caryclark return true; 2118e7b19d0f04f286ec283747ec128e9696c842858caryclark } 2128e7b19d0f04f286ec283747ec128e9696c842858caryclark if (memcmp(fPathRef->verbsMemBegin(), compare.fPathRef->verbsMemBegin(), 2138e7b19d0f04f286ec283747ec128e9696c842858caryclark count)) { 2148e7b19d0f04f286ec283747ec128e9696c842858caryclark return false; 2158e7b19d0f04f286ec283747ec128e9696c842858caryclark } 216dcd1fcc6e9891e1427c8ce4500edac45a8687fbdcaryclark return !fPathRef->countWeights() || 217dcd1fcc6e9891e1427c8ce4500edac45a8687fbdcaryclark !SkToBool(memcmp(fPathRef->conicWeights(), compare.fPathRef->conicWeights(), 2188e7b19d0f04f286ec283747ec128e9696c842858caryclark fPathRef->countWeights() * sizeof(*fPathRef->conicWeights()))); 2198e7b19d0f04f286ec283747ec128e9696c842858caryclark} 2208e7b19d0f04f286ec283747ec128e9696c842858caryclark 2218e7b19d0f04f286ec283747ec128e9696c842858caryclarkbool SkPath::interpolate(const SkPath& ending, SkScalar weight, SkPath* out) const { 2228e7b19d0f04f286ec283747ec128e9696c842858caryclark int verbCount = fPathRef->countVerbs(); 2238e7b19d0f04f286ec283747ec128e9696c842858caryclark if (verbCount != ending.fPathRef->countVerbs()) { 2248e7b19d0f04f286ec283747ec128e9696c842858caryclark return false; 2258e7b19d0f04f286ec283747ec128e9696c842858caryclark } 226a11053891225b7c08466eef37068d8ff2dada168caryclark if (!verbCount) { 227a11053891225b7c08466eef37068d8ff2dada168caryclark return true; 228a11053891225b7c08466eef37068d8ff2dada168caryclark } 2298e7b19d0f04f286ec283747ec128e9696c842858caryclark out->reset(); 2308e7b19d0f04f286ec283747ec128e9696c842858caryclark out->addPath(*this); 2316bd5284415bd983b0628c4941dff5def40018f5abungeman fPathRef->interpolate(*ending.fPathRef, weight, out->fPathRef.get()); 2328e7b19d0f04f286ec283747ec128e9696c842858caryclark return true; 2338e7b19d0f04f286ec283747ec128e9696c842858caryclark} 2348e7b19d0f04f286ec283747ec128e9696c842858caryclark 2359bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.comstatic inline bool check_edge_against_rect(const SkPoint& p0, 2369bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com const SkPoint& p1, 2379bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com const SkRect& rect, 238026beb52a29a620290fcfb24f1e7e9e75547b80freed SkPathPriv::FirstDirection dir) { 2399bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com const SkPoint* edgeBegin; 2409bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com SkVector v; 241026beb52a29a620290fcfb24f1e7e9e75547b80freed if (SkPathPriv::kCW_FirstDirection == dir) { 2429bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com v = p1 - p0; 2439bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com edgeBegin = &p0; 2449bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com } else { 2459bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com v = p0 - p1; 2469bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com edgeBegin = &p1; 2479bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com } 2489bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com if (v.fX || v.fY) { 2499bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com // check the cross product of v with the vec from edgeBegin to each rect corner 250a99b6ceff92183b424634f2e7276b9ea1d59e69dMike Reed SkScalar yL = v.fY * (rect.fLeft - edgeBegin->fX); 251a99b6ceff92183b424634f2e7276b9ea1d59e69dMike Reed SkScalar xT = v.fX * (rect.fTop - edgeBegin->fY); 252a99b6ceff92183b424634f2e7276b9ea1d59e69dMike Reed SkScalar yR = v.fY * (rect.fRight - edgeBegin->fX); 253a99b6ceff92183b424634f2e7276b9ea1d59e69dMike Reed SkScalar xB = v.fX * (rect.fBottom - edgeBegin->fY); 2549bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com if ((xT < yL) || (xT < yR) || (xB < yL) || (xB < yR)) { 2559bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com return false; 2569bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com } 2579bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com } 2589bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com return true; 2599bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com} 2609bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com 2619bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.combool SkPath::conservativelyContainsRect(const SkRect& rect) const { 2629bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com // This only handles non-degenerate convex paths currently. 2639bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com if (kConvex_Convexity != this->getConvexity()) { 2649bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com return false; 2659bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com } 266cec8de68217186d0f5676a696de44343aaa61de7skia.committer@gmail.com 267026beb52a29a620290fcfb24f1e7e9e75547b80freed SkPathPriv::FirstDirection direction; 268026beb52a29a620290fcfb24f1e7e9e75547b80freed if (!SkPathPriv::CheapComputeFirstDirection(*this, &direction)) { 2699bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com return false; 2709bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com } 2719bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com 2729bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com SkPoint firstPt; 2739bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com SkPoint prevPt; 274a19f024953f8b85b5f5fbda759d74c75514ea515Lee Salzman SkPath::Iter iter(*this, true); 2759bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com SkPath::Verb verb; 2769bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com SkPoint pts[4]; 2779bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com SkDEBUGCODE(int moveCnt = 0;) 27862df526042f8a753c6817ba9d809ff8dfc412d4acommit-bot@chromium.org SkDEBUGCODE(int segmentCount = 0;) 27962df526042f8a753c6817ba9d809ff8dfc412d4acommit-bot@chromium.org SkDEBUGCODE(int closeCount = 0;) 2809bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com 281a19f024953f8b85b5f5fbda759d74c75514ea515Lee Salzman while ((verb = iter.next(pts, true, true)) != kDone_Verb) { 2829bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com int nextPt = -1; 2839bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com switch (verb) { 2849bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com case kMove_Verb: 28562df526042f8a753c6817ba9d809ff8dfc412d4acommit-bot@chromium.org SkASSERT(!segmentCount && !closeCount); 2869bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com SkDEBUGCODE(++moveCnt); 2879bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com firstPt = prevPt = pts[0]; 2889bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com break; 2899bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com case kLine_Verb: 2909bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com nextPt = 1; 29162df526042f8a753c6817ba9d809ff8dfc412d4acommit-bot@chromium.org SkASSERT(moveCnt && !closeCount); 29262df526042f8a753c6817ba9d809ff8dfc412d4acommit-bot@chromium.org SkDEBUGCODE(++segmentCount); 2939bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com break; 2949bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com case kQuad_Verb: 295277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com case kConic_Verb: 29662df526042f8a753c6817ba9d809ff8dfc412d4acommit-bot@chromium.org SkASSERT(moveCnt && !closeCount); 29762df526042f8a753c6817ba9d809ff8dfc412d4acommit-bot@chromium.org SkDEBUGCODE(++segmentCount); 2989bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com nextPt = 2; 2999bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com break; 3009bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com case kCubic_Verb: 30162df526042f8a753c6817ba9d809ff8dfc412d4acommit-bot@chromium.org SkASSERT(moveCnt && !closeCount); 30262df526042f8a753c6817ba9d809ff8dfc412d4acommit-bot@chromium.org SkDEBUGCODE(++segmentCount); 3039bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com nextPt = 3; 3049bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com break; 3059bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com case kClose_Verb: 30662df526042f8a753c6817ba9d809ff8dfc412d4acommit-bot@chromium.org SkDEBUGCODE(++closeCount;) 3079bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com break; 3089bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com default: 3099bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com SkDEBUGFAIL("unknown verb"); 3109bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com } 3119bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com if (-1 != nextPt) { 312220f926d9d4b38a9018c922c095847bbd261f583reed if (SkPath::kConic_Verb == verb) { 313220f926d9d4b38a9018c922c095847bbd261f583reed SkConic orig; 314220f926d9d4b38a9018c922c095847bbd261f583reed orig.set(pts, iter.conicWeight()); 315220f926d9d4b38a9018c922c095847bbd261f583reed SkPoint quadPts[5]; 316220f926d9d4b38a9018c922c095847bbd261f583reed int count = orig.chopIntoQuadsPOW2(quadPts, 1); 317f2b340fc885ad2a12d2d73974eff9c8f4c94192cdjsollen SkASSERT_RELEASE(2 == count); 318220f926d9d4b38a9018c922c095847bbd261f583reed 319220f926d9d4b38a9018c922c095847bbd261f583reed if (!check_edge_against_rect(quadPts[0], quadPts[2], rect, direction)) { 320220f926d9d4b38a9018c922c095847bbd261f583reed return false; 321220f926d9d4b38a9018c922c095847bbd261f583reed } 322220f926d9d4b38a9018c922c095847bbd261f583reed if (!check_edge_against_rect(quadPts[2], quadPts[4], rect, direction)) { 323220f926d9d4b38a9018c922c095847bbd261f583reed return false; 324220f926d9d4b38a9018c922c095847bbd261f583reed } 325220f926d9d4b38a9018c922c095847bbd261f583reed } else { 326220f926d9d4b38a9018c922c095847bbd261f583reed if (!check_edge_against_rect(prevPt, pts[nextPt], rect, direction)) { 327220f926d9d4b38a9018c922c095847bbd261f583reed return false; 328220f926d9d4b38a9018c922c095847bbd261f583reed } 3299bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com } 3309bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com prevPt = pts[nextPt]; 3319bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com } 3329bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com } 3339bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com 3349bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com return check_edge_against_rect(prevPt, firstPt, rect, direction); 3359bee33afbeca29f531c8455513b925f6e93da633bsalomon@google.com} 3368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3377101abe5b37d82ea222e971a42615a97a2419edbrobertphillips@google.comuint32_t SkPath::getGenerationID() const { 3381ab9f737f000e530f0c7713c8fad282f39e26efecommit-bot@chromium.org uint32_t genID = fPathRef->genID(); 339523cda39435256bcb3e5665f47612d661d3c6bf9djsollen#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 3401ab9f737f000e530f0c7713c8fad282f39e26efecommit-bot@chromium.org SkASSERT((unsigned)fFillType < (1 << (32 - kPathRefGenIDBitCnt))); 3411ab9f737f000e530f0c7713c8fad282f39e26efecommit-bot@chromium.org genID |= static_cast<uint32_t>(fFillType) << kPathRefGenIDBitCnt; 3421ab9f737f000e530f0c7713c8fad282f39e26efecommit-bot@chromium.org#endif 3431ab9f737f000e530f0c7713c8fad282f39e26efecommit-bot@chromium.org return genID; 344f5dbe2f00f853c6a1719924bdd0c33335a53423adjsollen@google.com} 345e63793a2c8d2871bf7d95195be7b93ff669688d7djsollen@google.com 3468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkPath::reset() { 3478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDEBUGCODE(this->validate();) 3488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3491dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com fPathRef.reset(SkPathRef::CreateEmpty()); 350a5809a3e4cb356387c5201ab9c0a10edf11a01bebungeman@google.com this->resetFields(); 3518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 3528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkPath::rewind() { 3548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDEBUGCODE(this->validate();) 3558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3561dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com SkPathRef::Rewind(&fPathRef); 357a5809a3e4cb356387c5201ab9c0a10edf11a01bebungeman@google.com this->resetFields(); 3588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 3598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 360b1475b0d41efc580207183a4e25d14e920b57360fsbool SkPath::isLastContourClosed() const { 361b1475b0d41efc580207183a4e25d14e920b57360fs int verbCount = fPathRef->countVerbs(); 362b1475b0d41efc580207183a4e25d14e920b57360fs if (0 == verbCount) { 363b1475b0d41efc580207183a4e25d14e920b57360fs return false; 364b1475b0d41efc580207183a4e25d14e920b57360fs } 365b1475b0d41efc580207183a4e25d14e920b57360fs return kClose_Verb == fPathRef->atVerb(verbCount - 1); 366b1475b0d41efc580207183a4e25d14e920b57360fs} 367b1475b0d41efc580207183a4e25d14e920b57360fs 3687e6c4d16010550ee148f1c79cf088c0320fed5c1reed@google.combool SkPath::isLine(SkPoint line[2]) const { 3691dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com int verbCount = fPathRef->countVerbs(); 370fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 371a62efcc1e000e4b0ee4fdb3390cadd56452ce3c1commit-bot@chromium.org if (2 == verbCount) { 372a62efcc1e000e4b0ee4fdb3390cadd56452ce3c1commit-bot@chromium.org SkASSERT(kMove_Verb == fPathRef->atVerb(0)); 373a62efcc1e000e4b0ee4fdb3390cadd56452ce3c1commit-bot@chromium.org if (kLine_Verb == fPathRef->atVerb(1)) { 374a62efcc1e000e4b0ee4fdb3390cadd56452ce3c1commit-bot@chromium.org SkASSERT(2 == fPathRef->countPoints()); 3757e6c4d16010550ee148f1c79cf088c0320fed5c1reed@google.com if (line) { 3761dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com const SkPoint* pts = fPathRef->points(); 3777e6c4d16010550ee148f1c79cf088c0320fed5c1reed@google.com line[0] = pts[0]; 3787e6c4d16010550ee148f1c79cf088c0320fed5c1reed@google.com line[1] = pts[1]; 3797e6c4d16010550ee148f1c79cf088c0320fed5c1reed@google.com } 3807e6c4d16010550ee148f1c79cf088c0320fed5c1reed@google.com return true; 3817e6c4d16010550ee148f1c79cf088c0320fed5c1reed@google.com } 3827e6c4d16010550ee148f1c79cf088c0320fed5c1reed@google.com } 3837e6c4d16010550ee148f1c79cf088c0320fed5c1reed@google.com return false; 3847e6c4d16010550ee148f1c79cf088c0320fed5c1reed@google.com} 3857e6c4d16010550ee148f1c79cf088c0320fed5c1reed@google.com 386f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com/* 387f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com Determines if path is a rect by keeping track of changes in direction 388f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com and looking for a loop either clockwise or counterclockwise. 389fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 390f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com The direction is computed such that: 391f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com 0: vertical up 392f68154a3cf43eb22d45be11f3b09e25440c366a6caryclark@google.com 1: horizontal left 393f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com 2: vertical down 394f68154a3cf43eb22d45be11f3b09e25440c366a6caryclark@google.com 3: horizontal right 395fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 396f131694617ce0410eafcb01124459382576bb1d9caryclark@google.comA rectangle cycles up/right/down/left or up/left/down/right. 397f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com 398f131694617ce0410eafcb01124459382576bb1d9caryclark@google.comThe test fails if: 399f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com The path is closed, and followed by a line. 400f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com A second move creates a new endpoint. 401f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com A diagonal line is parsed. 402f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com There's more than four changes of direction. 403f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com There's a discontinuity on the line (e.g., a move in the middle) 404f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com The line reverses direction. 405f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com The path contains a quadratic or cubic. 406f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com The path contains fewer than four points. 40705ec2233e372cc11ad59b3337c96f0147a44ca29commit-bot@chromium.org *The rectangle doesn't complete a cycle. 40805ec2233e372cc11ad59b3337c96f0147a44ca29commit-bot@chromium.org *The final point isn't equal to the first point. 40905ec2233e372cc11ad59b3337c96f0147a44ca29commit-bot@chromium.org 41005ec2233e372cc11ad59b3337c96f0147a44ca29commit-bot@chromium.org *These last two conditions we relax if we have a 3-edge path that would 41105ec2233e372cc11ad59b3337c96f0147a44ca29commit-bot@chromium.org form a rectangle if it were closed (as we do when we fill a path) 412fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 413f131694617ce0410eafcb01124459382576bb1d9caryclark@google.comIt's OK if the path has: 414f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com Several colinear line segments composing a rectangle side. 415f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com Single points on the rectangle side. 416fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 417f131694617ce0410eafcb01124459382576bb1d9caryclark@google.comThe direction takes advantage of the corners found since opposite sides 418f131694617ce0410eafcb01124459382576bb1d9caryclark@google.commust travel in opposite directions. 419f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com 420f131694617ce0410eafcb01124459382576bb1d9caryclark@google.comFIXME: Allow colinear quads and cubics to be treated like lines. 421f131694617ce0410eafcb01124459382576bb1d9caryclark@google.comFIXME: If the API passes fill-only, return true if the filled stroke 422f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com is a rectangle, though the caller failed to close the path. 42305ec2233e372cc11ad59b3337c96f0147a44ca29commit-bot@chromium.org 42405ec2233e372cc11ad59b3337c96f0147a44ca29commit-bot@chromium.org first,last,next direction state-machine: 42505ec2233e372cc11ad59b3337c96f0147a44ca29commit-bot@chromium.org 0x1 is set if the segment is horizontal 42605ec2233e372cc11ad59b3337c96f0147a44ca29commit-bot@chromium.org 0x2 is set if the segment is moving to the right or down 42705ec2233e372cc11ad59b3337c96f0147a44ca29commit-bot@chromium.org thus: 42805ec2233e372cc11ad59b3337c96f0147a44ca29commit-bot@chromium.org two directions are opposites iff (dirA ^ dirB) == 0x2 42905ec2233e372cc11ad59b3337c96f0147a44ca29commit-bot@chromium.org two directions are perpendicular iff (dirA ^ dirB) == 0x1 430f5e67c12c864084fa797d1e005d8472ee6f71322skia.committer@gmail.com 431f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com */ 43205ec2233e372cc11ad59b3337c96f0147a44ca29commit-bot@chromium.orgstatic int rect_make_dir(SkScalar dx, SkScalar dy) { 43305ec2233e372cc11ad59b3337c96f0147a44ca29commit-bot@chromium.org return ((0 != dx) << 0) | ((dx > 0 || dy > 0) << 1); 43405ec2233e372cc11ad59b3337c96f0147a44ca29commit-bot@chromium.org} 435f68154a3cf43eb22d45be11f3b09e25440c366a6caryclark@google.combool SkPath::isRectContour(bool allowPartial, int* currVerb, const SkPoint** ptsPtr, 436f68154a3cf43eb22d45be11f3b09e25440c366a6caryclark@google.com bool* isClosed, Direction* direction) const { 437f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com int corners = 0; 438f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com SkPoint first, last; 43956f233ab54d228f3ce05d0f7e15996424f9d5dd2caryclark@google.com const SkPoint* pts = *ptsPtr; 44096fcdcc219d2a0d3579719b84b28bede76efba64halcanary const SkPoint* savePts = nullptr; 4412c2508d2ede7e6a8eb43dba0ef2419905ccbb3d8tomhudson@google.com first.set(0, 0); 4422c2508d2ede7e6a8eb43dba0ef2419905ccbb3d8tomhudson@google.com last.set(0, 0); 4432c2508d2ede7e6a8eb43dba0ef2419905ccbb3d8tomhudson@google.com int firstDirection = 0; 4442c2508d2ede7e6a8eb43dba0ef2419905ccbb3d8tomhudson@google.com int lastDirection = 0; 4452c2508d2ede7e6a8eb43dba0ef2419905ccbb3d8tomhudson@google.com int nextDirection = 0; 4462c2508d2ede7e6a8eb43dba0ef2419905ccbb3d8tomhudson@google.com bool closedOrMoved = false; 447f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com bool autoClose = false; 44895bc5f349561fef2d6fbae71adb08cf5c2eec0c9caryclark bool insertClose = false; 4491dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com int verbCnt = fPathRef->countVerbs(); 45056f233ab54d228f3ce05d0f7e15996424f9d5dd2caryclark@google.com while (*currVerb < verbCnt && (!allowPartial || !autoClose)) { 45195bc5f349561fef2d6fbae71adb08cf5c2eec0c9caryclark uint8_t verb = insertClose ? (uint8_t) kClose_Verb : fPathRef->atVerb(*currVerb); 45295bc5f349561fef2d6fbae71adb08cf5c2eec0c9caryclark switch (verb) { 453f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com case kClose_Verb: 45456f233ab54d228f3ce05d0f7e15996424f9d5dd2caryclark@google.com savePts = pts; 45556f233ab54d228f3ce05d0f7e15996424f9d5dd2caryclark@google.com pts = *ptsPtr; 456f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com autoClose = true; 45795bc5f349561fef2d6fbae71adb08cf5c2eec0c9caryclark insertClose = false; 458f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com case kLine_Verb: { 459f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com SkScalar left = last.fX; 460f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com SkScalar top = last.fY; 461f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com SkScalar right = pts->fX; 462f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com SkScalar bottom = pts->fY; 463f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com ++pts; 464f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com if (left != right && top != bottom) { 465f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com return false; // diagonal 466f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com } 467f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com if (left == right && top == bottom) { 468f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com break; // single point on side OK 469f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com } 47005ec2233e372cc11ad59b3337c96f0147a44ca29commit-bot@chromium.org nextDirection = rect_make_dir(right - left, bottom - top); 471f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com if (0 == corners) { 472f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com firstDirection = nextDirection; 473f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com first = last; 474f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com last = pts[-1]; 475f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com corners = 1; 476f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com closedOrMoved = false; 477f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com break; 478f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com } 479f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com if (closedOrMoved) { 480f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com return false; // closed followed by a line 481f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com } 482bfe90370ea68798b2b9b5ba44142db67d99555e8caryclark@google.com if (autoClose && nextDirection == firstDirection) { 483bfe90370ea68798b2b9b5ba44142db67d99555e8caryclark@google.com break; // colinear with first 484bfe90370ea68798b2b9b5ba44142db67d99555e8caryclark@google.com } 485f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com closedOrMoved = autoClose; 486f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com if (lastDirection != nextDirection) { 487f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com if (++corners > 4) { 488f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com return false; // too many direction changes 489f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com } 490f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com } 491f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com last = pts[-1]; 492f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com if (lastDirection == nextDirection) { 493f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com break; // colinear segment 494f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com } 495f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com // Possible values for corners are 2, 3, and 4. 496f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com // When corners == 3, nextDirection opposes firstDirection. 497f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com // Otherwise, nextDirection at corner 2 opposes corner 4. 4982c2508d2ede7e6a8eb43dba0ef2419905ccbb3d8tomhudson@google.com int turn = firstDirection ^ (corners - 1); 499f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com int directionCycle = 3 == corners ? 0 : nextDirection ^ turn; 500f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com if ((directionCycle ^ turn) != nextDirection) { 501f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com return false; // direction didn't follow cycle 502f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com } 503f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com break; 504f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com } 505f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com case kQuad_Verb: 506277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com case kConic_Verb: 507f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com case kCubic_Verb: 508f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com return false; // quadratic, cubic not allowed 509f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com case kMove_Verb: 51095bc5f349561fef2d6fbae71adb08cf5c2eec0c9caryclark if (allowPartial && !autoClose && firstDirection) { 51195bc5f349561fef2d6fbae71adb08cf5c2eec0c9caryclark insertClose = true; 51295bc5f349561fef2d6fbae71adb08cf5c2eec0c9caryclark *currVerb -= 1; // try move again afterwards 51395bc5f349561fef2d6fbae71adb08cf5c2eec0c9caryclark goto addMissingClose; 51495bc5f349561fef2d6fbae71adb08cf5c2eec0c9caryclark } 515f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com last = *pts++; 516f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com closedOrMoved = true; 517f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com break; 518277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com default: 519330313a8a8343876ee596da39da06a5d69badd9cmtklein@google.com SkDEBUGFAIL("unexpected verb"); 520277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com break; 521f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com } 52256f233ab54d228f3ce05d0f7e15996424f9d5dd2caryclark@google.com *currVerb += 1; 523f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com lastDirection = nextDirection; 52495bc5f349561fef2d6fbae71adb08cf5c2eec0c9caryclarkaddMissingClose: 52595bc5f349561fef2d6fbae71adb08cf5c2eec0c9caryclark ; 526f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com } 527f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com // Success if 4 corners and first point equals last 528bfe90370ea68798b2b9b5ba44142db67d99555e8caryclark@google.com bool result = 4 == corners && (first == last || autoClose); 52905ec2233e372cc11ad59b3337c96f0147a44ca29commit-bot@chromium.org if (!result) { 53005ec2233e372cc11ad59b3337c96f0147a44ca29commit-bot@chromium.org // check if we are just an incomplete rectangle, in which case we can 53105ec2233e372cc11ad59b3337c96f0147a44ca29commit-bot@chromium.org // return true, but not claim to be closed. 53205ec2233e372cc11ad59b3337c96f0147a44ca29commit-bot@chromium.org // e.g. 53305ec2233e372cc11ad59b3337c96f0147a44ca29commit-bot@chromium.org // 3 sided rectangle 53405ec2233e372cc11ad59b3337c96f0147a44ca29commit-bot@chromium.org // 4 sided but the last edge is not long enough to reach the start 53505ec2233e372cc11ad59b3337c96f0147a44ca29commit-bot@chromium.org // 53605ec2233e372cc11ad59b3337c96f0147a44ca29commit-bot@chromium.org SkScalar closeX = first.x() - last.x(); 53705ec2233e372cc11ad59b3337c96f0147a44ca29commit-bot@chromium.org SkScalar closeY = first.y() - last.y(); 53805ec2233e372cc11ad59b3337c96f0147a44ca29commit-bot@chromium.org if (closeX && closeY) { 53905ec2233e372cc11ad59b3337c96f0147a44ca29commit-bot@chromium.org return false; // we're diagonal, abort (can we ever reach this?) 54005ec2233e372cc11ad59b3337c96f0147a44ca29commit-bot@chromium.org } 54105ec2233e372cc11ad59b3337c96f0147a44ca29commit-bot@chromium.org int closeDirection = rect_make_dir(closeX, closeY); 54205ec2233e372cc11ad59b3337c96f0147a44ca29commit-bot@chromium.org // make sure the close-segment doesn't double-back on itself 54305ec2233e372cc11ad59b3337c96f0147a44ca29commit-bot@chromium.org if (3 == corners || (4 == corners && closeDirection == lastDirection)) { 54405ec2233e372cc11ad59b3337c96f0147a44ca29commit-bot@chromium.org result = true; 54505ec2233e372cc11ad59b3337c96f0147a44ca29commit-bot@chromium.org autoClose = false; // we are not closed 54605ec2233e372cc11ad59b3337c96f0147a44ca29commit-bot@chromium.org } 54705ec2233e372cc11ad59b3337c96f0147a44ca29commit-bot@chromium.org } 548bfe90370ea68798b2b9b5ba44142db67d99555e8caryclark@google.com if (savePts) { 549bfe90370ea68798b2b9b5ba44142db67d99555e8caryclark@google.com *ptsPtr = savePts; 550bfe90370ea68798b2b9b5ba44142db67d99555e8caryclark@google.com } 551f68154a3cf43eb22d45be11f3b09e25440c366a6caryclark@google.com if (result && isClosed) { 552f68154a3cf43eb22d45be11f3b09e25440c366a6caryclark@google.com *isClosed = autoClose; 553f68154a3cf43eb22d45be11f3b09e25440c366a6caryclark@google.com } 554f68154a3cf43eb22d45be11f3b09e25440c366a6caryclark@google.com if (result && direction) { 55512b4e27ae1a29460e91a59f38122483e1faec697sugoi@google.com *direction = firstDirection == ((lastDirection + 1) & 3) ? kCCW_Direction : kCW_Direction; 556f68154a3cf43eb22d45be11f3b09e25440c366a6caryclark@google.com } 55756f233ab54d228f3ce05d0f7e15996424f9d5dd2caryclark@google.com return result; 55856f233ab54d228f3ce05d0f7e15996424f9d5dd2caryclark@google.com} 55956f233ab54d228f3ce05d0f7e15996424f9d5dd2caryclark@google.com 5604f662e62cd44e302ef689fabdb2c0ae8d9471b02robertphillipsbool SkPath::isRect(SkRect* rect, bool* isClosed, Direction* direction) const { 56156f233ab54d228f3ce05d0f7e15996424f9d5dd2caryclark@google.com SkDEBUGCODE(this->validate();) 56256f233ab54d228f3ce05d0f7e15996424f9d5dd2caryclark@google.com int currVerb = 0; 56356f233ab54d228f3ce05d0f7e15996424f9d5dd2caryclark@google.com const SkPoint* pts = fPathRef->points(); 564fe7c427e3d1c2c98bce7a3fa0ae6b5864527f169robertphillips const SkPoint* first = pts; 5654f662e62cd44e302ef689fabdb2c0ae8d9471b02robertphillips if (!this->isRectContour(false, &currVerb, &pts, isClosed, direction)) { 566fe7c427e3d1c2c98bce7a3fa0ae6b5864527f169robertphillips return false; 567f131694617ce0410eafcb01124459382576bb1d9caryclark@google.com } 568fe7c427e3d1c2c98bce7a3fa0ae6b5864527f169robertphillips if (rect) { 5694f662e62cd44e302ef689fabdb2c0ae8d9471b02robertphillips int32_t num = SkToS32(pts - first); 5704f662e62cd44e302ef689fabdb2c0ae8d9471b02robertphillips if (num) { 5714f662e62cd44e302ef689fabdb2c0ae8d9471b02robertphillips rect->set(first, num); 572fe7c427e3d1c2c98bce7a3fa0ae6b5864527f169robertphillips } else { 573fe7c427e3d1c2c98bce7a3fa0ae6b5864527f169robertphillips // 'pts' isn't updated for open rects 574fe7c427e3d1c2c98bce7a3fa0ae6b5864527f169robertphillips *rect = this->getBounds(); 575fe7c427e3d1c2c98bce7a3fa0ae6b5864527f169robertphillips } 576fe7c427e3d1c2c98bce7a3fa0ae6b5864527f169robertphillips } 577fe7c427e3d1c2c98bce7a3fa0ae6b5864527f169robertphillips return true; 5788fd160350ca5f57fbb1b2e03383c5778414a9b48robertphillips@google.com} 579020b25becb4a99061e8643780c887ad472eb0648skia.committer@gmail.com 58095bc5f349561fef2d6fbae71adb08cf5c2eec0c9caryclarkbool SkPath::isNestedFillRects(SkRect rects[2], Direction dirs[2]) const { 58156f233ab54d228f3ce05d0f7e15996424f9d5dd2caryclark@google.com SkDEBUGCODE(this->validate();) 58256f233ab54d228f3ce05d0f7e15996424f9d5dd2caryclark@google.com int currVerb = 0; 58356f233ab54d228f3ce05d0f7e15996424f9d5dd2caryclark@google.com const SkPoint* pts = fPathRef->points(); 58456f233ab54d228f3ce05d0f7e15996424f9d5dd2caryclark@google.com const SkPoint* first = pts; 58583d1a68141830cbfa0d5fca6f9c9bccf9c978ad2robertphillips@google.com Direction testDirs[2]; 58696fcdcc219d2a0d3579719b84b28bede76efba64halcanary if (!isRectContour(true, &currVerb, &pts, nullptr, &testDirs[0])) { 58756f233ab54d228f3ce05d0f7e15996424f9d5dd2caryclark@google.com return false; 58856f233ab54d228f3ce05d0f7e15996424f9d5dd2caryclark@google.com } 58956f233ab54d228f3ce05d0f7e15996424f9d5dd2caryclark@google.com const SkPoint* last = pts; 59056f233ab54d228f3ce05d0f7e15996424f9d5dd2caryclark@google.com SkRect testRects[2]; 59195bc5f349561fef2d6fbae71adb08cf5c2eec0c9caryclark bool isClosed; 59295bc5f349561fef2d6fbae71adb08cf5c2eec0c9caryclark if (isRectContour(false, &currVerb, &pts, &isClosed, &testDirs[1])) { 593614f9e3a540b388c09eb96c1d43b8bfc6d28de81scroggo@google.com testRects[0].set(first, SkToS32(last - first)); 59495bc5f349561fef2d6fbae71adb08cf5c2eec0c9caryclark if (!isClosed) { 59595bc5f349561fef2d6fbae71adb08cf5c2eec0c9caryclark pts = fPathRef->points() + fPathRef->countPoints(); 59695bc5f349561fef2d6fbae71adb08cf5c2eec0c9caryclark } 597614f9e3a540b388c09eb96c1d43b8bfc6d28de81scroggo@google.com testRects[1].set(last, SkToS32(pts - last)); 59856f233ab54d228f3ce05d0f7e15996424f9d5dd2caryclark@google.com if (testRects[0].contains(testRects[1])) { 59956f233ab54d228f3ce05d0f7e15996424f9d5dd2caryclark@google.com if (rects) { 60056f233ab54d228f3ce05d0f7e15996424f9d5dd2caryclark@google.com rects[0] = testRects[0]; 60156f233ab54d228f3ce05d0f7e15996424f9d5dd2caryclark@google.com rects[1] = testRects[1]; 60256f233ab54d228f3ce05d0f7e15996424f9d5dd2caryclark@google.com } 60383d1a68141830cbfa0d5fca6f9c9bccf9c978ad2robertphillips@google.com if (dirs) { 60483d1a68141830cbfa0d5fca6f9c9bccf9c978ad2robertphillips@google.com dirs[0] = testDirs[0]; 60583d1a68141830cbfa0d5fca6f9c9bccf9c978ad2robertphillips@google.com dirs[1] = testDirs[1]; 60683d1a68141830cbfa0d5fca6f9c9bccf9c978ad2robertphillips@google.com } 60756f233ab54d228f3ce05d0f7e15996424f9d5dd2caryclark@google.com return true; 60856f233ab54d228f3ce05d0f7e15996424f9d5dd2caryclark@google.com } 60956f233ab54d228f3ce05d0f7e15996424f9d5dd2caryclark@google.com if (testRects[1].contains(testRects[0])) { 61056f233ab54d228f3ce05d0f7e15996424f9d5dd2caryclark@google.com if (rects) { 61156f233ab54d228f3ce05d0f7e15996424f9d5dd2caryclark@google.com rects[0] = testRects[1]; 61256f233ab54d228f3ce05d0f7e15996424f9d5dd2caryclark@google.com rects[1] = testRects[0]; 61356f233ab54d228f3ce05d0f7e15996424f9d5dd2caryclark@google.com } 61483d1a68141830cbfa0d5fca6f9c9bccf9c978ad2robertphillips@google.com if (dirs) { 61583d1a68141830cbfa0d5fca6f9c9bccf9c978ad2robertphillips@google.com dirs[0] = testDirs[1]; 61683d1a68141830cbfa0d5fca6f9c9bccf9c978ad2robertphillips@google.com dirs[1] = testDirs[0]; 61783d1a68141830cbfa0d5fca6f9c9bccf9c978ad2robertphillips@google.com } 61856f233ab54d228f3ce05d0f7e15996424f9d5dd2caryclark@google.com return true; 61956f233ab54d228f3ce05d0f7e15996424f9d5dd2caryclark@google.com } 62056f233ab54d228f3ce05d0f7e15996424f9d5dd2caryclark@google.com } 62156f233ab54d228f3ce05d0f7e15996424f9d5dd2caryclark@google.com return false; 62256f233ab54d228f3ce05d0f7e15996424f9d5dd2caryclark@google.com} 62356f233ab54d228f3ce05d0f7e15996424f9d5dd2caryclark@google.com 6241dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.comint SkPath::countPoints() const { 6251dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com return fPathRef->countPoints(); 6261dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com} 6271dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com 628df9d656c352928f995abce0a62c4ec3255232a45bsalomon@google.comint SkPath::getPoints(SkPoint dst[], int max) const { 6298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDEBUGCODE(this->validate();) 6308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 6318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkASSERT(max >= 0); 632df9d656c352928f995abce0a62c4ec3255232a45bsalomon@google.com SkASSERT(!max || dst); 6331dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com int count = SkMin32(max, fPathRef->countPoints()); 6348bf5d1754f08a3070c953f31cf20cde27a390cd0mtklein sk_careful_memcpy(dst, fPathRef->points(), count * sizeof(SkPoint)); 6351dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com return fPathRef->countPoints(); 6368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 6378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 638d3aa4ff7a564953dff9a15ff03fd42eebf64569freed@android.comSkPoint SkPath::getPoint(int index) const { 6391dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com if ((unsigned)index < (unsigned)fPathRef->countPoints()) { 6401dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com return fPathRef->atPoint(index); 641d3aa4ff7a564953dff9a15ff03fd42eebf64569freed@android.com } 642d3aa4ff7a564953dff9a15ff03fd42eebf64569freed@android.com return SkPoint::Make(0, 0); 643d3aa4ff7a564953dff9a15ff03fd42eebf64569freed@android.com} 644d3aa4ff7a564953dff9a15ff03fd42eebf64569freed@android.com 6451dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.comint SkPath::countVerbs() const { 6461dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com return fPathRef->countVerbs(); 6471dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com} 6481dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com 6491dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.comstatic inline void copy_verbs_reverse(uint8_t* inorderDst, 6501dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com const uint8_t* reversedSrc, 6511dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com int count) { 6521dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com for (int i = 0; i < count; ++i) { 6531dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com inorderDst[i] = reversedSrc[~i]; 6541dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com } 6551dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com} 6561dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com 657df9d656c352928f995abce0a62c4ec3255232a45bsalomon@google.comint SkPath::getVerbs(uint8_t dst[], int max) const { 658df9d656c352928f995abce0a62c4ec3255232a45bsalomon@google.com SkDEBUGCODE(this->validate();) 659df9d656c352928f995abce0a62c4ec3255232a45bsalomon@google.com 660df9d656c352928f995abce0a62c4ec3255232a45bsalomon@google.com SkASSERT(max >= 0); 661df9d656c352928f995abce0a62c4ec3255232a45bsalomon@google.com SkASSERT(!max || dst); 6621dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com int count = SkMin32(max, fPathRef->countVerbs()); 6631dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com copy_verbs_reverse(dst, fPathRef->verbs(), count); 6641dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com return fPathRef->countVerbs(); 665df9d656c352928f995abce0a62c4ec3255232a45bsalomon@google.com} 666df9d656c352928f995abce0a62c4ec3255232a45bsalomon@google.com 667294dd7b3d7b55ba38881cd4cabb6636abda23eb9reed@google.combool SkPath::getLastPt(SkPoint* lastPt) const { 6688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDEBUGCODE(this->validate();) 6698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 6701dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com int count = fPathRef->countPoints(); 671294dd7b3d7b55ba38881cd4cabb6636abda23eb9reed@google.com if (count > 0) { 672294dd7b3d7b55ba38881cd4cabb6636abda23eb9reed@google.com if (lastPt) { 6731dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com *lastPt = fPathRef->atPoint(count - 1); 6748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 675294dd7b3d7b55ba38881cd4cabb6636abda23eb9reed@google.com return true; 676294dd7b3d7b55ba38881cd4cabb6636abda23eb9reed@google.com } 677294dd7b3d7b55ba38881cd4cabb6636abda23eb9reed@google.com if (lastPt) { 678294dd7b3d7b55ba38881cd4cabb6636abda23eb9reed@google.com lastPt->set(0, 0); 6798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 680294dd7b3d7b55ba38881cd4cabb6636abda23eb9reed@google.com return false; 6818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 6828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 683aec251012542e971100e218bf463adbfb5d21d20caryclarkvoid SkPath::setPt(int index, SkScalar x, SkScalar y) { 684aec251012542e971100e218bf463adbfb5d21d20caryclark SkDEBUGCODE(this->validate();) 685aec251012542e971100e218bf463adbfb5d21d20caryclark 686aec251012542e971100e218bf463adbfb5d21d20caryclark int count = fPathRef->countPoints(); 687aec251012542e971100e218bf463adbfb5d21d20caryclark if (count <= index) { 688aec251012542e971100e218bf463adbfb5d21d20caryclark return; 689aec251012542e971100e218bf463adbfb5d21d20caryclark } else { 690aec251012542e971100e218bf463adbfb5d21d20caryclark SkPathRef::Editor ed(&fPathRef); 691aec251012542e971100e218bf463adbfb5d21d20caryclark ed.atPoint(index)->set(x, y); 692aec251012542e971100e218bf463adbfb5d21d20caryclark } 693aec251012542e971100e218bf463adbfb5d21d20caryclark} 694aec251012542e971100e218bf463adbfb5d21d20caryclark 6958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkPath::setLastPt(SkScalar x, SkScalar y) { 6968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDEBUGCODE(this->validate();) 6978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 6981dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com int count = fPathRef->countPoints(); 6998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (count == 0) { 7008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com this->moveTo(x, y); 7018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 7021dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com SkPathRef::Editor ed(&fPathRef); 7031dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com ed.atPoint(count-1)->set(x, y); 7048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 7058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 7068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 70704863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.comvoid SkPath::setConvexity(Convexity c) { 70804863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com if (fConvexity != c) { 70904863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com fConvexity = c; 71004863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com } 71104863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com} 71204863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com 7138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com////////////////////////////////////////////////////////////////////////////// 7148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// Construction methods 7158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 716026beb52a29a620290fcfb24f1e7e9e75547b80freed#define DIRTY_AFTER_EDIT \ 717026beb52a29a620290fcfb24f1e7e9e75547b80freed do { \ 718026beb52a29a620290fcfb24f1e7e9e75547b80freed fConvexity = kUnknown_Convexity; \ 719026beb52a29a620290fcfb24f1e7e9e75547b80freed fFirstDirection = SkPathPriv::kUnknown_FirstDirection; \ 720b54455e440e66e0b1c30954d226226f49aac26d6reed@google.com } while (0) 721b54455e440e66e0b1c30954d226226f49aac26d6reed@google.com 7228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkPath::incReserve(U16CPU inc) { 7238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDEBUGCODE(this->validate();) 7241dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com SkPathRef::Editor(&fPathRef, inc, inc); 7258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDEBUGCODE(this->validate();) 7268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 7278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 7288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkPath::moveTo(SkScalar x, SkScalar y) { 7298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDEBUGCODE(this->validate();) 7308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 7311dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com SkPathRef::Editor ed(&fPathRef); 7328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 7335e1a7f2cc621d357da5c62a7bc4ef750d94b96f3commit-bot@chromium.org // remember our index 7345e1a7f2cc621d357da5c62a7bc4ef750d94b96f3commit-bot@chromium.org fLastMoveToIndex = fPathRef->countPoints(); 7355e1a7f2cc621d357da5c62a7bc4ef750d94b96f3commit-bot@chromium.org 7361dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com ed.growForVerb(kMove_Verb)->set(x, y); 737b17c1291085e50819c0c46aae783067c30a67516bsalomon 738b17c1291085e50819c0c46aae783067c30a67516bsalomon DIRTY_AFTER_EDIT; 7398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 7408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 7418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkPath::rMoveTo(SkScalar x, SkScalar y) { 7428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPoint pt; 7438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com this->getLastPt(&pt); 7448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com this->moveTo(pt.fX + x, pt.fY + y); 7458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 7468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 7475e1a7f2cc621d357da5c62a7bc4ef750d94b96f3commit-bot@chromium.orgvoid SkPath::injectMoveToIfNeeded() { 7485e1a7f2cc621d357da5c62a7bc4ef750d94b96f3commit-bot@chromium.org if (fLastMoveToIndex < 0) { 7495e1a7f2cc621d357da5c62a7bc4ef750d94b96f3commit-bot@chromium.org SkScalar x, y; 7505e1a7f2cc621d357da5c62a7bc4ef750d94b96f3commit-bot@chromium.org if (fPathRef->countVerbs() == 0) { 7515e1a7f2cc621d357da5c62a7bc4ef750d94b96f3commit-bot@chromium.org x = y = 0; 7525e1a7f2cc621d357da5c62a7bc4ef750d94b96f3commit-bot@chromium.org } else { 7535e1a7f2cc621d357da5c62a7bc4ef750d94b96f3commit-bot@chromium.org const SkPoint& pt = fPathRef->atPoint(~fLastMoveToIndex); 7545e1a7f2cc621d357da5c62a7bc4ef750d94b96f3commit-bot@chromium.org x = pt.fX; 7555e1a7f2cc621d357da5c62a7bc4ef750d94b96f3commit-bot@chromium.org y = pt.fY; 7565e1a7f2cc621d357da5c62a7bc4ef750d94b96f3commit-bot@chromium.org } 7575e1a7f2cc621d357da5c62a7bc4ef750d94b96f3commit-bot@chromium.org this->moveTo(x, y); 7585e1a7f2cc621d357da5c62a7bc4ef750d94b96f3commit-bot@chromium.org } 7595e1a7f2cc621d357da5c62a7bc4ef750d94b96f3commit-bot@chromium.org} 7605e1a7f2cc621d357da5c62a7bc4ef750d94b96f3commit-bot@chromium.org 7618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkPath::lineTo(SkScalar x, SkScalar y) { 7628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDEBUGCODE(this->validate();) 7638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 7645e1a7f2cc621d357da5c62a7bc4ef750d94b96f3commit-bot@chromium.org this->injectMoveToIfNeeded(); 7655e1a7f2cc621d357da5c62a7bc4ef750d94b96f3commit-bot@chromium.org 7661dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com SkPathRef::Editor ed(&fPathRef); 7671dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com ed.growForVerb(kLine_Verb)->set(x, y); 7688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 769b54455e440e66e0b1c30954d226226f49aac26d6reed@google.com DIRTY_AFTER_EDIT; 7708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 7718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 7728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkPath::rLineTo(SkScalar x, SkScalar y) { 7739d54aeb8a192845f1f8122dba780d40ee6a0de1bcommit-bot@chromium.org this->injectMoveToIfNeeded(); // This can change the result of this->getLastPt(). 7748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPoint pt; 7758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com this->getLastPt(&pt); 7768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com this->lineTo(pt.fX + x, pt.fY + y); 7778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 7788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 7798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkPath::quadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) { 7808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDEBUGCODE(this->validate();) 78126da7f00aedba107d4b3e382283034e265db09b6skia.committer@gmail.com 7825e1a7f2cc621d357da5c62a7bc4ef750d94b96f3commit-bot@chromium.org this->injectMoveToIfNeeded(); 7835e1a7f2cc621d357da5c62a7bc4ef750d94b96f3commit-bot@chromium.org 7841dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com SkPathRef::Editor ed(&fPathRef); 7851dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com SkPoint* pts = ed.growForVerb(kQuad_Verb); 7868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com pts[0].set(x1, y1); 7878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com pts[1].set(x2, y2); 78826da7f00aedba107d4b3e382283034e265db09b6skia.committer@gmail.com 789b54455e440e66e0b1c30954d226226f49aac26d6reed@google.com DIRTY_AFTER_EDIT; 7908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 7918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 7928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkPath::rQuadTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2) { 7939d54aeb8a192845f1f8122dba780d40ee6a0de1bcommit-bot@chromium.org this->injectMoveToIfNeeded(); // This can change the result of this->getLastPt(). 7948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPoint pt; 7958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com this->getLastPt(&pt); 7968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com this->quadTo(pt.fX + x1, pt.fY + y1, pt.fX + x2, pt.fY + y2); 7978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 7988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 799277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.comvoid SkPath::conicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, 800277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com SkScalar w) { 801277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com // check for <= 0 or NaN with this test 802277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com if (!(w > 0)) { 803277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com this->lineTo(x2, y2); 804277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com } else if (!SkScalarIsFinite(w)) { 805277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com this->lineTo(x1, y1); 806277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com this->lineTo(x2, y2); 807277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com } else if (SK_Scalar1 == w) { 808277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com this->quadTo(x1, y1, x2, y2); 809277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com } else { 810277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com SkDEBUGCODE(this->validate();) 81126da7f00aedba107d4b3e382283034e265db09b6skia.committer@gmail.com 8125e1a7f2cc621d357da5c62a7bc4ef750d94b96f3commit-bot@chromium.org this->injectMoveToIfNeeded(); 8135e1a7f2cc621d357da5c62a7bc4ef750d94b96f3commit-bot@chromium.org 814277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com SkPathRef::Editor ed(&fPathRef); 8156b8dbb668f1f069270d35a47cfe98decd059c625robertphillips@google.com SkPoint* pts = ed.growForVerb(kConic_Verb, w); 816277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com pts[0].set(x1, y1); 817277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com pts[1].set(x2, y2); 81826da7f00aedba107d4b3e382283034e265db09b6skia.committer@gmail.com 819277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com DIRTY_AFTER_EDIT; 820277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com } 821277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com} 822277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com 823277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.comvoid SkPath::rConicTo(SkScalar dx1, SkScalar dy1, SkScalar dx2, SkScalar dy2, 824277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com SkScalar w) { 8259d54aeb8a192845f1f8122dba780d40ee6a0de1bcommit-bot@chromium.org this->injectMoveToIfNeeded(); // This can change the result of this->getLastPt(). 826277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com SkPoint pt; 827277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com this->getLastPt(&pt); 828277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com this->conicTo(pt.fX + dx1, pt.fY + dy1, pt.fX + dx2, pt.fY + dy2, w); 829277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com} 830277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com 8318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkPath::cubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, 8328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar x3, SkScalar y3) { 8338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDEBUGCODE(this->validate();) 8348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 8355e1a7f2cc621d357da5c62a7bc4ef750d94b96f3commit-bot@chromium.org this->injectMoveToIfNeeded(); 8365e1a7f2cc621d357da5c62a7bc4ef750d94b96f3commit-bot@chromium.org 8371dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com SkPathRef::Editor ed(&fPathRef); 8381dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com SkPoint* pts = ed.growForVerb(kCubic_Verb); 8398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com pts[0].set(x1, y1); 8408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com pts[1].set(x2, y2); 8418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com pts[2].set(x3, y3); 8428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 843b54455e440e66e0b1c30954d226226f49aac26d6reed@google.com DIRTY_AFTER_EDIT; 8448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 8458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 8468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkPath::rCubicTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, 8478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar x3, SkScalar y3) { 8489d54aeb8a192845f1f8122dba780d40ee6a0de1bcommit-bot@chromium.org this->injectMoveToIfNeeded(); // This can change the result of this->getLastPt(). 8498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPoint pt; 8508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com this->getLastPt(&pt); 8518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com this->cubicTo(pt.fX + x1, pt.fY + y1, pt.fX + x2, pt.fY + y2, 8528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com pt.fX + x3, pt.fY + y3); 8538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 8548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 8558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkPath::close() { 8568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDEBUGCODE(this->validate();) 8578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 8581dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com int count = fPathRef->countVerbs(); 8598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (count > 0) { 8601dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com switch (fPathRef->atVerb(count - 1)) { 8618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com case kLine_Verb: 8628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com case kQuad_Verb: 863277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com case kConic_Verb: 8648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com case kCubic_Verb: 8651dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com case kMove_Verb: { 8661dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com SkPathRef::Editor ed(&fPathRef); 8671dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com ed.growForVerb(kClose_Verb); 8688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 8691dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com } 870277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com case kClose_Verb: 871fa2f2a48f6822b88ab895fece1998af549c16ebereed@google.com // don't add a close if it's the first verb or a repeat 8727950a9eba71f65365d88021680a16f245ad3fa68reed@google.com break; 873277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com default: 874330313a8a8343876ee596da39da06a5d69badd9cmtklein@google.com SkDEBUGFAIL("unexpected verb"); 875277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com break; 8768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 8778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 8785e1a7f2cc621d357da5c62a7bc4ef750d94b96f3commit-bot@chromium.org 8795e1a7f2cc621d357da5c62a7bc4ef750d94b96f3commit-bot@chromium.org // signal that we need a moveTo to follow us (unless we're done) 8805e1a7f2cc621d357da5c62a7bc4ef750d94b96f3commit-bot@chromium.org#if 0 8815e1a7f2cc621d357da5c62a7bc4ef750d94b96f3commit-bot@chromium.org if (fLastMoveToIndex >= 0) { 8825e1a7f2cc621d357da5c62a7bc4ef750d94b96f3commit-bot@chromium.org fLastMoveToIndex = ~fLastMoveToIndex; 8835e1a7f2cc621d357da5c62a7bc4ef750d94b96f3commit-bot@chromium.org } 8845e1a7f2cc621d357da5c62a7bc4ef750d94b96f3commit-bot@chromium.org#else 8855e1a7f2cc621d357da5c62a7bc4ef750d94b96f3commit-bot@chromium.org fLastMoveToIndex ^= ~fLastMoveToIndex >> (8 * sizeof(fLastMoveToIndex) - 1); 8865e1a7f2cc621d357da5c62a7bc4ef750d94b96f3commit-bot@chromium.org#endif 8878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 8888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 8898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////////////////////////////////////////////////////////////// 890abf15c189b6333aa77a6c3f566cc67f4634ba338reed@google.com 891c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalitanamespace { 892c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita 893c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalitatemplate <unsigned N> 894c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalitaclass PointIterator { 895c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalitapublic: 896c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita PointIterator(SkPath::Direction dir, unsigned startIndex) 897c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita : fCurrent(startIndex % N) 898c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita , fAdvance(dir == SkPath::kCW_Direction ? 1 : N - 1) { } 899c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita 900c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita const SkPoint& current() const { 901c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita SkASSERT(fCurrent < N); 902c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita return fPts[fCurrent]; 903c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita } 904c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita 905c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita const SkPoint& next() { 906c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita fCurrent = (fCurrent + fAdvance) % N; 907c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita return this->current(); 908c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita } 909c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita 910c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalitaprotected: 911c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita SkPoint fPts[N]; 912c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita 913c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalitaprivate: 914c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita unsigned fCurrent; 915c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita unsigned fAdvance; 916c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita}; 917c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita 918c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalitaclass RectPointIterator : public PointIterator<4> { 919c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalitapublic: 920c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita RectPointIterator(const SkRect& rect, SkPath::Direction dir, unsigned startIndex) 921c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita : PointIterator(dir, startIndex) { 922c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita 923c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita fPts[0] = SkPoint::Make(rect.fLeft, rect.fTop); 924c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita fPts[1] = SkPoint::Make(rect.fRight, rect.fTop); 925c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita fPts[2] = SkPoint::Make(rect.fRight, rect.fBottom); 926c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita fPts[3] = SkPoint::Make(rect.fLeft, rect.fBottom); 927c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita } 928c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita}; 929c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita 930c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalitaclass OvalPointIterator : public PointIterator<4> { 931c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalitapublic: 932c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita OvalPointIterator(const SkRect& oval, SkPath::Direction dir, unsigned startIndex) 933c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita : PointIterator(dir, startIndex) { 934c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita 935c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita const SkScalar cx = oval.centerX(); 936c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita const SkScalar cy = oval.centerY(); 937c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita 938c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita fPts[0] = SkPoint::Make(cx, oval.fTop); 939c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita fPts[1] = SkPoint::Make(oval.fRight, cy); 940c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita fPts[2] = SkPoint::Make(cx, oval.fBottom); 941c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita fPts[3] = SkPoint::Make(oval.fLeft, cy); 942c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita } 943c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita}; 944c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita 945c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalitaclass RRectPointIterator : public PointIterator<8> { 946c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalitapublic: 947c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita RRectPointIterator(const SkRRect& rrect, SkPath::Direction dir, unsigned startIndex) 948c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita : PointIterator(dir, startIndex) { 949c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita 950c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita const SkRect& bounds = rrect.getBounds(); 951c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita const SkScalar L = bounds.fLeft; 952c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita const SkScalar T = bounds.fTop; 953c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita const SkScalar R = bounds.fRight; 954c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita const SkScalar B = bounds.fBottom; 955c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita 956c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita fPts[0] = SkPoint::Make(L + rrect.radii(SkRRect::kUpperLeft_Corner).fX, T); 957c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita fPts[1] = SkPoint::Make(R - rrect.radii(SkRRect::kUpperRight_Corner).fX, T); 958c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita fPts[2] = SkPoint::Make(R, T + rrect.radii(SkRRect::kUpperRight_Corner).fY); 959c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita fPts[3] = SkPoint::Make(R, B - rrect.radii(SkRRect::kLowerRight_Corner).fY); 960c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita fPts[4] = SkPoint::Make(R - rrect.radii(SkRRect::kLowerRight_Corner).fX, B); 961c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita fPts[5] = SkPoint::Make(L + rrect.radii(SkRRect::kLowerLeft_Corner).fX, B); 962c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita fPts[6] = SkPoint::Make(L, B - rrect.radii(SkRRect::kLowerLeft_Corner).fY); 963c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita fPts[7] = SkPoint::Make(L, T + rrect.radii(SkRRect::kUpperLeft_Corner).fY); 964c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita } 965c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita}; 966c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita 967c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita} // anonymous namespace 968c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita 969a8a3b3d9a027ad54ce20f8b4ed7c577a176b31careed@google.comstatic void assert_known_direction(int dir) { 970a8a3b3d9a027ad54ce20f8b4ed7c577a176b31careed@google.com SkASSERT(SkPath::kCW_Direction == dir || SkPath::kCCW_Direction == dir); 971a8a3b3d9a027ad54ce20f8b4ed7c577a176b31careed@google.com} 972a8a3b3d9a027ad54ce20f8b4ed7c577a176b31careed@google.com 9738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkPath::addRect(const SkRect& rect, Direction dir) { 974c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita this->addRect(rect, dir, 0); 9758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 9768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 9778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkPath::addRect(SkScalar left, SkScalar top, SkScalar right, 9788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar bottom, Direction dir) { 979c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita this->addRect(SkRect::MakeLTRB(left, top, right, bottom), dir, 0); 980c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita} 981c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita 982c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalitavoid SkPath::addRect(const SkRect &rect, Direction dir, unsigned startIndex) { 983a8a3b3d9a027ad54ce20f8b4ed7c577a176b31careed@google.com assert_known_direction(dir); 984026beb52a29a620290fcfb24f1e7e9e75547b80freed fFirstDirection = this->hasOnlyMoveTos() ? 985c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita (SkPathPriv::FirstDirection)dir : SkPathPriv::kUnknown_FirstDirection; 98630c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com SkAutoDisableDirectionCheck addc(this); 987c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita SkAutoPathBoundsUpdate apbu(this, rect); 98830c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com 989c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita SkDEBUGCODE(int initialVerbCount = this->countVerbs()); 9908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 991c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita const int kVerbs = 5; // moveTo + 3x lineTo + close 992c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita this->incReserve(kVerbs); 9938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 994c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita RectPointIterator iter(rect, dir, startIndex); 995c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita 996c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita this->moveTo(iter.current()); 997c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita this->lineTo(iter.next()); 998c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita this->lineTo(iter.next()); 999c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita this->lineTo(iter.next()); 10008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com this->close(); 1001c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita 1002c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita SkASSERT(this->countVerbs() == initialVerbCount + kVerbs); 10038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 10048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1005744fabad474e3e111e7cbd8609cf7e209df17f32reed@google.comvoid SkPath::addPoly(const SkPoint pts[], int count, bool close) { 1006744fabad474e3e111e7cbd8609cf7e209df17f32reed@google.com SkDEBUGCODE(this->validate();) 1007744fabad474e3e111e7cbd8609cf7e209df17f32reed@google.com if (count <= 0) { 1008744fabad474e3e111e7cbd8609cf7e209df17f32reed@google.com return; 1009744fabad474e3e111e7cbd8609cf7e209df17f32reed@google.com } 1010744fabad474e3e111e7cbd8609cf7e209df17f32reed@google.com 10115e1a7f2cc621d357da5c62a7bc4ef750d94b96f3commit-bot@chromium.org fLastMoveToIndex = fPathRef->countPoints(); 10125e1a7f2cc621d357da5c62a7bc4ef750d94b96f3commit-bot@chromium.org 1013744fabad474e3e111e7cbd8609cf7e209df17f32reed@google.com // +close makes room for the extra kClose_Verb 10146b8dbb668f1f069270d35a47cfe98decd059c625robertphillips@google.com SkPathRef::Editor ed(&fPathRef, count+close, count); 1015744fabad474e3e111e7cbd8609cf7e209df17f32reed@google.com 10166b8dbb668f1f069270d35a47cfe98decd059c625robertphillips@google.com ed.growForVerb(kMove_Verb)->set(pts[0].fX, pts[0].fY); 1017744fabad474e3e111e7cbd8609cf7e209df17f32reed@google.com if (count > 1) { 10186b8dbb668f1f069270d35a47cfe98decd059c625robertphillips@google.com SkPoint* p = ed.growForRepeatedVerb(kLine_Verb, count - 1); 10196b8dbb668f1f069270d35a47cfe98decd059c625robertphillips@google.com memcpy(p, &pts[1], (count-1) * sizeof(SkPoint)); 1020744fabad474e3e111e7cbd8609cf7e209df17f32reed@google.com } 10216b8dbb668f1f069270d35a47cfe98decd059c625robertphillips@google.com 1022744fabad474e3e111e7cbd8609cf7e209df17f32reed@google.com if (close) { 10236b8dbb668f1f069270d35a47cfe98decd059c625robertphillips@google.com ed.growForVerb(kClose_Verb); 102463c684a8a609d39da11b4a656223cebf52ca85dccaryclark fLastMoveToIndex ^= ~fLastMoveToIndex >> (8 * sizeof(fLastMoveToIndex) - 1); 1025744fabad474e3e111e7cbd8609cf7e209df17f32reed@google.com } 1026744fabad474e3e111e7cbd8609cf7e209df17f32reed@google.com 1027744fabad474e3e111e7cbd8609cf7e209df17f32reed@google.com DIRTY_AFTER_EDIT; 10281dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com SkDEBUGCODE(this->validate();) 1029744fabad474e3e111e7cbd8609cf7e209df17f32reed@google.com} 1030744fabad474e3e111e7cbd8609cf7e209df17f32reed@google.com 10311cc385b7a427ec8b511c56744a02046a60dd3fd8robertphillips@google.com#include "SkGeometry.h" 10321cc385b7a427ec8b511c56744a02046a60dd3fd8robertphillips@google.com 1033f90ea01522524b064141cf4ee5198b7cb053fd53reedstatic bool arc_is_lone_point(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, 1034f90ea01522524b064141cf4ee5198b7cb053fd53reed SkPoint* pt) { 1035f90ea01522524b064141cf4ee5198b7cb053fd53reed if (0 == sweepAngle && (0 == startAngle || SkIntToScalar(360) == startAngle)) { 10361cc385b7a427ec8b511c56744a02046a60dd3fd8robertphillips@google.com // Chrome uses this path to move into and out of ovals. If not 10371cc385b7a427ec8b511c56744a02046a60dd3fd8robertphillips@google.com // treated as a special case the moves can distort the oval's 10381cc385b7a427ec8b511c56744a02046a60dd3fd8robertphillips@google.com // bounding box (and break the circle special case). 1039f90ea01522524b064141cf4ee5198b7cb053fd53reed pt->set(oval.fRight, oval.centerY()); 1040f90ea01522524b064141cf4ee5198b7cb053fd53reed return true; 10411cc385b7a427ec8b511c56744a02046a60dd3fd8robertphillips@google.com } else if (0 == oval.width() && 0 == oval.height()) { 10421cc385b7a427ec8b511c56744a02046a60dd3fd8robertphillips@google.com // Chrome will sometimes create 0 radius round rects. Having degenerate 10431cc385b7a427ec8b511c56744a02046a60dd3fd8robertphillips@google.com // quad segments in the path prevents the path from being recognized as 10441cc385b7a427ec8b511c56744a02046a60dd3fd8robertphillips@google.com // a rect. 10451cc385b7a427ec8b511c56744a02046a60dd3fd8robertphillips@google.com // TODO: optimizing the case where only one of width or height is zero 10461cc385b7a427ec8b511c56744a02046a60dd3fd8robertphillips@google.com // should also be considered. This case, however, doesn't seem to be 10471cc385b7a427ec8b511c56744a02046a60dd3fd8robertphillips@google.com // as common as the single point case. 1048f90ea01522524b064141cf4ee5198b7cb053fd53reed pt->set(oval.fRight, oval.fTop); 1049f90ea01522524b064141cf4ee5198b7cb053fd53reed return true; 10501cc385b7a427ec8b511c56744a02046a60dd3fd8robertphillips@google.com } 1051f90ea01522524b064141cf4ee5198b7cb053fd53reed return false; 1052f90ea01522524b064141cf4ee5198b7cb053fd53reed} 10531cc385b7a427ec8b511c56744a02046a60dd3fd8robertphillips@google.com 1054d5d27d9b146731b871b1bcc6d6de36fba2d5ea44reed// Return the unit vectors pointing at the start/stop points for the given start/sweep angles 1055d5d27d9b146731b871b1bcc6d6de36fba2d5ea44reed// 1056d5d27d9b146731b871b1bcc6d6de36fba2d5ea44reedstatic void angles_to_unit_vectors(SkScalar startAngle, SkScalar sweepAngle, 1057d5d27d9b146731b871b1bcc6d6de36fba2d5ea44reed SkVector* startV, SkVector* stopV, SkRotationDirection* dir) { 1058d5d27d9b146731b871b1bcc6d6de36fba2d5ea44reed startV->fY = SkScalarSinCos(SkDegreesToRadians(startAngle), &startV->fX); 1059d5d27d9b146731b871b1bcc6d6de36fba2d5ea44reed stopV->fY = SkScalarSinCos(SkDegreesToRadians(startAngle + sweepAngle), &stopV->fX); 10601cc385b7a427ec8b511c56744a02046a60dd3fd8robertphillips@google.com 10611cc385b7a427ec8b511c56744a02046a60dd3fd8robertphillips@google.com /* If the sweep angle is nearly (but less than) 360, then due to precision 1062d5d27d9b146731b871b1bcc6d6de36fba2d5ea44reed loss in radians-conversion and/or sin/cos, we may end up with coincident 1063d5d27d9b146731b871b1bcc6d6de36fba2d5ea44reed vectors, which will fool SkBuildQuadArc into doing nothing (bad) instead 1064d5d27d9b146731b871b1bcc6d6de36fba2d5ea44reed of drawing a nearly complete circle (good). 1065d5d27d9b146731b871b1bcc6d6de36fba2d5ea44reed e.g. canvas.drawArc(0, 359.99, ...) 1066d5d27d9b146731b871b1bcc6d6de36fba2d5ea44reed -vs- canvas.drawArc(0, 359.9, ...) 1067d5d27d9b146731b871b1bcc6d6de36fba2d5ea44reed We try to detect this edge case, and tweak the stop vector 10681cc385b7a427ec8b511c56744a02046a60dd3fd8robertphillips@google.com */ 1069d5d27d9b146731b871b1bcc6d6de36fba2d5ea44reed if (*startV == *stopV) { 10701cc385b7a427ec8b511c56744a02046a60dd3fd8robertphillips@google.com SkScalar sw = SkScalarAbs(sweepAngle); 10711cc385b7a427ec8b511c56744a02046a60dd3fd8robertphillips@google.com if (sw < SkIntToScalar(360) && sw > SkIntToScalar(359)) { 10721cc385b7a427ec8b511c56744a02046a60dd3fd8robertphillips@google.com SkScalar stopRad = SkDegreesToRadians(startAngle + sweepAngle); 10731cc385b7a427ec8b511c56744a02046a60dd3fd8robertphillips@google.com // make a guess at a tiny angle (in radians) to tweak by 10741cc385b7a427ec8b511c56744a02046a60dd3fd8robertphillips@google.com SkScalar deltaRad = SkScalarCopySign(SK_Scalar1/512, sweepAngle); 10751cc385b7a427ec8b511c56744a02046a60dd3fd8robertphillips@google.com // not sure how much will be enough, so we use a loop 10761cc385b7a427ec8b511c56744a02046a60dd3fd8robertphillips@google.com do { 10771cc385b7a427ec8b511c56744a02046a60dd3fd8robertphillips@google.com stopRad -= deltaRad; 1078d5d27d9b146731b871b1bcc6d6de36fba2d5ea44reed stopV->fY = SkScalarSinCos(stopRad, &stopV->fX); 1079d5d27d9b146731b871b1bcc6d6de36fba2d5ea44reed } while (*startV == *stopV); 10801cc385b7a427ec8b511c56744a02046a60dd3fd8robertphillips@google.com } 10811cc385b7a427ec8b511c56744a02046a60dd3fd8robertphillips@google.com } 1082d5d27d9b146731b871b1bcc6d6de36fba2d5ea44reed *dir = sweepAngle > 0 ? kCW_SkRotationDirection : kCCW_SkRotationDirection; 1083d5d27d9b146731b871b1bcc6d6de36fba2d5ea44reed} 10841cc385b7a427ec8b511c56744a02046a60dd3fd8robertphillips@google.com 10859e779d495130009926fc5394a8971eec20494e5freed/** 10869e779d495130009926fc5394a8971eec20494e5freed * If this returns 0, then the caller should just line-to the singlePt, else it should 10879e779d495130009926fc5394a8971eec20494e5freed * ignore singlePt and append the specified number of conics. 10889e779d495130009926fc5394a8971eec20494e5freed */ 1089d5d27d9b146731b871b1bcc6d6de36fba2d5ea44reedstatic int build_arc_conics(const SkRect& oval, const SkVector& start, const SkVector& stop, 10909e779d495130009926fc5394a8971eec20494e5freed SkRotationDirection dir, SkConic conics[SkConic::kMaxConicsForArc], 10919e779d495130009926fc5394a8971eec20494e5freed SkPoint* singlePt) { 1092d5d27d9b146731b871b1bcc6d6de36fba2d5ea44reed SkMatrix matrix; 1093d5d27d9b146731b871b1bcc6d6de36fba2d5ea44reed 1094d5d27d9b146731b871b1bcc6d6de36fba2d5ea44reed matrix.setScale(SkScalarHalf(oval.width()), SkScalarHalf(oval.height())); 1095d5d27d9b146731b871b1bcc6d6de36fba2d5ea44reed matrix.postTranslate(oval.centerX(), oval.centerY()); 1096d5d27d9b146731b871b1bcc6d6de36fba2d5ea44reed 10979e779d495130009926fc5394a8971eec20494e5freed int count = SkConic::BuildUnitArc(start, stop, dir, &matrix, conics); 10989e779d495130009926fc5394a8971eec20494e5freed if (0 == count) { 109995e34a3d847684692184daea4a887f7825d65e51xidachen matrix.mapXY(stop.x(), stop.y(), singlePt); 11009e779d495130009926fc5394a8971eec20494e5freed } 11019e779d495130009926fc5394a8971eec20494e5freed return count; 1102d5d27d9b146731b871b1bcc6d6de36fba2d5ea44reed} 11031cc385b7a427ec8b511c56744a02046a60dd3fd8robertphillips@google.com 11044e18c7a9bbef6ac949d535aa61dfe1462ebb4452robertphillips@google.comvoid SkPath::addRoundRect(const SkRect& rect, const SkScalar radii[], 11058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com Direction dir) { 11064e18c7a9bbef6ac949d535aa61dfe1462ebb4452robertphillips@google.com SkRRect rrect; 11074e18c7a9bbef6ac949d535aa61dfe1462ebb4452robertphillips@google.com rrect.setRectRadii(rect, (const SkVector*) radii); 11084e18c7a9bbef6ac949d535aa61dfe1462ebb4452robertphillips@google.com this->addRRect(rrect, dir); 11094e18c7a9bbef6ac949d535aa61dfe1462ebb4452robertphillips@google.com} 11104e18c7a9bbef6ac949d535aa61dfe1462ebb4452robertphillips@google.com 11114e18c7a9bbef6ac949d535aa61dfe1462ebb4452robertphillips@google.comvoid SkPath::addRRect(const SkRRect& rrect, Direction dir) { 1112c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita // legacy start indices: 6 (CW) and 7(CCW) 1113c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita this->addRRect(rrect, dir, dir == kCW_Direction ? 6 : 7); 1114c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita} 11151b28a3a4890e3b84b43181b3fe3690ac565930dcreed 1116c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalitavoid SkPath::addRRect(const SkRRect &rrect, Direction dir, unsigned startIndex) { 1117c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita assert_known_direction(dir); 11181b28a3a4890e3b84b43181b3fe3690ac565930dcreed 1119c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita if (rrect.isEmpty()) { 1120c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita return; 1121c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita } 11221b28a3a4890e3b84b43181b3fe3690ac565930dcreed 1123da707bf5635c70d4c3c284a0b05d92489b76788ecaryclark bool isRRect = hasOnlyMoveTos(); 1124c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita const SkRect& bounds = rrect.getBounds(); 11251b28a3a4890e3b84b43181b3fe3690ac565930dcreed 1126c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita if (rrect.isRect()) { 1127c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita // degenerate(rect) => radii points are collapsing 1128c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita this->addRect(bounds, dir, (startIndex + 1) / 2); 1129c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita } else if (rrect.isOval()) { 1130c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita // degenerate(oval) => line points are collapsing 1131c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita this->addOval(bounds, dir, startIndex / 2); 11321b28a3a4890e3b84b43181b3fe3690ac565930dcreed } else { 1133c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita fFirstDirection = this->hasOnlyMoveTos() ? 1134c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita (SkPathPriv::FirstDirection)dir : SkPathPriv::kUnknown_FirstDirection; 1135c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita 1136c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita SkAutoPathBoundsUpdate apbu(this, bounds); 1137c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita SkAutoDisableDirectionCheck addc(this); 1138c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita 1139c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita // we start with a conic on odd indices when moving CW vs. even indices when moving CCW 1140c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita const bool startsWithConic = ((startIndex & 1) == (dir == kCW_Direction)); 1141c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita const SkScalar weight = SK_ScalarRoot2Over2; 1142c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita 1143c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita SkDEBUGCODE(int initialVerbCount = this->countVerbs()); 1144c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita const int kVerbs = startsWithConic 1145c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita ? 9 // moveTo + 4x conicTo + 3x lineTo + close 1146c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita : 10; // moveTo + 4x lineTo + 4x conicTo + close 1147c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita this->incReserve(kVerbs); 1148c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita 1149c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita RRectPointIterator rrectIter(rrect, dir, startIndex); 1150c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita // Corner iterator indices follow the collapsed radii model, 1151c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita // adjusted such that the start pt is "behind" the radii start pt. 1152c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita const unsigned rectStartIndex = startIndex / 2 + (dir == kCW_Direction ? 0 : 1); 1153c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita RectPointIterator rectIter(bounds, dir, rectStartIndex); 1154c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita 1155c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita this->moveTo(rrectIter.current()); 1156c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita if (startsWithConic) { 1157c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita for (unsigned i = 0; i < 3; ++i) { 1158c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita this->conicTo(rectIter.next(), rrectIter.next(), weight); 1159c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita this->lineTo(rrectIter.next()); 1160c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita } 1161c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita this->conicTo(rectIter.next(), rrectIter.next(), weight); 1162c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita // final lineTo handled by close(). 1163c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita } else { 1164c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita for (unsigned i = 0; i < 4; ++i) { 1165c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita this->lineTo(rrectIter.next()); 1166c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita this->conicTo(rectIter.next(), rrectIter.next(), weight); 1167c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita } 1168c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita } 1169c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita this->close(); 11701b28a3a4890e3b84b43181b3fe3690ac565930dcreed 1171da707bf5635c70d4c3c284a0b05d92489b76788ecaryclark SkPathRef::Editor ed(&fPathRef); 117278d58d1084f0390c1c0f9123ac6e48efcd226f39bsalomon ed.setIsRRect(isRRect, dir, startIndex % 8); 1173da707bf5635c70d4c3c284a0b05d92489b76788ecaryclark 1174c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita SkASSERT(this->countVerbs() == initialVerbCount + kVerbs); 11751b28a3a4890e3b84b43181b3fe3690ac565930dcreed } 1176c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita 1177c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita SkDEBUGCODE(fPathRef->validate();) 11784ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com} 11794ed0fb768409bf97b79899c3990d8c15f5e9d784reed@google.com 11806aa2965ca814dd3329b65398b5c5af980e54b101bsalomon@google.combool SkPath::hasOnlyMoveTos() const { 11811dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com int count = fPathRef->countVerbs(); 11821dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com const uint8_t* verbs = const_cast<const SkPathRef*>(fPathRef.get())->verbsMemBegin(); 11831dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com for (int i = 0; i < count; ++i) { 11846aa2965ca814dd3329b65398b5c5af980e54b101bsalomon@google.com if (*verbs == kLine_Verb || 11856aa2965ca814dd3329b65398b5c5af980e54b101bsalomon@google.com *verbs == kQuad_Verb || 1186a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org *verbs == kConic_Verb || 11876aa2965ca814dd3329b65398b5c5af980e54b101bsalomon@google.com *verbs == kCubic_Verb) { 11886aa2965ca814dd3329b65398b5c5af980e54b101bsalomon@google.com return false; 11896aa2965ca814dd3329b65398b5c5af980e54b101bsalomon@google.com } 11906aa2965ca814dd3329b65398b5c5af980e54b101bsalomon@google.com ++verbs; 11916aa2965ca814dd3329b65398b5c5af980e54b101bsalomon@google.com } 11926aa2965ca814dd3329b65398b5c5af980e54b101bsalomon@google.com return true; 11936aa2965ca814dd3329b65398b5c5af980e54b101bsalomon@google.com} 11946aa2965ca814dd3329b65398b5c5af980e54b101bsalomon@google.com 1195a2318576d6510dc63513ce335ed0027666bd55bfBrian Osmanbool SkPath::isZeroLengthSincePoint(int startPtIndex) const { 1196a2318576d6510dc63513ce335ed0027666bd55bfBrian Osman int count = fPathRef->countPoints() - startPtIndex; 1197d49a86ade0bab1fc3048d6ba5d8536abf25ed77ccaryclark if (count < 2) { 1198d49a86ade0bab1fc3048d6ba5d8536abf25ed77ccaryclark return true; 1199d49a86ade0bab1fc3048d6ba5d8536abf25ed77ccaryclark } 1200a2318576d6510dc63513ce335ed0027666bd55bfBrian Osman const SkPoint* pts = fPathRef.get()->points() + startPtIndex; 1201d49a86ade0bab1fc3048d6ba5d8536abf25ed77ccaryclark const SkPoint& first = *pts; 1202d49a86ade0bab1fc3048d6ba5d8536abf25ed77ccaryclark for (int index = 1; index < count; ++index) { 1203d49a86ade0bab1fc3048d6ba5d8536abf25ed77ccaryclark if (first != pts[index]) { 1204d49a86ade0bab1fc3048d6ba5d8536abf25ed77ccaryclark return false; 1205d49a86ade0bab1fc3048d6ba5d8536abf25ed77ccaryclark } 1206d49a86ade0bab1fc3048d6ba5d8536abf25ed77ccaryclark } 1207d49a86ade0bab1fc3048d6ba5d8536abf25ed77ccaryclark return true; 1208d49a86ade0bab1fc3048d6ba5d8536abf25ed77ccaryclark} 1209d49a86ade0bab1fc3048d6ba5d8536abf25ed77ccaryclark 1210b16033a25b91f9e45d07bd4b955c8dbcfd23e8d5mike@reedtribe.orgvoid SkPath::addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry, 1211b16033a25b91f9e45d07bd4b955c8dbcfd23e8d5mike@reedtribe.org Direction dir) { 1212b16033a25b91f9e45d07bd4b955c8dbcfd23e8d5mike@reedtribe.org assert_known_direction(dir); 12133284017a60ea4fc3dc5b95838ba0c301ee1e4e8dskia.committer@gmail.com 121475e3ca127cd14fffc9c8df7ea03d6529fb001831humper@google.com if (rx < 0 || ry < 0) { 121575e3ca127cd14fffc9c8df7ea03d6529fb001831humper@google.com return; 121675e3ca127cd14fffc9c8df7ea03d6529fb001831humper@google.com } 1217d9f65e3df45c9b4994c70f6bf13d29985afd2f65skia.committer@gmail.com 121842feaaf0a5fbb508b237d5c844c484a1a3b0c865commit-bot@chromium.org SkRRect rrect; 121942feaaf0a5fbb508b237d5c844c484a1a3b0c865commit-bot@chromium.org rrect.setRectXY(rect, rx, ry); 122042feaaf0a5fbb508b237d5c844c484a1a3b0c865commit-bot@chromium.org this->addRRect(rrect, dir); 1221b16033a25b91f9e45d07bd4b955c8dbcfd23e8d5mike@reedtribe.org} 1222b16033a25b91f9e45d07bd4b955c8dbcfd23e8d5mike@reedtribe.org 12238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkPath::addOval(const SkRect& oval, Direction dir) { 1224c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita // legacy start index: 1 1225c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita this->addOval(oval, dir, 1); 1226c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita} 1227c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita 1228c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalitavoid SkPath::addOval(const SkRect &oval, Direction dir, unsigned startPointIndex) { 1229a8a3b3d9a027ad54ce20f8b4ed7c577a176b31careed@google.com assert_known_direction(dir); 1230a8a3b3d9a027ad54ce20f8b4ed7c577a176b31careed@google.com 12316aa2965ca814dd3329b65398b5c5af980e54b101bsalomon@google.com /* If addOval() is called after previous moveTo(), 12326aa2965ca814dd3329b65398b5c5af980e54b101bsalomon@google.com this path is still marked as an oval. This is used to 12336aa2965ca814dd3329b65398b5c5af980e54b101bsalomon@google.com fit into WebKit's calling sequences. 12346aa2965ca814dd3329b65398b5c5af980e54b101bsalomon@google.com We can't simply check isEmpty() in this case, as additional 12356aa2965ca814dd3329b65398b5c5af980e54b101bsalomon@google.com moveTo() would mark the path non empty. 12366aa2965ca814dd3329b65398b5c5af980e54b101bsalomon@google.com */ 1237466310dbd3073add2ec934e336c30deaaf702eaerobertphillips@google.com bool isOval = hasOnlyMoveTos(); 1238466310dbd3073add2ec934e336c30deaaf702eaerobertphillips@google.com if (isOval) { 1239026beb52a29a620290fcfb24f1e7e9e75547b80freed fFirstDirection = (SkPathPriv::FirstDirection)dir; 124030c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com } else { 1241026beb52a29a620290fcfb24f1e7e9e75547b80freed fFirstDirection = SkPathPriv::kUnknown_FirstDirection; 124230c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com } 12436aa2965ca814dd3329b65398b5c5af980e54b101bsalomon@google.com 124430c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com SkAutoDisableDirectionCheck addc(this); 12458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkAutoPathBoundsUpdate apbu(this, oval); 12468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1247c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita SkDEBUGCODE(int initialVerbCount = this->countVerbs()); 1248c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita const int kVerbs = 6; // moveTo + 4x conicTo + close 1249c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita this->incReserve(kVerbs); 1250c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita 1251c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita OvalPointIterator ovalIter(oval, dir, startPointIndex); 1252c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita // The corner iterator pts are tracking "behind" the oval/radii pts. 1253c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita RectPointIterator rectIter(oval, dir, startPointIndex + (dir == kCW_Direction ? 0 : 1)); 1254220f926d9d4b38a9018c922c095847bbd261f583reed const SkScalar weight = SK_ScalarRoot2Over2; 1255220f926d9d4b38a9018c922c095847bbd261f583reed 1256c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita this->moveTo(ovalIter.current()); 1257c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita for (unsigned i = 0; i < 4; ++i) { 1258c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita this->conicTo(rectIter.next(), ovalIter.next(), weight); 1259220f926d9d4b38a9018c922c095847bbd261f583reed } 12608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com this->close(); 12618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1262c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita SkASSERT(this->countVerbs() == initialVerbCount + kVerbs); 1263c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita 1264466310dbd3073add2ec934e336c30deaaf702eaerobertphillips@google.com SkPathRef::Editor ed(&fPathRef); 12656aa2965ca814dd3329b65398b5c5af980e54b101bsalomon@google.com 126678d58d1084f0390c1c0f9123ac6e48efcd226f39bsalomon ed.setIsOval(isOval, kCCW_Direction == dir, startPointIndex % 4); 12676aa2965ca814dd3329b65398b5c5af980e54b101bsalomon@google.com} 12686aa2965ca814dd3329b65398b5c5af980e54b101bsalomon@google.com 12698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkPath::addCircle(SkScalar x, SkScalar y, SkScalar r, Direction dir) { 12708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (r > 0) { 1271c08d53ee175e190254d8fd6659d9ad051ac0ba46fmalita this->addOval(SkRect::MakeLTRB(x - r, y - r, x + r, y + r), dir); 12728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 12738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 12748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 12758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkPath::arcTo(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, 12768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com bool forceMoveTo) { 12778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (oval.width() < 0 || oval.height() < 0) { 12788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 12798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 12808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1281f90ea01522524b064141cf4ee5198b7cb053fd53reed if (fPathRef->countVerbs() == 0) { 1282f90ea01522524b064141cf4ee5198b7cb053fd53reed forceMoveTo = true; 1283f90ea01522524b064141cf4ee5198b7cb053fd53reed } 1284f90ea01522524b064141cf4ee5198b7cb053fd53reed 1285f90ea01522524b064141cf4ee5198b7cb053fd53reed SkPoint lonePt; 1286f90ea01522524b064141cf4ee5198b7cb053fd53reed if (arc_is_lone_point(oval, startAngle, sweepAngle, &lonePt)) { 1287f90ea01522524b064141cf4ee5198b7cb053fd53reed forceMoveTo ? this->moveTo(lonePt) : this->lineTo(lonePt); 1288f90ea01522524b064141cf4ee5198b7cb053fd53reed return; 1289f90ea01522524b064141cf4ee5198b7cb053fd53reed } 1290f90ea01522524b064141cf4ee5198b7cb053fd53reed 1291d5d27d9b146731b871b1bcc6d6de36fba2d5ea44reed SkVector startV, stopV; 1292d5d27d9b146731b871b1bcc6d6de36fba2d5ea44reed SkRotationDirection dir; 1293d5d27d9b146731b871b1bcc6d6de36fba2d5ea44reed angles_to_unit_vectors(startAngle, sweepAngle, &startV, &stopV, &dir); 1294d5d27d9b146731b871b1bcc6d6de36fba2d5ea44reed 12959e779d495130009926fc5394a8971eec20494e5freed SkPoint singlePt; 12966069ddabd8385ff838236dc25d7354e71649c9f3xidachen 12976069ddabd8385ff838236dc25d7354e71649c9f3xidachen // At this point, we know that the arc is not a lone point, but startV == stopV 12986069ddabd8385ff838236dc25d7354e71649c9f3xidachen // indicates that the sweepAngle is too small such that angles_to_unit_vectors 12996069ddabd8385ff838236dc25d7354e71649c9f3xidachen // cannot handle it. 13006069ddabd8385ff838236dc25d7354e71649c9f3xidachen if (startV == stopV) { 13016069ddabd8385ff838236dc25d7354e71649c9f3xidachen SkScalar endAngle = SkDegreesToRadians(startAngle + sweepAngle); 13026069ddabd8385ff838236dc25d7354e71649c9f3xidachen SkScalar radiusX = oval.width() / 2; 13036069ddabd8385ff838236dc25d7354e71649c9f3xidachen SkScalar radiusY = oval.height() / 2; 13046069ddabd8385ff838236dc25d7354e71649c9f3xidachen // We cannot use SkScalarSinCos function in the next line because 13056069ddabd8385ff838236dc25d7354e71649c9f3xidachen // SkScalarSinCos has a threshold *SkScalarNearlyZero*. When sin(startAngle) 13066069ddabd8385ff838236dc25d7354e71649c9f3xidachen // is 0 and sweepAngle is very small and radius is huge, the expected 1307e54c75f351c775201049743c506d7a508d0fef91Mike Klein // behavior here is to draw a line. But calling SkScalarSinCos will 13086069ddabd8385ff838236dc25d7354e71649c9f3xidachen // make sin(endAngle) to be 0 which will then draw a dot. 13096069ddabd8385ff838236dc25d7354e71649c9f3xidachen singlePt.set(oval.centerX() + radiusX * sk_float_cos(endAngle), 13106069ddabd8385ff838236dc25d7354e71649c9f3xidachen oval.centerY() + radiusY * sk_float_sin(endAngle)); 13116069ddabd8385ff838236dc25d7354e71649c9f3xidachen forceMoveTo ? this->moveTo(singlePt) : this->lineTo(singlePt); 13126069ddabd8385ff838236dc25d7354e71649c9f3xidachen return; 13136069ddabd8385ff838236dc25d7354e71649c9f3xidachen } 13146069ddabd8385ff838236dc25d7354e71649c9f3xidachen 1315d5d27d9b146731b871b1bcc6d6de36fba2d5ea44reed SkConic conics[SkConic::kMaxConicsForArc]; 13169e779d495130009926fc5394a8971eec20494e5freed int count = build_arc_conics(oval, startV, stopV, dir, conics, &singlePt); 1317d5d27d9b146731b871b1bcc6d6de36fba2d5ea44reed if (count) { 1318d5d27d9b146731b871b1bcc6d6de36fba2d5ea44reed this->incReserve(count * 2 + 1); 1319d5d27d9b146731b871b1bcc6d6de36fba2d5ea44reed const SkPoint& pt = conics[0].fPts[0]; 1320d5d27d9b146731b871b1bcc6d6de36fba2d5ea44reed forceMoveTo ? this->moveTo(pt) : this->lineTo(pt); 1321d5d27d9b146731b871b1bcc6d6de36fba2d5ea44reed for (int i = 0; i < count; ++i) { 1322d5d27d9b146731b871b1bcc6d6de36fba2d5ea44reed this->conicTo(conics[i].fPts[1], conics[i].fPts[2], conics[i].fW); 1323d5d27d9b146731b871b1bcc6d6de36fba2d5ea44reed } 13249e779d495130009926fc5394a8971eec20494e5freed } else { 13259e779d495130009926fc5394a8971eec20494e5freed forceMoveTo ? this->moveTo(singlePt) : this->lineTo(singlePt); 1326d5d27d9b146731b871b1bcc6d6de36fba2d5ea44reed } 13278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 13288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 132955d49053d1b6db42e013eb3409ffcfc7e235c685caryclark// This converts the SVG arc to conics. 133055d49053d1b6db42e013eb3409ffcfc7e235c685caryclark// Partly adapted from Niko's code in kdelibs/kdecore/svgicons. 133155d49053d1b6db42e013eb3409ffcfc7e235c685caryclark// Then transcribed from webkit/chrome's SVGPathNormalizer::decomposeArcToCubic() 133255d49053d1b6db42e013eb3409ffcfc7e235c685caryclark// See also SVG implementation notes: 133355d49053d1b6db42e013eb3409ffcfc7e235c685caryclark// http://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpointToCenter 133455d49053d1b6db42e013eb3409ffcfc7e235c685caryclark// Note that arcSweep bool value is flipped from the original implementation. 133555d49053d1b6db42e013eb3409ffcfc7e235c685caryclarkvoid SkPath::arcTo(SkScalar rx, SkScalar ry, SkScalar angle, SkPath::ArcSize arcLarge, 133655d49053d1b6db42e013eb3409ffcfc7e235c685caryclark SkPath::Direction arcSweep, SkScalar x, SkScalar y) { 1337f1d415188ffb4c34e2886c2cfceb363a148333f1caryclark this->injectMoveToIfNeeded(); 133855d49053d1b6db42e013eb3409ffcfc7e235c685caryclark SkPoint srcPts[2]; 133955d49053d1b6db42e013eb3409ffcfc7e235c685caryclark this->getLastPt(&srcPts[0]); 134055d49053d1b6db42e013eb3409ffcfc7e235c685caryclark // If rx = 0 or ry = 0 then this arc is treated as a straight line segment (a "lineto") 134155d49053d1b6db42e013eb3409ffcfc7e235c685caryclark // joining the endpoints. 134255d49053d1b6db42e013eb3409ffcfc7e235c685caryclark // http://www.w3.org/TR/SVG/implnote.html#ArcOutOfRangeParameters 134355d49053d1b6db42e013eb3409ffcfc7e235c685caryclark if (!rx || !ry) { 1344fc75253c82f838d0e687d05f5d7f82ebe6f26d5bcaryclark this->lineTo(x, y); 134555d49053d1b6db42e013eb3409ffcfc7e235c685caryclark return; 134655d49053d1b6db42e013eb3409ffcfc7e235c685caryclark } 134755d49053d1b6db42e013eb3409ffcfc7e235c685caryclark // If the current point and target point for the arc are identical, it should be treated as a 134855d49053d1b6db42e013eb3409ffcfc7e235c685caryclark // zero length path. This ensures continuity in animations. 134955d49053d1b6db42e013eb3409ffcfc7e235c685caryclark srcPts[1].set(x, y); 135055d49053d1b6db42e013eb3409ffcfc7e235c685caryclark if (srcPts[0] == srcPts[1]) { 1351fc75253c82f838d0e687d05f5d7f82ebe6f26d5bcaryclark this->lineTo(x, y); 135255d49053d1b6db42e013eb3409ffcfc7e235c685caryclark return; 135355d49053d1b6db42e013eb3409ffcfc7e235c685caryclark } 135455d49053d1b6db42e013eb3409ffcfc7e235c685caryclark rx = SkScalarAbs(rx); 135555d49053d1b6db42e013eb3409ffcfc7e235c685caryclark ry = SkScalarAbs(ry); 135655d49053d1b6db42e013eb3409ffcfc7e235c685caryclark SkVector midPointDistance = srcPts[0] - srcPts[1]; 135755d49053d1b6db42e013eb3409ffcfc7e235c685caryclark midPointDistance *= 0.5f; 135855d49053d1b6db42e013eb3409ffcfc7e235c685caryclark 135955d49053d1b6db42e013eb3409ffcfc7e235c685caryclark SkMatrix pointTransform; 136055d49053d1b6db42e013eb3409ffcfc7e235c685caryclark pointTransform.setRotate(-angle); 136155d49053d1b6db42e013eb3409ffcfc7e235c685caryclark 136255d49053d1b6db42e013eb3409ffcfc7e235c685caryclark SkPoint transformedMidPoint; 136355d49053d1b6db42e013eb3409ffcfc7e235c685caryclark pointTransform.mapPoints(&transformedMidPoint, &midPointDistance, 1); 136455d49053d1b6db42e013eb3409ffcfc7e235c685caryclark SkScalar squareRx = rx * rx; 136555d49053d1b6db42e013eb3409ffcfc7e235c685caryclark SkScalar squareRy = ry * ry; 136655d49053d1b6db42e013eb3409ffcfc7e235c685caryclark SkScalar squareX = transformedMidPoint.fX * transformedMidPoint.fX; 136755d49053d1b6db42e013eb3409ffcfc7e235c685caryclark SkScalar squareY = transformedMidPoint.fY * transformedMidPoint.fY; 136855d49053d1b6db42e013eb3409ffcfc7e235c685caryclark 136955d49053d1b6db42e013eb3409ffcfc7e235c685caryclark // Check if the radii are big enough to draw the arc, scale radii if not. 137055d49053d1b6db42e013eb3409ffcfc7e235c685caryclark // http://www.w3.org/TR/SVG/implnote.html#ArcCorrectionOutOfRangeRadii 137155d49053d1b6db42e013eb3409ffcfc7e235c685caryclark SkScalar radiiScale = squareX / squareRx + squareY / squareRy; 137255d49053d1b6db42e013eb3409ffcfc7e235c685caryclark if (radiiScale > 1) { 137355d49053d1b6db42e013eb3409ffcfc7e235c685caryclark radiiScale = SkScalarSqrt(radiiScale); 137455d49053d1b6db42e013eb3409ffcfc7e235c685caryclark rx *= radiiScale; 137555d49053d1b6db42e013eb3409ffcfc7e235c685caryclark ry *= radiiScale; 137655d49053d1b6db42e013eb3409ffcfc7e235c685caryclark } 137755d49053d1b6db42e013eb3409ffcfc7e235c685caryclark 137855d49053d1b6db42e013eb3409ffcfc7e235c685caryclark pointTransform.setScale(1 / rx, 1 / ry); 137955d49053d1b6db42e013eb3409ffcfc7e235c685caryclark pointTransform.preRotate(-angle); 138055d49053d1b6db42e013eb3409ffcfc7e235c685caryclark 138155d49053d1b6db42e013eb3409ffcfc7e235c685caryclark SkPoint unitPts[2]; 138255d49053d1b6db42e013eb3409ffcfc7e235c685caryclark pointTransform.mapPoints(unitPts, srcPts, (int) SK_ARRAY_COUNT(unitPts)); 138355d49053d1b6db42e013eb3409ffcfc7e235c685caryclark SkVector delta = unitPts[1] - unitPts[0]; 138455d49053d1b6db42e013eb3409ffcfc7e235c685caryclark 138555d49053d1b6db42e013eb3409ffcfc7e235c685caryclark SkScalar d = delta.fX * delta.fX + delta.fY * delta.fY; 138655d49053d1b6db42e013eb3409ffcfc7e235c685caryclark SkScalar scaleFactorSquared = SkTMax(1 / d - 0.25f, 0.f); 138755d49053d1b6db42e013eb3409ffcfc7e235c685caryclark 138855d49053d1b6db42e013eb3409ffcfc7e235c685caryclark SkScalar scaleFactor = SkScalarSqrt(scaleFactorSquared); 138955d49053d1b6db42e013eb3409ffcfc7e235c685caryclark if (SkToBool(arcSweep) != SkToBool(arcLarge)) { // flipped from the original implementation 139055d49053d1b6db42e013eb3409ffcfc7e235c685caryclark scaleFactor = -scaleFactor; 139155d49053d1b6db42e013eb3409ffcfc7e235c685caryclark } 139255d49053d1b6db42e013eb3409ffcfc7e235c685caryclark delta.scale(scaleFactor); 139355d49053d1b6db42e013eb3409ffcfc7e235c685caryclark SkPoint centerPoint = unitPts[0] + unitPts[1]; 139455d49053d1b6db42e013eb3409ffcfc7e235c685caryclark centerPoint *= 0.5f; 139555d49053d1b6db42e013eb3409ffcfc7e235c685caryclark centerPoint.offset(-delta.fY, delta.fX); 139655d49053d1b6db42e013eb3409ffcfc7e235c685caryclark unitPts[0] -= centerPoint; 139755d49053d1b6db42e013eb3409ffcfc7e235c685caryclark unitPts[1] -= centerPoint; 139855d49053d1b6db42e013eb3409ffcfc7e235c685caryclark SkScalar theta1 = SkScalarATan2(unitPts[0].fY, unitPts[0].fX); 139955d49053d1b6db42e013eb3409ffcfc7e235c685caryclark SkScalar theta2 = SkScalarATan2(unitPts[1].fY, unitPts[1].fX); 140055d49053d1b6db42e013eb3409ffcfc7e235c685caryclark SkScalar thetaArc = theta2 - theta1; 140155d49053d1b6db42e013eb3409ffcfc7e235c685caryclark if (thetaArc < 0 && !arcSweep) { // arcSweep flipped from the original implementation 140255d49053d1b6db42e013eb3409ffcfc7e235c685caryclark thetaArc += SK_ScalarPI * 2; 140355d49053d1b6db42e013eb3409ffcfc7e235c685caryclark } else if (thetaArc > 0 && arcSweep) { // arcSweep flipped from the original implementation 140455d49053d1b6db42e013eb3409ffcfc7e235c685caryclark thetaArc -= SK_ScalarPI * 2; 140555d49053d1b6db42e013eb3409ffcfc7e235c685caryclark } 140655d49053d1b6db42e013eb3409ffcfc7e235c685caryclark pointTransform.setRotate(angle); 140755d49053d1b6db42e013eb3409ffcfc7e235c685caryclark pointTransform.preScale(rx, ry); 140855d49053d1b6db42e013eb3409ffcfc7e235c685caryclark 140955d49053d1b6db42e013eb3409ffcfc7e235c685caryclark int segments = SkScalarCeilToInt(SkScalarAbs(thetaArc / (SK_ScalarPI / 2))); 141055d49053d1b6db42e013eb3409ffcfc7e235c685caryclark SkScalar thetaWidth = thetaArc / segments; 141155d49053d1b6db42e013eb3409ffcfc7e235c685caryclark SkScalar t = SkScalarTan(0.5f * thetaWidth); 141255d49053d1b6db42e013eb3409ffcfc7e235c685caryclark if (!SkScalarIsFinite(t)) { 141355d49053d1b6db42e013eb3409ffcfc7e235c685caryclark return; 141455d49053d1b6db42e013eb3409ffcfc7e235c685caryclark } 141555d49053d1b6db42e013eb3409ffcfc7e235c685caryclark SkScalar startTheta = theta1; 141655d49053d1b6db42e013eb3409ffcfc7e235c685caryclark SkScalar w = SkScalarSqrt(SK_ScalarHalf + SkScalarCos(thetaWidth) * SK_ScalarHalf); 141755d49053d1b6db42e013eb3409ffcfc7e235c685caryclark for (int i = 0; i < segments; ++i) { 141855d49053d1b6db42e013eb3409ffcfc7e235c685caryclark SkScalar endTheta = startTheta + thetaWidth; 141955d49053d1b6db42e013eb3409ffcfc7e235c685caryclark SkScalar cosEndTheta, sinEndTheta = SkScalarSinCos(endTheta, &cosEndTheta); 142055d49053d1b6db42e013eb3409ffcfc7e235c685caryclark 142155d49053d1b6db42e013eb3409ffcfc7e235c685caryclark unitPts[1].set(cosEndTheta, sinEndTheta); 142255d49053d1b6db42e013eb3409ffcfc7e235c685caryclark unitPts[1] += centerPoint; 142355d49053d1b6db42e013eb3409ffcfc7e235c685caryclark unitPts[0] = unitPts[1]; 142455d49053d1b6db42e013eb3409ffcfc7e235c685caryclark unitPts[0].offset(t * sinEndTheta, -t * cosEndTheta); 142555d49053d1b6db42e013eb3409ffcfc7e235c685caryclark SkPoint mapped[2]; 142655d49053d1b6db42e013eb3409ffcfc7e235c685caryclark pointTransform.mapPoints(mapped, unitPts, (int) SK_ARRAY_COUNT(unitPts)); 142755d49053d1b6db42e013eb3409ffcfc7e235c685caryclark this->conicTo(mapped[0], mapped[1], w); 142855d49053d1b6db42e013eb3409ffcfc7e235c685caryclark startTheta = endTheta; 142955d49053d1b6db42e013eb3409ffcfc7e235c685caryclark } 143055d49053d1b6db42e013eb3409ffcfc7e235c685caryclark} 143155d49053d1b6db42e013eb3409ffcfc7e235c685caryclark 143255d49053d1b6db42e013eb3409ffcfc7e235c685caryclarkvoid SkPath::rArcTo(SkScalar rx, SkScalar ry, SkScalar xAxisRotate, SkPath::ArcSize largeArc, 143355d49053d1b6db42e013eb3409ffcfc7e235c685caryclark SkPath::Direction sweep, SkScalar dx, SkScalar dy) { 143455d49053d1b6db42e013eb3409ffcfc7e235c685caryclark SkPoint currentPoint; 143555d49053d1b6db42e013eb3409ffcfc7e235c685caryclark this->getLastPt(¤tPoint); 143655d49053d1b6db42e013eb3409ffcfc7e235c685caryclark this->arcTo(rx, ry, xAxisRotate, largeArc, sweep, currentPoint.fX + dx, currentPoint.fY + dy); 143755d49053d1b6db42e013eb3409ffcfc7e235c685caryclark} 143855d49053d1b6db42e013eb3409ffcfc7e235c685caryclark 14391cc385b7a427ec8b511c56744a02046a60dd3fd8robertphillips@google.comvoid SkPath::addArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle) { 14408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (oval.isEmpty() || 0 == sweepAngle) { 14418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 14428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 14438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 14448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const SkScalar kFullCircleAngle = SkIntToScalar(360); 14458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 14468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (sweepAngle >= kFullCircleAngle || sweepAngle <= -kFullCircleAngle) { 14471978ce22eb488e3f05670189ea35d9dfae6a6784bsalomon // We can treat the arc as an oval if it begins at one of our legal starting positions. 14481978ce22eb488e3f05670189ea35d9dfae6a6784bsalomon // See SkPath::addOval() docs. 14491978ce22eb488e3f05670189ea35d9dfae6a6784bsalomon SkScalar startOver90 = startAngle / 90.f; 14501978ce22eb488e3f05670189ea35d9dfae6a6784bsalomon SkScalar startOver90I = SkScalarRoundToScalar(startOver90); 14511978ce22eb488e3f05670189ea35d9dfae6a6784bsalomon SkScalar error = startOver90 - startOver90I; 14521978ce22eb488e3f05670189ea35d9dfae6a6784bsalomon if (SkScalarNearlyEqual(error, 0)) { 14531978ce22eb488e3f05670189ea35d9dfae6a6784bsalomon // Index 1 is at startAngle == 0. 14541978ce22eb488e3f05670189ea35d9dfae6a6784bsalomon SkScalar startIndex = std::fmod(startOver90I + 1.f, 4.f); 14551978ce22eb488e3f05670189ea35d9dfae6a6784bsalomon startIndex = startIndex < 0 ? startIndex + 4.f : startIndex; 14561978ce22eb488e3f05670189ea35d9dfae6a6784bsalomon this->addOval(oval, sweepAngle > 0 ? kCW_Direction : kCCW_Direction, 14571978ce22eb488e3f05670189ea35d9dfae6a6784bsalomon (unsigned) startIndex); 14581978ce22eb488e3f05670189ea35d9dfae6a6784bsalomon return; 14591978ce22eb488e3f05670189ea35d9dfae6a6784bsalomon } 14608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 14611978ce22eb488e3f05670189ea35d9dfae6a6784bsalomon this->arcTo(oval, startAngle, sweepAngle, true); 14628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 14638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 14648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/* 14658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com Need to handle the case when the angle is sharp, and our computed end-points 14668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com for the arc go behind pt1 and/or p2... 14678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com*/ 1468c778904a5b686617ad7fdec850ddc21e103dca0freedvoid SkPath::arcTo(SkScalar x1, SkScalar y1, SkScalar x2, SkScalar y2, SkScalar radius) { 1469a8b326c01a92e7f331c2c5dcf75cd7ce7a99ce73reed if (radius == 0) { 1470a8b326c01a92e7f331c2c5dcf75cd7ce7a99ce73reed this->lineTo(x1, y1); 1471a8b326c01a92e7f331c2c5dcf75cd7ce7a99ce73reed return; 1472a8b326c01a92e7f331c2c5dcf75cd7ce7a99ce73reed } 1473a8b326c01a92e7f331c2c5dcf75cd7ce7a99ce73reed 1474a8b326c01a92e7f331c2c5dcf75cd7ce7a99ce73reed SkVector before, after; 1475abf15c189b6333aa77a6c3f566cc67f4634ba338reed@google.com 14768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // need to know our prev pt so we can construct tangent vectors 14778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com { 14788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPoint start; 14798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com this->getLastPt(&start); 148060eaa398ebdded0fb7957724c170baabef811e17senorblanco@chromium.org // Handle degenerate cases by adding a line to the first point and 148160eaa398ebdded0fb7957724c170baabef811e17senorblanco@chromium.org // bailing out. 14828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com before.setNormalize(x1 - start.fX, y1 - start.fY); 14838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com after.setNormalize(x2 - x1, y2 - y1); 14848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1485abf15c189b6333aa77a6c3f566cc67f4634ba338reed@google.com 14868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar cosh = SkPoint::DotProduct(before, after); 14878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkScalar sinh = SkPoint::CrossProduct(before, after); 14888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 14898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (SkScalarNearlyZero(sinh)) { // angle is too tight 149060eaa398ebdded0fb7957724c170baabef811e17senorblanco@chromium.org this->lineTo(x1, y1); 14918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 14928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1493abf15c189b6333aa77a6c3f566cc67f4634ba338reed@google.com 1494a99b6ceff92183b424634f2e7276b9ea1d59e69dMike Reed SkScalar dist = SkScalarAbs(radius * (1 - cosh) / sinh); 14958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1496a99b6ceff92183b424634f2e7276b9ea1d59e69dMike Reed SkScalar xx = x1 - dist * before.fX; 1497a99b6ceff92183b424634f2e7276b9ea1d59e69dMike Reed SkScalar yy = y1 - dist * before.fY; 149888651aeb551fb02003a7600679e8e7df8a589e7fcaryclark after.setLength(dist); 149988651aeb551fb02003a7600679e8e7df8a589e7fcaryclark this->lineTo(xx, yy); 150088651aeb551fb02003a7600679e8e7df8a589e7fcaryclark SkScalar weight = SkScalarSqrt(SK_ScalarHalf + cosh * SK_ScalarHalf); 150188651aeb551fb02003a7600679e8e7df8a589e7fcaryclark this->conicTo(x1, y1, x1 + after.fX, y1 + after.fY, weight); 15028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 15038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 15048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////////////////////////////////////////////////////////////// 15058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 150614747e58f8127a6d6b3c748bf0642b0d6a3a79e8commit-bot@chromium.orgvoid SkPath::addPath(const SkPath& path, SkScalar dx, SkScalar dy, AddPathMode mode) { 15078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMatrix matrix; 15088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 15098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com matrix.setTranslate(dx, dy); 151014747e58f8127a6d6b3c748bf0642b0d6a3a79e8commit-bot@chromium.org this->addPath(path, matrix, mode); 15118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 15128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 151314747e58f8127a6d6b3c748bf0642b0d6a3a79e8commit-bot@chromium.orgvoid SkPath::addPath(const SkPath& path, const SkMatrix& matrix, AddPathMode mode) { 15141dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com SkPathRef::Editor(&fPathRef, path.countVerbs(), path.countPoints()); 15158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 15166630d8d8ea7a897a18e3d950bab9fa40f065804aschenney@chromium.org RawIter iter(path); 15178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPoint pts[4]; 15188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com Verb verb; 15198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 15208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMatrix::MapPtsProc proc = matrix.getMapPtsProc(); 152114747e58f8127a6d6b3c748bf0642b0d6a3a79e8commit-bot@chromium.org bool firstVerb = true; 15228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com while ((verb = iter.next(pts)) != kDone_Verb) { 15238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com switch (verb) { 15248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com case kMove_Verb: 15258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com proc(matrix, &pts[0], &pts[0], 1); 152614747e58f8127a6d6b3c748bf0642b0d6a3a79e8commit-bot@chromium.org if (firstVerb && mode == kExtend_AddPathMode && !isEmpty()) { 152714747e58f8127a6d6b3c748bf0642b0d6a3a79e8commit-bot@chromium.org injectMoveToIfNeeded(); // In case last contour is closed 152814747e58f8127a6d6b3c748bf0642b0d6a3a79e8commit-bot@chromium.org this->lineTo(pts[0]); 152914747e58f8127a6d6b3c748bf0642b0d6a3a79e8commit-bot@chromium.org } else { 153014747e58f8127a6d6b3c748bf0642b0d6a3a79e8commit-bot@chromium.org this->moveTo(pts[0]); 153114747e58f8127a6d6b3c748bf0642b0d6a3a79e8commit-bot@chromium.org } 15328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 15338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com case kLine_Verb: 15348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com proc(matrix, &pts[1], &pts[1], 1); 15358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com this->lineTo(pts[1]); 15368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 15378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com case kQuad_Verb: 15388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com proc(matrix, &pts[1], &pts[1], 2); 15398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com this->quadTo(pts[1], pts[2]); 15408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 1541277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com case kConic_Verb: 1542277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com proc(matrix, &pts[1], &pts[1], 2); 1543277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com this->conicTo(pts[1], pts[2], iter.conicWeight()); 1544277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com break; 15458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com case kCubic_Verb: 15468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com proc(matrix, &pts[1], &pts[1], 3); 15478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com this->cubicTo(pts[1], pts[2], pts[3]); 15488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 15498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com case kClose_Verb: 15508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com this->close(); 15518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 15528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com default: 15530c00f21fee3f5cfa3aa7e5d46ff94cb8cf340451tomhudson@google.com SkDEBUGFAIL("unknown verb"); 15548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 155514747e58f8127a6d6b3c748bf0642b0d6a3a79e8commit-bot@chromium.org firstVerb = false; 15568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 15578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 15588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 15598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////////////////////////////////////////////////////////////// 15608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1561277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.comstatic int pts_in_verb(unsigned verb) { 1562277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com static const uint8_t gPtsInVerb[] = { 1563277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com 1, // kMove 1564277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com 1, // kLine 1565277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com 2, // kQuad 1566277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com 2, // kConic 1567277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com 3, // kCubic 1568277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com 0, // kClose 1569277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com 0 // kDone 1570277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com }; 1571277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com 1572277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com SkASSERT(verb < SK_ARRAY_COUNT(gPtsInVerb)); 1573277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com return gPtsInVerb[verb]; 1574277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com} 15758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 15768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// ignore the last point of the 1st contour 15778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkPath::reversePathTo(const SkPath& path) { 157851c5678f258736736c4a5d48d4e82c73be225428caryclark const uint8_t* verbs = path.fPathRef->verbsMemBegin(); // points at the last verb 157951c5678f258736736c4a5d48d4e82c73be225428caryclark if (!verbs) { // empty path returns nullptr 15808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 15818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 158251c5678f258736736c4a5d48d4e82c73be225428caryclark const uint8_t* verbsEnd = path.fPathRef->verbs() - 1; // points just past the first verb 158351c5678f258736736c4a5d48d4e82c73be225428caryclark SkASSERT(verbsEnd[0] == kMove_Verb); 158451c5678f258736736c4a5d48d4e82c73be225428caryclark const SkPoint* pts = path.fPathRef->pointsEnd() - 1; 158551c5678f258736736c4a5d48d4e82c73be225428caryclark const SkScalar* conicWeights = path.fPathRef->conicWeightsEnd(); 15868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 158751c5678f258736736c4a5d48d4e82c73be225428caryclark while (verbs < verbsEnd) { 158851c5678f258736736c4a5d48d4e82c73be225428caryclark uint8_t v = *verbs++; 158951c5678f258736736c4a5d48d4e82c73be225428caryclark pts -= pts_in_verb(v); 159051c5678f258736736c4a5d48d4e82c73be225428caryclark switch (v) { 159151c5678f258736736c4a5d48d4e82c73be225428caryclark case kMove_Verb: 159251c5678f258736736c4a5d48d4e82c73be225428caryclark // if the path has multiple contours, stop after reversing the last 159351c5678f258736736c4a5d48d4e82c73be225428caryclark return; 15948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com case kLine_Verb: 159551c5678f258736736c4a5d48d4e82c73be225428caryclark this->lineTo(pts[0]); 15968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 15978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com case kQuad_Verb: 159851c5678f258736736c4a5d48d4e82c73be225428caryclark this->quadTo(pts[1], pts[0]); 15998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 1600277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com case kConic_Verb: 160151c5678f258736736c4a5d48d4e82c73be225428caryclark this->conicTo(pts[1], pts[0], *--conicWeights); 1602277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com break; 16038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com case kCubic_Verb: 160451c5678f258736736c4a5d48d4e82c73be225428caryclark this->cubicTo(pts[2], pts[1], pts[0]); 160551c5678f258736736c4a5d48d4e82c73be225428caryclark break; 160651c5678f258736736c4a5d48d4e82c73be225428caryclark case kClose_Verb: 160751c5678f258736736c4a5d48d4e82c73be225428caryclark SkASSERT(verbs - path.fPathRef->verbsMemBegin() == 1); 16088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 16098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com default: 16100c00f21fee3f5cfa3aa7e5d46ff94cb8cf340451tomhudson@google.com SkDEBUGFAIL("bad verb"); 16118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 16128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 16138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 16148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 16158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 161663d73749fbe36491403ea521005fd298dc70a94creed@google.comvoid SkPath::reverseAddPath(const SkPath& src) { 16171dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com SkPathRef::Editor ed(&fPathRef, src.fPathRef->countPoints(), src.fPathRef->countVerbs()); 161863d73749fbe36491403ea521005fd298dc70a94creed@google.com 16191dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com const SkPoint* pts = src.fPathRef->pointsEnd(); 16201dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com // we will iterator through src's verbs backwards 16211dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com const uint8_t* verbs = src.fPathRef->verbsMemBegin(); // points at the last verb 16221dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com const uint8_t* verbsEnd = src.fPathRef->verbs(); // points just past the first verb 1623277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com const SkScalar* conicWeights = src.fPathRef->conicWeightsEnd(); 162463d73749fbe36491403ea521005fd298dc70a94creed@google.com 162563d73749fbe36491403ea521005fd298dc70a94creed@google.com bool needMove = true; 162663d73749fbe36491403ea521005fd298dc70a94creed@google.com bool needClose = false; 16271dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com while (verbs < verbsEnd) { 16281dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com uint8_t v = *(verbs++); 1629277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com int n = pts_in_verb(v); 163063d73749fbe36491403ea521005fd298dc70a94creed@google.com 163163d73749fbe36491403ea521005fd298dc70a94creed@google.com if (needMove) { 163263d73749fbe36491403ea521005fd298dc70a94creed@google.com --pts; 163363d73749fbe36491403ea521005fd298dc70a94creed@google.com this->moveTo(pts->fX, pts->fY); 163463d73749fbe36491403ea521005fd298dc70a94creed@google.com needMove = false; 163563d73749fbe36491403ea521005fd298dc70a94creed@google.com } 163663d73749fbe36491403ea521005fd298dc70a94creed@google.com pts -= n; 163763d73749fbe36491403ea521005fd298dc70a94creed@google.com switch (v) { 163863d73749fbe36491403ea521005fd298dc70a94creed@google.com case kMove_Verb: 163963d73749fbe36491403ea521005fd298dc70a94creed@google.com if (needClose) { 164063d73749fbe36491403ea521005fd298dc70a94creed@google.com this->close(); 164163d73749fbe36491403ea521005fd298dc70a94creed@google.com needClose = false; 164263d73749fbe36491403ea521005fd298dc70a94creed@google.com } 164363d73749fbe36491403ea521005fd298dc70a94creed@google.com needMove = true; 164463d73749fbe36491403ea521005fd298dc70a94creed@google.com pts += 1; // so we see the point in "if (needMove)" above 164563d73749fbe36491403ea521005fd298dc70a94creed@google.com break; 164663d73749fbe36491403ea521005fd298dc70a94creed@google.com case kLine_Verb: 164763d73749fbe36491403ea521005fd298dc70a94creed@google.com this->lineTo(pts[0]); 164863d73749fbe36491403ea521005fd298dc70a94creed@google.com break; 164963d73749fbe36491403ea521005fd298dc70a94creed@google.com case kQuad_Verb: 165063d73749fbe36491403ea521005fd298dc70a94creed@google.com this->quadTo(pts[1], pts[0]); 165163d73749fbe36491403ea521005fd298dc70a94creed@google.com break; 1652277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com case kConic_Verb: 1653277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com this->conicTo(pts[1], pts[0], *--conicWeights); 1654277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com break; 165563d73749fbe36491403ea521005fd298dc70a94creed@google.com case kCubic_Verb: 165663d73749fbe36491403ea521005fd298dc70a94creed@google.com this->cubicTo(pts[2], pts[1], pts[0]); 165763d73749fbe36491403ea521005fd298dc70a94creed@google.com break; 165863d73749fbe36491403ea521005fd298dc70a94creed@google.com case kClose_Verb: 165963d73749fbe36491403ea521005fd298dc70a94creed@google.com needClose = true; 166063d73749fbe36491403ea521005fd298dc70a94creed@google.com break; 166163d73749fbe36491403ea521005fd298dc70a94creed@google.com default: 1662330313a8a8343876ee596da39da06a5d69badd9cmtklein@google.com SkDEBUGFAIL("unexpected verb"); 166363d73749fbe36491403ea521005fd298dc70a94creed@google.com } 166463d73749fbe36491403ea521005fd298dc70a94creed@google.com } 166563d73749fbe36491403ea521005fd298dc70a94creed@google.com} 166663d73749fbe36491403ea521005fd298dc70a94creed@google.com 16678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////////////////////////////////////////////////////////////// 16688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 16698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkPath::offset(SkScalar dx, SkScalar dy, SkPath* dst) const { 16708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMatrix matrix; 16718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 16728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com matrix.setTranslate(dx, dy); 16738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com this->transform(matrix, dst); 16748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 16758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 16768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic void subdivide_cubic_to(SkPath* path, const SkPoint pts[4], 16778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com int level = 2) { 16788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (--level >= 0) { 16798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPoint tmp[7]; 16808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 16818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkChopCubicAtHalf(pts, tmp); 16828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com subdivide_cubic_to(path, &tmp[0], level); 16838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com subdivide_cubic_to(path, &tmp[3], level); 16848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 16858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com path->cubicTo(pts[1], pts[2], pts[3]); 16868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 16878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 16888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 16898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkPath::transform(const SkMatrix& matrix, SkPath* dst) const { 16908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDEBUGCODE(this->validate();) 169196fcdcc219d2a0d3579719b84b28bede76efba64halcanary if (dst == nullptr) { 16928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com dst = (SkPath*)this; 16938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 16948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 16958d430185e08d2067584837a76b7193b803fee7a0tomhudson@google.com if (matrix.hasPerspective()) { 16968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPath tmp; 16978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com tmp.fFillType = fFillType; 16988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 16998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPath::Iter iter(*this, false); 17008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPoint pts[4]; 17018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPath::Verb verb; 17028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 17034a3b714d73e585a3985d614600c6b79d5c8b1f1ereed@google.com while ((verb = iter.next(pts, false)) != kDone_Verb) { 17048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com switch (verb) { 17058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com case kMove_Verb: 17068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com tmp.moveTo(pts[0]); 17078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 17088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com case kLine_Verb: 17098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com tmp.lineTo(pts[1]); 17108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 17118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com case kQuad_Verb: 1712220f926d9d4b38a9018c922c095847bbd261f583reed // promote the quad to a conic 1713220f926d9d4b38a9018c922c095847bbd261f583reed tmp.conicTo(pts[1], pts[2], 1714220f926d9d4b38a9018c922c095847bbd261f583reed SkConic::TransformW(pts, SK_Scalar1, matrix)); 17158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 1716277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com case kConic_Verb: 1717220f926d9d4b38a9018c922c095847bbd261f583reed tmp.conicTo(pts[1], pts[2], 1718220f926d9d4b38a9018c922c095847bbd261f583reed SkConic::TransformW(pts, iter.conicWeight(), matrix)); 1719277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com break; 17208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com case kCubic_Verb: 17218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com subdivide_cubic_to(&tmp, pts); 17228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 17238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com case kClose_Verb: 17248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com tmp.close(); 17258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 17268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com default: 17270c00f21fee3f5cfa3aa7e5d46ff94cb8cf340451tomhudson@google.com SkDEBUGFAIL("unknown verb"); 17288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 17298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 17308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 17318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 17328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com dst->swap(tmp); 17331dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com SkPathRef::Editor ed(&dst->fPathRef); 17341dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com matrix.mapPoints(ed.points(), ed.pathRef()->countPoints()); 1735026beb52a29a620290fcfb24f1e7e9e75547b80freed dst->fFirstDirection = SkPathPriv::kUnknown_FirstDirection; 17368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 17371dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com SkPathRef::CreateTransformedCopy(&dst->fPathRef, *fPathRef.get(), matrix); 17381dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com 17398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (this != dst) { 17408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com dst->fFillType = fFillType; 17412a6f8abf35ff8c2640c24478d9d2eaedff5e78eareed@google.com dst->fConvexity = fConvexity; 1742b3eb687f8a89eb1eacd1afb4016401eb392f66abjvanverth dst->fIsVolatile = fIsVolatile; 17438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 17446aa2965ca814dd3329b65398b5c5af980e54b101bsalomon@google.com 1745026beb52a29a620290fcfb24f1e7e9e75547b80freed if (SkPathPriv::kUnknown_FirstDirection == fFirstDirection) { 1746026beb52a29a620290fcfb24f1e7e9e75547b80freed dst->fFirstDirection = SkPathPriv::kUnknown_FirstDirection; 174730c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com } else { 174830c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com SkScalar det2x2 = 1749a99b6ceff92183b424634f2e7276b9ea1d59e69dMike Reed matrix.get(SkMatrix::kMScaleX) * matrix.get(SkMatrix::kMScaleY) - 1750a99b6ceff92183b424634f2e7276b9ea1d59e69dMike Reed matrix.get(SkMatrix::kMSkewX) * matrix.get(SkMatrix::kMSkewY); 175130c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com if (det2x2 < 0) { 17529f4dbca3290cfaca7dd17b71eb6b5b3a0ba5323eherb dst->fFirstDirection = SkPathPriv::OppositeFirstDirection( 17539f4dbca3290cfaca7dd17b71eb6b5b3a0ba5323eherb (SkPathPriv::FirstDirection)fFirstDirection.load()); 175430c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com } else if (det2x2 > 0) { 17559f4dbca3290cfaca7dd17b71eb6b5b3a0ba5323eherb dst->fFirstDirection = fFirstDirection.load(); 175630c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com } else { 1757a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org dst->fConvexity = kUnknown_Convexity; 1758026beb52a29a620290fcfb24f1e7e9e75547b80freed dst->fFirstDirection = SkPathPriv::kUnknown_FirstDirection; 175930c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com } 176030c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com } 176130c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com 17628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDEBUGCODE(dst->validate();) 17638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 17648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 17658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 17668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////////////////////////////////////////////////////////////// 17678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////////////////////////////////////////////////////////////// 17688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 17694da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.orgenum SegmentState { 1770fde6b414d9cbfb69c7c3b046dab78e748d8d2ed4schenney@chromium.org kEmptyContour_SegmentState, // The current contour is empty. We may be 1771fde6b414d9cbfb69c7c3b046dab78e748d8d2ed4schenney@chromium.org // starting processing or we may have just 1772fde6b414d9cbfb69c7c3b046dab78e748d8d2ed4schenney@chromium.org // closed a contour. 17734da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org kAfterMove_SegmentState, // We have seen a move, but nothing else. 17744da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org kAfterPrimitive_SegmentState // We have seen a primitive but not yet 17754da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org // closed the path. Also the initial state. 17768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}; 17778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 17788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkPath::Iter::Iter() { 17798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_DEBUG 178096fcdcc219d2a0d3579719b84b28bede76efba64halcanary fPts = nullptr; 178196fcdcc219d2a0d3579719b84b28bede76efba64halcanary fConicWeights = nullptr; 17828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fMoveTo.fX = fMoveTo.fY = fLastPt.fX = fLastPt.fY = 0; 17834da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org fForceClose = fCloseLine = false; 1784fde6b414d9cbfb69c7c3b046dab78e748d8d2ed4schenney@chromium.org fSegmentState = kEmptyContour_SegmentState; 17858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif 17868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // need to init enough to make next() harmlessly return kDone_Verb 178796fcdcc219d2a0d3579719b84b28bede76efba64halcanary fVerbs = nullptr; 178896fcdcc219d2a0d3579719b84b28bede76efba64halcanary fVerbStop = nullptr; 17898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fNeedClose = false; 17908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 17918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 17928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkPath::Iter::Iter(const SkPath& path, bool forceClose) { 17938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com this->setPath(path, forceClose); 17948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 17958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 17968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkPath::Iter::setPath(const SkPath& path, bool forceClose) { 17971dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com fPts = path.fPathRef->points(); 17981dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com fVerbs = path.fPathRef->verbs(); 17991dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com fVerbStop = path.fPathRef->verbsMemBegin(); 18006942442ef7cc018ac136dd379ad6a30902a060e5caryclark fConicWeights = path.fPathRef->conicWeights(); 18016942442ef7cc018ac136dd379ad6a30902a060e5caryclark if (fConicWeights) { 18026942442ef7cc018ac136dd379ad6a30902a060e5caryclark fConicWeights -= 1; // begin one behind 18036942442ef7cc018ac136dd379ad6a30902a060e5caryclark } 18044da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org fLastPt.fX = fLastPt.fY = 0; 180572785c4c8928a8b0fc5bbdb48929f9356554daceschenney@chromium.org fMoveTo.fX = fMoveTo.fY = 0; 18068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fForceClose = SkToU8(forceClose); 18078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fNeedClose = false; 1808fde6b414d9cbfb69c7c3b046dab78e748d8d2ed4schenney@chromium.org fSegmentState = kEmptyContour_SegmentState; 18098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 18108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 18118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkPath::Iter::isClosedContour() const { 181296fcdcc219d2a0d3579719b84b28bede76efba64halcanary if (fVerbs == nullptr || fVerbs == fVerbStop) { 18138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return false; 18148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 18158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (fForceClose) { 18168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return true; 18178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 18188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 18198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const uint8_t* verbs = fVerbs; 18208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const uint8_t* stop = fVerbStop; 1821abf15c189b6333aa77a6c3f566cc67f4634ba338reed@google.com 18221dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com if (kMove_Verb == *(verbs - 1)) { 18231dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com verbs -= 1; // skip the initial moveto 18248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 18258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 18261dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com while (verbs > stop) { 18271dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com // verbs points one beyond the current verb, decrement first. 18281dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com unsigned v = *(--verbs); 18298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (kMove_Verb == v) { 18308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 18318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 18328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (kClose_Verb == v) { 18338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return true; 18348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 18358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 18368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return false; 18378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 18388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 18398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkPath::Verb SkPath::Iter::autoClose(SkPoint pts[2]) { 18409e25dbf589539dd44244bc2581590bd7591e17a2reed@google.com SkASSERT(pts); 18418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (fLastPt != fMoveTo) { 18424ddfe357da4a94f587b6ca18b398c23478fa1b24reed@android.com // A special case: if both points are NaN, SkPoint::operation== returns 18434ddfe357da4a94f587b6ca18b398c23478fa1b24reed@android.com // false, but the iterator expects that they are treated as the same. 18444ddfe357da4a94f587b6ca18b398c23478fa1b24reed@android.com // (consider SkPoint is a 2-dimension float point). 18459da1ae3f35a6f25adf4f58ae2589129ceec6d11breed@android.com if (SkScalarIsNaN(fLastPt.fX) || SkScalarIsNaN(fLastPt.fY) || 18469da1ae3f35a6f25adf4f58ae2589129ceec6d11breed@android.com SkScalarIsNaN(fMoveTo.fX) || SkScalarIsNaN(fMoveTo.fY)) { 18474ddfe357da4a94f587b6ca18b398c23478fa1b24reed@android.com return kClose_Verb; 18484ddfe357da4a94f587b6ca18b398c23478fa1b24reed@android.com } 18494ddfe357da4a94f587b6ca18b398c23478fa1b24reed@android.com 18509e25dbf589539dd44244bc2581590bd7591e17a2reed@google.com pts[0] = fLastPt; 18519e25dbf589539dd44244bc2581590bd7591e17a2reed@google.com pts[1] = fMoveTo; 18528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fLastPt = fMoveTo; 18538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fCloseLine = true; 18548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return kLine_Verb; 1855b3b8dfa31326c51dab8b5ed569e19ee715582d1bbsalomon@google.com } else { 1856b3b8dfa31326c51dab8b5ed569e19ee715582d1bbsalomon@google.com pts[0] = fMoveTo; 1857b3b8dfa31326c51dab8b5ed569e19ee715582d1bbsalomon@google.com return kClose_Verb; 18588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 18598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 18608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 18619e25dbf589539dd44244bc2581590bd7591e17a2reed@google.comconst SkPoint& SkPath::Iter::cons_moveTo() { 18624da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org if (fSegmentState == kAfterMove_SegmentState) { 18634da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org // Set the first return pt to the move pt 18644da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org fSegmentState = kAfterPrimitive_SegmentState; 18659e25dbf589539dd44244bc2581590bd7591e17a2reed@google.com return fMoveTo; 18668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 18674da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org SkASSERT(fSegmentState == kAfterPrimitive_SegmentState); 18684da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org // Set the first return pt to the last pt of the previous primitive. 18699e25dbf589539dd44244bc2581590bd7591e17a2reed@google.com return fPts[-1]; 18708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 18718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 18728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1873e8c5666e0387e70bd921e01558e627af3f1411dbcaryclarkvoid SkPath::Iter::consumeDegenerateSegments(bool exact) { 18744da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org // We need to step over anything that will not move the current draw point 18754da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org // forward before the next move is seen 18764da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org const uint8_t* lastMoveVerb = 0; 18774da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org const SkPoint* lastMovePt = 0; 187896fcdcc219d2a0d3579719b84b28bede76efba64halcanary const SkScalar* lastMoveWeight = nullptr; 18794da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org SkPoint lastPt = fLastPt; 18804da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org while (fVerbs != fVerbStop) { 18811dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com unsigned verb = *(fVerbs - 1); // fVerbs is one beyond the current verb 18824da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org switch (verb) { 18834da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org case kMove_Verb: 18844da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org // Keep a record of this most recent move 18854da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org lastMoveVerb = fVerbs; 18864da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org lastMovePt = fPts; 1887b8de1f46594c3cd9c537f0b128c6d6eb30a9f463robertphillips lastMoveWeight = fConicWeights; 1888b0af6dad94f3c51ea0d5d6426a9509354338c6b2schenney@chromium.org lastPt = fPts[0]; 18891dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com fVerbs--; 18904da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org fPts++; 18914da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org break; 18924da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org 18934da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org case kClose_Verb: 18947e963605d5b8177c30afa0d8e5541b0fbe1b6e13schenney@chromium.org // A close when we are in a segment is always valid except when it 18957e963605d5b8177c30afa0d8e5541b0fbe1b6e13schenney@chromium.org // follows a move which follows a segment. 18967e963605d5b8177c30afa0d8e5541b0fbe1b6e13schenney@chromium.org if (fSegmentState == kAfterPrimitive_SegmentState && !lastMoveVerb) { 18974da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org return; 18984da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org } 18994da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org // A close at any other time must be ignored 19001dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com fVerbs--; 19014da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org break; 19024da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org 19034da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org case kLine_Verb: 1904e8c5666e0387e70bd921e01558e627af3f1411dbcaryclark if (!IsLineDegenerate(lastPt, fPts[0], exact)) { 19054da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org if (lastMoveVerb) { 19064da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org fVerbs = lastMoveVerb; 19074da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org fPts = lastMovePt; 1908b8de1f46594c3cd9c537f0b128c6d6eb30a9f463robertphillips fConicWeights = lastMoveWeight; 19094da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org return; 19104da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org } 19114da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org return; 19124da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org } 19134da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org // Ignore this line and continue 19141dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com fVerbs--; 19154da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org fPts++; 19164da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org break; 19174da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org 1918277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com case kConic_Verb: 19194da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org case kQuad_Verb: 1920e8c5666e0387e70bd921e01558e627af3f1411dbcaryclark if (!IsQuadDegenerate(lastPt, fPts[0], fPts[1], exact)) { 19214da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org if (lastMoveVerb) { 19224da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org fVerbs = lastMoveVerb; 19234da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org fPts = lastMovePt; 1924b8de1f46594c3cd9c537f0b128c6d6eb30a9f463robertphillips fConicWeights = lastMoveWeight; 19254da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org return; 19264da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org } 19274da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org return; 19284da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org } 19294da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org // Ignore this line and continue 19301dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com fVerbs--; 19314da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org fPts += 2; 1932277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com fConicWeights += (kConic_Verb == verb); 19334da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org break; 19344da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org 19354da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org case kCubic_Verb: 1936e8c5666e0387e70bd921e01558e627af3f1411dbcaryclark if (!IsCubicDegenerate(lastPt, fPts[0], fPts[1], fPts[2], exact)) { 19374da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org if (lastMoveVerb) { 19384da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org fVerbs = lastMoveVerb; 19394da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org fPts = lastMovePt; 1940b8de1f46594c3cd9c537f0b128c6d6eb30a9f463robertphillips fConicWeights = lastMoveWeight; 19414da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org return; 19424da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org } 19434da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org return; 19444da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org } 19454da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org // Ignore this line and continue 19461dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com fVerbs--; 19474da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org fPts += 3; 19484da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org break; 1949b0af6dad94f3c51ea0d5d6426a9509354338c6b2schenney@chromium.org 19504da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org default: 19510c00f21fee3f5cfa3aa7e5d46ff94cb8cf340451tomhudson@google.com SkDEBUGFAIL("Should never see kDone_Verb"); 19524da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org } 19534da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org } 19544da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org} 19554da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org 19564a3b714d73e585a3985d614600c6b79d5c8b1f1ereed@google.comSkPath::Verb SkPath::Iter::doNext(SkPoint ptsParam[4]) { 19579e25dbf589539dd44244bc2581590bd7591e17a2reed@google.com SkASSERT(ptsParam); 19584da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org 19598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (fVerbs == fVerbStop) { 19604da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org // Close the curve if requested and if there is some curve to close 19614da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org if (fNeedClose && fSegmentState == kAfterPrimitive_SegmentState) { 19629e25dbf589539dd44244bc2581590bd7591e17a2reed@google.com if (kLine_Verb == this->autoClose(ptsParam)) { 19638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return kLine_Verb; 19648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 19658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fNeedClose = false; 19668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return kClose_Verb; 19678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 19688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return kDone_Verb; 19698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 19708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 19711dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com // fVerbs is one beyond the current verb, decrement first 19721dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com unsigned verb = *(--fVerbs); 19739e25dbf589539dd44244bc2581590bd7591e17a2reed@google.com const SkPoint* SK_RESTRICT srcPts = fPts; 19749e25dbf589539dd44244bc2581590bd7591e17a2reed@google.com SkPoint* SK_RESTRICT pts = ptsParam; 19758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 19768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com switch (verb) { 19778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com case kMove_Verb: 19788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (fNeedClose) { 19791dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com fVerbs++; // move back one verb 19808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com verb = this->autoClose(pts); 19818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (verb == kClose_Verb) { 19828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fNeedClose = false; 19838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 19848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return (Verb)verb; 19858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 19868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (fVerbs == fVerbStop) { // might be a trailing moveto 19878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return kDone_Verb; 19888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1989b0af6dad94f3c51ea0d5d6426a9509354338c6b2schenney@chromium.org fMoveTo = *srcPts; 19909e25dbf589539dd44244bc2581590bd7591e17a2reed@google.com pts[0] = *srcPts; 19918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com srcPts += 1; 1992b0af6dad94f3c51ea0d5d6426a9509354338c6b2schenney@chromium.org fSegmentState = kAfterMove_SegmentState; 19934da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org fLastPt = fMoveTo; 19948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fNeedClose = fForceClose; 19958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 19968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com case kLine_Verb: 19979e25dbf589539dd44244bc2581590bd7591e17a2reed@google.com pts[0] = this->cons_moveTo(); 19989e25dbf589539dd44244bc2581590bd7591e17a2reed@google.com pts[1] = srcPts[0]; 19998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fLastPt = srcPts[0]; 20008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fCloseLine = false; 20018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com srcPts += 1; 20028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 2003277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com case kConic_Verb: 2004277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com fConicWeights += 1; 2005277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com // fall-through 20068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com case kQuad_Verb: 20079e25dbf589539dd44244bc2581590bd7591e17a2reed@google.com pts[0] = this->cons_moveTo(); 20089e25dbf589539dd44244bc2581590bd7591e17a2reed@google.com memcpy(&pts[1], srcPts, 2 * sizeof(SkPoint)); 20098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fLastPt = srcPts[1]; 20108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com srcPts += 2; 20118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 20128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com case kCubic_Verb: 20139e25dbf589539dd44244bc2581590bd7591e17a2reed@google.com pts[0] = this->cons_moveTo(); 20149e25dbf589539dd44244bc2581590bd7591e17a2reed@google.com memcpy(&pts[1], srcPts, 3 * sizeof(SkPoint)); 20158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fLastPt = srcPts[2]; 20168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com srcPts += 3; 20178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 20188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com case kClose_Verb: 20198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com verb = this->autoClose(pts); 20208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (verb == kLine_Verb) { 20211dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com fVerbs++; // move back one verb 20228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 20238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fNeedClose = false; 2024fde6b414d9cbfb69c7c3b046dab78e748d8d2ed4schenney@chromium.org fSegmentState = kEmptyContour_SegmentState; 20258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 20264da06ab3351f2a96f9216d96106db33a77b19644schenney@chromium.org fLastPt = fMoveTo; 20278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 20288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 20298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fPts = srcPts; 20308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return (Verb)verb; 20318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 20328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 20338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////////////////////////////////////////////////////////////// 20348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 20358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/* 203694e75ee46a569cbcdf61fb7f04ee3a69d3ca0896djsollen@google.com Format in compressed buffer: [ptCount, verbCount, pts[], verbs[]] 20378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com*/ 20388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 20394faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.orgsize_t SkPath::writeToMemory(void* storage) const { 20408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDEBUGCODE(this->validate();) 20418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 204296fcdcc219d2a0d3579719b84b28bede76efba64halcanary if (nullptr == storage) { 20436900641e02c3b6c7ee15d0aa5bd4af0d42db480fcaryclark const int byteCount = sizeof(int32_t) * 2 + fPathRef->writeSize(); 204494e75ee46a569cbcdf61fb7f04ee3a69d3ca0896djsollen@google.com return SkAlign4(byteCount); 204594e75ee46a569cbcdf61fb7f04ee3a69d3ca0896djsollen@google.com } 204694e75ee46a569cbcdf61fb7f04ee3a69d3ca0896djsollen@google.com 204794e75ee46a569cbcdf61fb7f04ee3a69d3ca0896djsollen@google.com SkWBuffer buffer(storage); 204801ec2eb42e9c64f8d06afd51f80c055710147141robertphillips@google.com 2049466310dbd3073add2ec934e336c30deaaf702eaerobertphillips@google.com int32_t packed = (fConvexity << kConvexity_SerializationShift) | 205001ec2eb42e9c64f8d06afd51f80c055710147141robertphillips@google.com (fFillType << kFillType_SerializationShift) | 2051026beb52a29a620290fcfb24f1e7e9e75547b80freed (fFirstDirection << kDirection_SerializationShift) | 20528f086023bf615b2661b82bcf59cdedde78ad7374reed (fIsVolatile << kIsVolatile_SerializationShift) | 20538f086023bf615b2661b82bcf59cdedde78ad7374reed kCurrent_Version; 205401ec2eb42e9c64f8d06afd51f80c055710147141robertphillips@google.com 20552972bb5fd2441709026b350c6b9b66eecd80f868robertphillips@google.com buffer.write32(packed); 20566900641e02c3b6c7ee15d0aa5bd4af0d42db480fcaryclark buffer.write32(fLastMoveToIndex); 205701ec2eb42e9c64f8d06afd51f80c055710147141robertphillips@google.com 20581dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com fPathRef->writeToBuffer(&buffer); 205901ec2eb42e9c64f8d06afd51f80c055710147141robertphillips@google.com 206094e75ee46a569cbcdf61fb7f04ee3a69d3ca0896djsollen@google.com buffer.padToAlign4(); 20614faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.org return buffer.pos(); 20628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 20638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 20644faa869cdabbdcf4867118b4a1272296baaeeb52commit-bot@chromium.orgsize_t SkPath::readFromMemory(const void* storage, size_t length) { 20651026ccf1d2de57ae6e7d2f30ea92c245942121d3Mike Reed SkRBuffer buffer(storage, length); 206601ec2eb42e9c64f8d06afd51f80c055710147141robertphillips@google.com 20678f457e3230f1a4ce737f512ffbb5c919b8d02407commit-bot@chromium.org int32_t packed; 20688f457e3230f1a4ce737f512ffbb5c919b8d02407commit-bot@chromium.org if (!buffer.readS32(&packed)) { 20698f457e3230f1a4ce737f512ffbb5c919b8d02407commit-bot@chromium.org return 0; 20708f457e3230f1a4ce737f512ffbb5c919b8d02407commit-bot@chromium.org } 20718f457e3230f1a4ce737f512ffbb5c919b8d02407commit-bot@chromium.org 20728f086023bf615b2661b82bcf59cdedde78ad7374reed unsigned version = packed & 0xFF; 20736900641e02c3b6c7ee15d0aa5bd4af0d42db480fcaryclark if (version >= kPathPrivLastMoveToIndex_Version && !buffer.readS32(&fLastMoveToIndex)) { 20746900641e02c3b6c7ee15d0aa5bd4af0d42db480fcaryclark return 0; 20756900641e02c3b6c7ee15d0aa5bd4af0d42db480fcaryclark } 20761b24933e52f50773de29332387a12721811f3012mtklein 207701ec2eb42e9c64f8d06afd51f80c055710147141robertphillips@google.com fConvexity = (packed >> kConvexity_SerializationShift) & 0xFF; 20787070a3c44b24da5715dc4da618cb014f87e92451robertphillips fFillType = (packed >> kFillType_SerializationShift) & 0x3; 20798f086023bf615b2661b82bcf59cdedde78ad7374reed uint8_t dir = (packed >> kDirection_SerializationShift) & 0x3; 2080b3eb687f8a89eb1eacd1afb4016401eb392f66abjvanverth fIsVolatile = (packed >> kIsVolatile_SerializationShift) & 0x1; 2081fed2ab648341ec153ad2af746a31d368963171e4commit-bot@chromium.org SkPathRef* pathRef = SkPathRef::CreateFromBuffer(&buffer); 2082f8aec588bfd2df17130ee93593a8f4ae781afe1fajuma if (!pathRef) { 2083f8aec588bfd2df17130ee93593a8f4ae781afe1fajuma return 0; 2084f8aec588bfd2df17130ee93593a8f4ae781afe1fajuma } 2085f8aec588bfd2df17130ee93593a8f4ae781afe1fajuma 2086f8aec588bfd2df17130ee93593a8f4ae781afe1fajuma fPathRef.reset(pathRef); 2087f8aec588bfd2df17130ee93593a8f4ae781afe1fajuma SkDEBUGCODE(this->validate();) 2088f8aec588bfd2df17130ee93593a8f4ae781afe1fajuma buffer.skipToAlign4(); 2089abf15c189b6333aa77a6c3f566cc67f4634ba338reed@google.com 20908f086023bf615b2661b82bcf59cdedde78ad7374reed // compatibility check 20918f086023bf615b2661b82bcf59cdedde78ad7374reed if (version < kPathPrivFirstDirection_Version) { 20928f086023bf615b2661b82bcf59cdedde78ad7374reed switch (dir) { // old values 20938f086023bf615b2661b82bcf59cdedde78ad7374reed case 0: 20948f086023bf615b2661b82bcf59cdedde78ad7374reed fFirstDirection = SkPathPriv::kUnknown_FirstDirection; 20958f086023bf615b2661b82bcf59cdedde78ad7374reed break; 20968f086023bf615b2661b82bcf59cdedde78ad7374reed case 1: 20978f086023bf615b2661b82bcf59cdedde78ad7374reed fFirstDirection = SkPathPriv::kCW_FirstDirection; 20988f086023bf615b2661b82bcf59cdedde78ad7374reed break; 20998f086023bf615b2661b82bcf59cdedde78ad7374reed case 2: 21008f086023bf615b2661b82bcf59cdedde78ad7374reed fFirstDirection = SkPathPriv::kCCW_FirstDirection; 21018f086023bf615b2661b82bcf59cdedde78ad7374reed break; 21028f086023bf615b2661b82bcf59cdedde78ad7374reed default: 21038f086023bf615b2661b82bcf59cdedde78ad7374reed SkASSERT(false); 21048f086023bf615b2661b82bcf59cdedde78ad7374reed } 21058f086023bf615b2661b82bcf59cdedde78ad7374reed } else { 21068f086023bf615b2661b82bcf59cdedde78ad7374reed fFirstDirection = dir; 21078f086023bf615b2661b82bcf59cdedde78ad7374reed } 21088f086023bf615b2661b82bcf59cdedde78ad7374reed 2109f8aec588bfd2df17130ee93593a8f4ae781afe1fajuma return buffer.pos(); 21108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 21118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 21128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/////////////////////////////////////////////////////////////////////////////// 21138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 21144d1955c43aaab045511b74a495dfbea4ef0057c5Ben Wagner#include "SkString.h" 2115e05fed0d6339c63c8cceff74af0b8d120c07e54creed#include "SkStringUtils.h" 211666a5d8bf13fe98baae268db0211e9c25e5ece7facaryclark#include "SkStream.h" 211751bbe75875d654251c6e8bec21ca773ffd5f39d0reed@google.com 211851bbe75875d654251c6e8bec21ca773ffd5f39d0reed@google.comstatic void append_params(SkString* str, const char label[], const SkPoint pts[], 2119e05fed0d6339c63c8cceff74af0b8d120c07e54creed int count, SkScalarAsStringType strType, SkScalar conicWeight = -1) { 212051bbe75875d654251c6e8bec21ca773ffd5f39d0reed@google.com str->append(label); 212151bbe75875d654251c6e8bec21ca773ffd5f39d0reed@google.com str->append("("); 212215dd300ac6d7695b4d2aca81d8f3648eae704451skia.committer@gmail.com 212351bbe75875d654251c6e8bec21ca773ffd5f39d0reed@google.com const SkScalar* values = &pts[0].fX; 212451bbe75875d654251c6e8bec21ca773ffd5f39d0reed@google.com count *= 2; 212551bbe75875d654251c6e8bec21ca773ffd5f39d0reed@google.com 212651bbe75875d654251c6e8bec21ca773ffd5f39d0reed@google.com for (int i = 0; i < count; ++i) { 2127e05fed0d6339c63c8cceff74af0b8d120c07e54creed SkAppendScalar(str, values[i], strType); 212851bbe75875d654251c6e8bec21ca773ffd5f39d0reed@google.com if (i < count - 1) { 212951bbe75875d654251c6e8bec21ca773ffd5f39d0reed@google.com str->append(", "); 213051bbe75875d654251c6e8bec21ca773ffd5f39d0reed@google.com } 213151bbe75875d654251c6e8bec21ca773ffd5f39d0reed@google.com } 2132277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com if (conicWeight >= 0) { 2133277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com str->append(", "); 2134e05fed0d6339c63c8cceff74af0b8d120c07e54creed SkAppendScalar(str, conicWeight, strType); 2135277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com } 213608fa28cd31c96b4ebd9cb532539c3a8c88803d90caryclark str->append(");"); 2137e05fed0d6339c63c8cceff74af0b8d120c07e54creed if (kHex_SkScalarAsStringType == strType) { 213808fa28cd31c96b4ebd9cb532539c3a8c88803d90caryclark str->append(" // "); 213908fa28cd31c96b4ebd9cb532539c3a8c88803d90caryclark for (int i = 0; i < count; ++i) { 2140e05fed0d6339c63c8cceff74af0b8d120c07e54creed SkAppendScalarDec(str, values[i]); 214108fa28cd31c96b4ebd9cb532539c3a8c88803d90caryclark if (i < count - 1) { 214208fa28cd31c96b4ebd9cb532539c3a8c88803d90caryclark str->append(", "); 214308fa28cd31c96b4ebd9cb532539c3a8c88803d90caryclark } 214408fa28cd31c96b4ebd9cb532539c3a8c88803d90caryclark } 214508fa28cd31c96b4ebd9cb532539c3a8c88803d90caryclark if (conicWeight >= 0) { 214608fa28cd31c96b4ebd9cb532539c3a8c88803d90caryclark str->append(", "); 2147e05fed0d6339c63c8cceff74af0b8d120c07e54creed SkAppendScalarDec(str, conicWeight); 214808fa28cd31c96b4ebd9cb532539c3a8c88803d90caryclark } 214908fa28cd31c96b4ebd9cb532539c3a8c88803d90caryclark } 215008fa28cd31c96b4ebd9cb532539c3a8c88803d90caryclark str->append("\n"); 215151bbe75875d654251c6e8bec21ca773ffd5f39d0reed@google.com} 215251bbe75875d654251c6e8bec21ca773ffd5f39d0reed@google.com 2153e956259c5a4f71768afb34ec032eaed49dcbe9f2caryclarkvoid SkPath::dump(SkWStream* wStream, bool forceClose, bool dumpAsHex) const { 2154e05fed0d6339c63c8cceff74af0b8d120c07e54creed SkScalarAsStringType asType = dumpAsHex ? kHex_SkScalarAsStringType : kDec_SkScalarAsStringType; 21558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com Iter iter(*this, forceClose); 21568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkPoint pts[4]; 21578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com Verb verb; 21588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 215951bbe75875d654251c6e8bec21ca773ffd5f39d0reed@google.com SkString builder; 21609f67f044dd8765184669af6fd38e7feeff8777f9Cary Clark char const * const gFillTypeStrs[] = { 21619f67f044dd8765184669af6fd38e7feeff8777f9Cary Clark "Winding", 21629f67f044dd8765184669af6fd38e7feeff8777f9Cary Clark "EvenOdd", 21639f67f044dd8765184669af6fd38e7feeff8777f9Cary Clark "InverseWinding", 21649f67f044dd8765184669af6fd38e7feeff8777f9Cary Clark "InverseEvenOdd", 21659f67f044dd8765184669af6fd38e7feeff8777f9Cary Clark }; 21669f67f044dd8765184669af6fd38e7feeff8777f9Cary Clark builder.printf("path.setFillType(SkPath::k%s_FillType);\n", 21679f67f044dd8765184669af6fd38e7feeff8777f9Cary Clark gFillTypeStrs[(int) this->getFillType()]); 21684a3b714d73e585a3985d614600c6b79d5c8b1f1ereed@google.com while ((verb = iter.next(pts, false)) != kDone_Verb) { 21698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com switch (verb) { 21708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com case kMove_Verb: 2171e05fed0d6339c63c8cceff74af0b8d120c07e54creed append_params(&builder, "path.moveTo", &pts[0], 1, asType); 21728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 21738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com case kLine_Verb: 2174e05fed0d6339c63c8cceff74af0b8d120c07e54creed append_params(&builder, "path.lineTo", &pts[1], 1, asType); 21758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 21768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com case kQuad_Verb: 2177e05fed0d6339c63c8cceff74af0b8d120c07e54creed append_params(&builder, "path.quadTo", &pts[1], 2, asType); 21788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 2179277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com case kConic_Verb: 2180e05fed0d6339c63c8cceff74af0b8d120c07e54creed append_params(&builder, "path.conicTo", &pts[1], 2, asType, iter.conicWeight()); 2181277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com break; 21828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com case kCubic_Verb: 2183e05fed0d6339c63c8cceff74af0b8d120c07e54creed append_params(&builder, "path.cubicTo", &pts[1], 3, asType); 21848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 21858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com case kClose_Verb: 218666a5d8bf13fe98baae268db0211e9c25e5ece7facaryclark builder.append("path.close();\n"); 21878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 21888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com default: 21898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkDebugf(" path: UNKNOWN VERB %d, aborting dump...\n", verb); 21908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com verb = kDone_Verb; // stop the loop 21918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com break; 21928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 21931049f1246e7be4ccb68001361efceb8933e6f81ccaryclark if (!wStream && builder.size()) { 21941049f1246e7be4ccb68001361efceb8933e6f81ccaryclark SkDebugf("%s", builder.c_str()); 21951049f1246e7be4ccb68001361efceb8933e6f81ccaryclark builder.reset(); 21961049f1246e7be4ccb68001361efceb8933e6f81ccaryclark } 21978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 219866a5d8bf13fe98baae268db0211e9c25e5ece7facaryclark if (wStream) { 219966a5d8bf13fe98baae268db0211e9c25e5ece7facaryclark wStream->writeText(builder.c_str()); 220066a5d8bf13fe98baae268db0211e9c25e5ece7facaryclark } 22018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 22028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 2203e522ca5d5f249bd51a00cb68bb051f811d0a9e85reed@android.comvoid SkPath::dump() const { 220496fcdcc219d2a0d3579719b84b28bede76efba64halcanary this->dump(nullptr, false, false); 2205e956259c5a4f71768afb34ec032eaed49dcbe9f2caryclark} 2206e956259c5a4f71768afb34ec032eaed49dcbe9f2caryclark 2207e956259c5a4f71768afb34ec032eaed49dcbe9f2caryclarkvoid SkPath::dumpHex() const { 220896fcdcc219d2a0d3579719b84b28bede76efba64halcanary this->dump(nullptr, false, true); 2209e522ca5d5f249bd51a00cb68bb051f811d0a9e85reed@android.com} 2210e522ca5d5f249bd51a00cb68bb051f811d0a9e85reed@android.com 2211e522ca5d5f249bd51a00cb68bb051f811d0a9e85reed@android.com#ifdef SK_DEBUG 2212e522ca5d5f249bd51a00cb68bb051f811d0a9e85reed@android.comvoid SkPath::validate() const { 2213e522ca5d5f249bd51a00cb68bb051f811d0a9e85reed@android.com SkASSERT((fFillType & ~3) == 0); 2214abf15c189b6333aa77a6c3f566cc67f4634ba338reed@google.com 2215077348cfd0b4c424393ce83cb9ceded8afe60216djsollen@google.com#ifdef SK_DEBUG_PATH 2216e522ca5d5f249bd51a00cb68bb051f811d0a9e85reed@android.com if (!fBoundsIsDirty) { 2217e522ca5d5f249bd51a00cb68bb051f811d0a9e85reed@android.com SkRect bounds; 2218ed02c4d05e3f2ed86dbf4276a69827ab23810598tomhudson@google.com 22191dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com bool isFinite = compute_pt_bounds(&bounds, *fPathRef.get()); 22205d8d18651a64f62dbb8881794e23f53bf22c9a23robertphillips@google.com SkASSERT(SkToBool(fIsFinite) == isFinite); 2221ed02c4d05e3f2ed86dbf4276a69827ab23810598tomhudson@google.com 22221dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com if (fPathRef->countPoints() <= 1) { 2223e522ca5d5f249bd51a00cb68bb051f811d0a9e85reed@android.com // if we're empty, fBounds may be empty but translated, so we can't 2224e522ca5d5f249bd51a00cb68bb051f811d0a9e85reed@android.com // necessarily compare to bounds directly 2225e522ca5d5f249bd51a00cb68bb051f811d0a9e85reed@android.com // try path.addOval(2, 2, 2, 2) which is empty, but the bounds will 2226e522ca5d5f249bd51a00cb68bb051f811d0a9e85reed@android.com // be [2, 2, 2, 2] 2227e522ca5d5f249bd51a00cb68bb051f811d0a9e85reed@android.com SkASSERT(bounds.isEmpty()); 2228e522ca5d5f249bd51a00cb68bb051f811d0a9e85reed@android.com SkASSERT(fBounds.isEmpty()); 2229e522ca5d5f249bd51a00cb68bb051f811d0a9e85reed@android.com } else { 2230eac52bdb6c275a50832c4bba3a439d7fbf7f7807reed@google.com if (bounds.isEmpty()) { 2231eac52bdb6c275a50832c4bba3a439d7fbf7f7807reed@google.com SkASSERT(fBounds.isEmpty()); 2232eac52bdb6c275a50832c4bba3a439d7fbf7f7807reed@google.com } else { 22333563c9ee527f524d421964b54d9b09e12ec0bf6breed@google.com if (!fBounds.isEmpty()) { 22343563c9ee527f524d421964b54d9b09e12ec0bf6breed@google.com SkASSERT(fBounds.contains(bounds)); 22353563c9ee527f524d421964b54d9b09e12ec0bf6breed@google.com } 2236eac52bdb6c275a50832c4bba3a439d7fbf7f7807reed@google.com } 2237e522ca5d5f249bd51a00cb68bb051f811d0a9e85reed@android.com } 2238e522ca5d5f249bd51a00cb68bb051f811d0a9e85reed@android.com } 2239077348cfd0b4c424393ce83cb9ceded8afe60216djsollen@google.com#endif // SK_DEBUG_PATH 2240e522ca5d5f249bd51a00cb68bb051f811d0a9e85reed@android.com} 2241077348cfd0b4c424393ce83cb9ceded8afe60216djsollen@google.com#endif // SK_DEBUG 2242e522ca5d5f249bd51a00cb68bb051f811d0a9e85reed@android.com 224304863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com/////////////////////////////////////////////////////////////////////////////// 224404863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com 22450b7b98260784da07b2b15ea06530ccd8fb6ad02breed@google.comstatic int sign(SkScalar x) { return x < 0; } 22460b7b98260784da07b2b15ea06530ccd8fb6ad02breed@google.com#define kValueNeverReturnedBySign 2 224785b6e399d56d2421980daa432f30910beda41922reed@google.com 2248c506e3007e53fe7d1a77991de11fdb50a86fd532robertphillipsenum DirChange { 2249c506e3007e53fe7d1a77991de11fdb50a86fd532robertphillips kLeft_DirChange, 2250c506e3007e53fe7d1a77991de11fdb50a86fd532robertphillips kRight_DirChange, 2251c506e3007e53fe7d1a77991de11fdb50a86fd532robertphillips kStraight_DirChange, 2252c506e3007e53fe7d1a77991de11fdb50a86fd532robertphillips kBackwards_DirChange, 2253c506e3007e53fe7d1a77991de11fdb50a86fd532robertphillips 2254c506e3007e53fe7d1a77991de11fdb50a86fd532robertphillips kInvalid_DirChange 2255c506e3007e53fe7d1a77991de11fdb50a86fd532robertphillips}; 2256c506e3007e53fe7d1a77991de11fdb50a86fd532robertphillips 2257c506e3007e53fe7d1a77991de11fdb50a86fd532robertphillips 22588be07bb12d1f7a2d08fa154320fbe6940b370ea1commit-bot@chromium.orgstatic bool almost_equal(SkScalar compA, SkScalar compB) { 2259f91aaecbe9d3630123d803d80f7b29f06c8976c7commit-bot@chromium.org // The error epsilon was empirically derived; worse case round rects 2260f91aaecbe9d3630123d803d80f7b29f06c8976c7commit-bot@chromium.org // with a mid point outset by 2x float epsilon in tests had an error 2261f91aaecbe9d3630123d803d80f7b29f06c8976c7commit-bot@chromium.org // of 12. 2262f91aaecbe9d3630123d803d80f7b29f06c8976c7commit-bot@chromium.org const int epsilon = 16; 2263f91aaecbe9d3630123d803d80f7b29f06c8976c7commit-bot@chromium.org if (!SkScalarIsFinite(compA) || !SkScalarIsFinite(compB)) { 2264f91aaecbe9d3630123d803d80f7b29f06c8976c7commit-bot@chromium.org return false; 2265f91aaecbe9d3630123d803d80f7b29f06c8976c7commit-bot@chromium.org } 2266a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org // no need to check for small numbers because SkPath::Iter has removed degenerate values 2267f91aaecbe9d3630123d803d80f7b29f06c8976c7commit-bot@chromium.org int aBits = SkFloatAs2sCompliment(compA); 2268f91aaecbe9d3630123d803d80f7b29f06c8976c7commit-bot@chromium.org int bBits = SkFloatAs2sCompliment(compB); 2269f91aaecbe9d3630123d803d80f7b29f06c8976c7commit-bot@chromium.org return aBits < bBits + epsilon && bBits < aBits + epsilon; 227004863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com} 227104863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com 2272b421650e13faa2b77d29b018e78ab07ff693ca32caryclarkstatic bool approximately_zero_when_compared_to(double x, double y) { 2273b421650e13faa2b77d29b018e78ab07ff693ca32caryclark return x == 0 || fabs(x) < fabs(y * FLT_EPSILON); 2274c506e3007e53fe7d1a77991de11fdb50a86fd532robertphillips} 2275c506e3007e53fe7d1a77991de11fdb50a86fd532robertphillips 2276b421650e13faa2b77d29b018e78ab07ff693ca32caryclark 227704863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com// only valid for a single contour 227804863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.comstruct Convexicator { 227930c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com Convexicator() 228030c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com : fPtCount(0) 228130c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com , fConvexity(SkPath::kConvex_Convexity) 2282026beb52a29a620290fcfb24f1e7e9e75547b80freed , fFirstDirection(SkPathPriv::kUnknown_FirstDirection) 22835ccef577902ce1aefa05fb8107ad5d0aba848e7dcaryclark , fIsFinite(true) 22845ccef577902ce1aefa05fb8107ad5d0aba848e7dcaryclark , fIsCurve(false) { 2285c506e3007e53fe7d1a77991de11fdb50a86fd532robertphillips fExpectedDir = kInvalid_DirChange; 228604863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com // warnings 22872f124631583a838edaa1e48362031cc6c7f40764djsollen fPriorPt.set(0,0); 2288f91aaecbe9d3630123d803d80f7b29f06c8976c7commit-bot@chromium.org fLastPt.set(0, 0); 228904863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com fCurrPt.set(0, 0); 22908be07bb12d1f7a2d08fa154320fbe6940b370ea1commit-bot@chromium.org fLastVec.set(0, 0); 229104863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com fFirstVec.set(0, 0); 229285b6e399d56d2421980daa432f30910beda41922reed@google.com 229385b6e399d56d2421980daa432f30910beda41922reed@google.com fDx = fDy = 0; 22940b7b98260784da07b2b15ea06530ccd8fb6ad02breed@google.com fSx = fSy = kValueNeverReturnedBySign; 229504863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com } 229604863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com 229704863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com SkPath::Convexity getConvexity() const { return fConvexity; } 229804863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com 229930c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com /** The direction returned is only valid if the path is determined convex */ 2300026beb52a29a620290fcfb24f1e7e9e75547b80freed SkPathPriv::FirstDirection getFirstDirection() const { return fFirstDirection; } 230130c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com 230204863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com void addPt(const SkPoint& pt) { 2303d3d1a988b1ed144b0123dbe594c3a47a63d6451dcaryclark if (SkPath::kConcave_Convexity == fConvexity || !fIsFinite) { 230404863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com return; 230504863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com } 230604863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com 230704863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com if (0 == fPtCount) { 230804863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com fCurrPt = pt; 230904863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com ++fPtCount; 231004863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com } else { 231104863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com SkVector vec = pt - fCurrPt; 2312d3d1a988b1ed144b0123dbe594c3a47a63d6451dcaryclark SkScalar lengthSqd = vec.lengthSqd(); 2313d3d1a988b1ed144b0123dbe594c3a47a63d6451dcaryclark if (!SkScalarIsFinite(lengthSqd)) { 2314d3d1a988b1ed144b0123dbe594c3a47a63d6451dcaryclark fIsFinite = false; 2315e8c5666e0387e70bd921e01558e627af3f1411dbcaryclark } else if (lengthSqd) { 2316b421650e13faa2b77d29b018e78ab07ff693ca32caryclark fPriorPt = fLastPt; 2317f91aaecbe9d3630123d803d80f7b29f06c8976c7commit-bot@chromium.org fLastPt = fCurrPt; 231804863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com fCurrPt = pt; 231904863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com if (++fPtCount == 2) { 23208be07bb12d1f7a2d08fa154320fbe6940b370ea1commit-bot@chromium.org fFirstVec = fLastVec = vec; 232104863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com } else { 232204863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com SkASSERT(fPtCount > 2); 232304863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com this->addVec(vec); 232404863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com } 2325fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 232685b6e399d56d2421980daa432f30910beda41922reed@google.com int sx = sign(vec.fX); 232785b6e399d56d2421980daa432f30910beda41922reed@google.com int sy = sign(vec.fY); 232885b6e399d56d2421980daa432f30910beda41922reed@google.com fDx += (sx != fSx); 232985b6e399d56d2421980daa432f30910beda41922reed@google.com fDy += (sy != fSy); 233085b6e399d56d2421980daa432f30910beda41922reed@google.com fSx = sx; 233185b6e399d56d2421980daa432f30910beda41922reed@google.com fSy = sy; 2332fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 233385b6e399d56d2421980daa432f30910beda41922reed@google.com if (fDx > 3 || fDy > 3) { 233485b6e399d56d2421980daa432f30910beda41922reed@google.com fConvexity = SkPath::kConcave_Convexity; 233585b6e399d56d2421980daa432f30910beda41922reed@google.com } 233604863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com } 233704863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com } 233804863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com } 233904863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com 234004863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com void close() { 234104863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com if (fPtCount > 2) { 234204863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com this->addVec(fFirstVec); 234304863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com } 234404863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com } 234504863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com 2346b421650e13faa2b77d29b018e78ab07ff693ca32caryclark DirChange directionChange(const SkVector& curVec) { 2347b421650e13faa2b77d29b018e78ab07ff693ca32caryclark SkScalar cross = SkPoint::CrossProduct(fLastVec, curVec); 2348b421650e13faa2b77d29b018e78ab07ff693ca32caryclark 2349b421650e13faa2b77d29b018e78ab07ff693ca32caryclark SkScalar smallest = SkTMin(fCurrPt.fX, SkTMin(fCurrPt.fY, SkTMin(fLastPt.fX, fLastPt.fY))); 2350b421650e13faa2b77d29b018e78ab07ff693ca32caryclark SkScalar largest = SkTMax(fCurrPt.fX, SkTMax(fCurrPt.fY, SkTMax(fLastPt.fX, fLastPt.fY))); 2351b421650e13faa2b77d29b018e78ab07ff693ca32caryclark largest = SkTMax(largest, -smallest); 2352b421650e13faa2b77d29b018e78ab07ff693ca32caryclark 2353b421650e13faa2b77d29b018e78ab07ff693ca32caryclark if (!almost_equal(largest, largest + cross)) { 2354b421650e13faa2b77d29b018e78ab07ff693ca32caryclark int sign = SkScalarSignAsInt(cross); 2355b421650e13faa2b77d29b018e78ab07ff693ca32caryclark if (sign) { 2356b421650e13faa2b77d29b018e78ab07ff693ca32caryclark return (1 == sign) ? kRight_DirChange : kLeft_DirChange; 2357b421650e13faa2b77d29b018e78ab07ff693ca32caryclark } 2358b421650e13faa2b77d29b018e78ab07ff693ca32caryclark } 2359b421650e13faa2b77d29b018e78ab07ff693ca32caryclark 2360b421650e13faa2b77d29b018e78ab07ff693ca32caryclark if (cross) { 2361b421650e13faa2b77d29b018e78ab07ff693ca32caryclark double dLastVecX = SkScalarToDouble(fLastPt.fX) - SkScalarToDouble(fPriorPt.fX); 2362b421650e13faa2b77d29b018e78ab07ff693ca32caryclark double dLastVecY = SkScalarToDouble(fLastPt.fY) - SkScalarToDouble(fPriorPt.fY); 2363b421650e13faa2b77d29b018e78ab07ff693ca32caryclark double dCurrVecX = SkScalarToDouble(fCurrPt.fX) - SkScalarToDouble(fLastPt.fX); 2364b421650e13faa2b77d29b018e78ab07ff693ca32caryclark double dCurrVecY = SkScalarToDouble(fCurrPt.fY) - SkScalarToDouble(fLastPt.fY); 2365b421650e13faa2b77d29b018e78ab07ff693ca32caryclark double dCross = dLastVecX * dCurrVecY - dLastVecY * dCurrVecX; 2366b421650e13faa2b77d29b018e78ab07ff693ca32caryclark if (!approximately_zero_when_compared_to(dCross, SkScalarToDouble(largest))) { 2367b421650e13faa2b77d29b018e78ab07ff693ca32caryclark int sign = SkScalarSignAsInt(SkDoubleToScalar(dCross)); 2368b421650e13faa2b77d29b018e78ab07ff693ca32caryclark if (sign) { 2369b421650e13faa2b77d29b018e78ab07ff693ca32caryclark return (1 == sign) ? kRight_DirChange : kLeft_DirChange; 2370b421650e13faa2b77d29b018e78ab07ff693ca32caryclark } 2371b421650e13faa2b77d29b018e78ab07ff693ca32caryclark } 2372b421650e13faa2b77d29b018e78ab07ff693ca32caryclark } 2373b421650e13faa2b77d29b018e78ab07ff693ca32caryclark 2374b421650e13faa2b77d29b018e78ab07ff693ca32caryclark if (!SkScalarNearlyZero(fLastVec.lengthSqd(), SK_ScalarNearlyZero*SK_ScalarNearlyZero) && 2375b421650e13faa2b77d29b018e78ab07ff693ca32caryclark !SkScalarNearlyZero(curVec.lengthSqd(), SK_ScalarNearlyZero*SK_ScalarNearlyZero) && 2376b421650e13faa2b77d29b018e78ab07ff693ca32caryclark fLastVec.dot(curVec) < 0.0f) { 2377b421650e13faa2b77d29b018e78ab07ff693ca32caryclark return kBackwards_DirChange; 2378b421650e13faa2b77d29b018e78ab07ff693ca32caryclark } 2379b421650e13faa2b77d29b018e78ab07ff693ca32caryclark 2380b421650e13faa2b77d29b018e78ab07ff693ca32caryclark return kStraight_DirChange; 2381b421650e13faa2b77d29b018e78ab07ff693ca32caryclark } 2382b421650e13faa2b77d29b018e78ab07ff693ca32caryclark 2383b421650e13faa2b77d29b018e78ab07ff693ca32caryclark 2384d3d1a988b1ed144b0123dbe594c3a47a63d6451dcaryclark bool isFinite() const { 2385d3d1a988b1ed144b0123dbe594c3a47a63d6451dcaryclark return fIsFinite; 2386d3d1a988b1ed144b0123dbe594c3a47a63d6451dcaryclark } 2387d3d1a988b1ed144b0123dbe594c3a47a63d6451dcaryclark 23885ccef577902ce1aefa05fb8107ad5d0aba848e7dcaryclark void setCurve(bool isCurve) { 23895ccef577902ce1aefa05fb8107ad5d0aba848e7dcaryclark fIsCurve = isCurve; 23905ccef577902ce1aefa05fb8107ad5d0aba848e7dcaryclark } 23915ccef577902ce1aefa05fb8107ad5d0aba848e7dcaryclark 239204863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.comprivate: 239304863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com void addVec(const SkVector& vec) { 239404863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com SkASSERT(vec.fX || vec.fY); 2395b421650e13faa2b77d29b018e78ab07ff693ca32caryclark DirChange dir = this->directionChange(vec); 2396c506e3007e53fe7d1a77991de11fdb50a86fd532robertphillips switch (dir) { 2397c506e3007e53fe7d1a77991de11fdb50a86fd532robertphillips case kLeft_DirChange: // fall through 2398c506e3007e53fe7d1a77991de11fdb50a86fd532robertphillips case kRight_DirChange: 2399c506e3007e53fe7d1a77991de11fdb50a86fd532robertphillips if (kInvalid_DirChange == fExpectedDir) { 2400c506e3007e53fe7d1a77991de11fdb50a86fd532robertphillips fExpectedDir = dir; 2401026beb52a29a620290fcfb24f1e7e9e75547b80freed fFirstDirection = (kRight_DirChange == dir) ? SkPathPriv::kCW_FirstDirection 2402026beb52a29a620290fcfb24f1e7e9e75547b80freed : SkPathPriv::kCCW_FirstDirection; 2403c506e3007e53fe7d1a77991de11fdb50a86fd532robertphillips } else if (dir != fExpectedDir) { 2404c506e3007e53fe7d1a77991de11fdb50a86fd532robertphillips fConvexity = SkPath::kConcave_Convexity; 2405026beb52a29a620290fcfb24f1e7e9e75547b80freed fFirstDirection = SkPathPriv::kUnknown_FirstDirection; 2406c506e3007e53fe7d1a77991de11fdb50a86fd532robertphillips } 2407c506e3007e53fe7d1a77991de11fdb50a86fd532robertphillips fLastVec = vec; 2408c506e3007e53fe7d1a77991de11fdb50a86fd532robertphillips break; 2409c506e3007e53fe7d1a77991de11fdb50a86fd532robertphillips case kStraight_DirChange: 2410c506e3007e53fe7d1a77991de11fdb50a86fd532robertphillips break; 2411c506e3007e53fe7d1a77991de11fdb50a86fd532robertphillips case kBackwards_DirChange: 24125ccef577902ce1aefa05fb8107ad5d0aba848e7dcaryclark if (fIsCurve) { 2413bdabcc4cb873dc4de39263c995900a05e6a32cf4liyuqian // If any of the subsequent dir is non-backward, it'll be concave. 2414bdabcc4cb873dc4de39263c995900a05e6a32cf4liyuqian // Otherwise, it's still convex. 2415bdabcc4cb873dc4de39263c995900a05e6a32cf4liyuqian fExpectedDir = dir; 24165ccef577902ce1aefa05fb8107ad5d0aba848e7dcaryclark } 2417c506e3007e53fe7d1a77991de11fdb50a86fd532robertphillips fLastVec = vec; 2418c506e3007e53fe7d1a77991de11fdb50a86fd532robertphillips break; 2419c506e3007e53fe7d1a77991de11fdb50a86fd532robertphillips case kInvalid_DirChange: 2420c506e3007e53fe7d1a77991de11fdb50a86fd532robertphillips SkFAIL("Use of invalid direction change flag"); 2421c506e3007e53fe7d1a77991de11fdb50a86fd532robertphillips break; 242204863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com } 242304863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com } 242404863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com 2425b421650e13faa2b77d29b018e78ab07ff693ca32caryclark SkPoint fPriorPt; 2426f91aaecbe9d3630123d803d80f7b29f06c8976c7commit-bot@chromium.org SkPoint fLastPt; 242704863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com SkPoint fCurrPt; 24288be07bb12d1f7a2d08fa154320fbe6940b370ea1commit-bot@chromium.org // fLastVec does not necessarily start at fLastPt. We only advance it when the cross product 24298be07bb12d1f7a2d08fa154320fbe6940b370ea1commit-bot@chromium.org // value with the current vec is deemed to be of a significant value. 24308be07bb12d1f7a2d08fa154320fbe6940b370ea1commit-bot@chromium.org SkVector fLastVec, fFirstVec; 243104863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com int fPtCount; // non-degenerate points 2432c506e3007e53fe7d1a77991de11fdb50a86fd532robertphillips DirChange fExpectedDir; 243304863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com SkPath::Convexity fConvexity; 2434026beb52a29a620290fcfb24f1e7e9e75547b80freed SkPathPriv::FirstDirection fFirstDirection; 24350b7b98260784da07b2b15ea06530ccd8fb6ad02breed@google.com int fDx, fDy, fSx, fSy; 2436d3d1a988b1ed144b0123dbe594c3a47a63d6451dcaryclark bool fIsFinite; 24375ccef577902ce1aefa05fb8107ad5d0aba848e7dcaryclark bool fIsCurve; 243804863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com}; 243904863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com 244030c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.comSkPath::Convexity SkPath::internalGetConvexity() const { 244130c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com SkASSERT(kUnknown_Convexity == fConvexity); 244204863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com SkPoint pts[4]; 244304863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com SkPath::Verb verb; 244430c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com SkPath::Iter iter(*this, true); 244504863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com 244604863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com int contourCount = 0; 244704863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com int count; 244804863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com Convexicator state; 244904863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com 2450d3d1a988b1ed144b0123dbe594c3a47a63d6451dcaryclark if (!isFinite()) { 2451d3d1a988b1ed144b0123dbe594c3a47a63d6451dcaryclark return kUnknown_Convexity; 2452d3d1a988b1ed144b0123dbe594c3a47a63d6451dcaryclark } 2453e8c5666e0387e70bd921e01558e627af3f1411dbcaryclark while ((verb = iter.next(pts, true, true)) != SkPath::kDone_Verb) { 245404863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com switch (verb) { 245504863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com case kMove_Verb: 245604863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com if (++contourCount > 1) { 245730c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com fConvexity = kConcave_Convexity; 245804863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com return kConcave_Convexity; 245904863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com } 246004863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com pts[1] = pts[0]; 24615ccef577902ce1aefa05fb8107ad5d0aba848e7dcaryclark // fall through 24625ccef577902ce1aefa05fb8107ad5d0aba848e7dcaryclark case kLine_Verb: 246304863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com count = 1; 24645ccef577902ce1aefa05fb8107ad5d0aba848e7dcaryclark state.setCurve(false); 24655ccef577902ce1aefa05fb8107ad5d0aba848e7dcaryclark break; 24665ccef577902ce1aefa05fb8107ad5d0aba848e7dcaryclark case kQuad_Verb: 24675ccef577902ce1aefa05fb8107ad5d0aba848e7dcaryclark // fall through 24685ccef577902ce1aefa05fb8107ad5d0aba848e7dcaryclark case kConic_Verb: 24695ccef577902ce1aefa05fb8107ad5d0aba848e7dcaryclark // fall through 24705ccef577902ce1aefa05fb8107ad5d0aba848e7dcaryclark case kCubic_Verb: 24715ccef577902ce1aefa05fb8107ad5d0aba848e7dcaryclark count = 2 + (kCubic_Verb == verb); 24725ccef577902ce1aefa05fb8107ad5d0aba848e7dcaryclark // As an additional enhancement, this could set curve true only 24735ccef577902ce1aefa05fb8107ad5d0aba848e7dcaryclark // if the curve is nonlinear 24745ccef577902ce1aefa05fb8107ad5d0aba848e7dcaryclark state.setCurve(true); 247504863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com break; 247604863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com case kClose_Verb: 24775ccef577902ce1aefa05fb8107ad5d0aba848e7dcaryclark state.setCurve(false); 247804863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com state.close(); 247904863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com count = 0; 248004863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com break; 248104863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com default: 24820c00f21fee3f5cfa3aa7e5d46ff94cb8cf340451tomhudson@google.com SkDEBUGFAIL("bad verb"); 248330c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com fConvexity = kConcave_Convexity; 248404863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com return kConcave_Convexity; 248504863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com } 248604863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com 248704863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com for (int i = 1; i <= count; i++) { 248804863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com state.addPt(pts[i]); 248904863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com } 249004863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com // early exit 2491d3d1a988b1ed144b0123dbe594c3a47a63d6451dcaryclark if (!state.isFinite()) { 2492d3d1a988b1ed144b0123dbe594c3a47a63d6451dcaryclark return kUnknown_Convexity; 2493d3d1a988b1ed144b0123dbe594c3a47a63d6451dcaryclark } 249404863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com if (kConcave_Convexity == state.getConvexity()) { 249530c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com fConvexity = kConcave_Convexity; 249604863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com return kConcave_Convexity; 249704863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com } 249804863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com } 249930c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com fConvexity = state.getConvexity(); 2500026beb52a29a620290fcfb24f1e7e9e75547b80freed if (kConvex_Convexity == fConvexity && SkPathPriv::kUnknown_FirstDirection == fFirstDirection) { 2501026beb52a29a620290fcfb24f1e7e9e75547b80freed fFirstDirection = state.getFirstDirection(); 250230c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com } 250330c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com return static_cast<Convexity>(fConvexity); 250404863fa14a44ddf85acbc6268690ebc3f0d1d6dbreed@google.com} 250569a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com 250669a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com/////////////////////////////////////////////////////////////////////////////// 250769a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com 250869a9943b67cc52c24beac853c6f8865dcb197b85reed@google.comclass ContourIter { 250969a9943b67cc52c24beac853c6f8865dcb197b85reed@google.compublic: 25101dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com ContourIter(const SkPathRef& pathRef); 251169a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com 251269a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com bool done() const { return fDone; } 251369a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com // if !done() then these may be called 251469a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com int count() const { return fCurrPtCount; } 251569a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com const SkPoint* pts() const { return fCurrPt; } 251669a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com void next(); 251769a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com 251869a9943b67cc52c24beac853c6f8865dcb197b85reed@google.comprivate: 251969a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com int fCurrPtCount; 252069a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com const SkPoint* fCurrPt; 252169a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com const uint8_t* fCurrVerb; 252269a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com const uint8_t* fStopVerbs; 2523277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com const SkScalar* fCurrConicWeight; 252469a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com bool fDone; 2525d1ab9320b09b922bd2f3b3d4f888c754fde5b58creed@google.com SkDEBUGCODE(int fContourCounter;) 252669a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com}; 252769a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com 25281dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.comContourIter::ContourIter(const SkPathRef& pathRef) { 25291dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com fStopVerbs = pathRef.verbsMemBegin(); 253069a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com fDone = false; 25311dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com fCurrPt = pathRef.points(); 25321dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com fCurrVerb = pathRef.verbs(); 2533277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com fCurrConicWeight = pathRef.conicWeights(); 253469a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com fCurrPtCount = 0; 2535d1ab9320b09b922bd2f3b3d4f888c754fde5b58creed@google.com SkDEBUGCODE(fContourCounter = 0;) 253669a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com this->next(); 253769a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com} 253869a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com 253969a9943b67cc52c24beac853c6f8865dcb197b85reed@google.comvoid ContourIter::next() { 25401dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com if (fCurrVerb <= fStopVerbs) { 254169a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com fDone = true; 254269a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com } 254369a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com if (fDone) { 254469a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com return; 254569a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com } 254669a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com 254769a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com // skip pts of prev contour 254869a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com fCurrPt += fCurrPtCount; 254969a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com 25501dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com SkASSERT(SkPath::kMove_Verb == fCurrVerb[~0]); 255169a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com int ptCount = 1; // moveTo 255269a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com const uint8_t* verbs = fCurrVerb; 255369a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com 25541dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com for (--verbs; verbs > fStopVerbs; --verbs) { 25551dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com switch (verbs[~0]) { 255669a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com case SkPath::kMove_Verb: 255769a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com goto CONTOUR_END; 255869a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com case SkPath::kLine_Verb: 255969a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com ptCount += 1; 256069a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com break; 2561277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com case SkPath::kConic_Verb: 2562277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com fCurrConicWeight += 1; 2563277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com // fall-through 256469a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com case SkPath::kQuad_Verb: 256569a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com ptCount += 2; 256669a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com break; 256769a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com case SkPath::kCubic_Verb: 256869a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com ptCount += 3; 256969a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com break; 2570277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com case SkPath::kClose_Verb: 2571277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com break; 2572277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com default: 2573330313a8a8343876ee596da39da06a5d69badd9cmtklein@google.com SkDEBUGFAIL("unexpected verb"); 257469a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com break; 257569a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com } 257669a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com } 257769a9943b67cc52c24beac853c6f8865dcb197b85reed@google.comCONTOUR_END: 257869a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com fCurrPtCount = ptCount; 257969a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com fCurrVerb = verbs; 2580d1ab9320b09b922bd2f3b3d4f888c754fde5b58creed@google.com SkDEBUGCODE(++fContourCounter;) 258169a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com} 258269a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com 2583f0ed80a7ebef9b9c08093390b173e64bf300d7d7bsalomon@google.com// returns cross product of (p1 - p0) and (p2 - p0) 258469a9943b67cc52c24beac853c6f8865dcb197b85reed@google.comstatic SkScalar cross_prod(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2) { 2585f0ed80a7ebef9b9c08093390b173e64bf300d7d7bsalomon@google.com SkScalar cross = SkPoint::CrossProduct(p1 - p0, p2 - p0); 2586f0ed80a7ebef9b9c08093390b173e64bf300d7d7bsalomon@google.com // We may get 0 when the above subtracts underflow. We expect this to be 2587f0ed80a7ebef9b9c08093390b173e64bf300d7d7bsalomon@google.com // very rare and lazily promote to double. 2588f0ed80a7ebef9b9c08093390b173e64bf300d7d7bsalomon@google.com if (0 == cross) { 2589f0ed80a7ebef9b9c08093390b173e64bf300d7d7bsalomon@google.com double p0x = SkScalarToDouble(p0.fX); 2590f0ed80a7ebef9b9c08093390b173e64bf300d7d7bsalomon@google.com double p0y = SkScalarToDouble(p0.fY); 2591f0ed80a7ebef9b9c08093390b173e64bf300d7d7bsalomon@google.com 2592f0ed80a7ebef9b9c08093390b173e64bf300d7d7bsalomon@google.com double p1x = SkScalarToDouble(p1.fX); 2593f0ed80a7ebef9b9c08093390b173e64bf300d7d7bsalomon@google.com double p1y = SkScalarToDouble(p1.fY); 2594f0ed80a7ebef9b9c08093390b173e64bf300d7d7bsalomon@google.com 2595f0ed80a7ebef9b9c08093390b173e64bf300d7d7bsalomon@google.com double p2x = SkScalarToDouble(p2.fX); 2596f0ed80a7ebef9b9c08093390b173e64bf300d7d7bsalomon@google.com double p2y = SkScalarToDouble(p2.fY); 2597f0ed80a7ebef9b9c08093390b173e64bf300d7d7bsalomon@google.com 2598f0ed80a7ebef9b9c08093390b173e64bf300d7d7bsalomon@google.com cross = SkDoubleToScalar((p1x - p0x) * (p2y - p0y) - 2599f0ed80a7ebef9b9c08093390b173e64bf300d7d7bsalomon@google.com (p1y - p0y) * (p2x - p0x)); 2600f0ed80a7ebef9b9c08093390b173e64bf300d7d7bsalomon@google.com 2601f0ed80a7ebef9b9c08093390b173e64bf300d7d7bsalomon@google.com } 2602f0ed80a7ebef9b9c08093390b173e64bf300d7d7bsalomon@google.com return cross; 260369a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com} 260469a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com 2605c1ea60a9ea63fc590f11f49cd0d744e061891985reed@google.com// Returns the first pt with the maximum Y coordinate 260669a9943b67cc52c24beac853c6f8865dcb197b85reed@google.comstatic int find_max_y(const SkPoint pts[], int count) { 260769a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com SkASSERT(count > 0); 260869a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com SkScalar max = pts[0].fY; 2609c1ea60a9ea63fc590f11f49cd0d744e061891985reed@google.com int firstIndex = 0; 261069a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com for (int i = 1; i < count; ++i) { 2611c1ea60a9ea63fc590f11f49cd0d744e061891985reed@google.com SkScalar y = pts[i].fY; 2612c1ea60a9ea63fc590f11f49cd0d744e061891985reed@google.com if (y > max) { 2613c1ea60a9ea63fc590f11f49cd0d744e061891985reed@google.com max = y; 2614c1ea60a9ea63fc590f11f49cd0d744e061891985reed@google.com firstIndex = i; 261569a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com } 261669a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com } 2617c1ea60a9ea63fc590f11f49cd0d744e061891985reed@google.com return firstIndex; 261869a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com} 261969a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com 2620cabaf1daf3fdcc151c12d59b05bdbe136c178b3breed@google.comstatic int find_diff_pt(const SkPoint pts[], int index, int n, int inc) { 2621cabaf1daf3fdcc151c12d59b05bdbe136c178b3breed@google.com int i = index; 2622cabaf1daf3fdcc151c12d59b05bdbe136c178b3breed@google.com for (;;) { 2623cabaf1daf3fdcc151c12d59b05bdbe136c178b3breed@google.com i = (i + inc) % n; 2624cabaf1daf3fdcc151c12d59b05bdbe136c178b3breed@google.com if (i == index) { // we wrapped around, so abort 2625cabaf1daf3fdcc151c12d59b05bdbe136c178b3breed@google.com break; 2626cabaf1daf3fdcc151c12d59b05bdbe136c178b3breed@google.com } 2627cabaf1daf3fdcc151c12d59b05bdbe136c178b3breed@google.com if (pts[index] != pts[i]) { // found a different point, success! 2628cabaf1daf3fdcc151c12d59b05bdbe136c178b3breed@google.com break; 2629cabaf1daf3fdcc151c12d59b05bdbe136c178b3breed@google.com } 2630cabaf1daf3fdcc151c12d59b05bdbe136c178b3breed@google.com } 2631cabaf1daf3fdcc151c12d59b05bdbe136c178b3breed@google.com return i; 2632cabaf1daf3fdcc151c12d59b05bdbe136c178b3breed@google.com} 2633cabaf1daf3fdcc151c12d59b05bdbe136c178b3breed@google.com 2634c1ea60a9ea63fc590f11f49cd0d744e061891985reed@google.com/** 2635c1ea60a9ea63fc590f11f49cd0d744e061891985reed@google.com * Starting at index, and moving forward (incrementing), find the xmin and 2636c1ea60a9ea63fc590f11f49cd0d744e061891985reed@google.com * xmax of the contiguous points that have the same Y. 2637c1ea60a9ea63fc590f11f49cd0d744e061891985reed@google.com */ 2638c1ea60a9ea63fc590f11f49cd0d744e061891985reed@google.comstatic int find_min_max_x_at_y(const SkPoint pts[], int index, int n, 2639c1ea60a9ea63fc590f11f49cd0d744e061891985reed@google.com int* maxIndexPtr) { 2640c1ea60a9ea63fc590f11f49cd0d744e061891985reed@google.com const SkScalar y = pts[index].fY; 2641c1ea60a9ea63fc590f11f49cd0d744e061891985reed@google.com SkScalar min = pts[index].fX; 2642c1ea60a9ea63fc590f11f49cd0d744e061891985reed@google.com SkScalar max = min; 2643c1ea60a9ea63fc590f11f49cd0d744e061891985reed@google.com int minIndex = index; 2644c1ea60a9ea63fc590f11f49cd0d744e061891985reed@google.com int maxIndex = index; 2645c1ea60a9ea63fc590f11f49cd0d744e061891985reed@google.com for (int i = index + 1; i < n; ++i) { 2646c1ea60a9ea63fc590f11f49cd0d744e061891985reed@google.com if (pts[i].fY != y) { 2647c1ea60a9ea63fc590f11f49cd0d744e061891985reed@google.com break; 2648c1ea60a9ea63fc590f11f49cd0d744e061891985reed@google.com } 2649c1ea60a9ea63fc590f11f49cd0d744e061891985reed@google.com SkScalar x = pts[i].fX; 2650c1ea60a9ea63fc590f11f49cd0d744e061891985reed@google.com if (x < min) { 2651c1ea60a9ea63fc590f11f49cd0d744e061891985reed@google.com min = x; 2652c1ea60a9ea63fc590f11f49cd0d744e061891985reed@google.com minIndex = i; 2653c1ea60a9ea63fc590f11f49cd0d744e061891985reed@google.com } else if (x > max) { 2654c1ea60a9ea63fc590f11f49cd0d744e061891985reed@google.com max = x; 2655c1ea60a9ea63fc590f11f49cd0d744e061891985reed@google.com maxIndex = i; 2656c1ea60a9ea63fc590f11f49cd0d744e061891985reed@google.com } 2657c1ea60a9ea63fc590f11f49cd0d744e061891985reed@google.com } 2658c1ea60a9ea63fc590f11f49cd0d744e061891985reed@google.com *maxIndexPtr = maxIndex; 2659c1ea60a9ea63fc590f11f49cd0d744e061891985reed@google.com return minIndex; 2660c1ea60a9ea63fc590f11f49cd0d744e061891985reed@google.com} 2661c1ea60a9ea63fc590f11f49cd0d744e061891985reed@google.com 2662026beb52a29a620290fcfb24f1e7e9e75547b80freedstatic void crossToDir(SkScalar cross, SkPathPriv::FirstDirection* dir) { 2663026beb52a29a620290fcfb24f1e7e9e75547b80freed *dir = cross > 0 ? SkPathPriv::kCW_FirstDirection : SkPathPriv::kCCW_FirstDirection; 26644eefe6132cbf77696134f65762ebcae574227b77bsalomon@google.com} 26654eefe6132cbf77696134f65762ebcae574227b77bsalomon@google.com 2666ac8543ff574cb08ad46bee691d64e31fe31339e5reed@google.com/* 2667ac8543ff574cb08ad46bee691d64e31fe31339e5reed@google.com * We loop through all contours, and keep the computed cross-product of the 2668ac8543ff574cb08ad46bee691d64e31fe31339e5reed@google.com * contour that contained the global y-max. If we just look at the first 2669ac8543ff574cb08ad46bee691d64e31fe31339e5reed@google.com * contour, we may find one that is wound the opposite way (correctly) since 2670ac8543ff574cb08ad46bee691d64e31fe31339e5reed@google.com * it is the interior of a hole (e.g. 'o'). Thus we must find the contour 2671ac8543ff574cb08ad46bee691d64e31fe31339e5reed@google.com * that is outer most (or at least has the global y-max) before we can consider 2672ac8543ff574cb08ad46bee691d64e31fe31339e5reed@google.com * its cross product. 2673ac8543ff574cb08ad46bee691d64e31fe31339e5reed@google.com */ 2674026beb52a29a620290fcfb24f1e7e9e75547b80freedbool SkPathPriv::CheapComputeFirstDirection(const SkPath& path, FirstDirection* dir) { 26759f4dbca3290cfaca7dd17b71eb6b5b3a0ba5323eherb if (kUnknown_FirstDirection != path.fFirstDirection.load()) { 26769f4dbca3290cfaca7dd17b71eb6b5b3a0ba5323eherb *dir = static_cast<FirstDirection>(path.fFirstDirection.load()); 267730c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com return true; 267830c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com } 2679a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org 2680a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org // don't want to pay the cost for computing this if it 2681a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org // is unknown, so we don't call isConvex() 2682026beb52a29a620290fcfb24f1e7e9e75547b80freed if (SkPath::kConvex_Convexity == path.getConvexityOrUnknown()) { 2683026beb52a29a620290fcfb24f1e7e9e75547b80freed SkASSERT(kUnknown_FirstDirection == path.fFirstDirection); 26849f4dbca3290cfaca7dd17b71eb6b5b3a0ba5323eherb *dir = static_cast<FirstDirection>(path.fFirstDirection.load()); 2685a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org return false; 2686a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org } 268769a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com 2688026beb52a29a620290fcfb24f1e7e9e75547b80freed ContourIter iter(*path.fPathRef.get()); 268969a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com 2690ac8543ff574cb08ad46bee691d64e31fe31339e5reed@google.com // initialize with our logical y-min 2691026beb52a29a620290fcfb24f1e7e9e75547b80freed SkScalar ymax = path.getBounds().fTop; 2692ac8543ff574cb08ad46bee691d64e31fe31339e5reed@google.com SkScalar ymaxCross = 0; 2693ac8543ff574cb08ad46bee691d64e31fe31339e5reed@google.com 269469a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com for (; !iter.done(); iter.next()) { 269569a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com int n = iter.count(); 2696cabaf1daf3fdcc151c12d59b05bdbe136c178b3breed@google.com if (n < 3) { 2697cabaf1daf3fdcc151c12d59b05bdbe136c178b3breed@google.com continue; 2698cabaf1daf3fdcc151c12d59b05bdbe136c178b3breed@google.com } 2699e63793a2c8d2871bf7d95195be7b93ff669688d7djsollen@google.com 2700cabaf1daf3fdcc151c12d59b05bdbe136c178b3breed@google.com const SkPoint* pts = iter.pts(); 270169a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com SkScalar cross = 0; 2702a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org int index = find_max_y(pts, n); 2703a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org if (pts[index].fY < ymax) { 2704a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org continue; 2705a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org } 2706a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org 2707a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org // If there is more than 1 distinct point at the y-max, we take the 2708a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org // x-min and x-max of them and just subtract to compute the dir. 2709a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org if (pts[(index + 1) % n].fY == pts[index].fY) { 2710a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org int maxIndex; 2711a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org int minIndex = find_min_max_x_at_y(pts, index, n, &maxIndex); 2712a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org if (minIndex == maxIndex) { 2713a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org goto TRY_CROSSPROD; 271469a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com } 2715a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org SkASSERT(pts[minIndex].fY == pts[index].fY); 2716a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org SkASSERT(pts[maxIndex].fY == pts[index].fY); 2717a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org SkASSERT(pts[minIndex].fX <= pts[maxIndex].fX); 2718a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org // we just subtract the indices, and let that auto-convert to 2719a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org // SkScalar, since we just want - or + to signal the direction. 2720a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org cross = minIndex - maxIndex; 272169a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com } else { 2722a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org TRY_CROSSPROD: 2723a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org // Find a next and prev index to use for the cross-product test, 2724a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org // but we try to find pts that form non-zero vectors from pts[index] 2725a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org // 2726a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org // Its possible that we can't find two non-degenerate vectors, so 2727a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org // we have to guard our search (e.g. all the pts could be in the 2728a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org // same place). 2729a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org 2730a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org // we pass n - 1 instead of -1 so we don't foul up % operator by 2731a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org // passing it a negative LH argument. 2732a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org int prev = find_diff_pt(pts, index, n, n - 1); 2733a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org if (prev == index) { 2734a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org // completely degenerate, skip to next contour 2735ac8543ff574cb08ad46bee691d64e31fe31339e5reed@google.com continue; 2736ac8543ff574cb08ad46bee691d64e31fe31339e5reed@google.com } 2737a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org int next = find_diff_pt(pts, index, n, 1); 2738a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org SkASSERT(next != index); 2739a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org cross = cross_prod(pts[prev], pts[index], pts[next]); 2740a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org // if we get a zero and the points are horizontal, then we look at the spread in 2741a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org // x-direction. We really should continue to walk away from the degeneracy until 2742a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org // there is a divergence. 2743a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org if (0 == cross && pts[prev].fY == pts[index].fY && pts[next].fY == pts[index].fY) { 2744a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org // construct the subtract so we get the correct Direction below 2745a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org cross = pts[index].fX - pts[next].fX; 2746188bfcf7666f4d264329063fd9bf5c44e7734fd8reed@google.com } 2747a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org } 2748fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 2749a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org if (cross) { 2750a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org // record our best guess so far 2751a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org ymax = pts[index].fY; 2752a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org ymaxCross = cross; 275369a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com } 275469a9943b67cc52c24beac853c6f8865dcb197b85reed@google.com } 275530c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com if (ymaxCross) { 275630c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com crossToDir(ymaxCross, dir); 2757026beb52a29a620290fcfb24f1e7e9e75547b80freed path.fFirstDirection = *dir; 275830c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com return true; 275930c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com } else { 276030c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com return false; 276130c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com } 2762ac8543ff574cb08ad46bee691d64e31fe31339e5reed@google.com} 2763bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org 2764bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org/////////////////////////////////////////////////////////////////////////////// 2765bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org 27669aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclarkstatic bool between(SkScalar a, SkScalar b, SkScalar c) { 27679aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkASSERT(((a <= b && b <= c) || (a >= b && b >= c)) == ((a - b) * (c - b) <= 0) 27689aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark || (SkScalarNearlyZero(a) && SkScalarNearlyZero(b) && SkScalarNearlyZero(c))); 27699aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark return (a - b) * (c - b) <= 0; 27709aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark} 27719aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark 2772bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.orgstatic SkScalar eval_cubic_pts(SkScalar c0, SkScalar c1, SkScalar c2, SkScalar c3, 2773bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org SkScalar t) { 2774bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org SkScalar A = c3 + 3*(c1 - c2) - c0; 2775bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org SkScalar B = 3*(c2 - c1 - c1 + c0); 2776bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org SkScalar C = 3*(c1 - c0); 2777bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org SkScalar D = c0; 2778a99b6ceff92183b424634f2e7276b9ea1d59e69dMike Reed return poly_eval(A, B, C, D, t); 2779bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org} 2780bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org 2781bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.orgtemplate <size_t N> static void find_minmax(const SkPoint pts[], 2782bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org SkScalar* minPtr, SkScalar* maxPtr) { 2783bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org SkScalar min, max; 2784bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org min = max = pts[0].fX; 2785bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org for (size_t i = 1; i < N; ++i) { 2786bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org min = SkMinScalar(min, pts[i].fX); 2787bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org max = SkMaxScalar(max, pts[i].fX); 2788bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org } 2789bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org *minPtr = min; 2790bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org *maxPtr = max; 2791bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org} 2792bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org 27939cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclarkstatic bool checkOnCurve(SkScalar x, SkScalar y, const SkPoint& start, const SkPoint& end) { 27949cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark if (start.fY == end.fY) { 27959cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark return between(start.fX, x, end.fX) && x != end.fX; 27969cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark } else { 27979cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark return x == start.fX && y == start.fY; 27989cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark } 27999cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark} 28009cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark 28019aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclarkstatic int winding_mono_cubic(const SkPoint pts[], SkScalar x, SkScalar y, int* onCurveCount) { 28029cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark SkScalar y0 = pts[0].fY; 28039cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark SkScalar y3 = pts[3].fY; 28049cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark 28059cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark int dir = 1; 28069cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark if (y0 > y3) { 28079cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark SkTSwap(y0, y3); 28089cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark dir = -1; 28099cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark } 28109cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark if (y < y0 || y > y3) { 28119aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark return 0; 2812bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org } 28139cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark if (checkOnCurve(x, y, pts[0], pts[3])) { 28149cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark *onCurveCount += 1; 28159cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark return 0; 28169cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark } 28179cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark if (y == y3) { 2818bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org return 0; 2819bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org } 28209cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark 2821bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org // quickreject or quickaccept 2822bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org SkScalar min, max; 2823bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org find_minmax<4>(pts, &min, &max); 2824bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org if (x < min) { 2825bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org return 0; 2826bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org } 2827bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org if (x > max) { 2828bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org return dir; 2829bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org } 2830fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 2831bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org // compute the actual x(t) value 2832a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org SkScalar t; 2833276e63361c73fed6c6528b322400ece81fd1d067mbarbella if (!SkCubicClipper::ChopMonoAtY(pts, y, &t)) { 283499600d0a158e3b2f1ff077a6fd102e78ce9db0e4mbarbella return 0; 2835276e63361c73fed6c6528b322400ece81fd1d067mbarbella } 2836a1a097ee814d05a92487d85db8ad02e1d852fd6fcommit-bot@chromium.org SkScalar xt = eval_cubic_pts(pts[0].fX, pts[1].fX, pts[2].fX, pts[3].fX, t); 28379aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark if (SkScalarNearlyEqual(xt, x)) { 28389aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark if (x != pts[3].fX || y != pts[3].fY) { // don't test end points; they're start points 28399aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark *onCurveCount += 1; 28409cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark return 0; 28419aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark } 28429aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark } 2843bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org return xt < x ? dir : 0; 2844bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org} 2845bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org 28469aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclarkstatic int winding_cubic(const SkPoint pts[], SkScalar x, SkScalar y, int* onCurveCount) { 2847bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org SkPoint dst[10]; 2848bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org int n = SkChopCubicAtYExtrema(pts, dst); 2849bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org int w = 0; 2850bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org for (int i = 0; i <= n; ++i) { 28519aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark w += winding_mono_cubic(&dst[i * 3], x, y, onCurveCount); 2852bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org } 2853bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org return w; 2854bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org} 2855bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org 28569aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclarkstatic double conic_eval_numerator(const SkScalar src[], SkScalar w, SkScalar t) { 28579aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkASSERT(src); 28589aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkASSERT(t >= 0 && t <= 1); 28599aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkScalar src2w = src[2] * w; 28609aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkScalar C = src[0]; 28619aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkScalar A = src[4] - 2 * src2w + C; 28629aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkScalar B = 2 * (src2w - C); 2863a99b6ceff92183b424634f2e7276b9ea1d59e69dMike Reed return poly_eval(A, B, C, t); 28649aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark} 28659aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark 28669aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark 28679aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclarkstatic double conic_eval_denominator(SkScalar w, SkScalar t) { 28689aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkScalar B = 2 * (w - 1); 28699aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkScalar C = 1; 28709aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkScalar A = -B; 2871a99b6ceff92183b424634f2e7276b9ea1d59e69dMike Reed return poly_eval(A, B, C, t); 28729aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark} 28739aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark 28749aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclarkstatic int winding_mono_conic(const SkConic& conic, SkScalar x, SkScalar y, int* onCurveCount) { 28759aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark const SkPoint* pts = conic.fPts; 2876bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org SkScalar y0 = pts[0].fY; 2877bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org SkScalar y2 = pts[2].fY; 2878fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 2879bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org int dir = 1; 2880bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org if (y0 > y2) { 2881bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org SkTSwap(y0, y2); 2882bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org dir = -1; 2883bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org } 28849aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark if (y < y0 || y > y2) { 28859aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark return 0; 28869aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark } 28879cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark if (checkOnCurve(x, y, pts[0], pts[2])) { 28889cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark *onCurveCount += 1; 28899cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark return 0; 28909cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark } 28919aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark if (y == y2) { 2892bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org return 0; 2893bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org } 2894fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 28959aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkScalar roots[2]; 28969aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkScalar A = pts[2].fY; 28979aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkScalar B = pts[1].fY * conic.fW - y * conic.fW + y; 28989aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkScalar C = pts[0].fY; 28999aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark A += C - 2 * B; // A = a + c - 2*(b*w - yCept*w + yCept) 29009aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark B -= C; // B = b*w - w * yCept + yCept - a 29019aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark C -= y; 29029aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark int n = SkFindUnitQuadRoots(A, 2 * B, C, roots); 29039aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkASSERT(n <= 1); 29049aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkScalar xt; 29059aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark if (0 == n) { 29069cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark // zero roots are returned only when y0 == y 29079cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark // Need [0] if dir == 1 29089cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark // and [2] if dir == -1 29099cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark xt = pts[1 - dir].fX; 29109aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark } else { 29119aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkScalar t = roots[0]; 29129aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark xt = conic_eval_numerator(&pts[0].fX, conic.fW, t) / conic_eval_denominator(conic.fW, t); 29139aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark } 29149aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark if (SkScalarNearlyEqual(xt, x)) { 29159aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark if (x != pts[2].fX || y != pts[2].fY) { // don't test end points; they're start points 29169aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark *onCurveCount += 1; 29179cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark return 0; 29189aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark } 29199aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark } 29209aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark return xt < x ? dir : 0; 29219aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark} 29229aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark 29239aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclarkstatic bool is_mono_quad(SkScalar y0, SkScalar y1, SkScalar y2) { 29249aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark // return SkScalarSignAsInt(y0 - y1) + SkScalarSignAsInt(y1 - y2) != 0; 29259aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark if (y0 == y1) { 29269aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark return true; 29279aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark } 29289aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark if (y0 < y1) { 29299aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark return y1 <= y2; 29309aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark } else { 29319aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark return y1 >= y2; 29329aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark } 29339aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark} 29349aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark 29359aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclarkstatic int winding_conic(const SkPoint pts[], SkScalar x, SkScalar y, SkScalar weight, 29369aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark int* onCurveCount) { 29379aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkConic conic(pts, weight); 29389aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkConic chopped[2]; 29391e1e5094e0fda27b09826c573a3a68d08e7b6ae1caryclark // If the data points are very large, the conic may not be monotonic but may also 29401e1e5094e0fda27b09826c573a3a68d08e7b6ae1caryclark // fail to chop. Then, the chopper does not split the original conic in two. 2941e114dd63161b5efffbffb17e4d3facad77f34507caryclark bool isMono = is_mono_quad(pts[0].fY, pts[1].fY, pts[2].fY) || !conic.chopAtYExtrema(chopped); 2942e114dd63161b5efffbffb17e4d3facad77f34507caryclark int w = winding_mono_conic(isMono ? conic : chopped[0], x, y, onCurveCount); 2943e114dd63161b5efffbffb17e4d3facad77f34507caryclark if (!isMono) { 29449aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark w += winding_mono_conic(chopped[1], x, y, onCurveCount); 29459aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark } 29469aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark return w; 29479aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark} 29489aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark 29499aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclarkstatic int winding_mono_quad(const SkPoint pts[], SkScalar x, SkScalar y, int* onCurveCount) { 29509aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkScalar y0 = pts[0].fY; 29519aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkScalar y2 = pts[2].fY; 29529aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark 29539aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark int dir = 1; 29549aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark if (y0 > y2) { 29559aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkTSwap(y0, y2); 29569aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark dir = -1; 29579aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark } 29589aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark if (y < y0 || y > y2) { 29599aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark return 0; 29609aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark } 29619cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark if (checkOnCurve(x, y, pts[0], pts[2])) { 29629cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark *onCurveCount += 1; 29639cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark return 0; 29649cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark } 29659aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark if (y == y2) { 29669aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark return 0; 29679aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark } 2968bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org // bounds check on X (not required. is it faster?) 2969bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org#if 0 2970bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org if (pts[0].fX > x && pts[1].fX > x && pts[2].fX > x) { 2971bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org return 0; 2972bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org } 2973bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org#endif 2974fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 2975bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org SkScalar roots[2]; 2976bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org int n = SkFindUnitQuadRoots(pts[0].fY - 2 * pts[1].fY + pts[2].fY, 2977bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org 2 * (pts[1].fY - pts[0].fY), 2978bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org pts[0].fY - y, 2979bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org roots); 2980bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org SkASSERT(n <= 1); 2981bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org SkScalar xt; 2982bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org if (0 == n) { 29839cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark // zero roots are returned only when y0 == y 29849cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark // Need [0] if dir == 1 29859cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark // and [2] if dir == -1 29869cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark xt = pts[1 - dir].fX; 2987bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org } else { 2988bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org SkScalar t = roots[0]; 2989bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org SkScalar C = pts[0].fX; 2990bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org SkScalar A = pts[2].fX - 2 * pts[1].fX + C; 2991bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org SkScalar B = 2 * (pts[1].fX - C); 2992a99b6ceff92183b424634f2e7276b9ea1d59e69dMike Reed xt = poly_eval(A, B, C, t); 2993bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org } 29949aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark if (SkScalarNearlyEqual(xt, x)) { 29959aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark if (x != pts[2].fX || y != pts[2].fY) { // don't test end points; they're start points 29969aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark *onCurveCount += 1; 29979cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark return 0; 29989aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark } 2999bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org } 30009aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark return xt < x ? dir : 0; 3001bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org} 3002bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org 30039aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclarkstatic int winding_quad(const SkPoint pts[], SkScalar x, SkScalar y, int* onCurveCount) { 3004bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org SkPoint dst[5]; 3005bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org int n = 0; 3006fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 3007bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org if (!is_mono_quad(pts[0].fY, pts[1].fY, pts[2].fY)) { 3008bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org n = SkChopQuadAtYExtrema(pts, dst); 3009bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org pts = dst; 3010bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org } 30119aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark int w = winding_mono_quad(pts, x, y, onCurveCount); 3012bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org if (n > 0) { 30139aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark w += winding_mono_quad(&pts[2], x, y, onCurveCount); 3014bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org } 3015bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org return w; 3016bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org} 3017bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org 30189aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclarkstatic int winding_line(const SkPoint pts[], SkScalar x, SkScalar y, int* onCurveCount) { 3019bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org SkScalar x0 = pts[0].fX; 3020bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org SkScalar y0 = pts[0].fY; 3021bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org SkScalar x1 = pts[1].fX; 3022bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org SkScalar y1 = pts[1].fY; 3023fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 3024bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org SkScalar dy = y1 - y0; 3025fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 3026bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org int dir = 1; 3027bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org if (y0 > y1) { 3028bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org SkTSwap(y0, y1); 3029bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org dir = -1; 3030bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org } 30319aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark if (y < y0 || y > y1) { 3032bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org return 0; 3033bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org } 30349cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark if (checkOnCurve(x, y, pts[0], pts[1])) { 30359cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark *onCurveCount += 1; 30369cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark return 0; 30379cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark } 30389cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark if (y == y1) { 30399aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark return 0; 30409aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark } 3041a99b6ceff92183b424634f2e7276b9ea1d59e69dMike Reed SkScalar cross = (x1 - x0) * (y - pts[0].fY) - dy * (x - x0); 3042fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 30439aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark if (!cross) { 3044c91065d028472688ce15e635a29abe5256ff89effs // zero cross means the point is on the line, and since the case where 3045c91065d028472688ce15e635a29abe5256ff89effs // y of the query point is at the end point is handled above, we can be 3046c91065d028472688ce15e635a29abe5256ff89effs // sure that we're on the line (excluding the end point) here 30479cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark if (x != x1 || y != pts[1].fY) { 30489cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark *onCurveCount += 1; 30499cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark } 30509aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark dir = 0; 30519aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark } else if (SkScalarSignAsInt(cross) == dir) { 3052bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org dir = 0; 3053bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org } 3054bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org return dir; 3055bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org} 3056bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org 30579aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclarkstatic void tangent_cubic(const SkPoint pts[], SkScalar x, SkScalar y, 30589aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkTDArray<SkVector>* tangents) { 30599aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark if (!between(pts[0].fY, y, pts[1].fY) && !between(pts[1].fY, y, pts[2].fY) 30609aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark && !between(pts[2].fY, y, pts[3].fY)) { 30619aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark return; 30629aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark } 30639aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark if (!between(pts[0].fX, x, pts[1].fX) && !between(pts[1].fX, x, pts[2].fX) 30649aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark && !between(pts[2].fX, x, pts[3].fX)) { 30659aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark return; 30669aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark } 30679aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkPoint dst[10]; 30689aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark int n = SkChopCubicAtYExtrema(pts, dst); 30699aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark for (int i = 0; i <= n; ++i) { 30709aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkPoint* c = &dst[i * 3]; 30719aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkScalar t; 3072276e63361c73fed6c6528b322400ece81fd1d067mbarbella if (!SkCubicClipper::ChopMonoAtY(c, y, &t)) { 307399600d0a158e3b2f1ff077a6fd102e78ce9db0e4mbarbella continue; 3074276e63361c73fed6c6528b322400ece81fd1d067mbarbella } 30759aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkScalar xt = eval_cubic_pts(c[0].fX, c[1].fX, c[2].fX, c[3].fX, t); 30769aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark if (!SkScalarNearlyEqual(x, xt)) { 30779aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark continue; 30789aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark } 30799aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkVector tangent; 30809aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkEvalCubicAt(c, t, nullptr, &tangent, nullptr); 30819aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark tangents->push(tangent); 30829aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark } 30839aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark} 30849aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark 30859aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclarkstatic void tangent_conic(const SkPoint pts[], SkScalar x, SkScalar y, SkScalar w, 30869aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkTDArray<SkVector>* tangents) { 30879aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark if (!between(pts[0].fY, y, pts[1].fY) && !between(pts[1].fY, y, pts[2].fY)) { 30889aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark return; 30899aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark } 30909aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark if (!between(pts[0].fX, x, pts[1].fX) && !between(pts[1].fX, x, pts[2].fX)) { 30919aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark return; 30929aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark } 30939aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkScalar roots[2]; 30949aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkScalar A = pts[2].fY; 30959aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkScalar B = pts[1].fY * w - y * w + y; 30969aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkScalar C = pts[0].fY; 30979aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark A += C - 2 * B; // A = a + c - 2*(b*w - yCept*w + yCept) 30989aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark B -= C; // B = b*w - w * yCept + yCept - a 30999aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark C -= y; 31009aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark int n = SkFindUnitQuadRoots(A, 2 * B, C, roots); 31019aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark for (int index = 0; index < n; ++index) { 31029aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkScalar t = roots[index]; 31039aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkScalar xt = conic_eval_numerator(&pts[0].fX, w, t) / conic_eval_denominator(w, t); 31049aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark if (!SkScalarNearlyEqual(x, xt)) { 31059aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark continue; 31069aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark } 31079aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkConic conic(pts, w); 31089aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark tangents->push(conic.evalTangentAt(t)); 31099aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark } 31109aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark} 31119aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark 31129aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclarkstatic void tangent_quad(const SkPoint pts[], SkScalar x, SkScalar y, 31139aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkTDArray<SkVector>* tangents) { 31149aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark if (!between(pts[0].fY, y, pts[1].fY) && !between(pts[1].fY, y, pts[2].fY)) { 31159aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark return; 31169aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark } 31179aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark if (!between(pts[0].fX, x, pts[1].fX) && !between(pts[1].fX, x, pts[2].fX)) { 31189aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark return; 31199aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark } 31209aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkScalar roots[2]; 31219aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark int n = SkFindUnitQuadRoots(pts[0].fY - 2 * pts[1].fY + pts[2].fY, 31229aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark 2 * (pts[1].fY - pts[0].fY), 31239aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark pts[0].fY - y, 31249aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark roots); 31259aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark for (int index = 0; index < n; ++index) { 31269aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkScalar t = roots[index]; 31279aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkScalar C = pts[0].fX; 31289aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkScalar A = pts[2].fX - 2 * pts[1].fX + C; 31299aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkScalar B = 2 * (pts[1].fX - C); 3130a99b6ceff92183b424634f2e7276b9ea1d59e69dMike Reed SkScalar xt = poly_eval(A, B, C, t); 31319aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark if (!SkScalarNearlyEqual(x, xt)) { 31329aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark continue; 31339aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark } 31349aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark tangents->push(SkEvalQuadTangentAt(pts, t)); 31359aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark } 31369aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark} 31379aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark 31389aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclarkstatic void tangent_line(const SkPoint pts[], SkScalar x, SkScalar y, 31399aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkTDArray<SkVector>* tangents) { 31409aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkScalar y0 = pts[0].fY; 31419aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkScalar y1 = pts[1].fY; 31429aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark if (!between(y0, y, y1)) { 31439aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark return; 31449aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark } 31459aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkScalar x0 = pts[0].fX; 31469aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkScalar x1 = pts[1].fX; 31479aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark if (!between(x0, x, x1)) { 31489aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark return; 31499aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark } 31509aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkScalar dx = x1 - x0; 31519aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkScalar dy = y1 - y0; 31529aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark if (!SkScalarNearlyEqual((x - x0) * dy, dx * (y - y0))) { 31539aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark return; 31549aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark } 31559aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkVector v; 31569aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark v.set(dx, dy); 31579aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark tangents->push(v); 31589aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark} 31599aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark 31604db592c4085afed2be27a208d778f9ee13e671abreed@google.comstatic bool contains_inclusive(const SkRect& r, SkScalar x, SkScalar y) { 31614db592c4085afed2be27a208d778f9ee13e671abreed@google.com return r.fLeft <= x && x <= r.fRight && r.fTop <= y && y <= r.fBottom; 31624db592c4085afed2be27a208d778f9ee13e671abreed@google.com} 31634db592c4085afed2be27a208d778f9ee13e671abreed@google.com 3164bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.orgbool SkPath::contains(SkScalar x, SkScalar y) const { 3165bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org bool isInverse = this->isInverseFillType(); 3166bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org if (this->isEmpty()) { 3167bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org return isInverse; 3168bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org } 3169fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 31704db592c4085afed2be27a208d778f9ee13e671abreed@google.com if (!contains_inclusive(this->getBounds(), x, y)) { 3171bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org return isInverse; 3172bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org } 3173fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 3174bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org SkPath::Iter iter(*this, true); 3175bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org bool done = false; 3176bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org int w = 0; 31779aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark int onCurveCount = 0; 3178bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org do { 3179bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org SkPoint pts[4]; 3180bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org switch (iter.next(pts, false)) { 3181bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org case SkPath::kMove_Verb: 3182bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org case SkPath::kClose_Verb: 3183bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org break; 3184bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org case SkPath::kLine_Verb: 31859aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark w += winding_line(pts, x, y, &onCurveCount); 3186bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org break; 3187bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org case SkPath::kQuad_Verb: 31889aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark w += winding_quad(pts, x, y, &onCurveCount); 3189bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org break; 3190277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com case SkPath::kConic_Verb: 31919aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark w += winding_conic(pts, x, y, iter.conicWeight(), &onCurveCount); 3192277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com break; 3193bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org case SkPath::kCubic_Verb: 31949aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark w += winding_cubic(pts, x, y, &onCurveCount); 3195bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org break; 3196bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org case SkPath::kDone_Verb: 3197bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org done = true; 3198bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org break; 3199277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com } 3200bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org } while (!done); 32019aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark bool evenOddFill = SkPath::kEvenOdd_FillType == this->getFillType() 32029aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark || SkPath::kInverseEvenOdd_FillType == this->getFillType(); 32039aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark if (evenOddFill) { 32049aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark w &= 1; 32059aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark } 32069aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark if (w) { 32079aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark return !isInverse; 32089aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark } 32099aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark if (onCurveCount <= 1) { 32109aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark return SkToBool(onCurveCount) ^ isInverse; 3211bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org } 32129aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark if ((onCurveCount & 1) || evenOddFill) { 32139aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark return SkToBool(onCurveCount & 1) ^ isInverse; 32149aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark } 32159d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary // If the point touches an even number of curves, and the fill is winding, check for 32169aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark // coincidence. Count coincidence as places where the on curve points have identical tangents. 32179aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark iter.setPath(*this, true); 32189cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark done = false; 32199aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkTDArray<SkVector> tangents; 32209aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark do { 32219aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark SkPoint pts[4]; 32229aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark int oldCount = tangents.count(); 32239aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark switch (iter.next(pts, false)) { 32249aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark case SkPath::kMove_Verb: 32259aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark case SkPath::kClose_Verb: 32269aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark break; 32279aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark case SkPath::kLine_Verb: 32289aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark tangent_line(pts, x, y, &tangents); 32299aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark break; 32309aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark case SkPath::kQuad_Verb: 32319aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark tangent_quad(pts, x, y, &tangents); 32329aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark break; 32339aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark case SkPath::kConic_Verb: 32349aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark tangent_conic(pts, x, y, iter.conicWeight(), &tangents); 32359aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark break; 32369aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark case SkPath::kCubic_Verb: 32379aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark tangent_cubic(pts, x, y, &tangents); 32389aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark break; 32399aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark case SkPath::kDone_Verb: 32409aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark done = true; 32419aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark break; 32429aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark } 32439aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark if (tangents.count() > oldCount) { 32449aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark int last = tangents.count() - 1; 32459aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark const SkVector& tangent = tangents[last]; 32469aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark if (SkScalarNearlyZero(tangent.lengthSqd())) { 32479aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark tangents.remove(last); 32489aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark } else { 32499aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark for (int index = 0; index < last; ++index) { 32509aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark const SkVector& test = tangents[index]; 32519aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark if (SkScalarNearlyZero(test.cross(tangent)) 32529cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark && SkScalarSignAsInt(tangent.fX * test.fX) <= 0 32539cb5d755e7ea8647bcf8bb1ee151ca4c86051107caryclark && SkScalarSignAsInt(tangent.fY * test.fY) <= 0) { 32549aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark tangents.remove(last); 32559aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark tangents.removeShuffle(index); 32569aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark break; 32579aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark } 32589aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark } 32599aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark } 32609aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark } 32619aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark } while (!done); 32629aacd9029c7076d5c0f0e62338b82ce91de68ef9caryclark return SkToBool(tangents.count()) ^ isInverse; 3263bad1b2ff1d34ff86693b776f89d7b46995746127mike@reedtribe.org} 3264aa0df4e98d39cf0691fbaf0766c9f5f7ec72177ffmalita 3265aa0df4e98d39cf0691fbaf0766c9f5f7ec72177ffmalitaint SkPath::ConvertConicToQuads(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2, 3266aa0df4e98d39cf0691fbaf0766c9f5f7ec72177ffmalita SkScalar w, SkPoint pts[], int pow2) { 3267aa0df4e98d39cf0691fbaf0766c9f5f7ec72177ffmalita const SkConic conic(p0, p1, p2, w); 3268aa0df4e98d39cf0691fbaf0766c9f5f7ec72177ffmalita return conic.chopIntoQuadsPOW2(pts, pow2); 3269aa0df4e98d39cf0691fbaf0766c9f5f7ec72177ffmalita} 3270edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon 3271edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomonbool SkPathPriv::IsSimpleClosedRect(const SkPath& path, SkRect* rect, SkPath::Direction* direction, 3272edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon unsigned* start) { 3273edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon if (path.getSegmentMasks() != SkPath::kLine_SegmentMask) { 3274edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon return false; 3275edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon } 3276edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon SkPath::RawIter iter(path); 3277edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon SkPoint verbPts[4]; 3278edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon SkPath::Verb v; 3279edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon SkPoint rectPts[5]; 3280edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon int rectPtCnt = 0; 3281edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon while ((v = iter.next(verbPts)) != SkPath::kDone_Verb) { 3282edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon switch (v) { 3283edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon case SkPath::kMove_Verb: 3284edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon if (0 != rectPtCnt) { 3285edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon return false; 3286edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon } 3287edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon rectPts[0] = verbPts[0]; 3288edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon ++rectPtCnt; 3289edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon break; 3290edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon case SkPath::kLine_Verb: 3291edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon if (5 == rectPtCnt) { 3292edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon return false; 3293edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon } 3294edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon rectPts[rectPtCnt] = verbPts[1]; 3295edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon ++rectPtCnt; 3296edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon break; 3297edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon case SkPath::kClose_Verb: 3298edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon if (4 == rectPtCnt) { 3299edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon rectPts[4] = rectPts[0]; 3300edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon rectPtCnt = 5; 3301edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon } 3302edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon break; 3303edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon default: 3304edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon return false; 3305edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon } 3306edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon } 3307edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon if (rectPtCnt < 5) { 3308edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon return false; 3309edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon } 3310edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon if (rectPts[0] != rectPts[4]) { 3311edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon return false; 3312edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon } 3313057ae8a15ddd2af639a829d63aca29cbc6b1bb57bsalomon // Check for two cases of rectangles: pts 0 and 3 form a vertical edge or a horizontal edge ( 3314057ae8a15ddd2af639a829d63aca29cbc6b1bb57bsalomon // and pts 1 and 2 the opposite vertical or horizontal edge). 3315057ae8a15ddd2af639a829d63aca29cbc6b1bb57bsalomon bool vec03IsVertical; 3316057ae8a15ddd2af639a829d63aca29cbc6b1bb57bsalomon if (rectPts[0].fX == rectPts[3].fX && rectPts[1].fX == rectPts[2].fX && 3317057ae8a15ddd2af639a829d63aca29cbc6b1bb57bsalomon rectPts[0].fY == rectPts[1].fY && rectPts[3].fY == rectPts[2].fY) { 3318057ae8a15ddd2af639a829d63aca29cbc6b1bb57bsalomon // Make sure it has non-zero width and height 3319057ae8a15ddd2af639a829d63aca29cbc6b1bb57bsalomon if (rectPts[0].fX == rectPts[1].fX || rectPts[0].fY == rectPts[3].fY) { 3320057ae8a15ddd2af639a829d63aca29cbc6b1bb57bsalomon return false; 3321edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon } 3322057ae8a15ddd2af639a829d63aca29cbc6b1bb57bsalomon vec03IsVertical = true; 3323057ae8a15ddd2af639a829d63aca29cbc6b1bb57bsalomon } else if (rectPts[0].fY == rectPts[3].fY && rectPts[1].fY == rectPts[2].fY && 3324057ae8a15ddd2af639a829d63aca29cbc6b1bb57bsalomon rectPts[0].fX == rectPts[1].fX && rectPts[3].fX == rectPts[2].fX) { 3325057ae8a15ddd2af639a829d63aca29cbc6b1bb57bsalomon // Make sure it has non-zero width and height 3326057ae8a15ddd2af639a829d63aca29cbc6b1bb57bsalomon if (rectPts[0].fY == rectPts[1].fY || rectPts[0].fX == rectPts[3].fX) { 3327edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon return false; 3328edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon } 3329057ae8a15ddd2af639a829d63aca29cbc6b1bb57bsalomon vec03IsVertical = false; 3330057ae8a15ddd2af639a829d63aca29cbc6b1bb57bsalomon } else { 3331edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon return false; 3332edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon } 3333057ae8a15ddd2af639a829d63aca29cbc6b1bb57bsalomon // Set sortFlags so that it has the low bit set if pt index 0 is on right edge and second bit 3334057ae8a15ddd2af639a829d63aca29cbc6b1bb57bsalomon // set if it is on the bottom edge. 3335057ae8a15ddd2af639a829d63aca29cbc6b1bb57bsalomon unsigned sortFlags = 3336057ae8a15ddd2af639a829d63aca29cbc6b1bb57bsalomon ((rectPts[0].fX < rectPts[2].fX) ? 0b00 : 0b01) | 3337057ae8a15ddd2af639a829d63aca29cbc6b1bb57bsalomon ((rectPts[0].fY < rectPts[2].fY) ? 0b00 : 0b10); 3338057ae8a15ddd2af639a829d63aca29cbc6b1bb57bsalomon switch (sortFlags) { 3339057ae8a15ddd2af639a829d63aca29cbc6b1bb57bsalomon case 0b00: 3340057ae8a15ddd2af639a829d63aca29cbc6b1bb57bsalomon rect->set(rectPts[0].fX, rectPts[0].fY, rectPts[2].fX, rectPts[2].fY); 3341057ae8a15ddd2af639a829d63aca29cbc6b1bb57bsalomon *direction = vec03IsVertical ? SkPath::kCW_Direction : SkPath::kCCW_Direction; 3342057ae8a15ddd2af639a829d63aca29cbc6b1bb57bsalomon *start = 0; 3343057ae8a15ddd2af639a829d63aca29cbc6b1bb57bsalomon break; 3344057ae8a15ddd2af639a829d63aca29cbc6b1bb57bsalomon case 0b01: 3345057ae8a15ddd2af639a829d63aca29cbc6b1bb57bsalomon rect->set(rectPts[2].fX, rectPts[0].fY, rectPts[0].fX, rectPts[2].fY); 3346057ae8a15ddd2af639a829d63aca29cbc6b1bb57bsalomon *direction = vec03IsVertical ? SkPath::kCCW_Direction : SkPath::kCW_Direction; 3347057ae8a15ddd2af639a829d63aca29cbc6b1bb57bsalomon *start = 1; 3348057ae8a15ddd2af639a829d63aca29cbc6b1bb57bsalomon break; 3349057ae8a15ddd2af639a829d63aca29cbc6b1bb57bsalomon case 0b10: 3350057ae8a15ddd2af639a829d63aca29cbc6b1bb57bsalomon rect->set(rectPts[0].fX, rectPts[2].fY, rectPts[2].fX, rectPts[0].fY); 3351057ae8a15ddd2af639a829d63aca29cbc6b1bb57bsalomon *direction = vec03IsVertical ? SkPath::kCCW_Direction : SkPath::kCW_Direction; 3352057ae8a15ddd2af639a829d63aca29cbc6b1bb57bsalomon *start = 3; 3353057ae8a15ddd2af639a829d63aca29cbc6b1bb57bsalomon break; 3354057ae8a15ddd2af639a829d63aca29cbc6b1bb57bsalomon case 0b11: 3355057ae8a15ddd2af639a829d63aca29cbc6b1bb57bsalomon rect->set(rectPts[2].fX, rectPts[2].fY, rectPts[0].fX, rectPts[0].fY); 3356057ae8a15ddd2af639a829d63aca29cbc6b1bb57bsalomon *direction = vec03IsVertical ? SkPath::kCW_Direction : SkPath::kCCW_Direction; 3357057ae8a15ddd2af639a829d63aca29cbc6b1bb57bsalomon *start = 2; 3358057ae8a15ddd2af639a829d63aca29cbc6b1bb57bsalomon break; 3359edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon } 3360edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon return true; 3361edc743a57657107b873ed2fc2efeeff1b1efcd23bsalomon} 336221af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon 336321af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomonvoid SkPathPriv::CreateDrawArcPath(SkPath* path, const SkRect& oval, SkScalar startAngle, 336421af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon SkScalar sweepAngle, bool useCenter, bool isFillNoPathEffect) { 336521af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon SkASSERT(!oval.isEmpty()); 336621af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon SkASSERT(sweepAngle); 336721af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon 336821af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon path->reset(); 336921af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon path->setIsVolatile(true); 337021af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon path->setFillType(SkPath::kWinding_FillType); 337121af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon if (isFillNoPathEffect && SkScalarAbs(sweepAngle) >= 360.f) { 337221af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon path->addOval(oval); 337321af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon return; 337421af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon } 337521af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon if (useCenter) { 337621af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon path->moveTo(oval.centerX(), oval.centerY()); 337721af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon } 337821af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon // Arc to mods at 360 and drawArc is not supposed to. 337921af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon bool forceMoveTo = !useCenter; 338021af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon while (sweepAngle <= -360.f) { 338121af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon path->arcTo(oval, startAngle, -180.f, forceMoveTo); 338221af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon startAngle -= 180.f; 338321af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon path->arcTo(oval, startAngle, -180.f, false); 338421af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon startAngle -= 180.f; 338521af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon forceMoveTo = false; 338621af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon sweepAngle += 360.f; 338721af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon } 338821af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon while (sweepAngle >= 360.f) { 338921af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon path->arcTo(oval, startAngle, 180.f, forceMoveTo); 339021af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon startAngle += 180.f; 339121af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon path->arcTo(oval, startAngle, 180.f, false); 339221af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon startAngle += 180.f; 339321af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon forceMoveTo = false; 339421af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon sweepAngle -= 360.f; 339521af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon } 339621af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon path->arcTo(oval, startAngle, sweepAngle, forceMoveTo); 339721af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon if (useCenter) { 339821af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon path->close(); 339921af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon } 340021af9ca1b1f54d9ba1de055aa8475928d5c8ecdfbsalomon} 34010d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed 34020d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed/////////////////////////////////////////////////////////////////////////////////////////////////// 34030d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed#include "SkNx.h" 34040d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed 34050d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reedstatic int compute_quad_extremas(const SkPoint src[3], SkPoint extremas[3]) { 34060d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed SkScalar ts[2]; 34070d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed int n = SkFindQuadExtrema(src[0].fX, src[1].fX, src[2].fX, ts); 34080d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed n += SkFindQuadExtrema(src[0].fY, src[1].fY, src[2].fY, &ts[n]); 34090d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed SkASSERT(n >= 0 && n <= 2); 34100d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed for (int i = 0; i < n; ++i) { 34110d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed extremas[i] = SkEvalQuadAt(src, ts[i]); 34120d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed } 34130d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed extremas[n] = src[2]; 34140d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed return n + 1; 34150d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed} 34160d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed 34170d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reedstatic int compute_conic_extremas(const SkPoint src[3], SkScalar w, SkPoint extremas[3]) { 34180d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed SkConic conic(src[0], src[1], src[2], w); 34190d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed SkScalar ts[2]; 34200d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed int n = conic.findXExtrema(ts); 34210d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed n += conic.findYExtrema(&ts[n]); 34220d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed SkASSERT(n >= 0 && n <= 2); 34230d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed for (int i = 0; i < n; ++i) { 34240d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed extremas[i] = conic.evalAt(ts[i]); 34250d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed } 34260d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed extremas[n] = src[2]; 34270d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed return n + 1; 34280d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed} 34290d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed 34300d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reedstatic int compute_cubic_extremas(const SkPoint src[3], SkPoint extremas[5]) { 34310d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed SkScalar ts[4]; 34320d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed int n = SkFindCubicExtrema(src[0].fX, src[1].fX, src[2].fX, src[3].fX, ts); 34330d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed n += SkFindCubicExtrema(src[0].fY, src[1].fY, src[2].fY, src[3].fY, &ts[n]); 34340d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed SkASSERT(n >= 0 && n <= 4); 34350d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed for (int i = 0; i < n; ++i) { 34360d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed SkEvalCubicAt(src, ts[i], &extremas[i], nullptr, nullptr); 34370d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed } 34380d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed extremas[n] = src[3]; 34390d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed return n + 1; 34400d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed} 34410d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed 34428d3196bdfcf478982bec9885d21e1d664ab9a72bMike ReedSkRect SkPath::computeTightBounds() const { 34438d3196bdfcf478982bec9885d21e1d664ab9a72bMike Reed if (0 == this->countVerbs()) { 34448d3196bdfcf478982bec9885d21e1d664ab9a72bMike Reed return SkRect::MakeEmpty(); 34450d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed } 34460d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed 34478d3196bdfcf478982bec9885d21e1d664ab9a72bMike Reed if (this->getSegmentMasks() == SkPath::kLine_SegmentMask) { 34488d3196bdfcf478982bec9885d21e1d664ab9a72bMike Reed return this->getBounds(); 34490d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed } 34500d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed 34510d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed SkPoint extremas[5]; // big enough to hold worst-case curve type (cubic) extremas + 1 34520d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed SkPoint pts[4]; 34538d3196bdfcf478982bec9885d21e1d664ab9a72bMike Reed SkPath::RawIter iter(*this); 34540d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed 34550d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed // initial with the first MoveTo, so we don't have to check inside the switch 34560d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed Sk2s min, max; 34578d3196bdfcf478982bec9885d21e1d664ab9a72bMike Reed min = max = from_point(this->getPoint(0)); 34580d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed for (;;) { 34590d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed int count = 0; 34600d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed switch (iter.next(pts)) { 34610d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed case SkPath::kMove_Verb: 34620d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed extremas[0] = pts[0]; 34630d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed count = 1; 34640d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed break; 34650d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed case SkPath::kLine_Verb: 34660d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed extremas[0] = pts[1]; 34670d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed count = 1; 34680d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed break; 34690d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed case SkPath::kQuad_Verb: 34700d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed count = compute_quad_extremas(pts, extremas); 34710d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed break; 34720d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed case SkPath::kConic_Verb: 34730d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed count = compute_conic_extremas(pts, iter.conicWeight(), extremas); 34740d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed break; 34750d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed case SkPath::kCubic_Verb: 34760d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed count = compute_cubic_extremas(pts, extremas); 34770d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed break; 34780d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed case SkPath::kClose_Verb: 34790d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed break; 34800d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed case SkPath::kDone_Verb: 34810d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed goto DONE; 34820d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed } 34830d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed for (int i = 0; i < count; ++i) { 34840d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed Sk2s tmp = from_point(extremas[i]); 34850d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed min = Sk2s::Min(min, tmp); 34860d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed max = Sk2s::Max(max, tmp); 34870d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed } 34880d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed } 34890d7dac8fb8c404cada8d46646a980772b9dc55d6Mike ReedDONE: 34908d3196bdfcf478982bec9885d21e1d664ab9a72bMike Reed SkRect bounds; 34918d3196bdfcf478982bec9885d21e1d664ab9a72bMike Reed min.store((SkPoint*)&bounds.fLeft); 34928d3196bdfcf478982bec9885d21e1d664ab9a72bMike Reed max.store((SkPoint*)&bounds.fRight); 34938d3196bdfcf478982bec9885d21e1d664ab9a72bMike Reed return bounds; 34940d7dac8fb8c404cada8d46646a980772b9dc55d6Mike Reed} 3495