GrAAConvexPathRenderer.cpp revision 71c9260e6fa1798ad1e41b2c2ae9b3cce08bb610
169cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com 269cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com/* 369cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com * Copyright 2012 Google Inc. 469cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com * 569cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com * Use of this source code is governed by a BSD-style license that can be 669cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com * found in the LICENSE file. 769cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com */ 869cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com 969cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com#include "GrAAConvexPathRenderer.h" 1069cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com 1169cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com#include "GrContext.h" 1269cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com#include "GrDrawState.h" 13c26d94fd7dc0b00cd6d0e42d28285f4a38aff021bsalomon@google.com#include "GrDrawTargetCaps.h" 14eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt#include "GrGeometryProcessor.h" 15605dd0fbce9dbb2a0d3313e13e161f2bd54870d7egdaniel#include "GrInvariantOutput.h" 16b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt#include "GrProcessor.h" 1769cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com#include "GrPathUtils.h" 18af18a09d13611526c4217656c98947f9067cb07aegdaniel#include "SkGeometry.h" 1969cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com#include "SkString.h" 205f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com#include "SkStrokeRec.h" 21933e65d914eb86b1fbbf8ea9cf1da58ac7c42500commit-bot@chromium.org#include "SkTraceEvent.h" 22b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt#include "gl/GrGLProcessor.h" 2390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org#include "gl/GrGLSL.h" 24249af15fb82833d2274850c589812b6e69df0033joshualitt#include "gl/GrGLGeometryProcessor.h" 25eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt#include "gl/builders/GrGLProgramBuilder.h" 26234d4fba75aac009e34c088037fcd9e244798c40commit-bot@chromium.org 2769cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.comGrAAConvexPathRenderer::GrAAConvexPathRenderer() { 2869cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com} 2969cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com 3069cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.comstruct Segment { 3169cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com enum { 329b1517edc7eb3e116902a3b3da447a73aaa56585bsalomon@google.com // These enum values are assumed in member functions below. 339b1517edc7eb3e116902a3b3da447a73aaa56585bsalomon@google.com kLine = 0, 349b1517edc7eb3e116902a3b3da447a73aaa56585bsalomon@google.com kQuad = 1, 3569cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com } fType; 369b1517edc7eb3e116902a3b3da447a73aaa56585bsalomon@google.com 379aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com // line uses one pt, quad uses 2 pts 38972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org SkPoint fPts[2]; 399aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com // normal to edge ending at each pt 40972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org SkVector fNorms[2]; 419aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com // is the corner where the previous segment meets this segment 429aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com // sharp. If so, fMid is a normalized bisector facing outward. 43972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org SkVector fMid; 449aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com 459aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com int countPoints() { 469b1517edc7eb3e116902a3b3da447a73aaa56585bsalomon@google.com GR_STATIC_ASSERT(0 == kLine && 1 == kQuad); 479b1517edc7eb3e116902a3b3da447a73aaa56585bsalomon@google.com return fType + 1; 489aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com } 499aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com const SkPoint& endPt() const { 509b1517edc7eb3e116902a3b3da447a73aaa56585bsalomon@google.com GR_STATIC_ASSERT(0 == kLine && 1 == kQuad); 519b1517edc7eb3e116902a3b3da447a73aaa56585bsalomon@google.com return fPts[fType]; 529aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com }; 539aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com const SkPoint& endNorm() const { 549b1517edc7eb3e116902a3b3da447a73aaa56585bsalomon@google.com GR_STATIC_ASSERT(0 == kLine && 1 == kQuad); 559b1517edc7eb3e116902a3b3da447a73aaa56585bsalomon@google.com return fNorms[fType]; 569aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com }; 5769cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com}; 5869cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com 5969cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.comtypedef SkTArray<Segment, true> SegmentArray; 6069cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com 61fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.orgstatic void center_of_mass(const SegmentArray& segments, SkPoint* c) { 6281712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com SkScalar area = 0; 636390c72cfb3e371a774a627d5f496dc67558e119vandebo@chromium.org SkPoint center = {0, 0}; 649aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com int count = segments.count(); 656390c72cfb3e371a774a627d5f496dc67558e119vandebo@chromium.org SkPoint p0 = {0, 0}; 665b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com if (count > 2) { 675b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com // We translate the polygon so that the first point is at the origin. 685b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com // This avoids some precision issues with small area polygons far away 695b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com // from the origin. 705b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com p0 = segments[0].endPt(); 715b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com SkPoint pi; 725b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com SkPoint pj; 73a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com // the first and last iteration of the below loop would compute 745b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com // zeros since the starting / ending point is (0,0). So instead we start 755b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com // at i=1 and make the last iteration i=count-2. 765b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com pj = segments[1].endPt() - p0; 775b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com for (int i = 1; i < count - 1; ++i) { 785b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com pi = pj; 795b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com const SkPoint pj = segments[i + 1].endPt() - p0; 805b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com 8181712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com SkScalar t = SkScalarMul(pi.fX, pj.fY) - SkScalarMul(pj.fX, pi.fY); 825b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com area += t; 835b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com center.fX += (pi.fX + pj.fX) * t; 845b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com center.fY += (pi.fY + pj.fY) * t; 855b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com 865b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com } 879aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com } 88278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com // If the poly has no area then we instead return the average of 89278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com // its points. 905b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com if (SkScalarNearlyZero(area)) { 91278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com SkPoint avg; 92278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com avg.set(0, 0); 93278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com for (int i = 0; i < count; ++i) { 94278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com const SkPoint& pt = segments[i].endPt(); 95278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com avg.fX += pt.fX; 96278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com avg.fY += pt.fY; 97278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com } 98278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com SkScalar denom = SK_Scalar1 / count; 99278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com avg.scale(denom); 100278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com *c = avg; 101278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com } else { 102278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com area *= 3; 10381712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com area = SkScalarDiv(SK_Scalar1, area); 10481712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com center.fX = SkScalarMul(center.fX, area); 10581712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com center.fY = SkScalarMul(center.fY, area); 1065b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com // undo the translate of p0 to the origin. 1075b56d9e43fee4393f25f41d400981ce3960cd1aabsalomon@google.com *c = center + p0; 108278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com } 109f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(!SkScalarIsNaN(c->fX) && !SkScalarIsNaN(c->fY)); 1109aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com} 1119aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com 112fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.orgstatic void compute_vectors(SegmentArray* segments, 113fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org SkPoint* fanPt, 114fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org SkPath::Direction dir, 115fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org int* vCount, 116fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org int* iCount) { 1179aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com center_of_mass(*segments, fanPt); 1189aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com int count = segments->count(); 1199aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com 120278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com // Make the normals point towards the outside 121972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org SkPoint::Side normSide; 122278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com if (dir == SkPath::kCCW_Direction) { 123972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org normSide = SkPoint::kRight_Side; 124278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com } else { 125972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org normSide = SkPoint::kLeft_Side; 126278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com } 1279aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com 1289aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com *vCount = 0; 1299aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com *iCount = 0; 1309aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com // compute normals at all points 1319aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com for (int a = 0; a < count; ++a) { 1327d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com Segment& sega = (*segments)[a]; 1339aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com int b = (a + 1) % count; 1349aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com Segment& segb = (*segments)[b]; 1359aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com 136972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org const SkPoint* prevPt = &sega.endPt(); 1379aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com int n = segb.countPoints(); 1389aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com for (int p = 0; p < n; ++p) { 1399aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com segb.fNorms[p] = segb.fPts[p] - *prevPt; 1409aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com segb.fNorms[p].normalize(); 1419aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com segb.fNorms[p].setOrthog(segb.fNorms[p], normSide); 1429aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com prevPt = &segb.fPts[p]; 1439aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com } 1449aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com if (Segment::kLine == segb.fType) { 1459aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com *vCount += 5; 1469aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com *iCount += 9; 1479aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com } else { 1489aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com *vCount += 6; 1499aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com *iCount += 12; 1509aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com } 1519aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com } 1529aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com 1539aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com // compute mid-vectors where segments meet. TODO: Detect shallow corners 1549aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com // and leave out the wedges and close gaps by stitching segments together. 1559aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com for (int a = 0; a < count; ++a) { 1569aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com const Segment& sega = (*segments)[a]; 1579aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com int b = (a + 1) % count; 1589aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com Segment& segb = (*segments)[b]; 1599aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com segb.fMid = segb.fNorms[0] + sega.endNorm(); 1609aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com segb.fMid.normalize(); 1619aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com // corner wedges 1629aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com *vCount += 4; 1639aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com *iCount += 6; 1649aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com } 1659aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com} 1669aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com 1679732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.comstruct DegenerateTestData { 1689732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com DegenerateTestData() { fStage = kInitial; } 1699732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com bool isDegenerate() const { return kNonDegenerate != fStage; } 1709732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com enum { 1719732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com kInitial, 1729732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com kPoint, 1739732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com kLine, 1749732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com kNonDegenerate 1759732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com } fStage; 176972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org SkPoint fFirstPoint; 177972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org SkVector fLineNormal; 17881712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com SkScalar fLineC; 1799732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com}; 1809732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com 181fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.orgstatic const SkScalar kClose = (SK_Scalar1 / 16); 182fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.orgstatic const SkScalar kCloseSqd = SkScalarMul(kClose, kClose); 1839732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com 184972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.orgstatic void update_degenerate_test(DegenerateTestData* data, const SkPoint& pt) { 1859732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com switch (data->fStage) { 1869732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com case DegenerateTestData::kInitial: 1879732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com data->fFirstPoint = pt; 1889732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com data->fStage = DegenerateTestData::kPoint; 1899732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com break; 1909732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com case DegenerateTestData::kPoint: 191fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org if (pt.distanceToSqd(data->fFirstPoint) > kCloseSqd) { 1929732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com data->fLineNormal = pt - data->fFirstPoint; 1939732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com data->fLineNormal.normalize(); 1949732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com data->fLineNormal.setOrthog(data->fLineNormal); 1959732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com data->fLineC = -data->fLineNormal.dot(data->fFirstPoint); 1969732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com data->fStage = DegenerateTestData::kLine; 1979732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com } 1989732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com break; 1999732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com case DegenerateTestData::kLine: 200fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org if (SkScalarAbs(data->fLineNormal.dot(pt) + data->fLineC) > kClose) { 2019732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com data->fStage = DegenerateTestData::kNonDegenerate; 2029732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com } 2039732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com case DegenerateTestData::kNonDegenerate: 2049732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com break; 2059732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com default: 20688cb22b6b4816c7a9ca6c5b795965b4606f9eb7bcommit-bot@chromium.org SkFAIL("Unexpected degenerate test stage."); 2079732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com } 2089732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com} 2099732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com 210fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.orgstatic inline bool get_direction(const SkPath& path, const SkMatrix& m, SkPath::Direction* dir) { 211a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com if (!path.cheapComputeDirection(dir)) { 212a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com return false; 213a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com } 214af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com // check whether m reverses the orientation 215f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(!m.hasPerspective()); 21681712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com SkScalar det2x2 = SkScalarMul(m.get(SkMatrix::kMScaleX), m.get(SkMatrix::kMScaleY)) - 21781712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com SkScalarMul(m.get(SkMatrix::kMSkewX), m.get(SkMatrix::kMSkewY)); 218af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com if (det2x2 < 0) { 21930c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com *dir = SkPath::OppositeDirection(*dir); 220af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com } 221a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com return true; 222af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com} 223af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com 224106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.orgstatic inline void add_line_to_segment(const SkPoint& pt, 225106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org SegmentArray* segments, 226106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org SkRect* devBounds) { 227fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org segments->push_back(); 228fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org segments->back().fType = Segment::kLine; 229fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org segments->back().fPts[0] = pt; 230106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org devBounds->growToInclude(pt.fX, pt.fY); 231fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org} 232fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org 2334b7d6730898abc9e02d1e12c2fd732945f4c1ab4commit-bot@chromium.org#ifdef SK_DEBUG 234106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.orgstatic inline bool contains_inclusive(const SkRect& rect, const SkPoint& p) { 235106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org return p.fX >= rect.fLeft && p.fX <= rect.fRight && p.fY >= rect.fTop && p.fY <= rect.fBottom; 236106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org} 2374b7d6730898abc9e02d1e12c2fd732945f4c1ab4commit-bot@chromium.org#endif 2384b7d6730898abc9e02d1e12c2fd732945f4c1ab4commit-bot@chromium.org 239106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.orgstatic inline void add_quad_segment(const SkPoint pts[3], 240106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org SegmentArray* segments, 241106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org SkRect* devBounds) { 242fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org if (pts[0].distanceToSqd(pts[1]) < kCloseSqd || pts[1].distanceToSqd(pts[2]) < kCloseSqd) { 243fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org if (pts[0] != pts[2]) { 244106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org add_line_to_segment(pts[2], segments, devBounds); 245fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org } 246fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org } else { 247fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org segments->push_back(); 248fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org segments->back().fType = Segment::kQuad; 249fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org segments->back().fPts[0] = pts[1]; 250fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org segments->back().fPts[1] = pts[2]; 251106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org SkASSERT(contains_inclusive(*devBounds, pts[0])); 252106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org devBounds->growToInclude(pts + 1, 2); 253fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org } 254fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org} 255fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org 256fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.orgstatic inline void add_cubic_segments(const SkPoint pts[4], 257fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org SkPath::Direction dir, 258106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org SegmentArray* segments, 259106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org SkRect* devBounds) { 260fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org SkSTArray<15, SkPoint, true> quads; 261fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org GrPathUtils::convertCubicToQuads(pts, SK_Scalar1, true, dir, &quads); 262fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org int count = quads.count(); 263fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org for (int q = 0; q < count; q += 3) { 264106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org add_quad_segment(&quads[q], segments, devBounds); 265fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org } 266fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org} 267fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org 268fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.orgstatic bool get_segments(const SkPath& path, 269fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org const SkMatrix& m, 270fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org SegmentArray* segments, 271fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org SkPoint* fanPt, 272fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org int* vCount, 273106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org int* iCount, 274106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org SkRect* devBounds) { 27569cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com SkPath::Iter iter(path, true); 27630c174b9ce6b9777ee50ae0d0565a01b2a060f01bsalomon@google.com // This renderer over-emphasizes very thin path regions. We use the distance 2775cc90d132220a69c1d5734178d851f9c7cd57f16bsalomon@google.com // to the path from the sample to compute coverage. Every pixel intersected 2785cc90d132220a69c1d5734178d851f9c7cd57f16bsalomon@google.com // by the path will be hit and the maximum distance is sqrt(2)/2. We don't 279fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com // notice that the sample may be close to a very thin area of the path and 2805cc90d132220a69c1d5734178d851f9c7cd57f16bsalomon@google.com // thus should be very light. This is particularly egregious for degenerate 2815cc90d132220a69c1d5734178d851f9c7cd57f16bsalomon@google.com // line paths. We detect paths that are very close to a line (zero area) and 2825cc90d132220a69c1d5734178d851f9c7cd57f16bsalomon@google.com // draw nothing. 2839732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com DegenerateTestData degenerateData; 284a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com SkPath::Direction dir; 285a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com // get_direction can fail for some degenerate paths. 286a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com if (!get_direction(path, m, &dir)) { 287a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com return false; 288a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com } 2899732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com 29069cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com for (;;) { 291972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org SkPoint pts[4]; 29294b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com SkPath::Verb verb = iter.next(pts); 29394b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com switch (verb) { 29494b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com case SkPath::kMove_Verb: 2951a38d5508f7a0e2c186d3aa8ea807045a46b663dbsalomon@google.com m.mapPoints(pts, 1); 2969732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com update_degenerate_test(°enerateData, pts[0]); 297106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org devBounds->set(pts->fX, pts->fY, pts->fX, pts->fY); 2989732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com break; 29994b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com case SkPath::kLine_Verb: { 300fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org m.mapPoints(&pts[1], 1); 3011a38d5508f7a0e2c186d3aa8ea807045a46b663dbsalomon@google.com update_degenerate_test(°enerateData, pts[1]); 302106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org add_line_to_segment(pts[1], segments, devBounds); 30369cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com break; 30469cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com } 30594b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com case SkPath::kQuad_Verb: 306fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org m.mapPoints(pts, 3); 3079732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com update_degenerate_test(°enerateData, pts[1]); 3089732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com update_degenerate_test(°enerateData, pts[2]); 309106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org add_quad_segment(pts, segments, devBounds); 31069cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com break; 311af18a09d13611526c4217656c98947f9067cb07aegdaniel case SkPath::kConic_Verb: { 312af18a09d13611526c4217656c98947f9067cb07aegdaniel m.mapPoints(pts, 3); 313af18a09d13611526c4217656c98947f9067cb07aegdaniel SkScalar weight = iter.conicWeight(); 314af18a09d13611526c4217656c98947f9067cb07aegdaniel SkAutoConicToQuads converter; 315af18a09d13611526c4217656c98947f9067cb07aegdaniel const SkPoint* quadPts = converter.computeQuads(pts, weight, 0.5f); 316af18a09d13611526c4217656c98947f9067cb07aegdaniel for (int i = 0; i < converter.countQuads(); ++i) { 317af18a09d13611526c4217656c98947f9067cb07aegdaniel update_degenerate_test(°enerateData, quadPts[2*i + 1]); 318af18a09d13611526c4217656c98947f9067cb07aegdaniel update_degenerate_test(°enerateData, quadPts[2*i + 2]); 319af18a09d13611526c4217656c98947f9067cb07aegdaniel add_quad_segment(quadPts + 2*i, segments, devBounds); 320af18a09d13611526c4217656c98947f9067cb07aegdaniel } 321af18a09d13611526c4217656c98947f9067cb07aegdaniel break; 322af18a09d13611526c4217656c98947f9067cb07aegdaniel } 32394b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com case SkPath::kCubic_Verb: { 3241a38d5508f7a0e2c186d3aa8ea807045a46b663dbsalomon@google.com m.mapPoints(pts, 4); 3259732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com update_degenerate_test(°enerateData, pts[1]); 3269732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com update_degenerate_test(°enerateData, pts[2]); 3279732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com update_degenerate_test(°enerateData, pts[3]); 328106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org add_cubic_segments(pts, dir, segments, devBounds); 32969cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com break; 33069cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com }; 33194b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com case SkPath::kDone_Verb: 3329732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com if (degenerateData.isDegenerate()) { 3339732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com return false; 3349732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com } else { 335278dc6929b6481204874dcfcc055e2aaa30a95b2bsalomon@google.com compute_vectors(segments, fanPt, dir, vCount, iCount); 3369732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com return true; 3379732f62eaec427e0d4a8de06748ebb59450dfe31bsalomon@google.com } 33869cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com default: 33969cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com break; 34069cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com } 34169cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com } 34269cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com} 34369cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com 34469cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.comstruct QuadVertex { 345972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org SkPoint fPos; 346972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org SkPoint fUV; 34781712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com SkScalar fD0; 34881712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com SkScalar fD1; 34969cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com}; 350fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 3517d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.comstruct Draw { 3527d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com Draw() : fVertexCnt(0), fIndexCnt(0) {} 3537d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com int fVertexCnt; 3547d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com int fIndexCnt; 3557d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com}; 3567d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com 3577d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.comtypedef SkTArray<Draw, true> DrawArray; 3587d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com 359fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.orgstatic void create_vertices(const SegmentArray& segments, 360fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org const SkPoint& fanPt, 361fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org DrawArray* draws, 362fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org QuadVertex* verts, 363fdfbb9d5f0d29cb4a956a693c499653f87f04ac4commit-bot@chromium.org uint16_t* idxs) { 3647d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com Draw* draw = &draws->push_back(); 3657d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com // alias just to make vert/index assignments easier to read. 3667d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com int* v = &draw->fVertexCnt; 3677d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com int* i = &draw->fIndexCnt; 36869cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com 3699aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com int count = segments.count(); 3709aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com for (int a = 0; a < count; ++a) { 3719aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com const Segment& sega = segments[a]; 3729aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com int b = (a + 1) % count; 3739aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com const Segment& segb = segments[b]; 374fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 3757d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com // Check whether adding the verts for this segment to the current draw would cause index 3767d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com // values to overflow. 3777d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com int vCount = 4; 3787d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com if (Segment::kLine == segb.fType) { 3797d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com vCount += 5; 3807d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com } else { 3817d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com vCount += 6; 3827d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com } 3837d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com if (draw->fVertexCnt + vCount > (1 << 16)) { 3847d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts += *v; 3857d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com idxs += *i; 3867d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com draw = &draws->push_back(); 3877d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com v = &draw->fVertexCnt; 3887d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com i = &draw->fIndexCnt; 3897d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com } 3907d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com 3919aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com // FIXME: These tris are inset in the 1 unit arc around the corner 3927d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 0].fPos = sega.endPt(); 3937d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 1].fPos = verts[*v + 0].fPos + sega.endNorm(); 3947d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 2].fPos = verts[*v + 0].fPos + segb.fMid; 3957d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 3].fPos = verts[*v + 0].fPos + segb.fNorms[0]; 3967d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 0].fUV.set(0,0); 3977d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 1].fUV.set(0,-SK_Scalar1); 3987d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 2].fUV.set(0,-SK_Scalar1); 3997d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 3].fUV.set(0,-SK_Scalar1); 4007d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 0].fD0 = verts[*v + 0].fD1 = -SK_Scalar1; 4017d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 1].fD0 = verts[*v + 1].fD1 = -SK_Scalar1; 4027d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 2].fD0 = verts[*v + 2].fD1 = -SK_Scalar1; 4037d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 3].fD0 = verts[*v + 3].fD1 = -SK_Scalar1; 4047d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com 4057d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com idxs[*i + 0] = *v + 0; 4067d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com idxs[*i + 1] = *v + 2; 4077d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com idxs[*i + 2] = *v + 1; 4087d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com idxs[*i + 3] = *v + 0; 4097d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com idxs[*i + 4] = *v + 3; 4107d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com idxs[*i + 5] = *v + 2; 4117d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com 4127d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com *v += 4; 4137d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com *i += 6; 41469cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com 4159aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com if (Segment::kLine == segb.fType) { 4167d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 0].fPos = fanPt; 4177d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 1].fPos = sega.endPt(); 4187d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 2].fPos = segb.fPts[0]; 4199aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com 4207d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 3].fPos = verts[*v + 1].fPos + segb.fNorms[0]; 4217d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 4].fPos = verts[*v + 2].fPos + segb.fNorms[0]; 4229aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com 4239aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com // we draw the line edge as a degenerate quad (u is 0, v is the 4249aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com // signed distance to the edge) 4257d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com SkScalar dist = fanPt.distanceToLineBetween(verts[*v + 1].fPos, 4267d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 2].fPos); 4277d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 0].fUV.set(0, dist); 4287d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 1].fUV.set(0, 0); 4297d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 2].fUV.set(0, 0); 4307d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 3].fUV.set(0, -SK_Scalar1); 4317d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 4].fUV.set(0, -SK_Scalar1); 4327d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com 4337d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 0].fD0 = verts[*v + 0].fD1 = -SK_Scalar1; 4347d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 1].fD0 = verts[*v + 1].fD1 = -SK_Scalar1; 4357d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 2].fD0 = verts[*v + 2].fD1 = -SK_Scalar1; 4367d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 3].fD0 = verts[*v + 3].fD1 = -SK_Scalar1; 4377d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 4].fD0 = verts[*v + 4].fD1 = -SK_Scalar1; 4387d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com 4397d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com idxs[*i + 0] = *v + 0; 4407d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com idxs[*i + 1] = *v + 2; 4417d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com idxs[*i + 2] = *v + 1; 4427d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com 4437d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com idxs[*i + 3] = *v + 3; 4447d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com idxs[*i + 4] = *v + 1; 4457d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com idxs[*i + 5] = *v + 2; 4467d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com 4477d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com idxs[*i + 6] = *v + 4; 4487d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com idxs[*i + 7] = *v + 3; 4497d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com idxs[*i + 8] = *v + 2; 4507d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com 4517d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com *v += 5; 4527d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com *i += 9; 453068096148179062c4343138c112b87518e4ab3b1bsalomon@google.com } else { 454972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org SkPoint qpts[] = {sega.endPt(), segb.fPts[0], segb.fPts[1]}; 4559aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com 456972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org SkVector midVec = segb.fNorms[0] + segb.fNorms[1]; 4579aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com midVec.normalize(); 4589aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com 4597d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 0].fPos = fanPt; 4607d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 1].fPos = qpts[0]; 4617d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 2].fPos = qpts[2]; 4627d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 3].fPos = qpts[0] + segb.fNorms[0]; 4637d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 4].fPos = qpts[2] + segb.fNorms[1]; 4647d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 5].fPos = qpts[1] + midVec; 4659aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com 46681712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com SkScalar c = segb.fNorms[0].dot(qpts[0]); 4677d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 0].fD0 = -segb.fNorms[0].dot(fanPt) + c; 4687d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 1].fD0 = 0.f; 4697d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 2].fD0 = -segb.fNorms[0].dot(qpts[2]) + c; 4707d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 3].fD0 = -SK_ScalarMax/100; 4717d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 4].fD0 = -SK_ScalarMax/100; 4727d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 5].fD0 = -SK_ScalarMax/100; 4739aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com 4749aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com c = segb.fNorms[1].dot(qpts[2]); 4757d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 0].fD1 = -segb.fNorms[1].dot(fanPt) + c; 4767d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 1].fD1 = -segb.fNorms[1].dot(qpts[0]) + c; 4777d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 2].fD1 = 0.f; 4787d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 3].fD1 = -SK_ScalarMax/100; 4797d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 4].fD1 = -SK_ScalarMax/100; 4807d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com verts[*v + 5].fD1 = -SK_ScalarMax/100; 4819aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com 4821971317bb43580330a9e7e9a1c09c5025fe84aacbsalomon@google.com GrPathUtils::QuadUVMatrix toUV(qpts); 483972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org toUV.apply<6, sizeof(QuadVertex), sizeof(SkPoint)>(verts + *v); 4849aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com 4857d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com idxs[*i + 0] = *v + 3; 4867d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com idxs[*i + 1] = *v + 1; 4877d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com idxs[*i + 2] = *v + 2; 4887d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com idxs[*i + 3] = *v + 4; 4897d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com idxs[*i + 4] = *v + 3; 4907d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com idxs[*i + 5] = *v + 2; 4919aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com 4927d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com idxs[*i + 6] = *v + 5; 4937d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com idxs[*i + 7] = *v + 3; 4947d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com idxs[*i + 8] = *v + 4; 4959aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com 4967d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com idxs[*i + 9] = *v + 0; 4977d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com idxs[*i + 10] = *v + 2; 4987d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com idxs[*i + 11] = *v + 1; 4999aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com 5007d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com *v += 6; 5017d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com *i += 12; 50269cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com } 50369cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com } 50469cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com} 50569cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com 50690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org/////////////////////////////////////////////////////////////////////////////// 50790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 50890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org/* 50990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org * Quadratic specified by 0=u^2-v canonical coords. u and v are the first 51090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org * two components of the vertex attribute. Coverage is based on signed 51190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org * distance with negative being inside, positive outside. The edge is specified in 51290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org * window space (y-down). If either the third or fourth component of the interpolated 51390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org * vertex coord is > 0 then the pixel is considered outside the edge. This is used to 514041e2dbc0614e3341e1349fd0e962744a45b6194skia.committer@gmail.com * attempt to trim to a portion of the infinite quad. 515041e2dbc0614e3341e1349fd0e962744a45b6194skia.committer@gmail.com * Requires shader derivative instruction support. 51690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org */ 51790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 518249af15fb82833d2274850c589812b6e69df0033joshualittclass QuadEdgeEffect : public GrGeometryProcessor { 51990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.orgpublic: 52090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 521d27f73ef27ff65a6a0a5d00aa8e5b784b1a0b47ejoshualitt static GrGeometryProcessor* Create(GrColor color, const SkMatrix& localMatrix) { 522d27f73ef27ff65a6a0a5d00aa8e5b784b1a0b47ejoshualitt return SkNEW_ARGS(QuadEdgeEffect, (color, localMatrix)); 52390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org } 52490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 52590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org virtual ~QuadEdgeEffect() {} 52690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 52772c9faab45124e08c85f70ca38536914862d947cmtklein const char* name() const SK_OVERRIDE { return "QuadEdge"; } 52890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 52971c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt const Attribute* inPosition() const { return fInPosition; } 53071c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt const Attribute* inQuadEdge() const { return fInQuadEdge; } 531249af15fb82833d2274850c589812b6e69df0033joshualitt 532b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt class GLProcessor : public GrGLGeometryProcessor { 53390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org public: 534eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt GLProcessor(const GrGeometryProcessor&, 5359b98932adaceb7ad0a617ade16616923f6bffe84joshualitt const GrBatchTracker&) 5369b98932adaceb7ad0a617ade16616923f6bffe84joshualitt : fColor(GrColor_ILLEGAL) {} 53790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 538abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt void onEmitCode(EmitArgs& args) SK_OVERRIDE { 5392dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt const QuadEdgeEffect& qe = args.fGP.cast<QuadEdgeEffect>(); 5409b98932adaceb7ad0a617ade16616923f6bffe84joshualitt GrGLGPBuilder* pb = args.fPB; 5419b98932adaceb7ad0a617ade16616923f6bffe84joshualitt GrGLVertexBuilder* vsBuilder = pb->getVertexShaderBuilder(); 5422dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt 543abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt // emit attributes 544abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt vsBuilder->emitAttributes(qe); 545abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt 54674077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt GrGLVertToFrag v(kVec4f_GrSLType); 54774077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt args.fPB->addVarying("QuadEdge", &v); 5482dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt vsBuilder->codeAppendf("%s = %s;", v.vsOut(), qe.inQuadEdge()->fName); 5492dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt 5509b98932adaceb7ad0a617ade16616923f6bffe84joshualitt const BatchTracker& local = args.fBT.cast<BatchTracker>(); 5519b98932adaceb7ad0a617ade16616923f6bffe84joshualitt 5529b98932adaceb7ad0a617ade16616923f6bffe84joshualitt // Setup pass through color 5539b98932adaceb7ad0a617ade16616923f6bffe84joshualitt this->setupColorPassThrough(pb, local.fInputColorType, args.fOutputColor, NULL, 5549b98932adaceb7ad0a617ade16616923f6bffe84joshualitt &fColorUniform); 5559b98932adaceb7ad0a617ade16616923f6bffe84joshualitt 556ee2af95db72152dfa61c841875df0594ca93437djoshualitt // setup uniform viewMatrix 557ee2af95db72152dfa61c841875df0594ca93437djoshualitt this->addUniformViewMatrix(pb); 558ee2af95db72152dfa61c841875df0594ca93437djoshualitt 559abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt // Setup position 560abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt vsBuilder->codeAppendf("%s = %s * vec3(%s, 1);", this->position(), this->uViewM(), 561abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt qe.inPosition()->fName); 562abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt 563abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt // emit transforms 564abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt this->emitTransforms(args.fPB, this->position(), qe.inPosition()->fName, 565abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt qe.localMatrix(), args.fTransformsIn, args.fTransformsOut); 56690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 567c369e7c9992a86151a3ea0516ce5308c211b196bjoshualitt GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder(); 56830ba436f04e61d4505fb854d5fc56079636e0788joshualitt 56930ba436f04e61d4505fb854d5fc56079636e0788joshualitt SkAssertResult(fsBuilder->enableFeature( 57030ba436f04e61d4505fb854d5fc56079636e0788joshualitt GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature)); 57174077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt fsBuilder->codeAppendf("float edgeAlpha;"); 57230ba436f04e61d4505fb854d5fc56079636e0788joshualitt 57390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org // keep the derivative instructions outside the conditional 57474077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt fsBuilder->codeAppendf("vec2 duvdx = dFdx(%s.xy);", v.fsIn()); 57574077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt fsBuilder->codeAppendf("vec2 duvdy = dFdy(%s.xy);", v.fsIn()); 57674077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt fsBuilder->codeAppendf("if (%s.z > 0.0 && %s.w > 0.0) {", v.fsIn(), v.fsIn()); 57790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org // today we know z and w are in device space. We could use derivatives 57874077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt fsBuilder->codeAppendf("edgeAlpha = min(min(%s.z, %s.w) + 0.5, 1.0);", v.fsIn(), 57974077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt v.fsIn()); 58074077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt fsBuilder->codeAppendf ("} else {"); 58174077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt fsBuilder->codeAppendf("vec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y," 58274077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt " 2.0*%s.x*duvdy.x - duvdy.y);", 58374077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt v.fsIn(), v.fsIn()); 58474077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt fsBuilder->codeAppendf("edgeAlpha = (%s.x*%s.x - %s.y);", v.fsIn(), v.fsIn(), 58574077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt v.fsIn()); 58674077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt fsBuilder->codeAppendf("edgeAlpha = " 58774077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt "clamp(0.5 - edgeAlpha / length(gF), 0.0, 1.0);}"); 58874077b9941ed3f73d92ba978ef29bf3e6f630cbcjoshualitt 5892dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt fsBuilder->codeAppendf("%s = vec4(edgeAlpha);", args.fOutputCoverage); 59090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org } 59190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 5929b98932adaceb7ad0a617ade16616923f6bffe84joshualitt static inline void GenKey(const GrGeometryProcessor& gp, 5939b98932adaceb7ad0a617ade16616923f6bffe84joshualitt const GrBatchTracker& bt, 59487f48d997ec29e5eeaa7567355775e93465dd60djoshualitt const GrGLCaps&, 5959b98932adaceb7ad0a617ade16616923f6bffe84joshualitt GrProcessorKeyBuilder* b) { 5969b98932adaceb7ad0a617ade16616923f6bffe84joshualitt const BatchTracker& local = bt.cast<BatchTracker>(); 5978fc6c2d82c1f30ff82274334c01f0799def6a609joshualitt b->add32((local.fInputColorType << 16) | 5988fc6c2d82c1f30ff82274334c01f0799def6a609joshualitt (local.fUsesLocalCoords && gp.localMatrix().hasPerspective() ? 0x1 : 0x0)); 5999b98932adaceb7ad0a617ade16616923f6bffe84joshualitt } 60090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 6019b98932adaceb7ad0a617ade16616923f6bffe84joshualitt virtual void setData(const GrGLProgramDataManager& pdman, 6029b98932adaceb7ad0a617ade16616923f6bffe84joshualitt const GrPrimitiveProcessor& gp, 6039b98932adaceb7ad0a617ade16616923f6bffe84joshualitt const GrBatchTracker& bt) SK_OVERRIDE { 604ee2af95db72152dfa61c841875df0594ca93437djoshualitt this->setUniformViewMatrix(pdman, gp.viewMatrix()); 605ee2af95db72152dfa61c841875df0594ca93437djoshualitt 6069b98932adaceb7ad0a617ade16616923f6bffe84joshualitt const BatchTracker& local = bt.cast<BatchTracker>(); 6079b98932adaceb7ad0a617ade16616923f6bffe84joshualitt if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) { 6089b98932adaceb7ad0a617ade16616923f6bffe84joshualitt GrGLfloat c[4]; 6099b98932adaceb7ad0a617ade16616923f6bffe84joshualitt GrColorToRGBAFloat(local.fColor, c); 6109b98932adaceb7ad0a617ade16616923f6bffe84joshualitt pdman.set4fv(fColorUniform, 1, c); 6119b98932adaceb7ad0a617ade16616923f6bffe84joshualitt fColor = local.fColor; 6129b98932adaceb7ad0a617ade16616923f6bffe84joshualitt } 6139b98932adaceb7ad0a617ade16616923f6bffe84joshualitt } 61490c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 61590c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org private: 6169b98932adaceb7ad0a617ade16616923f6bffe84joshualitt GrColor fColor; 6179b98932adaceb7ad0a617ade16616923f6bffe84joshualitt UniformHandle fColorUniform; 6189b98932adaceb7ad0a617ade16616923f6bffe84joshualitt 619249af15fb82833d2274850c589812b6e69df0033joshualitt typedef GrGLGeometryProcessor INHERITED; 62090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org }; 621041e2dbc0614e3341e1349fd0e962744a45b6194skia.committer@gmail.com 622eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt virtual void getGLProcessorKey(const GrBatchTracker& bt, 623eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt const GrGLCaps& caps, 624eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt GrProcessorKeyBuilder* b) const SK_OVERRIDE { 625eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt GLProcessor::GenKey(*this, bt, caps, b); 626eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt } 627eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt 628abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt virtual GrGLPrimitiveProcessor* createGLInstance(const GrBatchTracker& bt, 629abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt const GrGLCaps&) const SK_OVERRIDE { 630eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt return SkNEW_ARGS(GLProcessor, (*this, bt)); 631eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt } 632eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt 6339b98932adaceb7ad0a617ade16616923f6bffe84joshualitt void initBatchTracker(GrBatchTracker* bt, const InitBT& init) const SK_OVERRIDE { 6349b98932adaceb7ad0a617ade16616923f6bffe84joshualitt BatchTracker* local = bt->cast<BatchTracker>(); 6359b98932adaceb7ad0a617ade16616923f6bffe84joshualitt local->fInputColorType = GetColorInputType(&local->fColor, this->color(), init, false); 636290c09b8bbd8d221d363150e2ce87158f4668df0joshualitt local->fUsesLocalCoords = init.fUsesLocalCoords; 6379b98932adaceb7ad0a617ade16616923f6bffe84joshualitt } 6389b98932adaceb7ad0a617ade16616923f6bffe84joshualitt 639290c09b8bbd8d221d363150e2ce87158f4668df0joshualitt bool onCanMakeEqual(const GrBatchTracker& m, 640290c09b8bbd8d221d363150e2ce87158f4668df0joshualitt const GrGeometryProcessor& that, 641290c09b8bbd8d221d363150e2ce87158f4668df0joshualitt const GrBatchTracker& t) const SK_OVERRIDE { 6429b98932adaceb7ad0a617ade16616923f6bffe84joshualitt const BatchTracker& mine = m.cast<BatchTracker>(); 6439b98932adaceb7ad0a617ade16616923f6bffe84joshualitt const BatchTracker& theirs = t.cast<BatchTracker>(); 644290c09b8bbd8d221d363150e2ce87158f4668df0joshualitt return CanCombineLocalMatrices(*this, mine.fUsesLocalCoords, 645290c09b8bbd8d221d363150e2ce87158f4668df0joshualitt that, theirs.fUsesLocalCoords) && 646290c09b8bbd8d221d363150e2ce87158f4668df0joshualitt CanCombineOutput(mine.fInputColorType, mine.fColor, 6479b98932adaceb7ad0a617ade16616923f6bffe84joshualitt theirs.fInputColorType, theirs.fColor); 6489b98932adaceb7ad0a617ade16616923f6bffe84joshualitt } 6499b98932adaceb7ad0a617ade16616923f6bffe84joshualitt 65090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.orgprivate: 651d27f73ef27ff65a6a0a5d00aa8e5b784b1a0b47ejoshualitt QuadEdgeEffect(GrColor color, const SkMatrix& localMatrix) 6528059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt : INHERITED(color, SkMatrix::I(), localMatrix) { 653eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt this->initClassID<QuadEdgeEffect>(); 65471c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType)); 65571c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt fInQuadEdge = &this->addVertexAttrib(Attribute("inQuadEdge", kVec4f_GrVertexAttribType)); 65690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org } 65790c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 65872c9faab45124e08c85f70ca38536914862d947cmtklein bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE { 65990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org return true; 66090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org } 66190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 66272c9faab45124e08c85f70ca38536914862d947cmtklein void onGetInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRIDE { 66356995b5cc00c9c83bd5fcf86bca9a67e939a96cbjoshualitt out->setUnknownSingleComponent(); 6641a8ecdfb73a15de600d5779b75d7c4b61863c50begdaniel } 6651a8ecdfb73a15de600d5779b75d7c4b61863c50begdaniel 6669b98932adaceb7ad0a617ade16616923f6bffe84joshualitt struct BatchTracker { 6679b98932adaceb7ad0a617ade16616923f6bffe84joshualitt GrGPInput fInputColorType; 6689b98932adaceb7ad0a617ade16616923f6bffe84joshualitt GrColor fColor; 669290c09b8bbd8d221d363150e2ce87158f4668df0joshualitt bool fUsesLocalCoords; 6709b98932adaceb7ad0a617ade16616923f6bffe84joshualitt }; 6719b98932adaceb7ad0a617ade16616923f6bffe84joshualitt 67271c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt const Attribute* fInPosition; 67371c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt const Attribute* fInQuadEdge; 674249af15fb82833d2274850c589812b6e69df0033joshualitt 675b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt GR_DECLARE_GEOMETRY_PROCESSOR_TEST; 67690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 6772e3b3e369d79e78f7635d4c20e83a47ab571bdf2joshualitt typedef GrGeometryProcessor INHERITED; 67890c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org}; 67990c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 680b0a8a377f832c59cee939ad721e1f87d378b7142joshualittGR_DEFINE_GEOMETRY_PROCESSOR_TEST(QuadEdgeEffect); 68190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 682b0a8a377f832c59cee939ad721e1f87d378b7142joshualittGrGeometryProcessor* QuadEdgeEffect::TestCreate(SkRandom* random, 683b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt GrContext*, 684b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt const GrDrawTargetCaps& caps, 685b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt GrTexture*[]) { 68690c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org // Doesn't work without derivative instructions. 687d27f73ef27ff65a6a0a5d00aa8e5b784b1a0b47ejoshualitt return caps.shaderDerivativeSupport() ? 688d27f73ef27ff65a6a0a5d00aa8e5b784b1a0b47ejoshualitt QuadEdgeEffect::Create(GrRandomColor(random), 689d27f73ef27ff65a6a0a5d00aa8e5b784b1a0b47ejoshualitt GrProcessorUnitTest::TestMatrix(random)) : NULL; 69090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org} 69190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 69290c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org/////////////////////////////////////////////////////////////////////////////// 69390c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 6949853ccef19c200be93a6211f32589fa82a53067cjoshualittbool GrAAConvexPathRenderer::canDrawPath(const GrDrawTarget* target, 6959853ccef19c200be93a6211f32589fa82a53067cjoshualitt const GrDrawState*, 6968059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt const SkMatrix& viewMatrix, 6979853ccef19c200be93a6211f32589fa82a53067cjoshualitt const SkPath& path, 698e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com const SkStrokeRec& stroke, 6998a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com bool antiAlias) const { 700bcce8926524827775539874346dd424a9510dbc9bsalomon@google.com return (target->caps()->shaderDerivativeSupport() && antiAlias && 701e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com stroke.isFillStyle() && !path.isInverseFillType() && path.isConvex()); 702c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com} 703c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com 7049853ccef19c200be93a6211f32589fa82a53067cjoshualittbool GrAAConvexPathRenderer::onDrawPath(GrDrawTarget* target, 7059853ccef19c200be93a6211f32589fa82a53067cjoshualitt GrDrawState* drawState, 7062e3b3e369d79e78f7635d4c20e83a47ab571bdf2joshualitt GrColor color, 7078059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt const SkMatrix& vm, 7089853ccef19c200be93a6211f32589fa82a53067cjoshualitt const SkPath& origPath, 709e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com const SkStrokeRec&, 710c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com bool antiAlias) { 711c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com 712e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com const SkPath* path = &origPath; 713af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com if (path->isEmpty()) { 714c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com return true; 71569cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com } 7164647f9059825c062169d4d454c12640d82ae16c0bsalomon@google.com 7178059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt SkMatrix viewMatrix = vm; 718d27f73ef27ff65a6a0a5d00aa8e5b784b1a0b47ejoshualitt SkMatrix invert; 719d27f73ef27ff65a6a0a5d00aa8e5b784b1a0b47ejoshualitt if (!viewMatrix.invert(&invert)) { 720e3d3216fe17b6afb2e613271b5246a2766e12df6bsalomon@google.com return false; 72169cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com } 72269cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com 723af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com // We use the fact that SkPath::transform path does subdivision based on 724af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com // perspective. Otherwise, we apply the view matrix when copying to the 725af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com // segment representation. 726af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com SkPath tmpPath; 727137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com if (viewMatrix.hasPerspective()) { 728e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com origPath.transform(viewMatrix, &tmpPath); 729af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com path = &tmpPath; 730137f1347abaf0bb6a945e91c2f6cb49f0ee69bc3bsalomon@google.com viewMatrix = SkMatrix::I(); 731af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com } 732af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com 73369cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com QuadVertex *verts; 73469cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com uint16_t* idxs; 73569cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com 7369aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com int vCount; 7379aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com int iCount; 73868a5b260e2045070ed0796af98624c3769f590c5bsalomon@google.com enum { 73968a5b260e2045070ed0796af98624c3769f590c5bsalomon@google.com kPreallocSegmentCnt = 512 / sizeof(Segment), 7407d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com kPreallocDrawCnt = 4, 74168a5b260e2045070ed0796af98624c3769f590c5bsalomon@google.com }; 74268a5b260e2045070ed0796af98624c3769f590c5bsalomon@google.com SkSTArray<kPreallocSegmentCnt, Segment, true> segments; 7439aed114505a06679bbc7fa836e224aae82b3e5f4bsalomon@google.com SkPoint fanPt; 744af90f7f142a3939ca34f55b39460688e8eb5dc6bbsalomon@google.com 745106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org // We can't simply use the path bounds because we may degenerate cubics to quads which produces 746106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org // new control points outside the original convex hull. 747106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org SkRect devBounds; 748106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org if (!get_segments(*path, viewMatrix, &segments, &fanPt, &vCount, &iCount, &devBounds)) { 749c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com return false; 75069cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com } 75169cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com 752106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org // Our computed verts should all be within one pixel of the segment control points. 753106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org devBounds.outset(SK_Scalar1, SK_Scalar1); 754106655efdf2516f7084c19d6d5a7bc59fd8b866ccommit-bot@chromium.org 755d27f73ef27ff65a6a0a5d00aa8e5b784b1a0b47ejoshualitt SkAutoTUnref<GrGeometryProcessor> quadProcessor(QuadEdgeEffect::Create(color, invert)); 7564647f9059825c062169d4d454c12640d82ae16c0bsalomon@google.com 7572dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt GrDrawTarget::AutoReleaseGeometry arg(target, vCount, quadProcessor->getVertexStride(), iCount); 7582dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt SkASSERT(quadProcessor->getVertexStride() == sizeof(QuadVertex)); 759b372942bbc842b5728cbc8e9dd024928a793846absalomon@google.com if (!arg.succeeded()) { 760c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com return false; 76169cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com } 762b372942bbc842b5728cbc8e9dd024928a793846absalomon@google.com verts = reinterpret_cast<QuadVertex*>(arg.vertices()); 763b372942bbc842b5728cbc8e9dd024928a793846absalomon@google.com idxs = reinterpret_cast<uint16_t*>(arg.indices()); 76469cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com 7657d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com SkSTArray<kPreallocDrawCnt, Draw, true> draws; 7667d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com create_vertices(segments, fanPt, &draws, verts, idxs); 7677d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com 7681dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com // Check devBounds 769515dcd36032997ce335daa0163c6d67e851bcad1commit-bot@chromium.org#ifdef SK_DEBUG 7701dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com SkRect tolDevBounds = devBounds; 7711dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com tolDevBounds.outset(SK_Scalar1 / 10000, SK_Scalar1 / 10000); 7721dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com SkRect actualBounds; 7731dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com actualBounds.set(verts[0].fPos, verts[1].fPos); 7741dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com for (int i = 2; i < vCount; ++i) { 7751dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com actualBounds.growToInclude(verts[i].fPos.fX, verts[i].fPos.fY); 7761dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com } 777f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(tolDevBounds.contains(actualBounds)); 7781dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com#endif 7791dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com 7807d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com int vOffset = 0; 7817d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com for (int i = 0; i < draws.count(); ++i) { 7827d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com const Draw& draw = draws[i]; 7839853ccef19c200be93a6211f32589fa82a53067cjoshualitt target->drawIndexed(drawState, 78456995b5cc00c9c83bd5fcf86bca9a67e939a96cbjoshualitt quadProcessor, 7859853ccef19c200be93a6211f32589fa82a53067cjoshualitt kTriangles_GrPrimitiveType, 7867d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com vOffset, // start vertex 7877d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com 0, // start index 7887d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com draw.fVertexCnt, 7891dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com draw.fIndexCnt, 7901dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com &devBounds); 7917d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com vOffset += draw.fVertexCnt; 7927d9ffc8a04533d0207efe5511b587e89ecb9d898bsalomon@google.com } 793a834746cc1bd92301fd0840a221ca1623c0bbb29bsalomon@google.com 794c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com return true; 79569cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com} 796