GrAAHairLinePathRenderer.cpp revision e79f320ed6c5ec9f6164ba84be1ff586532e6517
15f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka/* 25f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * Copyright 2011 Google Inc. 35f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * 45f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * Use of this source code is governed by a BSD-style license that can be 55f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka * found in the LICENSE file. 65f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka */ 75f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 85f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka#include "GrAAHairLinePathRenderer.h" 95f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 105f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka#include "GrContext.h" 115f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka#include "GrDrawState.h" 125f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka#include "GrDrawTargetCaps.h" 135f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka#include "GrEffect.h" 145f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka#include "GrGpu.h" 155f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka#include "GrIndexBuffer.h" 165f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka#include "GrPathUtils.h" 175f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka#include "GrTBackendEffectFactory.h" 185f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka#include "SkGeometry.h" 19d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka#include "SkStroke.h" 2031c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka#include "SkTemplates.h" 215f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 2213ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka#include "effects/GrBezierEffect.h" 235f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 244112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaokanamespace { 256dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka// quadratics are rendered as 5-sided polys in order to bound the 26f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka// AA stroke around the center-curve. See comments in push_quad_index_buffer and 2722b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka// bloat_quad. Quadratics and conics share an index buffer 284112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaokastatic const int kVertsPerQuad = 5; 29bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaokastatic const int kIdxsPerQuad = 9; 3013ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka 315f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka// lines are rendered as: 325f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka// *______________* 335f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka// |\ -_______ /| 345f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka// | \ \ / | 355f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka// | *--------* | 36b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka// | / ______/ \ | 37f6972561fcb45310f18230ce217f0c6bb57e7eeeTadashi G. Takaoka// */_-__________\* 380e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka// For: 6 vertices and 18 indices (for 6 triangles) 395f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokastatic const int kVertsPerLineSeg = 6; 405f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokastatic const int kIdxsPerLineSeg = 18; 414d146d5e3e00cab1cca7d0d29fe00c0d629b5eacTadashi G. Takaoka 4215f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaokastatic const int kNumQuadsInIdxBuffer = 256; 432fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasastatic const size_t kQuadIdxSBufize = kIdxsPerQuad * 44cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka sizeof(uint16_t) * 45cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka kNumQuadsInIdxBuffer; 46cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka 4749d8af8a4e900f3c68c333aba7fde0a11fd368b1Tadashi G. Takaokastatic const int kNumLineSegsInIdxBuffer = 256; 48bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaokastatic const size_t kLineSegIdxSBufize = kIdxsPerLineSeg * 490e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka sizeof(uint16_t) * 507dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka kNumLineSegsInIdxBuffer; 51b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka 52cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaokastatic bool push_quad_index_data(GrIndexBuffer* qIdxBuffer) { 532fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa uint16_t* data = (uint16_t*) qIdxBuffer->lock(); 544daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang bool tempData = NULL == data; 5515d4793911fa305e0a58aced925961e948582979satok if (tempData) { 565f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka data = SkNEW_ARRAY(uint16_t, kNumQuadsInIdxBuffer * kIdxsPerQuad); 57375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 58c166697e3f5ec600089987dbbff0be7f3e308565Ken Wakasa for (int i = 0; i < kNumQuadsInIdxBuffer; ++i) { 59a7d2fc6befa1b16883200a653fc01deb4d94944dKen Wakasa 60e28eba5074664d5716b8e58b8d0a235746b261ebKen Wakasa // Each quadratic is rendered as a five sided polygon. This poly bounds 619364d46ac3590d23b8117a66efc8756454cef772Tadashi G. Takaoka // the quadratic's bounding triangle but has been expanded so that the 62ccf4a310279b13bbf0b6aac76a0878178c1dfb7dTadashi G. Takaoka // 1-pixel wide area around the curve is inside the poly. 634be6198cb73cc24e10834153c4e049644ed187e3Tadashi G. Takaoka // If a,b,c are the original control points then the poly a0,b0,c0,c1,a1 646b966160ac8570271547bf63217efa5e228d4accKurt Partridge // that is rendered would look like this: 655f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // b0 665f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // b 675f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // 685f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // a0 c0 695f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // a c 705f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // a1 c1 712fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // Each is drawn as three triangles specified by these 9 indices: 722fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa int baseIdx = i * kIdxsPerQuad; 7341f9f1ef703ca4d63f1ef08b51d1365a17b4065aTadashi G. Takaoka uint16_t baseVert = (uint16_t)(i * kVertsPerQuad); 742fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa data[0 + baseIdx] = baseVert + 0; // a0 75dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka data[1 + baseIdx] = baseVert + 1; // a1 76dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka data[2 + baseIdx] = baseVert + 2; // b0 77dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka data[3 + baseIdx] = baseVert + 2; // b0 78dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka data[4 + baseIdx] = baseVert + 4; // c1 79dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka data[5 + baseIdx] = baseVert + 3; // c0 80dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka data[6 + baseIdx] = baseVert + 1; // a1 81dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka data[7 + baseIdx] = baseVert + 4; // c1 822fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa data[8 + baseIdx] = baseVert + 2; // b0 83dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka } 84dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka if (tempData) { 85dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka bool ret = qIdxBuffer->updateData(data, kQuadIdxSBufize); 86dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka delete[] data; 87dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka return ret; 88375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } else { 890e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka qIdxBuffer->unlock(); 900e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka return true; 910e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 92d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka} 93f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka 94dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaokastatic bool push_line_index_data(GrIndexBuffer* lIdxBuffer) { 95375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka uint16_t* data = (uint16_t*) lIdxBuffer->lock(); 963623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka bool tempData = NULL == data; 973623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka if (tempData) { 983623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka data = SkNEW_ARRAY(uint16_t, kNumLineSegsInIdxBuffer * kIdxsPerLineSeg); 993623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka } 1003623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka for (int i = 0; i < kNumLineSegsInIdxBuffer; ++i) { 1013623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka // Each line segment is rendered as two quads and two triangles. 1023623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka // p0 and p1 have alpha = 1 while all other points have alpha = 0. 1033623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka // The four external points are offset 1 pixel perpendicular to the 1043623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka // line and half a pixel parallel to the line. 1053623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka // 1063623b9767b3d5f122f574d4c4d14aa79ed305752Tadashi G. Takaoka // p4 p5 1075f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // p0 p1 1082fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // p2 p3 1092fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // 110c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka // Each is drawn as six triangles specified by these 18 indices: 1115f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka int baseIdx = i * kIdxsPerLineSeg; 112bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka uint16_t baseVert = (uint16_t)(i * kVertsPerLineSeg); 113bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka data[0 + baseIdx] = baseVert + 0; 114bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka data[1 + baseIdx] = baseVert + 1; 1152fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa data[2 + baseIdx] = baseVert + 3; 1164112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 117bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka data[3 + baseIdx] = baseVert + 0; 11831c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka data[4 + baseIdx] = baseVert + 3; 11931c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka data[5 + baseIdx] = baseVert + 2; 1207dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka 121fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka data[6 + baseIdx] = baseVert + 0; 1224daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang data[7 + baseIdx] = baseVert + 4; 1232fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa data[8 + baseIdx] = baseVert + 5; 1242fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa 1252fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa data[9 + baseIdx] = baseVert + 0; 12641f9f1ef703ca4d63f1ef08b51d1365a17b4065aTadashi G. Takaoka data[10+ baseIdx] = baseVert + 5; 1272fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa data[11+ baseIdx] = baseVert + 1; 12841f9f1ef703ca4d63f1ef08b51d1365a17b4065aTadashi G. Takaoka 129bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka data[12 + baseIdx] = baseVert + 0; 130bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka data[13 + baseIdx] = baseVert + 2; 13115d4793911fa305e0a58aced925961e948582979satok data[14 + baseIdx] = baseVert + 4; 13273a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka 1332fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa data[15 + baseIdx] = baseVert + 1; 1342fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa data[16 + baseIdx] = baseVert + 5; 1354daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang data[17 + baseIdx] = baseVert + 3; 13673a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka } 137cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka if (tempData) { 138cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka bool ret = lIdxBuffer->updateData(data, kLineSegIdxSBufize); 139375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka delete[] data; 140cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka return ret; 141cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka } else { 142cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka lIdxBuffer->unlock(); 143375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka return true; 1440e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 145992c5219092ccafe66363451fbf4ca7c5a43fb20Tadashi G. Takaoka} 146bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka} 1470e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 1482affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. TakaokaGrPathRenderer* GrAAHairLinePathRenderer::Create(GrContext* context) { 149f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka GrGpu* gpu = context->getGpu(); 150f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka GrIndexBuffer* qIdxBuf = gpu->createIndexBuffer(kQuadIdxSBufize, false); 151a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka SkAutoTUnref<GrIndexBuffer> qIdxBuffer(qIdxBuf); 152a91561aa58db1c43092c1caecc051a11fa5391c7Tadashi G. Takaoka if (NULL == qIdxBuf || !push_quad_index_data(qIdxBuf)) { 1532affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka return NULL; 154d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka } 155d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka GrIndexBuffer* lIdxBuf = gpu->createIndexBuffer(kLineSegIdxSBufize, false); 156d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka SkAutoTUnref<GrIndexBuffer> lIdxBuffer(lIdxBuf); 1575f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (NULL == lIdxBuf || !push_line_index_data(lIdxBuf)) { 158375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka return NULL; 159375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 160375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka return SkNEW_ARGS(GrAAHairLinePathRenderer, 161375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka (context, lIdxBuf, qIdxBuf)); 1622fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa} 163b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka 1645f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. TakaokaGrAAHairLinePathRenderer::GrAAHairLinePathRenderer( 1652fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa const GrContext* context, 166741831d32295acfb7675d7e0781a634d78868c63Satoshi Kataoka const GrIndexBuffer* linesIndexBuffer, 1675f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka const GrIndexBuffer* quadsIndexBuffer) { 1682fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa fLinesIndexBuffer = linesIndexBuffer; 1692fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa linesIndexBuffer->ref(); 170375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka fQuadsIndexBuffer = quadsIndexBuffer; 1714d146d5e3e00cab1cca7d0d29fe00c0d629b5eacTadashi G. Takaoka quadsIndexBuffer->ref(); 172bca7e4e9a2ed07d5d87f4dce9f793e40edb09691Tadashi G. Takaoka} 173dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka 174c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. TakaokaGrAAHairLinePathRenderer::~GrAAHairLinePathRenderer() { 1755f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka fLinesIndexBuffer->unref(); 1765f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka fQuadsIndexBuffer->unref(); 177dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka} 1785f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 1795f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokanamespace { 180cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka 1812fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa#define PREALLOC_PTARRAY(N) SkSTArray<(N),SkPoint, true> 1822fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa 1832fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa// Takes 178th time of logf on Z600 / VC2010 1842fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasaint get_float_exp(float x) { 1852fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa GR_STATIC_ASSERT(sizeof(int) == sizeof(float)); 1862fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa#ifdef SK_DEBUG 1872fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa static bool tested; 1882fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa if (!tested) { 1892fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa tested = true; 1902fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa SkASSERT(get_float_exp(0.25f) == -2); 1912fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa SkASSERT(get_float_exp(0.3f) == -2); 1922fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa SkASSERT(get_float_exp(0.5f) == -1); 1932fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa SkASSERT(get_float_exp(1.f) == 0); 1942fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa SkASSERT(get_float_exp(2.f) == 1); 1952fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa SkASSERT(get_float_exp(2.5f) == 1); 1962fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa SkASSERT(get_float_exp(8.f) == 3); 1972fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa SkASSERT(get_float_exp(100.f) == 6); 198921a32f0a923ca00c4818d3869f0abd9a63dcf0eTadashi G. Takaoka SkASSERT(get_float_exp(1000.f) == 9); 1992fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa SkASSERT(get_float_exp(1024.f) == 10); 20013ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka SkASSERT(get_float_exp(3000000.f) == 21); 20113ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka } 202a5ff9f0c77005769f92ca1131882bb4e3ca18980Tadashi G. Takaoka#endif 20313ae76d7a342581160c172cd21706b3d57d32dadTadashi G. Takaoka const int* iptr = (const int*)&x; 204b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka return (((*iptr) & 0x7f800000) >> 23) - 127; 205b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka} 206b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka 207921a32f0a923ca00c4818d3869f0abd9a63dcf0eTadashi G. Takaoka// Uses the max curvature function for quads to estimate 20822b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka// where to chop the conic. If the max curvature is not 209f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka// found along the curve segment it will return 1 and 210f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka// dst[0] is the original conic. If it returns 2 the dst[0] 211f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka// and dst[1] are the two new conics. 212f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaokaint split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) { 2132fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa SkScalar t = SkFindQuadMaxCurvature(src); 2142fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa if (t == 0) { 2152fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa if (dst) { 2162fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa dst[0].set(src, weight); 21741f9f1ef703ca4d63f1ef08b51d1365a17b4065aTadashi G. Takaoka } 21841f9f1ef703ca4d63f1ef08b51d1365a17b4065aTadashi G. Takaoka return 1; 21941f9f1ef703ca4d63f1ef08b51d1365a17b4065aTadashi G. Takaoka } else { 2202fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa if (dst) { 2212fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa SkConic conic; 222d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka conic.set(src, weight); 223c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka conic.chopAt(t, dst); 2244daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang } 225d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka return 2; 226c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka } 227d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka} 228c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka 229d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka// Calls split_conic on the entire conic and then once more on each subsection. 230c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka// Most cases will result in either 1 conic (chop point is not within t range) 231160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka// or 3 points (split once and then one subsection is split again). 232992c5219092ccafe66363451fbf4ca7c5a43fb20Tadashi G. Takaokaint chop_conic(const SkPoint src[3], SkConic dst[4], const SkScalar weight) { 233bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka SkConic dstTemp[2]; 234bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka int conicCnt = split_conic(src, dstTemp, weight); 235a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka if (2 == conicCnt) { 236d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka int conicCnt2 = split_conic(dstTemp[0].fPts, dst, dstTemp[0].fW); 237d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka conicCnt = conicCnt2 + split_conic(dstTemp[1].fPts, &dst[conicCnt2], dstTemp[1].fW); 238c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka } else { 239375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka dst[0] = dstTemp[0]; 240375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 241375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka return conicCnt; 242fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka} 243cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka 244cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka// returns 0 if quad/conic is degen or close to it 245cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka// in this case approx the path with lines 246fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka// otherwise returns 1 247cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaokaint is_degen_quad_or_conic(const SkPoint p[3]) { 248cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka static const SkScalar gDegenerateToLineTol = SK_Scalar1; 249cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka static const SkScalar gDegenerateToLineTolSqd = 250fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka SkScalarMul(gDegenerateToLineTol, gDegenerateToLineTol); 251cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka 252cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka if (p[0].distanceToSqd(p[1]) < gDegenerateToLineTolSqd || 253cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka p[1].distanceToSqd(p[2]) < gDegenerateToLineTolSqd) { 254d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka return 1; 255160f01211d169d64102205e80e9ac8d46c7d674bTadashi G. Takaoka } 256a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka 257a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka SkScalar dsqd = p[1].distanceToLineBetweenSqd(p[0], p[2]); 25831c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka if (dsqd < gDegenerateToLineTolSqd) { 25931c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka return 1; 26031c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka } 26131c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka 26231c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka if (p[2].distanceToLineBetweenSqd(p[1], p[0]) < gDegenerateToLineTolSqd) { 26331c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka return 1; 264f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka } 265f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka return 0; 266741831d32295acfb7675d7e0781a634d78868c63Satoshi Kataoka} 2672fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa 2682fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa// we subdivide the quads to avoid huge overfill 269bca7e4e9a2ed07d5d87f4dce9f793e40edb09691Tadashi G. Takaoka// if it returns -1 then should be drawn as lines 2704d146d5e3e00cab1cca7d0d29fe00c0d629b5eacTadashi G. Takaokaint num_quad_subdivs(const SkPoint p[3]) { 27131c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka static const SkScalar gDegenerateToLineTol = SK_Scalar1; 27231c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka static const SkScalar gDegenerateToLineTolSqd = 27352876bbefd774e8647910f73a2e4c17ac4e6bf5cKen Wakasa SkScalarMul(gDegenerateToLineTol, gDegenerateToLineTol); 27452876bbefd774e8647910f73a2e4c17ac4e6bf5cKen Wakasa 27552876bbefd774e8647910f73a2e4c17ac4e6bf5cKen Wakasa if (p[0].distanceToSqd(p[1]) < gDegenerateToLineTolSqd || 276cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka p[1].distanceToSqd(p[2]) < gDegenerateToLineTolSqd) { 27752876bbefd774e8647910f73a2e4c17ac4e6bf5cKen Wakasa return -1; 27852876bbefd774e8647910f73a2e4c17ac4e6bf5cKen Wakasa } 279dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka 28020dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka SkScalar dsqd = p[1].distanceToLineBetweenSqd(p[0], p[2]); 28157372fd3da2e879f190e4ccd41a00813774c9019Tadashi G. Takaoka if (dsqd < gDegenerateToLineTolSqd) { 28220dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return -1; 28320dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } 28431c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka 28531c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka if (p[2].distanceToLineBetweenSqd(p[1], p[0]) < gDegenerateToLineTolSqd) { 286d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka return -1; 28731c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka } 28873a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka 28931c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka // tolerance of triangle height in pixels 29031c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka // tuned on windows Quadro FX 380 / Z600 29173a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka // trade off of fill vs cpu time on verts 2922fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // maybe different when do this using gpu (geo or tess shaders) 2932fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa static const SkScalar gSubdivTol = 175 * SK_Scalar1; 2942fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa 2952fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa if (dsqd <= SkScalarMul(gSubdivTol, gSubdivTol)) { 2962fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa return 0; 2972fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } else { 2982fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa static const int kMaxSub = 4; 2992fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // subdividing the quad reduces d by 4. so we want x = log4(d/tol) 3002fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // = log4(d*d/tol*tol)/2 3012fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // = log2(d*d/tol*tol) 3022fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa 3032fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // +1 since we're ignoring the mantissa contribution. 3042fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa int log = get_float_exp(dsqd/(gSubdivTol*gSubdivTol)) + 1; 3052fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa log = GrMin(GrMax(0, log), kMaxSub); 3062fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa return log; 3072fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 3082fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa} 3092fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa 3102fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa/** 3112fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa * Generates the lines and quads to be rendered. Lines are always recorded in 3122fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa * device space. We will do a device space bloat to account for the 1pixel 3132fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa * thickness. 3142fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa * Quads are recorded in device space unless m contains 3152fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa * perspective, then in they are in src space. We do this because we will 3162fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa * subdivide large quads to reduce over-fill. This subdivision has to be 3172fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa * performed before applying the perspective matrix. 3182fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa */ 3192fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasaint generate_lines_and_quads(const SkPath& path, 3202fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa const SkMatrix& m, 32115f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka const SkIRect& devClipBounds, 32231c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka GrAAHairLinePathRenderer::PtArray* lines, 32331c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka GrAAHairLinePathRenderer::PtArray* quads, 324d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka GrAAHairLinePathRenderer::PtArray* conics, 325d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka GrAAHairLinePathRenderer::IntArray* quadSubdivCnts, 32615f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka GrAAHairLinePathRenderer::FloatArray* conicWeights) { 327dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka SkPath::Iter iter(path, false); 32831c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka 32931c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka int totalQuadCount = 0; 33031c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka SkRect bounds; 33131c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka SkIRect ibounds; 33215f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka 33331c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka bool persp = m.hasPerspective(); 33431c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka 33531c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka for (;;) { 33631c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka GrPoint pathPts[4]; 33715f6d4ae34664ea3d92827a2c3003198c0bac70bTadashi G. Takaoka GrPoint devPts[4]; 338dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka SkPath::Verb verb = iter.next(pathPts); 3395141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka switch (verb) { 3405141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka case SkPath::kConic_Verb: { 3415141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka SkConic dst[4]; 3425141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka // We chop the conics to create tighter clipping to hide error 34331c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka // that appears near max curvature of very thin conics. Thin 3445141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka // hyperbolas with high weight still show error. 3455141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka int conicCnt = chop_conic(pathPts, dst, iter.conicWeight()); 3465141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka for (int i = 0; i < conicCnt; ++i) { 3475141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka SkPoint* chopPnts = dst[i].fPts; 3485141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka m.mapPoints(devPts, chopPnts, 3); 3495141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka bounds.setBounds(devPts, 3); 3505141f04ef3b213fbe4816168d1c42f30449fc446Tadashi G. Takaoka bounds.outset(SK_Scalar1, SK_Scalar1); 3515f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka bounds.roundOut(&ibounds); 3525f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka if (SkIRect::Intersects(devClipBounds, ibounds)) { 353dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka if (is_degen_quad_or_conic(devPts)) { 3545f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka SkPoint* pts = lines->push_back_n(4); 3555c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka pts[0] = devPts[0]; 3565f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka pts[1] = devPts[1]; 3575f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka pts[2] = devPts[1]; 3582fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa pts[3] = devPts[2]; 3592fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } else { 3602fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // when in perspective keep conics in src space 3612fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa SkPoint* cPts = persp ? chopPnts : devPts; 3625f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka SkPoint* pts = conics->push_back_n(3); 3635f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka pts[0] = cPts[0]; 3642fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa pts[1] = cPts[1]; 3652fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa pts[2] = cPts[2]; 3662fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa conicWeights->push_back() = dst[i].fW; 3672fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 3680efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka } 3690efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka } 3705f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka break; 3715f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 3725f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka case SkPath::kMove_Verb: 3735f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka break; 3745f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka case SkPath::kLine_Verb: 3755f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka m.mapPoints(devPts, pathPts, 2); 3765f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka bounds.setBounds(devPts, 2); 3775f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka bounds.outset(SK_Scalar1, SK_Scalar1); 378dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka bounds.roundOut(&ibounds); 3795cbda70956af14453fca7395d892c59aabbd8fd3Jean Chalard if (SkIRect::Intersects(devClipBounds, ibounds)) { 3805cbda70956af14453fca7395d892c59aabbd8fd3Jean Chalard SkPoint* pts = lines->push_back_n(2); 3815f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka pts[0] = devPts[0]; 3825a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka pts[1] = devPts[1]; 38308ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka } 3848335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka break; 385a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka case SkPath::kQuad_Verb: { 3864112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka SkPoint choppedPts[5]; 387240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka // Chopping the quad helps when the quad is either degenerate or nearly degenerate. 3884112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka // When it is degenerate it allows the approximation with lines to work since the 3892fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // chop point (if there is one) will be at the parabola's vertex. In the nearly 3909c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa // degenerate the QuadUVMatrix computed for the points is almost singular which 39115c42454c0117d869f31ce278021f53ec74c4aa2Tadashi G. Takaoka // can cause rendering artifacts. 39215c42454c0117d869f31ce278021f53ec74c4aa2Tadashi G. Takaoka int n = SkChopQuadAtMaxCurvature(pathPts, choppedPts); 39348a7681e064ae259b840f0e757da2d716043d893Kurt Partridge for (int i = 0; i < n; ++i) { 394f147794fd41491a3383e6aca6d49007f58124068alanv SkPoint* quadPts = choppedPts + i * 2; 395bca7e4e9a2ed07d5d87f4dce9f793e40edb09691Tadashi G. Takaoka m.mapPoints(devPts, quadPts, 3); 3965f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka bounds.setBounds(devPts, 3); 3975f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka bounds.outset(SK_Scalar1, SK_Scalar1); 3980e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka bounds.roundOut(&ibounds); 3990e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 4000e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka if (SkIRect::Intersects(devClipBounds, ibounds)) { 4010e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka int subdiv = num_quad_subdivs(devPts); 4020e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka SkASSERT(subdiv >= -1); 4030e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka if (-1 == subdiv) { 4040e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka SkPoint* pts = lines->push_back_n(4); 4050e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka pts[0] = devPts[0]; 4067d09b5681202d3df9df1d5634071091f3f45fbe5Tadashi G. Takaoka pts[1] = devPts[1]; 4070e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka pts[2] = devPts[1]; 4080e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka pts[3] = devPts[2]; 409276b1a2ebc6d5ea3fa36fa9271cdc6310db34021Tadashi G. Takaoka } else { 410276b1a2ebc6d5ea3fa36fa9271cdc6310db34021Tadashi G. Takaoka // when in perspective keep quads in src space 411276b1a2ebc6d5ea3fa36fa9271cdc6310db34021Tadashi G. Takaoka SkPoint* qPts = persp ? quadPts : devPts; 412276b1a2ebc6d5ea3fa36fa9271cdc6310db34021Tadashi G. Takaoka SkPoint* pts = quads->push_back_n(3); 413276b1a2ebc6d5ea3fa36fa9271cdc6310db34021Tadashi G. Takaoka pts[0] = qPts[0]; 414276b1a2ebc6d5ea3fa36fa9271cdc6310db34021Tadashi G. Takaoka pts[1] = qPts[1]; 415375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka pts[2] = qPts[2]; 416375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka quadSubdivCnts->push_back() = subdiv; 4170c01fc6f1c01a2009546a2982818e68c08012ab3Tadashi G. Takaoka totalQuadCount += 1 << subdiv; 4180c01fc6f1c01a2009546a2982818e68c08012ab3Tadashi G. Takaoka } 4190c01fc6f1c01a2009546a2982818e68c08012ab3Tadashi G. Takaoka } 4200c01fc6f1c01a2009546a2982818e68c08012ab3Tadashi G. Takaoka } 421375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka break; 422375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } 423375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka case SkPath::kCubic_Verb: 424375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka m.mapPoints(devPts, pathPts, 4); 425375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka bounds.setBounds(devPts, 4); 426375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka bounds.outset(SK_Scalar1, SK_Scalar1); 427375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka bounds.roundOut(&ibounds); 428375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka if (SkIRect::Intersects(devClipBounds, ibounds)) { 429cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka PREALLOC_PTARRAY(32) q; 4300c01fc6f1c01a2009546a2982818e68c08012ab3Tadashi G. Takaoka // we don't need a direction if we aren't constraining the subdivision 431375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka static const SkPath::Direction kDummyDir = SkPath::kCCW_Direction; 4320c01fc6f1c01a2009546a2982818e68c08012ab3Tadashi G. Takaoka // We convert cubics to quadratics (for now). 433375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka // In perspective have to do conversion in src space. 434375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka if (persp) { 4350e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka SkScalar tolScale = 4360e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka GrPathUtils::scaleToleranceToSrc(SK_Scalar1, m, 4370e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka path.getBounds()); 4380e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka GrPathUtils::convertCubicToQuads(pathPts, tolScale, false, kDummyDir, &q); 4390e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } else { 4400e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka GrPathUtils::convertCubicToQuads(devPts, SK_Scalar1, false, kDummyDir, &q); 4417d09b5681202d3df9df1d5634071091f3f45fbe5Tadashi G. Takaoka } 4420e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka for (int i = 0; i < q.count(); i += 3) { 4430e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka SkPoint* qInDevSpace; 4442fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // bounds has to be calculated in device space, but q is 4452fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // in src space when there is perspective. 4462fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa if (persp) { 447bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka m.mapPoints(devPts, &q[i], 3); 448375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka bounds.setBounds(devPts, 3); 449375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka qInDevSpace = devPts; 450375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka } else { 4510e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka bounds.setBounds(&q[i], 3); 4522fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa qInDevSpace = &q[i]; 4530e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 4540e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka bounds.outset(SK_Scalar1, SK_Scalar1); 4550e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka bounds.roundOut(&ibounds); 4560e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka if (SkIRect::Intersects(devClipBounds, ibounds)) { 4570e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka int subdiv = num_quad_subdivs(qInDevSpace); 4580e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka SkASSERT(subdiv >= -1); 4590e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka if (-1 == subdiv) { 4602fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa SkPoint* pts = lines->push_back_n(4); 4612fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // lines should always be in device coords 4627d09b5681202d3df9df1d5634071091f3f45fbe5Tadashi G. Takaoka pts[0] = qInDevSpace[0]; 463992c5219092ccafe66363451fbf4ca7c5a43fb20Tadashi G. Takaoka pts[1] = qInDevSpace[1]; 4642fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa pts[2] = qInDevSpace[1]; 4652fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa pts[3] = qInDevSpace[2]; 4662fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } else { 467bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka SkPoint* pts = quads->push_back_n(3); 468bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka // q is already in src space when there is no 469bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka // perspective and dev coords otherwise. 4700e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka pts[0] = q[0 + i]; 471bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka pts[1] = q[1 + i]; 472bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka pts[2] = q[2 + i]; 473bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka quadSubdivCnts->push_back() = subdiv; 4742fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa totalQuadCount += 1 << subdiv; 4752fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 4762fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 4770e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } 4782fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 479bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka break; 4802fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa case SkPath::kClose_Verb: 4812fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa break; 4822fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa case SkPath::kDone_Verb: 4832fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa return totalQuadCount; 4842fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 4852fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 4862fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa} 4872fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa 4887d09b5681202d3df9df1d5634071091f3f45fbe5Tadashi G. Takaokastruct LineVertex { 4892fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa GrPoint fPos; 4902fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa GrColor fCoverage; 491bb476be4e62b3bed7848d37df42f8fa7363b58d1Tadashi G. Takaoka}; 4920e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 4930e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaokastruct BezierVertex { 494ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka GrPoint fPos; 495cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka union { 496ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka struct { 497ff961ddf8c58df569c97684bfd83a01b2a9470aaTadashi G. Takaoka SkScalar fK; 4980e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka SkScalar fL; 4990e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka SkScalar fM; 5000e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka } fConic; 501cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka GrVec fQuadCoord; 5020e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka struct { 5030e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka SkScalar fBogus[4]; 5040e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka }; 5050e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka }; 506cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka}; 5070e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. Takaoka 5080e4f0da449d0fc4f0c4c6b49b4c24961da36a5d1Tadashi G. TakaokaGR_STATIC_ASSERT(sizeof(BezierVertex) == 3 * sizeof(GrPoint)); 509724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa 510724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasavoid intersect_lines(const SkPoint& ptA, const SkVector& normA, 511cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka const SkPoint& ptB, const SkVector& normB, 512cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka SkPoint* result) { 513375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 514375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka SkScalar lineAW = -normA.dot(ptA); 5152fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa SkScalar lineBW = -normB.dot(ptB); 5162fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa 517375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka SkScalar wInv = SkScalarMul(normA.fX, normB.fY) - 518375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka SkScalarMul(normA.fY, normB.fX); 519cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka wInv = SkScalarInvert(wInv); 520375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 521375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka result->fX = SkScalarMul(normA.fY, lineBW) - SkScalarMul(lineAW, normB.fY); 522375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka result->fX = SkScalarMul(result->fX, wInv); 523375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 524375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka result->fY = SkScalarMul(lineAW, normB.fX) - SkScalarMul(normA.fX, lineBW); 525375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka result->fY = SkScalarMul(result->fY, wInv); 526375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka} 527fb523d7f5d40123a49a9128c455815db320c90fcTadashi G. Takaoka 528212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaokavoid set_uv_quad(const SkPoint qpts[3], BezierVertex verts[kVertsPerQuad]) { 529212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka // this should be in the src space, not dev coords, when we have perspective 530375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka GrPathUtils::QuadUVMatrix DevToUV(qpts); 531212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka DevToUV.apply<kVertsPerQuad, sizeof(BezierVertex), sizeof(GrPoint)>(verts); 532cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka} 533212165b0b8308802a461a6a526d367ba67b5567aTadashi G. Takaoka 534cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaokavoid bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice, 535375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka const SkMatrix* toSrc, BezierVertex verts[kVertsPerQuad], 536375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka SkRect* devBounds) { 5378335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka SkASSERT(!toDevice == !toSrc); 538c1e6100bdea95872cb66a64b7ee14ab0ae46476fTadashi G. Takaoka // original quad is specified by tri a,b,c 539dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka SkPoint a = qpts[0]; 5408335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka SkPoint b = qpts[1]; 5418335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka SkPoint c = qpts[2]; 5428335c59ea7715f3dbc6625f128a7a038f314a89fTadashi G. Takaoka 543724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa if (toDevice) { 544724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa toDevice->mapPoints(&a, 1); 545724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa toDevice->mapPoints(&b, 1); 546724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa toDevice->mapPoints(&c, 1); 547724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa } 548724db044957eb3544323c9814cbb4f20e81b8594Ken Wakasa // make a new poly where we replace a and c by a 1-pixel wide edges orthog 5490657b9698a110f8e895448d829478982ce37b6d1Tadashi G. Takaoka // to edges ab and bc: 5500657b9698a110f8e895448d829478982ce37b6d1Tadashi G. Takaoka // 5515f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // before | after 5524331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge // | b0 5534331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge // b | 5540c01fc6f1c01a2009546a2982818e68c08012ab3Tadashi G. Takaoka // | 5559c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa // | a0 c0 5569c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa // a c | a1 c1 5579c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa // 5589c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa // edges a0->b0 and b0->c0 are parallel to original edges a->b and b->c, 559c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka // respectively. 560c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka BezierVertex& a0 = verts[0]; 561c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka BezierVertex& a1 = verts[1]; 562c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka BezierVertex& b0 = verts[2]; 563c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka BezierVertex& c0 = verts[3]; 564c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka BezierVertex& c1 = verts[4]; 565c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka 566cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka SkVector ab = b; 5679c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa ab -= a; 5689c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa SkVector ac = c; 5699c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa ac -= a; 5709c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa SkVector cb = b; 571c3f78c9057a5710898feaf8027659484477e5821Tadashi G. Takaoka cb -= c; 5724331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge 5734331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge // We should have already handled degenerates 5744331012a9e7779ff7c8359a443dc5815ee6ea8d9Kurt Partridge SkASSERT(ab.length() > 0 && cb.length() > 0); 575a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka 5767dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka ab.normalize(); 5775f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka SkVector abN; 57820dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka abN.setOrthog(ab, SkVector::kLeft_Side); 579a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka if (abN.dot(ac) > 0) { 580a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka abN.negate(); 581a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka } 582a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka 583a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka cb.normalize(); 58420dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka SkVector cbN; 5855f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka cbN.setOrthog(cb, SkVector::kLeft_Side); 586a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka if (cbN.dot(ac) < 0) { 5872affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka cbN.negate(); 5882affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka } 5892affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka 590b8dc67466339dc14653ad634c86851025373326bTadashi G. Takaoka a0.fPos = a; 5912affaf91a04d63e0994102299816014a8bbe11e1Tadashi G. Takaoka a0.fPos += abN; 5925f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka a1.fPos = a; 5935f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka a1.fPos -= abN; 5942fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa 5955f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka c0.fPos = c; 596d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka c0.fPos += cbN; 5975f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka c1.fPos = c; 5985f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka c1.fPos -= cbN; 5992fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa 6002fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa intersect_lines(a0.fPos, abN, c0.fPos, cbN, &b0.fPos); 601a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka devBounds->growToInclude(&verts[0].fPos, sizeof(BezierVertex), kVertsPerQuad); 60296efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka 603a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka if (toSrc) { 604a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka toSrc->mapPointsWithStride(&verts[0].fPos, sizeof(BezierVertex), kVertsPerQuad); 605a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka } 60696efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka} 607a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka 6089c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa// Equations based off of Loop-Blinn Quadratic GPU Rendering 609c8e45ddb032554f4e9d4411d8ef47d98db62d77bTadashi G. Takaoka// Input Parametric: 6109bc29d78a6ce83f77869aa63748176241e29d43cKurt Partridge// 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) 611f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka// Output Implicit: 6129552badf3c24d2098d227b0ddca0721b928a10b1Tadashi G. Takaoka// f(x, y, w) = f(P) = K^2 - LM 6137dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka// K = dot(k, P), L = dot(l, P), M = dot(m, P) 6143708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka// k, l, m are calculated in function GrPathUtils::getConicKLM 615ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaokavoid set_conic_coeffs(const SkPoint p[3], BezierVertex verts[kVertsPerQuad], 6162282e8520a2c1984989a14fb09896536f5033b26Jean Chalard const SkScalar weight) { 6172282e8520a2c1984989a14fb09896536f5033b26Jean Chalard SkScalar klm[9]; 618f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka 61996efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka GrPathUtils::getConicKLM(p, weight, klm); 6203708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka 6217dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka for (int i = 0; i < kVertsPerQuad; ++i) { 622a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka const SkPoint pnt = verts[i].fPos; 6233708787fe91227083d2a1874fa41493d3bc9fe10Tadashi G. Takaoka verts[i].fConic.fK = pnt.fX * klm[0] + pnt.fY * klm[1] + klm[2]; 624f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka verts[i].fConic.fL = pnt.fX * klm[3] + pnt.fY * klm[4] + klm[5]; 6256dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka verts[i].fConic.fM = pnt.fX * klm[6] + pnt.fY * klm[7] + klm[8]; 626f87e8f7ec1efb93398d909c67468d716b0248fe7Tadashi G. Takaoka } 62796efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka} 6286dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka 6296dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaokavoid add_conics(const SkPoint p[3], 63096efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka const SkScalar weight, 6316dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka const SkMatrix* toDevice, 6326dde878d515f7bf5268d16a8fe4921d8821c5ae7Tadashi G. Takaoka const SkMatrix* toSrc, 63396efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka BezierVertex** vert, 634a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka SkRect* devBounds) { 6359d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka bloat_quad(p, toDevice, toSrc, *vert, devBounds); 63696efb1252a0bf84ac72ef3d438ea3b3d5ac8ddd7Tadashi G. Takaoka set_conic_coeffs(p, *vert, weight); 6375f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka *vert += kVertsPerQuad; 63863c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka} 639547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka 640547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaokavoid add_quads(const SkPoint p[3], 641a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka int subdiv, 6427ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka const SkMatrix* toDevice, 6437ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka const SkMatrix* toSrc, 6447ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka BezierVertex** vert, 6457ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka SkRect* devBounds) { 646547b638194c05f971003edb06c3c6c489a76da5fTadashi G. Takaoka SkASSERT(subdiv >= 0); 6477dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka if (subdiv) { 6487ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka SkPoint newP[5]; 6497ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka SkChopQuadAtHalf(p, newP); 6507ecc1081ab9b4e41e4b2aec7877aaaf8df29e611Tadashi G. Takaoka add_quads(newP + 0, subdiv-1, toDevice, toSrc, vert, devBounds); 65129d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka add_quads(newP + 2, subdiv-1, toDevice, toSrc, vert, devBounds); 65229d5973fd35438a83acf7f44b5d55d5620278ee3Tadashi G. Takaoka } else { 653992c5219092ccafe66363451fbf4ca7c5a43fb20Tadashi G. Takaoka bloat_quad(p, toDevice, toSrc, *vert, devBounds); 654fa2d543785c52f639ad3157c57420f58a199c550Tom Ouyang set_uv_quad(p, *vert); 65533482a9b9ccf605c63fab7c9b8273a240bbc2035Tadashi G. Takaoka *vert += kVertsPerQuad; 6562fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 6572fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa} 6585f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 6595f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaokavoid add_line(const SkPoint p[2], 6602fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa const SkMatrix* toSrc, 661a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka GrColor coverage, 66263c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka LineVertex** vert) { 6635f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka const SkPoint& a = p[0]; 6642fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa const SkPoint& b = p[1]; 6655f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 6665f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka SkVector ortho, vec = b; 667d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka vec -= a; 668d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka 6691b6eea89037158a1e271730eacdacb8b6e550d3aTadashi G. Takaoka if (vec.setLength(SK_ScalarHalf)) { 670cf915ddc878699909365dd599a0e154552e244e2Tadashi G. Takaoka // Create a vector orthogonal to 'vec' and of unit length 671d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka ortho.fX = 2.0f * vec.fY; 672a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka ortho.fY = -2.0f * vec.fX; 673d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka 674d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka (*vert)[0].fPos = a; 675d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka (*vert)[0].fCoverage = coverage; 676a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka (*vert)[1].fPos = b; 677d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka (*vert)[1].fCoverage = coverage; 678d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka (*vert)[2].fPos = a - vec + ortho; 679d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka (*vert)[2].fCoverage = 0; 6801f215a58c99f0eb2f536e9cccd51371f2883e201Tadashi G. Takaoka (*vert)[3].fPos = b + vec + ortho; 681d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka (*vert)[3].fCoverage = 0; 682d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka (*vert)[4].fPos = a - vec - ortho; 683d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka (*vert)[4].fCoverage = 0; 684d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka (*vert)[5].fPos = b + vec - ortho; 6851f215a58c99f0eb2f536e9cccd51371f2883e201Tadashi G. Takaoka (*vert)[5].fCoverage = 0; 686d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka 687d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka if (NULL != toSrc) { 6887f8345d59a82a9b1d458b8e55ffd12c2a0d466a7Tadashi G. Takaoka toSrc->mapPointsWithStride(&(*vert)->fPos, 689d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka sizeof(LineVertex), 690d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka kVertsPerLineSeg); 691d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka } 692d9449ccf3ce9e5eabb022aed6a45bba680bce115Tadashi G. Takaoka } else { 6935433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka // just make it degenerate and likely offscreen 6945433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka for (int i = 0; i < kVertsPerLineSeg; ++i) { 6955433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka (*vert)[i].fPos.set(SK_ScalarMax, SK_ScalarMax); 6965433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka } 6975433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka } 6985433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka 6995433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka *vert += kVertsPerLineSeg; 7005433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka} 7015433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka 7025433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka} 7035433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka 7045433ce64c0f141bc4ee82912844f47f575654af5Tadashi G. Takaoka/////////////////////////////////////////////////////////////////////////////// 7055f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 706dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaokanamespace { 70746286874f30c4a6ef44646c4e4adf36fe55c74b9Tadashi G. Takaoka 70846286874f30c4a6ef44646c4e4adf36fe55c74b9Tadashi G. Takaoka// position + edge 70946286874f30c4a6ef44646c4e4adf36fe55c74b9Tadashi G. Takaokaextern const GrVertexAttrib gHairlineBezierAttribs[] = { 710b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding}, 711b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka {kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding} 712b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka}; 7132fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa 714b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka// position + coverage 715b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaokaextern const GrVertexAttrib gHairlineLineAttribs[] = { 7162fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding}, 717b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kCoverage_GrVertexAttribBinding}, 718b6cc3a85ab68cff2fae4c3858b48d9c5d7b45690Tadashi G. Takaoka}; 719310ea9ab9058e922a562309cb0dc5d5e092000f1Tadashi G. Takaoka 720c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka}; 721c403a46f6d787b79768895272d53d296100677ddTadashi G. Takaoka 722dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaokabool GrAAHairLinePathRenderer::createLineGeom(const SkPath& path, 72330977a151e15e30f5385a349e92fb770b987435fTadashi G. Takaoka GrDrawTarget* target, 72430977a151e15e30f5385a349e92fb770b987435fTadashi G. Takaoka const PtArray& lines, 725d05afa3f4c59641c8fabed034e457cb25f0c57f0Kurt Partridge int lineCnt, 726fca71cfddb7a5062e7a4fb512e1faab401c65cd3Tadashi G. Takaoka GrDrawTarget::AutoReleaseGeometry* arg, 7279c3860ce461c3791891bf667edc77fe798c8d332Ken Wakasa SkRect* devBounds) { 72854dd1bed528331208f15df2693bcd01004dd471aTadashi G. Takaoka GrDrawState* drawState = target->drawState(); 72915d4793911fa305e0a58aced925961e948582979satok 7305f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka const SkMatrix& viewM = drawState->getViewMatrix(); 731e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka 732e08c418ff8b374244677960903cee8dd52a4d831Tadashi G. Takaoka int vertCnt = kVertsPerLineSeg * lineCnt; 7332fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa 7342fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa drawState->setVertexAttribs<gHairlineLineAttribs>(SK_ARRAY_COUNT(gHairlineLineAttribs)); 7352fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa SkASSERT(sizeof(LineVertex) == drawState->getVertexSize()); 7362fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa 7372fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa if (!arg->set(target, vertCnt, 0)) { 7382fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa return false; 7392fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa } 7402fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa 7415f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka LineVertex* verts = reinterpret_cast<LineVertex*>(arg->vertices()); 7425f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka 7435f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka const SkMatrix* toSrc = NULL; 7445c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka SkMatrix ivm; 745375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka 746375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka if (viewM.hasPerspective()) { 7475c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka if (viewM.invert(&ivm)) { 7485c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka toSrc = &ivm; 7495c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka } 7505c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka } 7515c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka devBounds->set(lines.begin(), lines.count()); 752375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka for (int i = 0; i < lineCnt; ++i) { 753375982106bf073971fccd14b2c65ec8e089bb2aeTadashi G. Takaoka add_line(&lines[2*i], toSrc, drawState->getCoverageColor(), &verts); 7545f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka } 7555c095e59f679f726df1b6655fbbd73e310ac0decTadashi G. Takaoka // All the verts computed by add_line are within sqrt(1^2 + 0.5^2) of the end points. 756a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka static const SkScalar kSqrtOfOneAndAQuarter = 1.118f; 7575f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka // Add a little extra to account for vector normalization precision. 7585f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka static const SkScalar kOutset = kSqrtOfOneAndAQuarter + SK_Scalar1 / 20; 759bca7e4e9a2ed07d5d87f4dce9f793e40edb09691Tadashi G. Takaoka devBounds->outset(kOutset, kOutset); 7601ead609e6fd64fd5ac2979ac3802d8bada7d7f49Tadashi G. Takaoka 7611ead609e6fd64fd5ac2979ac3802d8bada7d7f49Tadashi G. Takaoka return true; 7621ead609e6fd64fd5ac2979ac3802d8bada7d7f49Tadashi G. Takaoka} 763bca7e4e9a2ed07d5d87f4dce9f793e40edb09691Tadashi G. Takaoka 764bca7e4e9a2ed07d5d87f4dce9f793e40edb09691Tadashi G. Takaokabool GrAAHairLinePathRenderer::createBezierGeom( 765586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette const SkPath& path, 7669647d7fbee4cbd72876e949e6544dc43fadbd148Tadashi G. Takaoka GrDrawTarget* target, 767586a15c3f0d44590a5162e0ab4c3c52511f13f26Alan Viverette const PtArray& quads, 768c6435f92a80c6664870f9d1a4bb2a1c5153ef2c3Tadashi G. Takaoka int quadCnt, 7699647d7fbee4cbd72876e949e6544dc43fadbd148Tadashi G. Takaoka const PtArray& conics, 7709647d7fbee4cbd72876e949e6544dc43fadbd148Tadashi G. Takaoka int conicCnt, 7719647d7fbee4cbd72876e949e6544dc43fadbd148Tadashi G. Takaoka const IntArray& qSubdivs, 7725f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka const FloatArray& cWeights, 7739647d7fbee4cbd72876e949e6544dc43fadbd148Tadashi G. Takaoka GrDrawTarget::AutoReleaseGeometry* arg, 7745f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka SkRect* devBounds) { 77522b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka GrDrawState* drawState = target->drawState(); 776dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka 7777bd714c086a78e2058543b0971ac92f5a30b2362Tadashi G. Takaoka const SkMatrix& viewM = drawState->getViewMatrix(); 77820dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka 77920dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka int vertCnt = kVertsPerQuad * quadCnt + kVertsPerQuad * conicCnt; 78020dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka 781240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka target->drawState()->setVertexAttribs<gHairlineBezierAttribs>(SK_ARRAY_COUNT(gHairlineBezierAttribs)); 78220dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka SkASSERT(sizeof(BezierVertex) == target->getDrawState().getVertexSize()); 78320dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka 78420dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka if (!arg->set(target, vertCnt, 0)) { 7857bd714c086a78e2058543b0971ac92f5a30b2362Tadashi G. Takaoka return false; 7867bd714c086a78e2058543b0971ac92f5a30b2362Tadashi G. Takaoka } 7875afc3ae2d9df0c2c93f2c66af13b128889ac3b5dTadashi G. Takaoka 7885afc3ae2d9df0c2c93f2c66af13b128889ac3b5dTadashi G. Takaoka BezierVertex* verts = reinterpret_cast<BezierVertex*>(arg->vertices()); 789dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka 7907dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka const SkMatrix* toDevice = NULL; 7917dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka const SkMatrix* toSrc = NULL; 7927dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka SkMatrix ivm; 793fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka 794fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka if (viewM.hasPerspective()) { 795d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka if (viewM.invert(&ivm)) { 7967dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka toDevice = &viewM; 7974c0c638a189c1073b1fb6e43fe5fddb6f9932038Tadashi G. Takaoka toSrc = &ivm; 7987dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka } 7997dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka } 8004daf32b6c0358f0273a99b622a259ecdf6b44fa4Tom Ouyang 80131c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka // Seed the dev bounds with some pts known to be inside. Each quad and conic grows the bounding 80231c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka // box to include its vertices. 80331c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka SkPoint seedPts[2]; 804d7c4ba170982ddce5ac12ea92c3c3d8b53d524baTadashi G. Takaoka if (quadCnt) { 805dabf96896ef4c304c6dad36b307a2a458a58209dTadashi G. Takaoka seedPts[0] = quads[0]; 80631c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka seedPts[1] = quads[2]; 80731c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka } else if (conicCnt) { 80831c94cea82f1788e3a04f2a1e012945f35497f0aTadashi G. Takaoka seedPts[0] = conics[0]; 809dabf96896ef4c304c6dad36b307a2a458a58209dTadashi G. Takaoka seedPts[1] = conics[2]; 8104c0c638a189c1073b1fb6e43fe5fddb6f9932038Tadashi G. Takaoka } 8114112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka if (NULL != toDevice) { 8124112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka toDevice->mapPoints(seedPts, 2); 8134112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka } 814a729377395967f7652d93992cbcf50cd2ff522d1Tadashi G. Takaoka devBounds->set(seedPts[0], seedPts[1]); 815f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka 816f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka int unsubdivQuadCnt = quads.count() / 3; 817f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka for (int i = 0; i < unsubdivQuadCnt; ++i) { 818f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka SkASSERT(qSubdivs[i] >= 0); 819f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts, devBounds); 820f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka } 821f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka 822f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka // Start Conics 823f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka for (int i = 0; i < conicCnt; ++i) { 824f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka add_conics(&conics[3*i], cWeights[i], toDevice, toSrc, &verts, devBounds); 825f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka } 826f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka return true; 827f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka} 82808ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka 829f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaokabool GrAAHairLinePathRenderer::canDrawPath(const SkPath& path, 830f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka const SkStrokeRec& stroke, 831f3c4cd45a5df6f90b922ea44db259e53117bb25aTadashi G. Takaoka const GrDrawTarget* target, 83222b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka bool antiAlias) const { 833dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka if (!antiAlias) { 834dc34da218a22489d92d1015e9e5dac8d951b89f4Tadashi G. Takaoka return false; 8356bc9186457219daeb3734531a01271b0e4fa37fbTadashi G. Takaoka } 83673a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka 83773a46bfeb7a109b49be196e5d679e44c9e66a2e8Tadashi G. Takaoka if (!IsStrokeHairlineOrEquivalent(stroke, 83841808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka target->getDrawState().getViewMatrix(), 8397dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka NULL)) { 8407dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka return false; 84141808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka } 84241808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka 84341808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka if (SkPath::kLine_SegmentMask == path.getSegmentMasks() || 84441808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka target->caps()->shaderDerivativeSupport()) { 8454112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka return true; 846fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaoka } 847bd93eddb52816acedd5242864e467781d4adfd71Tadashi G. Takaoka return false; 8484112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka} 8497dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka 850fd60b2f97035382b14dce207b3613711982a613eTadashi G. Takaokatemplate <class VertexType> 85122b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaokabool check_bounds(GrDrawState* drawState, const SkRect& devBounds, void* vertices, int vCount) 85222b48de11ce6f31a0edf90e1308073e67a7a2adbTadashi G. Takaoka{ 8534112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka SkRect tolDevBounds = devBounds; 854741831d32295acfb7675d7e0781a634d78868c63Satoshi Kataoka // The bounds ought to be tight, but in perspective the below code runs the verts 855741831d32295acfb7675d7e0781a634d78868c63Satoshi Kataoka // through the view matrix to get back to dev coords, which can introduce imprecision. 856bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka if (drawState->getViewMatrix().hasPerspective()) { 8572fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa tolDevBounds.outset(SK_Scalar1 / 1000, SK_Scalar1 / 1000); 85820dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka } else { 85920dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka // Non-persp matrices cause this path renderer to draw in device space. 86020dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka SkASSERT(drawState->getViewMatrix().isIdentity()); 861bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka } 862741831d32295acfb7675d7e0781a634d78868c63Satoshi Kataoka SkRect actualBounds; 86320dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka 86420dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka VertexType* verts = reinterpret_cast<VertexType*>(vertices); 86520dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka bool first = true; 866bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka for (int i = 0; i < vCount; ++i) { 867bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka SkPoint pos = verts[i].fPos; 8682fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa // This is a hack to workaround the fact that we move some degenerate segments offscreen. 869bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka if (SK_ScalarMax == pos.fX) { 870bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka continue; 871bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka } 872741831d32295acfb7675d7e0781a634d78868c63Satoshi Kataoka drawState->getViewMatrix().mapPoints(&pos, 1); 87308ae0d5ca03ed455827e82222df249d1cafb5d71Tadashi G. Takaoka if (first) { 874bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka actualBounds.set(pos.fX, pos.fY, pos.fX, pos.fY); 8757dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka first = false; 8767dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka } else { 8777dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka actualBounds.growToInclude(pos.fX, pos.fY); 8787dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka } 8797dd32dfc065c13e946c0d42a0e000f4ce7298ed7Tadashi G. Takaoka } 880bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka if (!first) { 881bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaoka return tolDevBounds.contains(actualBounds); 8829364d46ac3590d23b8117a66efc8756454cef772Tadashi G. Takaoka } 88320dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka 88420dd1bc090abdd3e88855fe54b1865949aa1168dTadashi G. Takaoka return true; 8854112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka} 8864112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka 887bd2ca9c0214ea80fa860f4a9d118f866e16b03caTadashi G. Takaokabool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path, 8884112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka const SkStrokeRec& stroke, 8894112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka GrDrawTarget* target, 89041808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka bool antiAlias) { 8917dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka GrDrawState* drawState = target->drawState(); 8927dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka 89341808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka SkScalar hairlineCoverage; 89441808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka if (IsStrokeHairlineOrEquivalent(stroke, 89541808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka target->getDrawState().getViewMatrix(), 89641808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka &hairlineCoverage)) { 89741808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka uint8_t newCoverage = SkScalarRoundToInt(hairlineCoverage * 89841808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka target->getDrawState().getCoverage()); 89941808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka target->drawState()->setCoverage(newCoverage); 90041808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka } 90141808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka 90241808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka SkIRect devClipBounds; 90341808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka target->getClip()->getConservativeBounds(drawState->getRenderTarget(), &devClipBounds); 90441808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka 90541808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka int lineCnt; 90641f9f1ef703ca4d63f1ef08b51d1365a17b4065aTadashi G. Takaoka int quadCnt; 9074112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka int conicCnt; 90841808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka PREALLOC_PTARRAY(128) lines; 90941808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka PREALLOC_PTARRAY(128) quads; 91041808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka PREALLOC_PTARRAY(128) conics; 91141808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka IntArray qSubdivs; 91241808192d3a64d3e823e13ace27e3ce80b1c5bdaTadashi G. Takaoka FloatArray cWeights; 9134112dc05002d7a880e558418639cf25c4bd02a5aTadashi G. Takaoka quadCnt = generate_lines_and_quads(path, drawState->getViewMatrix(), devClipBounds, 914c8814e20b7b0ed5f7e11292480e89152618dd862Ken Wakasa &lines, &quads, &conics, &qSubdivs, &cWeights); 915e68d565d0f9704145adbf781105f1ac9a90f0a98Ken Wakasa lineCnt = lines.count() / 2; 916c8814e20b7b0ed5f7e11292480e89152618dd862Ken Wakasa conicCnt = conics.count() / 3; 917e68d565d0f9704145adbf781105f1ac9a90f0a98Ken Wakasa 918afca1ddd233c03d79433931a0b6ba97ed22663edTadashi G. Takaoka // do lines first 919c8814e20b7b0ed5f7e11292480e89152618dd862Ken Wakasa if (lineCnt) { 9205f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka GrDrawTarget::AutoReleaseGeometry arg; 921 SkRect devBounds; 922 923 if (!this->createLineGeom(path, 924 target, 925 lines, 926 lineCnt, 927 &arg, 928 &devBounds)) { 929 return false; 930 } 931 932 GrDrawTarget::AutoStateRestore asr; 933 934 // createLineGeom transforms the geometry to device space when the matrix does not have 935 // perspective. 936 if (target->getDrawState().getViewMatrix().hasPerspective()) { 937 asr.set(target, GrDrawTarget::kPreserve_ASRInit); 938 } else if (!asr.setIdentity(target, GrDrawTarget::kPreserve_ASRInit)) { 939 return false; 940 } 941 GrDrawState* drawState = target->drawState(); 942 943 // Check devBounds 944 SkASSERT(check_bounds<LineVertex>(drawState, devBounds, arg.vertices(), 945 kVertsPerLineSeg * lineCnt)); 946 947 { 948 GrDrawState::AutoRestoreEffects are(drawState); 949 target->setIndexSourceToBuffer(fLinesIndexBuffer); 950 int lines = 0; 951 while (lines < lineCnt) { 952 int n = GrMin(lineCnt - lines, kNumLineSegsInIdxBuffer); 953 target->drawIndexed(kTriangles_GrPrimitiveType, 954 kVertsPerLineSeg*lines, // startV 955 0, // startI 956 kVertsPerLineSeg*n, // vCount 957 kIdxsPerLineSeg*n, // iCount 958 &devBounds); 959 lines += n; 960 } 961 } 962 } 963 964 // then quadratics/conics 965 if (quadCnt || conicCnt) { 966 GrDrawTarget::AutoReleaseGeometry arg; 967 SkRect devBounds; 968 969 if (!this->createBezierGeom(path, 970 target, 971 quads, 972 quadCnt, 973 conics, 974 conicCnt, 975 qSubdivs, 976 cWeights, 977 &arg, 978 &devBounds)) { 979 return false; 980 } 981 982 GrDrawTarget::AutoStateRestore asr; 983 984 // createGeom transforms the geometry to device space when the matrix does not have 985 // perspective. 986 if (target->getDrawState().getViewMatrix().hasPerspective()) { 987 asr.set(target, GrDrawTarget::kPreserve_ASRInit); 988 } else if (!asr.setIdentity(target, GrDrawTarget::kPreserve_ASRInit)) { 989 return false; 990 } 991 GrDrawState* drawState = target->drawState(); 992 993 static const int kEdgeAttrIndex = 1; 994 995 // Check devBounds 996 SkASSERT(check_bounds<BezierVertex>(drawState, devBounds, arg.vertices(), 997 kVertsPerQuad * quadCnt + kVertsPerQuad * conicCnt)); 998 999 if (quadCnt > 0) { 1000 GrEffectRef* hairQuadEffect = GrQuadEffect::Create(kHairAA_GrBezierEdgeType, 1001 *target->caps()); 1002 SkASSERT(NULL != hairQuadEffect); 1003 GrDrawState::AutoRestoreEffects are(drawState); 1004 target->setIndexSourceToBuffer(fQuadsIndexBuffer); 1005 drawState->addCoverageEffect(hairQuadEffect, kEdgeAttrIndex)->unref(); 1006 int quads = 0; 1007 while (quads < quadCnt) { 1008 int n = GrMin(quadCnt - quads, kNumQuadsInIdxBuffer); 1009 target->drawIndexed(kTriangles_GrPrimitiveType, 1010 kVertsPerQuad*quads, // startV 1011 0, // startI 1012 kVertsPerQuad*n, // vCount 1013 kIdxsPerQuad*n, // iCount 1014 &devBounds); 1015 quads += n; 1016 } 1017 } 1018 1019 if (conicCnt > 0) { 1020 GrDrawState::AutoRestoreEffects are(drawState); 1021 GrEffectRef* hairConicEffect = GrConicEffect::Create(kHairAA_GrBezierEdgeType, 1022 *target->caps()); 1023 SkASSERT(NULL != hairConicEffect); 1024 drawState->addCoverageEffect(hairConicEffect, 1, 2)->unref(); 1025 int conics = 0; 1026 while (conics < conicCnt) { 1027 int n = GrMin(conicCnt - conics, kNumQuadsInIdxBuffer); 1028 target->drawIndexed(kTriangles_GrPrimitiveType, 1029 kVertsPerQuad*(quadCnt + conics), // startV 1030 0, // startI 1031 kVertsPerQuad*n, // vCount 1032 kIdxsPerQuad*n, // iCount 1033 &devBounds); 1034 conics += n; 1035 } 1036 } 1037 } 1038 1039 target->resetIndexSource(); 1040 1041 return true; 1042} 1043