GrAAHairLinePathRenderer.cpp revision 5ead6da4abaa3d8fb479fd84631138f83b7aa5b6
1f75b84e94b1ca1540295584421de0158d87a9b52bsalomon@google.com/* 2f75b84e94b1ca1540295584421de0158d87a9b52bsalomon@google.com * Copyright 2011 Google Inc. 3f75b84e94b1ca1540295584421de0158d87a9b52bsalomon@google.com * 4f75b84e94b1ca1540295584421de0158d87a9b52bsalomon@google.com * Use of this source code is governed by a BSD-style license that can be 5f75b84e94b1ca1540295584421de0158d87a9b52bsalomon@google.com * found in the LICENSE file. 6f75b84e94b1ca1540295584421de0158d87a9b52bsalomon@google.com */ 7f75b84e94b1ca1540295584421de0158d87a9b52bsalomon@google.com 8aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com#include "GrAAHairLinePathRenderer.h" 9aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 10aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com#include "GrContext.h" 119381363050ec9d3e724076a8e9152bfa9a8de1d1tomhudson@google.com#include "GrDrawState.h" 12c26d94fd7dc0b00cd6d0e42d28285f4a38aff021bsalomon@google.com#include "GrDrawTargetCaps.h" 13b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt#include "GrProcessor.h" 14aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com#include "GrGpu.h" 15aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com#include "GrIndexBuffer.h" 16dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com#include "GrPathUtils.h" 17b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt#include "GrTBackendProcessorFactory.h" 18aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com#include "SkGeometry.h" 1912b4e27ae1a29460e91a59f38122483e1faec697sugoi@google.com#include "SkStroke.h" 20aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com#include "SkTemplates.h" 21aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 2207e1c3fd5030869c480c15ff30d36bd161718262commit-bot@chromium.org#include "effects/GrBezierEffect.h" 234647f9059825c062169d4d454c12640d82ae16c0bsalomon@google.com 24aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com// quadratics are rendered as 5-sided polys in order to bound the 25aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com// AA stroke around the center-curve. See comments in push_quad_index_buffer and 265383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// bloat_quad. Quadratics and conics share an index buffer 27aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 28ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com// lines are rendered as: 29ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com// *______________* 30ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com// |\ -_______ /| 31ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com// | \ \ / | 32ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com// | *--------* | 33ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com// | / ______/ \ | 34ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com// */_-__________\* 35ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com// For: 6 vertices and 18 indices (for 6 triangles) 36681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com 375ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// Each quadratic is rendered as a five sided polygon. This poly bounds 385ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// the quadratic's bounding triangle but has been expanded so that the 395ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// 1-pixel wide area around the curve is inside the poly. 405ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// If a,b,c are the original control points then the poly a0,b0,c0,c1,a1 415ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// that is rendered would look like this: 425ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// b0 435ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// b 445ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// 455ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// a0 c0 465ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// a c 475ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// a1 c1 485ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// Each is drawn as three triangles specified by these 9 indices: 495ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualittstatic const uint16_t kQuadIdxBufPattern[] = { 505ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt 0, 1, 2, 515ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt 2, 4, 3, 525ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt 1, 4, 2 535ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt}; 545ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt 555ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualittstatic const int kIdxsPerQuad = SK_ARRAY_COUNT(kQuadIdxBufPattern); 565ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualittstatic const int kQuadNumVertices = 5; 575ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualittstatic const int kQuadsNumInIdxBuffer = 256; 585ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt 595ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt 605ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// Each line segment is rendered as two quads and two triangles. 615ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// p0 and p1 have alpha = 1 while all other points have alpha = 0. 625ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// The four external points are offset 1 pixel perpendicular to the 635ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// line and half a pixel parallel to the line. 645ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// 655ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// p4 p5 665ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// p0 p1 675ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// p2 p3 685ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// 695ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt// Each is drawn as six triangles specified by these 18 indices: 705ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt 715ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualittstatic const uint16_t kLineSegIdxBufPattern[] = { 725ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt 0, 1, 3, 735ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt 0, 3, 2, 745ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt 0, 4, 5, 755ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt 0, 5, 1, 765ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt 0, 2, 4, 775ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt 1, 5, 3 785ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt}; 795ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt 805ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualittstatic const int kIdxsPerLineSeg = SK_ARRAY_COUNT(kLineSegIdxBufPattern); 815ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualittstatic const int kLineSegNumVertices = 6; 825ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualittstatic const int kLineSegsNumInIdxBuffer = 256; 83aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 84aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comGrPathRenderer* GrAAHairLinePathRenderer::Create(GrContext* context) { 85a8a6a32f428e77ee865780ad93bd5f8e1ce3c687bsalomon@google.com GrGpu* gpu = context->getGpu(); 865ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt GrIndexBuffer* qIdxBuf = gpu->createInstancedIndexBuffer(kQuadIdxBufPattern, 875ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt kIdxsPerQuad, 885ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt kQuadsNumInIdxBuffer, 895ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt kQuadNumVertices); 90a8a6a32f428e77ee865780ad93bd5f8e1ce3c687bsalomon@google.com SkAutoTUnref<GrIndexBuffer> qIdxBuffer(qIdxBuf); 915ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt GrIndexBuffer* lIdxBuf = gpu->createInstancedIndexBuffer(kLineSegIdxBufPattern, 925ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt kIdxsPerLineSeg, 935ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt kLineSegsNumInIdxBuffer, 945ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt kLineSegNumVertices); 95681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com SkAutoTUnref<GrIndexBuffer> lIdxBuffer(lIdxBuf); 96c377baf406996aed18d82d328029c82dbc3b8ddatomhudson@google.com return SkNEW_ARGS(GrAAHairLinePathRenderer, 97681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com (context, lIdxBuf, qIdxBuf)); 98aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com} 99aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 100aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comGrAAHairLinePathRenderer::GrAAHairLinePathRenderer( 101aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com const GrContext* context, 102aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com const GrIndexBuffer* linesIndexBuffer, 103aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com const GrIndexBuffer* quadsIndexBuffer) { 104aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com fLinesIndexBuffer = linesIndexBuffer; 105aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com linesIndexBuffer->ref(); 106aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com fQuadsIndexBuffer = quadsIndexBuffer; 107aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com quadsIndexBuffer->ref(); 108aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com} 109aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 110aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comGrAAHairLinePathRenderer::~GrAAHairLinePathRenderer() { 111aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com fLinesIndexBuffer->unref(); 112aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com fQuadsIndexBuffer->unref(); 113aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com} 114aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 115aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comnamespace { 116aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 11792669014aa7ab821cdc09cc9ad610316eb16b490bsalomon@google.com#define PREALLOC_PTARRAY(N) SkSTArray<(N),SkPoint, true> 118aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 119aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com// Takes 178th time of logf on Z600 / VC2010 120aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comint get_float_exp(float x) { 121aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com GR_STATIC_ASSERT(sizeof(int) == sizeof(float)); 122515dcd36032997ce335daa0163c6d67e851bcad1commit-bot@chromium.org#ifdef SK_DEBUG 123aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com static bool tested; 124aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com if (!tested) { 125aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com tested = true; 126f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(get_float_exp(0.25f) == -2); 127f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(get_float_exp(0.3f) == -2); 128f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(get_float_exp(0.5f) == -1); 129f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(get_float_exp(1.f) == 0); 130f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(get_float_exp(2.f) == 1); 131f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(get_float_exp(2.5f) == 1); 132f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(get_float_exp(8.f) == 3); 133f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(get_float_exp(100.f) == 6); 134f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(get_float_exp(1000.f) == 9); 135f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(get_float_exp(1024.f) == 10); 136f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(get_float_exp(3000000.f) == 21); 137aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 138aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com#endif 1392ec7280a178ad3dcfd2e645bc330eeb04a84bfcfbsalomon@google.com const int* iptr = (const int*)&x; 1402ec7280a178ad3dcfd2e645bc330eeb04a84bfcfbsalomon@google.com return (((*iptr) & 0x7f800000) >> 23) - 127; 141aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com} 142aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 1435383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// Uses the max curvature function for quads to estimate 1445383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// where to chop the conic. If the max curvature is not 1455383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// found along the curve segment it will return 1 and 1463f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com// dst[0] is the original conic. If it returns 2 the dst[0] 1475383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// and dst[1] are the two new conics. 1483f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.comint split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) { 1495383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com SkScalar t = SkFindQuadMaxCurvature(src); 1505383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com if (t == 0) { 1515383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com if (dst) { 1525383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com dst[0].set(src, weight); 1535383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 1545383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com return 1; 1555383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } else { 1565383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com if (dst) { 1575383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com SkConic conic; 1585383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com conic.set(src, weight); 1595383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com conic.chopAt(t, dst); 1605383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 1615383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com return 2; 1625383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 1635383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com} 1645383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 1653f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com// Calls split_conic on the entire conic and then once more on each subsection. 1663f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com// Most cases will result in either 1 conic (chop point is not within t range) 1673f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com// or 3 points (split once and then one subsection is split again). 1683f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.comint chop_conic(const SkPoint src[3], SkConic dst[4], const SkScalar weight) { 1693f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com SkConic dstTemp[2]; 1703f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com int conicCnt = split_conic(src, dstTemp, weight); 1713f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com if (2 == conicCnt) { 1723f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com int conicCnt2 = split_conic(dstTemp[0].fPts, dst, dstTemp[0].fW); 1733f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com conicCnt = conicCnt2 + split_conic(dstTemp[1].fPts, &dst[conicCnt2], dstTemp[1].fW); 1743f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com } else { 1753f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com dst[0] = dstTemp[0]; 1763f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com } 1773f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com return conicCnt; 1783f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com} 1793f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com 1805383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// returns 0 if quad/conic is degen or close to it 1815383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// in this case approx the path with lines 1825383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// otherwise returns 1 1835383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.comint is_degen_quad_or_conic(const SkPoint p[3]) { 1845383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com static const SkScalar gDegenerateToLineTol = SK_Scalar1; 1855383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com static const SkScalar gDegenerateToLineTolSqd = 1865383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com SkScalarMul(gDegenerateToLineTol, gDegenerateToLineTol); 1875383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 1885383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com if (p[0].distanceToSqd(p[1]) < gDegenerateToLineTolSqd || 1895383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com p[1].distanceToSqd(p[2]) < gDegenerateToLineTolSqd) { 1905383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com return 1; 1915383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 1925383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 1935383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com SkScalar dsqd = p[1].distanceToLineBetweenSqd(p[0], p[2]); 1945383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com if (dsqd < gDegenerateToLineTolSqd) { 1955383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com return 1; 1965383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 1975383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 1985383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com if (p[2].distanceToLineBetweenSqd(p[1], p[0]) < gDegenerateToLineTolSqd) { 1995383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com return 1; 2005383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 2015383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com return 0; 2025383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com} 2035383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 204aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com// we subdivide the quads to avoid huge overfill 205aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com// if it returns -1 then should be drawn as lines 206aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comint num_quad_subdivs(const SkPoint p[3]) { 207aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com static const SkScalar gDegenerateToLineTol = SK_Scalar1; 208fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com static const SkScalar gDegenerateToLineTolSqd = 20946a2a1ee46b591b43a76f80d0c9d7e78b5a0a96cbsalomon@google.com SkScalarMul(gDegenerateToLineTol, gDegenerateToLineTol); 21046a2a1ee46b591b43a76f80d0c9d7e78b5a0a96cbsalomon@google.com 21146a2a1ee46b591b43a76f80d0c9d7e78b5a0a96cbsalomon@google.com if (p[0].distanceToSqd(p[1]) < gDegenerateToLineTolSqd || 21246a2a1ee46b591b43a76f80d0c9d7e78b5a0a96cbsalomon@google.com p[1].distanceToSqd(p[2]) < gDegenerateToLineTolSqd) { 21346a2a1ee46b591b43a76f80d0c9d7e78b5a0a96cbsalomon@google.com return -1; 21446a2a1ee46b591b43a76f80d0c9d7e78b5a0a96cbsalomon@google.com } 215aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 21681712883419f76e25d2ffec38a9438284a45a48dbsalomon@google.com SkScalar dsqd = p[1].distanceToLineBetweenSqd(p[0], p[2]); 21746a2a1ee46b591b43a76f80d0c9d7e78b5a0a96cbsalomon@google.com if (dsqd < gDegenerateToLineTolSqd) { 218aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com return -1; 219aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 22046a2a1ee46b591b43a76f80d0c9d7e78b5a0a96cbsalomon@google.com 22146a2a1ee46b591b43a76f80d0c9d7e78b5a0a96cbsalomon@google.com if (p[2].distanceToLineBetweenSqd(p[1], p[0]) < gDegenerateToLineTolSqd) { 222aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com return -1; 223aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 224aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 225aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // tolerance of triangle height in pixels 226aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // tuned on windows Quadro FX 380 / Z600 227aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // trade off of fill vs cpu time on verts 228aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // maybe different when do this using gpu (geo or tess shaders) 229aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com static const SkScalar gSubdivTol = 175 * SK_Scalar1; 230aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 2317460b378d68217167013ca889a4cdcae742908e7robertphillips@google.com if (dsqd <= SkScalarMul(gSubdivTol, gSubdivTol)) { 232aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com return 0; 233aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } else { 23487379e17c5e95c6fe0d88b3b9ae134355cfafc66robertphillips@google.com static const int kMaxSub = 4; 235aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // subdividing the quad reduces d by 4. so we want x = log4(d/tol) 236aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // = log4(d*d/tol*tol)/2 237aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // = log2(d*d/tol*tol) 238aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 239aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // +1 since we're ignoring the mantissa contribution. 240aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com int log = get_float_exp(dsqd/(gSubdivTol*gSubdivTol)) + 1; 241972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org log = SkTMin(SkTMax(0, log), kMaxSub); 242aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com return log; 243aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 244aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com} 245aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 246dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com/** 247dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com * Generates the lines and quads to be rendered. Lines are always recorded in 248dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com * device space. We will do a device space bloat to account for the 1pixel 249dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com * thickness. 250dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com * Quads are recorded in device space unless m contains 251dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com * perspective, then in they are in src space. We do this because we will 252dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com * subdivide large quads to reduce over-fill. This subdivision has to be 253dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com * performed before applying the perspective matrix. 254dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com */ 255dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.comint generate_lines_and_quads(const SkPath& path, 256dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com const SkMatrix& m, 257fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org const SkIRect& devClipBounds, 258681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com GrAAHairLinePathRenderer::PtArray* lines, 259681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com GrAAHairLinePathRenderer::PtArray* quads, 260681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com GrAAHairLinePathRenderer::PtArray* conics, 261681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com GrAAHairLinePathRenderer::IntArray* quadSubdivCnts, 262681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com GrAAHairLinePathRenderer::FloatArray* conicWeights) { 263aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com SkPath::Iter iter(path, false); 264aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 265aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com int totalQuadCount = 0; 266fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org SkRect bounds; 267fd03d4a829efe2d77a712fd991927c55f59a2ffecommit-bot@chromium.org SkIRect ibounds; 268dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com 269dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com bool persp = m.hasPerspective(); 270dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com 271aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com for (;;) { 272972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org SkPoint pathPts[4]; 273972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org SkPoint devPts[4]; 274912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org SkPath::Verb verb = iter.next(pathPts); 27594b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com switch (verb) { 2765383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com case SkPath::kConic_Verb: { 2773f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com SkConic dst[4]; 2783f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com // We chop the conics to create tighter clipping to hide error 2793f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com // that appears near max curvature of very thin conics. Thin 2803f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com // hyperbolas with high weight still show error. 2815383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com int conicCnt = chop_conic(pathPts, dst, iter.conicWeight()); 2825383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com for (int i = 0; i < conicCnt; ++i) { 2835383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com SkPoint* chopPnts = dst[i].fPts; 2845383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com m.mapPoints(devPts, chopPnts, 3); 2855383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com bounds.setBounds(devPts, 3); 2865383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com bounds.outset(SK_Scalar1, SK_Scalar1); 2875383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com bounds.roundOut(&ibounds); 2885383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com if (SkIRect::Intersects(devClipBounds, ibounds)) { 2895383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com if (is_degen_quad_or_conic(devPts)) { 2905383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com SkPoint* pts = lines->push_back_n(4); 2915383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com pts[0] = devPts[0]; 2925383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com pts[1] = devPts[1]; 2935383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com pts[2] = devPts[1]; 2945383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com pts[3] = devPts[2]; 2955383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } else { 2965383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com // when in perspective keep conics in src space 2975383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com SkPoint* cPts = persp ? chopPnts : devPts; 2985383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com SkPoint* pts = conics->push_back_n(3); 2995383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com pts[0] = cPts[0]; 3005383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com pts[1] = cPts[1]; 3015383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com pts[2] = cPts[2]; 3025383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com conicWeights->push_back() = dst[i].fW; 3035383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 3045383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 3055383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 306277c3f87656c44e0a651ed0dd56efa16c0ab07b4reed@google.com break; 3075383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 3085383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com case SkPath::kMove_Verb: 309aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com break; 31094b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com case SkPath::kLine_Verb: 311912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org m.mapPoints(devPts, pathPts, 2); 312dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com bounds.setBounds(devPts, 2); 313aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com bounds.outset(SK_Scalar1, SK_Scalar1); 314aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com bounds.roundOut(&ibounds); 3157b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com if (SkIRect::Intersects(devClipBounds, ibounds)) { 316a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com SkPoint* pts = lines->push_back_n(2); 317a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com pts[0] = devPts[0]; 318a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com pts[1] = devPts[1]; 319aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 320aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com break; 321912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org case SkPath::kQuad_Verb: { 322912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org SkPoint choppedPts[5]; 323912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org // Chopping the quad helps when the quad is either degenerate or nearly degenerate. 324912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org // When it is degenerate it allows the approximation with lines to work since the 325912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org // chop point (if there is one) will be at the parabola's vertex. In the nearly 326912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org // degenerate the QuadUVMatrix computed for the points is almost singular which 327912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org // can cause rendering artifacts. 328912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org int n = SkChopQuadAtMaxCurvature(pathPts, choppedPts); 329912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org for (int i = 0; i < n; ++i) { 330912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org SkPoint* quadPts = choppedPts + i * 2; 331912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org m.mapPoints(devPts, quadPts, 3); 332912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org bounds.setBounds(devPts, 3); 333912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org bounds.outset(SK_Scalar1, SK_Scalar1); 334912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org bounds.roundOut(&ibounds); 335912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org 336912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org if (SkIRect::Intersects(devClipBounds, ibounds)) { 337912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org int subdiv = num_quad_subdivs(devPts); 338f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(subdiv >= -1); 339912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org if (-1 == subdiv) { 340912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org SkPoint* pts = lines->push_back_n(4); 341912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org pts[0] = devPts[0]; 342912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org pts[1] = devPts[1]; 343912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org pts[2] = devPts[1]; 344912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org pts[3] = devPts[2]; 345912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org } else { 346912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org // when in perspective keep quads in src space 347912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org SkPoint* qPts = persp ? quadPts : devPts; 348912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org SkPoint* pts = quads->push_back_n(3); 349912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org pts[0] = qPts[0]; 350912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org pts[1] = qPts[1]; 351912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org pts[2] = qPts[2]; 352912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org quadSubdivCnts->push_back() = subdiv; 353912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org totalQuadCount += 1 << subdiv; 354912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org } 355aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 356aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 357a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com break; 358912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org } 35994b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com case SkPath::kCubic_Verb: 360912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org m.mapPoints(devPts, pathPts, 4); 361dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com bounds.setBounds(devPts, 4); 362aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com bounds.outset(SK_Scalar1, SK_Scalar1); 363aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com bounds.roundOut(&ibounds); 3647b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com if (SkIRect::Intersects(devClipBounds, ibounds)) { 36592669014aa7ab821cdc09cc9ad610316eb16b490bsalomon@google.com PREALLOC_PTARRAY(32) q; 366a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com // we don't need a direction if we aren't constraining the subdivision 367a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com static const SkPath::Direction kDummyDir = SkPath::kCCW_Direction; 36869cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com // We convert cubics to quadratics (for now). 36969cc6ad20ed03f35f9d3c8119a2c32187669a22bbsalomon@google.com // In perspective have to do conversion in src space. 370dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com if (persp) { 371fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com SkScalar tolScale = 372dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com GrPathUtils::scaleToleranceToSrc(SK_Scalar1, m, 373dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com path.getBounds()); 374912e68ec469f714ec76b5ed419e5b7ea10e45500commit-bot@chromium.org GrPathUtils::convertCubicToQuads(pathPts, tolScale, false, kDummyDir, &q); 375dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com } else { 376a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com GrPathUtils::convertCubicToQuads(devPts, SK_Scalar1, false, kDummyDir, &q); 377dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com } 378aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com for (int i = 0; i < q.count(); i += 3) { 379dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com SkPoint* qInDevSpace; 380dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // bounds has to be calculated in device space, but q is 381dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // in src space when there is perspective. 382dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com if (persp) { 383dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com m.mapPoints(devPts, &q[i], 3); 384dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com bounds.setBounds(devPts, 3); 385dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com qInDevSpace = devPts; 386dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com } else { 387dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com bounds.setBounds(&q[i], 3); 388dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com qInDevSpace = &q[i]; 389dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com } 390aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com bounds.outset(SK_Scalar1, SK_Scalar1); 391aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com bounds.roundOut(&ibounds); 3927b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com if (SkIRect::Intersects(devClipBounds, ibounds)) { 393dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com int subdiv = num_quad_subdivs(qInDevSpace); 394f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(subdiv >= -1); 395aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com if (-1 == subdiv) { 396a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com SkPoint* pts = lines->push_back_n(4); 397dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // lines should always be in device coords 398a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com pts[0] = qInDevSpace[0]; 399a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com pts[1] = qInDevSpace[1]; 400a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com pts[2] = qInDevSpace[1]; 401a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com pts[3] = qInDevSpace[2]; 402aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } else { 403a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com SkPoint* pts = quads->push_back_n(3); 404dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // q is already in src space when there is no 405dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // perspective and dev coords otherwise. 406a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com pts[0] = q[0 + i]; 407a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com pts[1] = q[1 + i]; 408a996fec40444e8b914cd84c17037f0c84301f717bsalomon@google.com pts[2] = q[2 + i]; 409aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com quadSubdivCnts->push_back() = subdiv; 410aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com totalQuadCount += 1 << subdiv; 411aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 412aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 413aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 414aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 415a51ab8416db9772a2eae3122f4f69801642daeb5bsalomon@google.com break; 41694b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com case SkPath::kClose_Verb: 417aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com break; 41894b284d719ee5ccd3e2efbd1d7084ec554583bacbsalomon@google.com case SkPath::kDone_Verb: 419aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com return totalQuadCount; 420aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 421aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 422aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com} 423aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 424681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.comstruct LineVertex { 425972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org SkPoint fPos; 426681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com GrColor fCoverage; 427681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com}; 4287475811143e190e172bf83d13c4bdba85704b604skia.committer@gmail.com 429681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.comstruct BezierVertex { 430972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org SkPoint fPos; 431aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com union { 432aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com struct { 4333f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com SkScalar fK; 4343f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com SkScalar fL; 4353f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com SkScalar fM; 4365383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } fConic; 437972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org SkVector fQuadCoord; 438aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com struct { 4393f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com SkScalar fBogus[4]; 440aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com }; 441aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com }; 442aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com}; 4435383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 444972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.orgGR_STATIC_ASSERT(sizeof(BezierVertex) == 3 * sizeof(SkPoint)); 445aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 446aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comvoid intersect_lines(const SkPoint& ptA, const SkVector& normA, 447aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com const SkPoint& ptB, const SkVector& normB, 448aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com SkPoint* result) { 449aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 450aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com SkScalar lineAW = -normA.dot(ptA); 451aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com SkScalar lineBW = -normB.dot(ptB); 452aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 453aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com SkScalar wInv = SkScalarMul(normA.fX, normB.fY) - 4545383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com SkScalarMul(normA.fY, normB.fX); 455aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com wInv = SkScalarInvert(wInv); 456aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 457aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com result->fX = SkScalarMul(normA.fY, lineBW) - SkScalarMul(lineAW, normB.fY); 458aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com result->fX = SkScalarMul(result->fX, wInv); 459fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com 460aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com result->fY = SkScalarMul(lineAW, normB.fX) - SkScalarMul(normA.fX, lineBW); 461aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com result->fY = SkScalarMul(result->fY, wInv); 462aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com} 463aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 4645ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualittvoid set_uv_quad(const SkPoint qpts[3], BezierVertex verts[kQuadNumVertices]) { 46534b05ca3799f4adc2994d57a22d78ae1bdf6fb4aegdaniel@google.com // this should be in the src space, not dev coords, when we have perspective 46634b05ca3799f4adc2994d57a22d78ae1bdf6fb4aegdaniel@google.com GrPathUtils::QuadUVMatrix DevToUV(qpts); 4675ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt DevToUV.apply<kQuadNumVertices, sizeof(BezierVertex), sizeof(SkPoint)>(verts); 46834b05ca3799f4adc2994d57a22d78ae1bdf6fb4aegdaniel@google.com} 46934b05ca3799f4adc2994d57a22d78ae1bdf6fb4aegdaniel@google.com 470b9086a026844e4cfd08b219e49ce3f12294cba98bsalomon@google.comvoid bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice, 4715ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt const SkMatrix* toSrc, BezierVertex verts[kQuadNumVertices], 4721dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com SkRect* devBounds) { 473f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(!toDevice == !toSrc); 474aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // original quad is specified by tri a,b,c 475dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com SkPoint a = qpts[0]; 476dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com SkPoint b = qpts[1]; 477dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com SkPoint c = qpts[2]; 478aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 479dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com if (toDevice) { 480dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com toDevice->mapPoints(&a, 1); 481dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com toDevice->mapPoints(&b, 1); 482dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com toDevice->mapPoints(&c, 1); 483dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com } 484dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // make a new poly where we replace a and c by a 1-pixel wide edges orthog 485dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // to edges ab and bc: 486dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // 487dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // before | after 488dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // | b0 489dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // b | 490dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // | 491dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // | a0 c0 492dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // a c | a1 c1 493dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // 494dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // edges a0->b0 and b0->c0 are parallel to original edges a->b and b->c, 495dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com // respectively. 496681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com BezierVertex& a0 = verts[0]; 497681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com BezierVertex& a1 = verts[1]; 498681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com BezierVertex& b0 = verts[2]; 499681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com BezierVertex& c0 = verts[3]; 500681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com BezierVertex& c1 = verts[4]; 501dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com 502aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com SkVector ab = b; 503aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com ab -= a; 504aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com SkVector ac = c; 505aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com ac -= a; 506aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com SkVector cb = b; 507aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com cb -= c; 508aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 509aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // We should have already handled degenerates 510f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(ab.length() > 0 && cb.length() > 0); 511aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 512aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com ab.normalize(); 513aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com SkVector abN; 514aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com abN.setOrthog(ab, SkVector::kLeft_Side); 515aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com if (abN.dot(ac) > 0) { 516aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com abN.negate(); 517aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 518aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 519aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com cb.normalize(); 520aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com SkVector cbN; 521aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com cbN.setOrthog(cb, SkVector::kLeft_Side); 522aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com if (cbN.dot(ac) < 0) { 523aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com cbN.negate(); 524aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 525aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 526aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com a0.fPos = a; 527aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com a0.fPos += abN; 528aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com a1.fPos = a; 529aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com a1.fPos -= abN; 530aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 531aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com c0.fPos = c; 532aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com c0.fPos += cbN; 533aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com c1.fPos = c; 534aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com c1.fPos -= cbN; 535aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 536aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com intersect_lines(a0.fPos, abN, c0.fPos, cbN, &b0.fPos); 5375ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt devBounds->growToInclude(&verts[0].fPos, sizeof(BezierVertex), kQuadNumVertices); 538aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 539dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com if (toSrc) { 5405ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt toSrc->mapPointsWithStride(&verts[0].fPos, sizeof(BezierVertex), kQuadNumVertices); 541dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com } 542aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com} 543aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 5443f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com// Equations based off of Loop-Blinn Quadratic GPU Rendering 5455383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// Input Parametric: 5465383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// P(t) = (P0*(1-t)^2 + 2*w*P1*t*(1-t) + P2*t^2) / (1-t)^2 + 2*w*t*(1-t) + t^2) 5475383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com// Output Implicit: 5483f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com// f(x, y, w) = f(P) = K^2 - LM 5493f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com// K = dot(k, P), L = dot(l, P), M = dot(m, P) 550139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org// k, l, m are calculated in function GrPathUtils::getConicKLM 5515ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualittvoid set_conic_coeffs(const SkPoint p[3], BezierVertex verts[kQuadNumVertices], 552139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org const SkScalar weight) { 553139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org SkScalar klm[9]; 5543f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com 555139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org GrPathUtils::getConicKLM(p, weight, klm); 5565383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 5575ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt for (int i = 0; i < kQuadNumVertices; ++i) { 5583f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com const SkPoint pnt = verts[i].fPos; 559139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org verts[i].fConic.fK = pnt.fX * klm[0] + pnt.fY * klm[1] + klm[2]; 560139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org verts[i].fConic.fL = pnt.fX * klm[3] + pnt.fY * klm[4] + klm[5]; 561139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org verts[i].fConic.fM = pnt.fX * klm[6] + pnt.fY * klm[7] + klm[8]; 5625383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 5635383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com} 5645383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 5655383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.comvoid add_conics(const SkPoint p[3], 566139484095f014ab08265c32337fddeeec6c0877dcommit-bot@chromium.org const SkScalar weight, 5675383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com const SkMatrix* toDevice, 5685383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com const SkMatrix* toSrc, 569681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com BezierVertex** vert, 5705383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com SkRect* devBounds) { 5715383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com bloat_quad(p, toDevice, toSrc, *vert, devBounds); 5725383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com set_conic_coeffs(p, *vert, weight); 5735ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt *vert += kQuadNumVertices; 5745383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com} 5755383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com 576aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comvoid add_quads(const SkPoint p[3], 577aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com int subdiv, 578b9086a026844e4cfd08b219e49ce3f12294cba98bsalomon@google.com const SkMatrix* toDevice, 579b9086a026844e4cfd08b219e49ce3f12294cba98bsalomon@google.com const SkMatrix* toSrc, 580681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com BezierVertex** vert, 5811dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com SkRect* devBounds) { 582f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(subdiv >= 0); 583aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com if (subdiv) { 584aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com SkPoint newP[5]; 585aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com SkChopQuadAtHalf(p, newP); 5861dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com add_quads(newP + 0, subdiv-1, toDevice, toSrc, vert, devBounds); 5871dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com add_quads(newP + 2, subdiv-1, toDevice, toSrc, vert, devBounds); 588aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } else { 5891dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com bloat_quad(p, toDevice, toSrc, *vert, devBounds); 59034b05ca3799f4adc2994d57a22d78ae1bdf6fb4aegdaniel@google.com set_uv_quad(p, *vert); 5915ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt *vert += kQuadNumVertices; 592aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 593aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com} 594aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 595aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.comvoid add_line(const SkPoint p[2], 596dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com const SkMatrix* toSrc, 597681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com GrColor coverage, 598681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com LineVertex** vert) { 599aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com const SkPoint& a = p[0]; 600aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com const SkPoint& b = p[1]; 601aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 602ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com SkVector ortho, vec = b; 603ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com vec -= a; 604ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com 605ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com if (vec.setLength(SK_ScalarHalf)) { 606ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com // Create a vector orthogonal to 'vec' and of unit length 607ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com ortho.fX = 2.0f * vec.fY; 608ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com ortho.fY = -2.0f * vec.fX; 609ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com 610ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com (*vert)[0].fPos = a; 611ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com (*vert)[0].fCoverage = coverage; 612ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com (*vert)[1].fPos = b; 613ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com (*vert)[1].fCoverage = coverage; 614ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com (*vert)[2].fPos = a - vec + ortho; 615ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com (*vert)[2].fCoverage = 0; 616ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com (*vert)[3].fPos = b + vec + ortho; 617ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com (*vert)[3].fCoverage = 0; 618ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com (*vert)[4].fPos = a - vec - ortho; 619ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com (*vert)[4].fCoverage = 0; 620ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com (*vert)[5].fPos = b + vec - ortho; 621ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com (*vert)[5].fCoverage = 0; 622aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 62349f085dddff10473b6ebf832a974288300224e60bsalomon if (toSrc) { 624dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com toSrc->mapPointsWithStride(&(*vert)->fPos, 625681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com sizeof(LineVertex), 6265ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt kLineSegNumVertices); 627dbeeac33329f5fd7dbd3514cd7189ca6ed080476bsalomon@google.com } 628aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } else { 629aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com // just make it degenerate and likely offscreen 6305ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt for (int i = 0; i < kLineSegNumVertices; ++i) { 631681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com (*vert)[i].fPos.set(SK_ScalarMax, SK_ScalarMax); 632681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com } 633aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 634aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 6355ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt *vert += kLineSegNumVertices; 636aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com} 637aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 638aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com} 639aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 64090c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org/////////////////////////////////////////////////////////////////////////////// 64190c240aca0c0f4cd71bbde11f20c7949b2a37c1ecommit-bot@chromium.org 6425e2d270f6346125b322afa461d874a28edfa28d5jvanverth@google.comnamespace { 6435e2d270f6346125b322afa461d874a28edfa28d5jvanverth@google.com 6445e2d270f6346125b322afa461d874a28edfa28d5jvanverth@google.com// position + edge 645681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.comextern const GrVertexAttrib gHairlineBezierAttribs[] = { 6465e2d270f6346125b322afa461d874a28edfa28d5jvanverth@google.com {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding}, 647b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt {kVec4f_GrVertexAttribType, sizeof(SkPoint), kGeometryProcessor_GrVertexAttribBinding} 6485e2d270f6346125b322afa461d874a28edfa28d5jvanverth@google.com}; 649681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com 650681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com// position + coverage 651681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.comextern const GrVertexAttrib gHairlineLineAttribs[] = { 652681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding}, 653972f9cd7a063d0544f8c919fd12b9a3adbd12b24commit-bot@chromium.org {kVec4ub_GrVertexAttribType, sizeof(SkPoint), kCoverage_GrVertexAttribBinding}, 654681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com}; 655681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com 6565e2d270f6346125b322afa461d874a28edfa28d5jvanverth@google.com}; 6575e2d270f6346125b322afa461d874a28edfa28d5jvanverth@google.com 658ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.combool GrAAHairLinePathRenderer::createLineGeom(const SkPath& path, 659ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com GrDrawTarget* target, 660ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com const PtArray& lines, 661ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com int lineCnt, 662ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com GrDrawTarget::AutoReleaseGeometry* arg, 663ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com SkRect* devBounds) { 66485eef600dfb5d4865e2db5db8ca2b8b23f898f7ccommit-bot@chromium.org GrDrawState* drawState = target->drawState(); 6655e2d270f6346125b322afa461d874a28edfa28d5jvanverth@google.com 666681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com const SkMatrix& viewM = drawState->getViewMatrix(); 6675e2d270f6346125b322afa461d874a28edfa28d5jvanverth@google.com 6685ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt int vertCnt = kLineSegNumVertices * lineCnt; 6695e2d270f6346125b322afa461d874a28edfa28d5jvanverth@google.com 6707b3d5ee72c2238aa239bce4d5b3aea98a437ca7aegdaniel drawState->setVertexAttribs<gHairlineLineAttribs>(SK_ARRAY_COUNT(gHairlineLineAttribs), 6717b3d5ee72c2238aa239bce4d5b3aea98a437ca7aegdaniel sizeof(LineVertex)); 6725e2d270f6346125b322afa461d874a28edfa28d5jvanverth@google.com 67385eef600dfb5d4865e2db5db8ca2b8b23f898f7ccommit-bot@chromium.org if (!arg->set(target, vertCnt, 0)) { 67485eef600dfb5d4865e2db5db8ca2b8b23f898f7ccommit-bot@chromium.org return false; 67585eef600dfb5d4865e2db5db8ca2b8b23f898f7ccommit-bot@chromium.org } 6765e2d270f6346125b322afa461d874a28edfa28d5jvanverth@google.com 677681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com LineVertex* verts = reinterpret_cast<LineVertex*>(arg->vertices()); 6785e2d270f6346125b322afa461d874a28edfa28d5jvanverth@google.com 67985eef600dfb5d4865e2db5db8ca2b8b23f898f7ccommit-bot@chromium.org const SkMatrix* toSrc = NULL; 68085eef600dfb5d4865e2db5db8ca2b8b23f898f7ccommit-bot@chromium.org SkMatrix ivm; 6815e2d270f6346125b322afa461d874a28edfa28d5jvanverth@google.com 68285eef600dfb5d4865e2db5db8ca2b8b23f898f7ccommit-bot@chromium.org if (viewM.hasPerspective()) { 68385eef600dfb5d4865e2db5db8ca2b8b23f898f7ccommit-bot@chromium.org if (viewM.invert(&ivm)) { 68485eef600dfb5d4865e2db5db8ca2b8b23f898f7ccommit-bot@chromium.org toSrc = &ivm; 68585eef600dfb5d4865e2db5db8ca2b8b23f898f7ccommit-bot@chromium.org } 68685eef600dfb5d4865e2db5db8ca2b8b23f898f7ccommit-bot@chromium.org } 687b8bd6cbbcde9846094ade18cafadfad46dc00889commit-bot@chromium.org devBounds->set(lines.begin(), lines.count()); 688681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com for (int i = 0; i < lineCnt; ++i) { 689e0a868c84ebc34c5a16b5faa1546016abb9ca0accommit-bot@chromium.org add_line(&lines[2*i], toSrc, drawState->getCoverageColor(), &verts); 6905e2d270f6346125b322afa461d874a28edfa28d5jvanverth@google.com } 691f91e3d4f54de9976b6538decadd977b19e49eaddskia.committer@gmail.com // All the verts computed by add_line are within sqrt(1^2 + 0.5^2) of the end points. 6924b413c8bb123e42ca4b9c7bfa6bc2167283cb84ccommit-bot@chromium.org static const SkScalar kSqrtOfOneAndAQuarter = 1.118f; 69352c75262117aa1251c7ddaf78430a55b707b8db4robertphillips@google.com // Add a little extra to account for vector normalization precision. 69452c75262117aa1251c7ddaf78430a55b707b8db4robertphillips@google.com static const SkScalar kOutset = kSqrtOfOneAndAQuarter + SK_Scalar1 / 20; 695b8bd6cbbcde9846094ade18cafadfad46dc00889commit-bot@chromium.org devBounds->outset(kOutset, kOutset); 6965e2d270f6346125b322afa461d874a28edfa28d5jvanverth@google.com 697681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com return true; 698681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com} 699681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com 700681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.combool GrAAHairLinePathRenderer::createBezierGeom( 701681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com const SkPath& path, 702681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com GrDrawTarget* target, 703681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com const PtArray& quads, 704681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com int quadCnt, 705681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com const PtArray& conics, 706681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com int conicCnt, 707681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com const IntArray& qSubdivs, 708681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com const FloatArray& cWeights, 709681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com GrDrawTarget::AutoReleaseGeometry* arg, 710681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com SkRect* devBounds) { 711681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com GrDrawState* drawState = target->drawState(); 7127475811143e190e172bf83d13c4bdba85704b604skia.committer@gmail.com 713681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com const SkMatrix& viewM = drawState->getViewMatrix(); 7147475811143e190e172bf83d13c4bdba85704b604skia.committer@gmail.com 7155ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt int vertCnt = kQuadNumVertices * quadCnt + kQuadNumVertices * conicCnt; 7167475811143e190e172bf83d13c4bdba85704b604skia.committer@gmail.com 7177b3d5ee72c2238aa239bce4d5b3aea98a437ca7aegdaniel int vAttribCnt = SK_ARRAY_COUNT(gHairlineBezierAttribs); 7187b3d5ee72c2238aa239bce4d5b3aea98a437ca7aegdaniel target->drawState()->setVertexAttribs<gHairlineBezierAttribs>(vAttribCnt, sizeof(BezierVertex)); 7197475811143e190e172bf83d13c4bdba85704b604skia.committer@gmail.com 720681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com if (!arg->set(target, vertCnt, 0)) { 721681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com return false; 722681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com } 7237475811143e190e172bf83d13c4bdba85704b604skia.committer@gmail.com 724681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com BezierVertex* verts = reinterpret_cast<BezierVertex*>(arg->vertices()); 7257475811143e190e172bf83d13c4bdba85704b604skia.committer@gmail.com 726681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com const SkMatrix* toDevice = NULL; 727681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com const SkMatrix* toSrc = NULL; 728681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com SkMatrix ivm; 7297475811143e190e172bf83d13c4bdba85704b604skia.committer@gmail.com 730681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com if (viewM.hasPerspective()) { 731681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com if (viewM.invert(&ivm)) { 732681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com toDevice = &viewM; 733681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com toSrc = &ivm; 734681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com } 735681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com } 7367475811143e190e172bf83d13c4bdba85704b604skia.committer@gmail.com 737b8bd6cbbcde9846094ade18cafadfad46dc00889commit-bot@chromium.org // Seed the dev bounds with some pts known to be inside. Each quad and conic grows the bounding 738b8bd6cbbcde9846094ade18cafadfad46dc00889commit-bot@chromium.org // box to include its vertices. 739b8bd6cbbcde9846094ade18cafadfad46dc00889commit-bot@chromium.org SkPoint seedPts[2]; 740b8bd6cbbcde9846094ade18cafadfad46dc00889commit-bot@chromium.org if (quadCnt) { 741b8bd6cbbcde9846094ade18cafadfad46dc00889commit-bot@chromium.org seedPts[0] = quads[0]; 742b8bd6cbbcde9846094ade18cafadfad46dc00889commit-bot@chromium.org seedPts[1] = quads[2]; 743b8bd6cbbcde9846094ade18cafadfad46dc00889commit-bot@chromium.org } else if (conicCnt) { 744b8bd6cbbcde9846094ade18cafadfad46dc00889commit-bot@chromium.org seedPts[0] = conics[0]; 745b8bd6cbbcde9846094ade18cafadfad46dc00889commit-bot@chromium.org seedPts[1] = conics[2]; 746b8bd6cbbcde9846094ade18cafadfad46dc00889commit-bot@chromium.org } 74749f085dddff10473b6ebf832a974288300224e60bsalomon if (toDevice) { 748b8bd6cbbcde9846094ade18cafadfad46dc00889commit-bot@chromium.org toDevice->mapPoints(seedPts, 2); 749b8bd6cbbcde9846094ade18cafadfad46dc00889commit-bot@chromium.org } 750b8bd6cbbcde9846094ade18cafadfad46dc00889commit-bot@chromium.org devBounds->set(seedPts[0], seedPts[1]); 751b8bd6cbbcde9846094ade18cafadfad46dc00889commit-bot@chromium.org 752aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com int unsubdivQuadCnt = quads.count() / 3; 753aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com for (int i = 0; i < unsubdivQuadCnt; ++i) { 754f6de475e5cbd143f348ff7738919e397b7fe7f57tfarina@chromium.org SkASSERT(qSubdivs[i] >= 0); 7551dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts, devBounds); 756aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 7577475811143e190e172bf83d13c4bdba85704b604skia.committer@gmail.com 7585383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com // Start Conics 759681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com for (int i = 0; i < conicCnt; ++i) { 7605383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com add_conics(&conics[3*i], cWeights[i], toDevice, toSrc, &verts, devBounds); 7615383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 762aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com return true; 763aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com} 764aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 765e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.combool GrAAHairLinePathRenderer::canDrawPath(const SkPath& path, 766e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com const SkStrokeRec& stroke, 7678a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com const GrDrawTarget* target, 7688a4fc40b02fa0a8300ade26863f4ddae69197d62robertphillips@google.com bool antiAlias) const { 769e0a868c84ebc34c5a16b5faa1546016abb9ca0accommit-bot@chromium.org if (!antiAlias) { 770e0a868c84ebc34c5a16b5faa1546016abb9ca0accommit-bot@chromium.org return false; 771e0a868c84ebc34c5a16b5faa1546016abb9ca0accommit-bot@chromium.org } 772e0a868c84ebc34c5a16b5faa1546016abb9ca0accommit-bot@chromium.org 773e0a868c84ebc34c5a16b5faa1546016abb9ca0accommit-bot@chromium.org if (!IsStrokeHairlineOrEquivalent(stroke, 774e0a868c84ebc34c5a16b5faa1546016abb9ca0accommit-bot@chromium.org target->getDrawState().getViewMatrix(), 775e0a868c84ebc34c5a16b5faa1546016abb9ca0accommit-bot@chromium.org NULL)) { 776c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com return false; 777c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com } 778c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com 779e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com if (SkPath::kLine_SegmentMask == path.getSegmentMasks() || 7803f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com target->caps()->shaderDerivativeSupport()) { 7813f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com return true; 782c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com } 7833f2a2d5fdc833dd20900ee90249b03474d0e00b3egdaniel@google.com return false; 784c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com} 785aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 786681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.comtemplate <class VertexType> 787681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.combool check_bounds(GrDrawState* drawState, const SkRect& devBounds, void* vertices, int vCount) 788681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com{ 7891dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com SkRect tolDevBounds = devBounds; 790b8bd6cbbcde9846094ade18cafadfad46dc00889commit-bot@chromium.org // The bounds ought to be tight, but in perspective the below code runs the verts 791b8bd6cbbcde9846094ade18cafadfad46dc00889commit-bot@chromium.org // through the view matrix to get back to dev coords, which can introduce imprecision. 792b8bd6cbbcde9846094ade18cafadfad46dc00889commit-bot@chromium.org if (drawState->getViewMatrix().hasPerspective()) { 793b8bd6cbbcde9846094ade18cafadfad46dc00889commit-bot@chromium.org tolDevBounds.outset(SK_Scalar1 / 1000, SK_Scalar1 / 1000); 794b8bd6cbbcde9846094ade18cafadfad46dc00889commit-bot@chromium.org } else { 795b8bd6cbbcde9846094ade18cafadfad46dc00889commit-bot@chromium.org // Non-persp matrices cause this path renderer to draw in device space. 796b8bd6cbbcde9846094ade18cafadfad46dc00889commit-bot@chromium.org SkASSERT(drawState->getViewMatrix().isIdentity()); 797b8bd6cbbcde9846094ade18cafadfad46dc00889commit-bot@chromium.org } 7981dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com SkRect actualBounds; 7997475811143e190e172bf83d13c4bdba85704b604skia.committer@gmail.com 800681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com VertexType* verts = reinterpret_cast<VertexType*>(vertices); 8011dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com bool first = true; 8021dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com for (int i = 0; i < vCount; ++i) { 8031dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com SkPoint pos = verts[i].fPos; 8041dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com // This is a hack to workaround the fact that we move some degenerate segments offscreen. 8051dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com if (SK_ScalarMax == pos.fX) { 8061dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com continue; 8071dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com } 8081dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com drawState->getViewMatrix().mapPoints(&pos, 1); 8091dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com if (first) { 8101dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com actualBounds.set(pos.fX, pos.fY, pos.fX, pos.fY); 8111dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com first = false; 8121dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com } else { 8131dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com actualBounds.growToInclude(pos.fX, pos.fY); 8141dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com } 8151dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com } 8161dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com if (!first) { 817681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com return tolDevBounds.contains(actualBounds); 8181dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com } 8197475811143e190e172bf83d13c4bdba85704b604skia.committer@gmail.com 820681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com return true; 821681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com} 8221dd9baa6c8faeb4ce837c39d179ce9c9a09719efbsalomon@google.com 823e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.combool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path, 824e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com const SkStrokeRec& stroke, 825681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com GrDrawTarget* target, 826681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com bool antiAlias) { 827681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com GrDrawState* drawState = target->drawState(); 8287475811143e190e172bf83d13c4bdba85704b604skia.committer@gmail.com 829e0a868c84ebc34c5a16b5faa1546016abb9ca0accommit-bot@chromium.org SkScalar hairlineCoverage; 830e0a868c84ebc34c5a16b5faa1546016abb9ca0accommit-bot@chromium.org if (IsStrokeHairlineOrEquivalent(stroke, 831e0a868c84ebc34c5a16b5faa1546016abb9ca0accommit-bot@chromium.org target->getDrawState().getViewMatrix(), 832e0a868c84ebc34c5a16b5faa1546016abb9ca0accommit-bot@chromium.org &hairlineCoverage)) { 833e0a868c84ebc34c5a16b5faa1546016abb9ca0accommit-bot@chromium.org uint8_t newCoverage = SkScalarRoundToInt(hairlineCoverage * 834e0a868c84ebc34c5a16b5faa1546016abb9ca0accommit-bot@chromium.org target->getDrawState().getCoverage()); 835e0a868c84ebc34c5a16b5faa1546016abb9ca0accommit-bot@chromium.org target->drawState()->setCoverage(newCoverage); 836e0a868c84ebc34c5a16b5faa1546016abb9ca0accommit-bot@chromium.org } 837e0a868c84ebc34c5a16b5faa1546016abb9ca0accommit-bot@chromium.org 838681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com SkIRect devClipBounds; 839681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com target->getClip()->getConservativeBounds(drawState->getRenderTarget(), &devClipBounds); 8407475811143e190e172bf83d13c4bdba85704b604skia.committer@gmail.com 841681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com int lineCnt; 842681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com int quadCnt; 843681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com int conicCnt; 844681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com PREALLOC_PTARRAY(128) lines; 845681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com PREALLOC_PTARRAY(128) quads; 846681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com PREALLOC_PTARRAY(128) conics; 847681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com IntArray qSubdivs; 848681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com FloatArray cWeights; 849e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com quadCnt = generate_lines_and_quads(path, drawState->getViewMatrix(), devClipBounds, 850681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com &lines, &quads, &conics, &qSubdivs, &cWeights); 851681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com lineCnt = lines.count() / 2; 852681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com conicCnt = conics.count() / 3; 8537475811143e190e172bf83d13c4bdba85704b604skia.committer@gmail.com 854681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com // do lines first 855b8bd6cbbcde9846094ade18cafadfad46dc00889commit-bot@chromium.org if (lineCnt) { 856681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com GrDrawTarget::AutoReleaseGeometry arg; 857681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com SkRect devBounds; 858681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com 859e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com if (!this->createLineGeom(path, 860681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com target, 861681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com lines, 862681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com lineCnt, 863681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com &arg, 864681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com &devBounds)) { 865681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com return false; 866eb6879f50a5564eeb981ec5616b55bf685eb76fcbsalomon@google.com } 867aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com 868681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com GrDrawTarget::AutoStateRestore asr; 869681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com 870ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com // createLineGeom transforms the geometry to device space when the matrix does not have 871681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com // perspective. 872681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com if (target->getDrawState().getViewMatrix().hasPerspective()) { 873681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com asr.set(target, GrDrawTarget::kPreserve_ASRInit); 874681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com } else if (!asr.setIdentity(target, GrDrawTarget::kPreserve_ASRInit)) { 875681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com return false; 876681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com } 877681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com GrDrawState* drawState = target->drawState(); 878681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com 879681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com // Check devBounds 88052c75262117aa1251c7ddaf78430a55b707b8db4robertphillips@google.com SkASSERT(check_bounds<LineVertex>(drawState, devBounds, arg.vertices(), 8815ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt kLineSegNumVertices * lineCnt)); 882681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com 883681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com { 884681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com GrDrawState::AutoRestoreEffects are(drawState); 885681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com target->setIndexSourceToBuffer(fLinesIndexBuffer); 886681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com int lines = 0; 887681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com while (lines < lineCnt) { 8885ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt int n = SkTMin(lineCnt - lines, kLineSegsNumInIdxBuffer); 889681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com target->drawIndexed(kTriangles_GrPrimitiveType, 8905ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt kLineSegNumVertices*lines, // startV 8915ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt 0, // startI 8925ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt kLineSegNumVertices*n, // vCount 8935ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt kIdxsPerLineSeg*n, // iCount 894ada90dac10fa804b49cac9d4e8aa036cb587044frobertphillips@google.com &devBounds); 895681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com lines += n; 896681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com } 8975383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 8985383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 8997475811143e190e172bf83d13c4bdba85704b604skia.committer@gmail.com 900681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com // then quadratics/conics 901b8bd6cbbcde9846094ade18cafadfad46dc00889commit-bot@chromium.org if (quadCnt || conicCnt) { 902681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com GrDrawTarget::AutoReleaseGeometry arg; 903681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com SkRect devBounds; 9047475811143e190e172bf83d13c4bdba85704b604skia.committer@gmail.com 905e79f320ed6c5ec9f6164ba84be1ff586532e6517robertphillips@google.com if (!this->createBezierGeom(path, 906681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com target, 907681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com quads, 908681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com quadCnt, 909681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com conics, 910681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com conicCnt, 911681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com qSubdivs, 912681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com cWeights, 913681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com &arg, 914681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com &devBounds)) { 915681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com return false; 916681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com } 9177475811143e190e172bf83d13c4bdba85704b604skia.committer@gmail.com 918681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com GrDrawTarget::AutoStateRestore asr; 9197475811143e190e172bf83d13c4bdba85704b604skia.committer@gmail.com 920681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com // createGeom transforms the geometry to device space when the matrix does not have 921681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com // perspective. 922681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com if (target->getDrawState().getViewMatrix().hasPerspective()) { 923681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com asr.set(target, GrDrawTarget::kPreserve_ASRInit); 924681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com } else if (!asr.setIdentity(target, GrDrawTarget::kPreserve_ASRInit)) { 925681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com return false; 926681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com } 927681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com GrDrawState* drawState = target->drawState(); 928681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com 929681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com // Check devBounds 930681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com SkASSERT(check_bounds<BezierVertex>(drawState, devBounds, arg.vertices(), 9315ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt kQuadNumVertices * quadCnt + kQuadNumVertices * conicCnt)); 9327475811143e190e172bf83d13c4bdba85704b604skia.committer@gmail.com 933884624764c1c6e6763484d86c69ebb46080ec49ccommit-bot@chromium.org if (quadCnt > 0) { 934b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt GrGeometryProcessor* hairQuadProcessor = 935b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt GrQuadEffect::Create(kHairlineAA_GrProcessorEdgeType, *target->caps()); 936b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt SkASSERT(hairQuadProcessor); 937681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com GrDrawState::AutoRestoreEffects are(drawState); 938681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com target->setIndexSourceToBuffer(fQuadsIndexBuffer); 939b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt drawState->setGeometryProcessor(hairQuadProcessor)->unref(); 940884624764c1c6e6763484d86c69ebb46080ec49ccommit-bot@chromium.org int quads = 0; 941681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com while (quads < quadCnt) { 9425ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt int n = SkTMin(quadCnt - quads, kQuadsNumInIdxBuffer); 943681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com target->drawIndexed(kTriangles_GrPrimitiveType, 9445ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt kQuadNumVertices*quads, // startV 9455ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt 0, // startI 9465ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt kQuadNumVertices*n, // vCount 9475ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt kIdxsPerQuad*n, // iCount 948681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com &devBounds); 949681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com quads += n; 950681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com } 951681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com } 9527475811143e190e172bf83d13c4bdba85704b604skia.committer@gmail.com 953884624764c1c6e6763484d86c69ebb46080ec49ccommit-bot@chromium.org if (conicCnt > 0) { 954681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com GrDrawState::AutoRestoreEffects are(drawState); 955b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt GrGeometryProcessor* hairConicProcessor = GrConicEffect::Create( 956b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt kHairlineAA_GrProcessorEdgeType, *target->caps()); 957b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt SkASSERT(hairConicProcessor); 958b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt drawState->setGeometryProcessor(hairConicProcessor)->unref(); 959884624764c1c6e6763484d86c69ebb46080ec49ccommit-bot@chromium.org int conics = 0; 960681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com while (conics < conicCnt) { 9615ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt int n = SkTMin(conicCnt - conics, kQuadsNumInIdxBuffer); 962681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com target->drawIndexed(kTriangles_GrPrimitiveType, 9635ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt kQuadNumVertices*(quadCnt + conics), // startV 9645ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt 0, // startI 9655ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt kQuadNumVertices*n, // vCount 9665ead6da4abaa3d8fb479fd84631138f83b7aa5b6joshualitt kIdxsPerQuad*n, // iCount 967681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com &devBounds); 968681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com conics += n; 969681ccf08758d33f6307d8d466bbe8ffe0e8b9312jvanverth@google.com } 9705383a7525355dec72efa2083aeadffdd09a962b9egdaniel@google.com } 971aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com } 9727475811143e190e172bf83d13c4bdba85704b604skia.committer@gmail.com 9730406b9e1faee06c6ecb2732a1bcf3b0e53104e07bsalomon@google.com target->resetIndexSource(); 9744647f9059825c062169d4d454c12640d82ae16c0bsalomon@google.com 975c2099d2707abcc94e139627399aed4b8894b69bbbsalomon@google.com return true; 976aeb2160b1dd34f8e640e8e56544fe407d4ff6311bsalomon@google.com} 977