GrDashingEffect.cpp revision 9853ccef19c200be93a6211f32589fa82a53067c
18d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi/* 28d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * Copyright 2014 Google Inc. 38d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * 48d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * Use of this source code is governed by a BSD-style license that can be 58d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * found in the LICENSE file. 68d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi */ 78d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 88d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi#include "GrDashingEffect.h" 98d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi#include "../GrAARectRenderer.h" 118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi#include "GrGeometryProcessor.h" 138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi#include "GrContext.h" 148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi#include "GrCoordTransform.h" 158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi#include "GrDefaultGeoProcFactory.h" 168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi#include "GrDrawTarget.h" 178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi#include "GrDrawTargetCaps.h" 188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi#include "GrInvariantOutput.h" 198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi#include "GrProcessor.h" 208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi#include "GrStrokeInfo.h" 218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi#include "GrTBackendProcessorFactory.h" 228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi#include "SkGr.h" 238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi#include "gl/GrGLGeometryProcessor.h" 248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi#include "gl/GrGLProcessor.h" 258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi#include "gl/GrGLSL.h" 268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi#include "gl/builders/GrGLProgramBuilder.h" 278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi/////////////////////////////////////////////////////////////////////////////// 298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi// Returns whether or not the gpu can fast path the dash line effect. 318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoistatic bool can_fast_path_dash(const SkPoint pts[2], const GrStrokeInfo& strokeInfo, 328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi const GrDrawTarget& target, const GrDrawState& ds, 338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi const SkMatrix& viewMatrix) { 348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi if (ds.getRenderTarget()->isMultisampled()) { 358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi return false; 368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } 378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi // Pts must be either horizontal or vertical in src space 398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi if (pts[0].fX != pts[1].fX && pts[0].fY != pts[1].fY) { 408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi return false; 418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } 428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi // May be able to relax this to include skew. As of now cannot do perspective 448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi // because of the non uniform scaling of bloating a rect 458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi if (!viewMatrix.preservesRightAngles()) { 468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi return false; 478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } 488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi if (!strokeInfo.isDashed() || 2 != strokeInfo.dashCount()) { 508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi return false; 518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } 528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi const SkPathEffect::DashInfo& info = strokeInfo.getDashInfo(); 548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi if (0 == info.fIntervals[0] && 0 == info.fIntervals[1]) { 558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi return false; 568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } 578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkPaint::Cap cap = strokeInfo.getStrokeRec().getCap(); 598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi // Current we do don't handle Round or Square cap dashes 608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi if (SkPaint::kRound_Cap == cap && info.fIntervals[0] != 0.f) { 618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi return false; 628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } 638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi return true; 658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi} 668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoinamespace { 688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoistruct DashLineVertex { 708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkPoint fPos; 718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkPoint fDashPos; 728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi}; 738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiextern const GrVertexAttrib gDashLineVertexAttribs[] = { 758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding }, 768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi { kVec2f_GrVertexAttribType, sizeof(SkPoint), kGeometryProcessor_GrVertexAttribBinding }, 778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi}; 788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi}; 808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoistatic void calc_dash_scaling(SkScalar* parallelScale, SkScalar* perpScale, 818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi const SkMatrix& viewMatrix, const SkPoint pts[2]) { 828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkVector vecSrc = pts[1] - pts[0]; 838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkScalar magSrc = vecSrc.length(); 848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkScalar invSrc = magSrc ? SkScalarInvert(magSrc) : 0; 858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi vecSrc.scale(invSrc); 868d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 878d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkVector vecSrcPerp; 888d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi vecSrc.rotateCW(&vecSrcPerp); 898d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi viewMatrix.mapVectors(&vecSrc, 1); 908d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi viewMatrix.mapVectors(&vecSrcPerp, 1); 918d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 928d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi // parallelScale tells how much to scale along the line parallel to the dash line 938d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi // perpScale tells how much to scale in the direction perpendicular to the dash line 948d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi *parallelScale = vecSrc.length(); 958d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi *perpScale = vecSrcPerp.length(); 968d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi} 978d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 988d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi// calculates the rotation needed to aligned pts to the x axis with pts[0] < pts[1] 99cef7893435aa41160dd1255c43cb8498279738ccChris Craik// Stores the rotation matrix in rotMatrix, and the mapped points in ptsRot 100cef7893435aa41160dd1255c43cb8498279738ccChris Craikstatic void align_to_x_axis(const SkPoint pts[2], SkMatrix* rotMatrix, SkPoint ptsRot[2] = NULL) { 101cef7893435aa41160dd1255c43cb8498279738ccChris Craik SkVector vec = pts[1] - pts[0]; 1028d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkScalar mag = vec.length(); 1038d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkScalar inv = mag ? SkScalarInvert(mag) : 0; 1048d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 1058d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi vec.scale(inv); 1068d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi rotMatrix->setSinCos(-vec.fY, vec.fX, pts[0].fX, pts[0].fY); 1078d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi if (ptsRot) { 1088d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi rotMatrix->mapPoints(ptsRot, pts, 2); 1098d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi // correction for numerical issues if map doesn't make ptsRot exactly horizontal 1108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi ptsRot[1].fY = pts[0].fY; 1118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } 1128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi} 1138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 1148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi// Assumes phase < sum of all intervals 1158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoistatic SkScalar calc_start_adjustment(const SkPathEffect::DashInfo& info) { 1168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkASSERT(info.fPhase < info.fIntervals[0] + info.fIntervals[1]); 1178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi if (info.fPhase >= info.fIntervals[0] && info.fPhase != 0) { 1188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkScalar srcIntervalLen = info.fIntervals[0] + info.fIntervals[1]; 1198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi return srcIntervalLen - info.fPhase; 1208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } 1218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi return 0; 1228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi} 1238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 1248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoistatic SkScalar calc_end_adjustment(const SkPathEffect::DashInfo& info, const SkPoint pts[2], 1258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkScalar phase, SkScalar* endingInt) { 1268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi if (pts[1].fX <= pts[0].fX) { 1278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi return 0; 1288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } 1298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkScalar srcIntervalLen = info.fIntervals[0] + info.fIntervals[1]; 1308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkScalar totalLen = pts[1].fX - pts[0].fX; 1318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkScalar temp = SkScalarDiv(totalLen, srcIntervalLen); 1328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkScalar numFullIntervals = SkScalarFloorToScalar(temp); 1338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi *endingInt = totalLen - numFullIntervals * srcIntervalLen + phase; 1348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi temp = SkScalarDiv(*endingInt, srcIntervalLen); 1358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi *endingInt = *endingInt - SkScalarFloorToScalar(temp) * srcIntervalLen; 1368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi if (0 == *endingInt) { 1378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi *endingInt = srcIntervalLen; 1388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } 1398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi if (*endingInt > info.fIntervals[0]) { 1408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi if (0 == info.fIntervals[0]) { 1418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi *endingInt -= 0.01f; // make sure we capture the last zero size pnt (used if has caps) 1428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } 1438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi return *endingInt - info.fIntervals[0]; 1448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } 1458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi return 0; 1468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi} 1478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 1488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoistatic void setup_dashed_rect(const SkRect& rect, DashLineVertex* verts, int idx, const SkMatrix& matrix, 1498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkScalar offset, SkScalar bloat, SkScalar len, SkScalar stroke) { 1508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkScalar startDashX = offset - bloat; 1518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkScalar endDashX = offset + len + bloat; 1528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkScalar startDashY = -stroke - bloat; 1538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkScalar endDashY = stroke + bloat; 1548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi verts[idx].fDashPos = SkPoint::Make(startDashX , startDashY); 1558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi verts[idx + 1].fDashPos = SkPoint::Make(startDashX, endDashY); 1568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi verts[idx + 2].fDashPos = SkPoint::Make(endDashX, endDashY); 1578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi verts[idx + 3].fDashPos = SkPoint::Make(endDashX, startDashY); 1588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi verts[idx].fPos = SkPoint::Make(rect.fLeft, rect.fTop); 1598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi verts[idx + 1].fPos = SkPoint::Make(rect.fLeft, rect.fBottom); 1608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi verts[idx + 2].fPos = SkPoint::Make(rect.fRight, rect.fBottom); 1618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi verts[idx + 3].fPos = SkPoint::Make(rect.fRight, rect.fTop); 1628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi matrix.mapPointsWithStride(&verts[idx].fPos, sizeof(DashLineVertex), 4); 1638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi} 1648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 1658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoistatic void setup_dashed_rect_pos(const SkRect& rect, int idx, const SkMatrix& matrix, 1668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkPoint* verts) { 1678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi verts[idx] = SkPoint::Make(rect.fLeft, rect.fTop); 1688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi verts[idx + 1] = SkPoint::Make(rect.fLeft, rect.fBottom); 1698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi verts[idx + 2] = SkPoint::Make(rect.fRight, rect.fBottom); 1708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi verts[idx + 3] = SkPoint::Make(rect.fRight, rect.fTop); 1718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi matrix.mapPoints(&verts[idx], 4); 1728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi} 1738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 1748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoibool GrDashingEffect::DrawDashLine(GrGpu* gpu, GrDrawTarget* target, GrDrawState* drawState, 1758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi const SkPoint pts[2], const GrPaint& paint, 1768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi const GrStrokeInfo& strokeInfo, const SkMatrix& vm) { 1778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 1788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi if (!can_fast_path_dash(pts, strokeInfo, *target, *drawState, vm)) { 1798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi return false; 1808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } 1818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 1828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi const SkPathEffect::DashInfo& info = strokeInfo.getDashInfo(); 1838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 1848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkPaint::Cap cap = strokeInfo.getStrokeRec().getCap(); 1858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 1868d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkScalar srcStrokeWidth = strokeInfo.getStrokeRec().getWidth(); 1878d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 1888d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi // the phase should be normalized to be [0, sum of all intervals) 1898d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkASSERT(info.fPhase >= 0 && info.fPhase < info.fIntervals[0] + info.fIntervals[1]); 1908d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 1918d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkScalar srcPhase = info.fPhase; 1928d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 1938d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi // Rotate the src pts so they are aligned horizontally with pts[0].fX < pts[1].fX 1948d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkMatrix srcRotInv; 1958d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkPoint ptsRot[2]; 1968d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi if (pts[0].fY != pts[1].fY || pts[0].fX > pts[1].fX) { 1978d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkMatrix rotMatrix; 1988d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi align_to_x_axis(pts, &rotMatrix, ptsRot); 1998d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi if(!rotMatrix.invert(&srcRotInv)) { 2008d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkDebugf("Failed to create invertible rotation matrix!\n"); 2018d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi return false; 2028d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } 2038d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } else { 2048d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi srcRotInv.reset(); 2058d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi memcpy(ptsRot, pts, 2 * sizeof(SkPoint)); 2068d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } 2078d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 2088d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi bool useAA = paint.isAntiAlias(); 2098d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 2108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi // Scale corrections of intervals and stroke from view matrix 2118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkScalar parallelScale; 2128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkScalar perpScale; 2138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi calc_dash_scaling(¶llelScale, &perpScale, vm, ptsRot); 2148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 2158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi bool hasCap = SkPaint::kButt_Cap != cap && 0 != srcStrokeWidth; 2168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 2178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi // We always want to at least stroke out half a pixel on each side in device space 2188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi // so 0.5f / perpScale gives us this min in src space 2198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkScalar halfSrcStroke = SkMaxScalar(srcStrokeWidth * 0.5f, 0.5f / perpScale); 2208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 2218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkScalar strokeAdj; 2228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi if (!hasCap) { 2238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi strokeAdj = 0.f; 2248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } else { 2258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi strokeAdj = halfSrcStroke; 2268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } 2278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 2288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkScalar startAdj = 0; 2298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 2308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkMatrix combinedMatrix = srcRotInv; 2318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi combinedMatrix.postConcat(vm); 2328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 2338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi bool lineDone = false; 2348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkRect startRect; 2358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi bool hasStartRect = false; 2368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi // If we are using AA, check to see if we are drawing a partial dash at the start. If so 2378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi // draw it separately here and adjust our start point accordingly 2388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi if (useAA) { 2398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi if (srcPhase > 0 && srcPhase < info.fIntervals[0]) { 2408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkPoint startPts[2]; 2418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi startPts[0] = ptsRot[0]; 2428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi startPts[1].fY = startPts[0].fY; 2438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi startPts[1].fX = SkMinScalar(startPts[0].fX + info.fIntervals[0] - srcPhase, 2448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi ptsRot[1].fX); 2458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi startRect.set(startPts, 2); 2468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi startRect.outset(strokeAdj, halfSrcStroke); 2478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 2488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi hasStartRect = true; 2498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi startAdj = info.fIntervals[0] + info.fIntervals[1] - srcPhase; 2508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } 2518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } 2528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 2538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi // adjustments for start and end of bounding rect so we only draw dash intervals 2548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi // contained in the original line segment. 2558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi startAdj += calc_start_adjustment(info); 2568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi if (startAdj != 0) { 2578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi ptsRot[0].fX += startAdj; 2588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi srcPhase = 0; 2598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } 2608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkScalar endingInterval = 0; 2618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkScalar endAdj = calc_end_adjustment(info, ptsRot, srcPhase, &endingInterval); 2628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi ptsRot[1].fX -= endAdj; 2638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi if (ptsRot[0].fX >= ptsRot[1].fX) { 2648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi lineDone = true; 2658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } 2668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 2678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkRect endRect; 2688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi bool hasEndRect = false; 2698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi // If we are using AA, check to see if we are drawing a partial dash at then end. If so 2708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi // draw it separately here and adjust our end point accordingly 2718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi if (useAA && !lineDone) { 2728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi // If we adjusted the end then we will not be drawing a partial dash at the end. 2738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi // If we didn't adjust the end point then we just need to make sure the ending 2748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi // dash isn't a full dash 2758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi if (0 == endAdj && endingInterval != info.fIntervals[0]) { 2768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkPoint endPts[2]; 2778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi endPts[1] = ptsRot[1]; 2788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi endPts[0].fY = endPts[1].fY; 2798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi endPts[0].fX = endPts[1].fX - endingInterval; 2808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 2818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi endRect.set(endPts, 2); 2828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi endRect.outset(strokeAdj, halfSrcStroke); 2838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 2848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi hasEndRect = true; 2858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi endAdj = endingInterval + info.fIntervals[1]; 2868d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 2878d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi ptsRot[1].fX -= endAdj; 2888d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi if (ptsRot[0].fX >= ptsRot[1].fX) { 2898d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi lineDone = true; 2908d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } 2918d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } 2928d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } 2938d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 2948d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi if (startAdj != 0) { 2958d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi srcPhase = 0; 2968d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } 2978d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 2988d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi // Change the dashing info from src space into device space 2998d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkScalar devIntervals[2]; 3008d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi devIntervals[0] = info.fIntervals[0] * parallelScale; 3018d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi devIntervals[1] = info.fIntervals[1] * parallelScale; 3028d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkScalar devPhase = srcPhase * parallelScale; 3038d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkScalar strokeWidth = srcStrokeWidth * perpScale; 3048d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 3058d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi if ((strokeWidth < 1.f && !useAA) || 0.f == strokeWidth) { 3068d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi strokeWidth = 1.f; 3078d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } 3088d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 3098d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkScalar halfDevStroke = strokeWidth * 0.5f; 3108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 3118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi if (SkPaint::kSquare_Cap == cap && 0 != srcStrokeWidth) { 3128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi // add cap to on interveal and remove from off interval 3138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi devIntervals[0] += strokeWidth; 3148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi devIntervals[1] -= strokeWidth; 3158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } 3168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkScalar startOffset = devIntervals[1] * 0.5f + devPhase; 3178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 3188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkScalar bloatX = useAA ? 0.5f / parallelScale : 0.f; 3198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkScalar bloatY = useAA ? 0.5f / perpScale : 0.f; 3208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 3218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkScalar devBloat = useAA ? 0.5f : 0.f; 3228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 3238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi if (devIntervals[1] <= 0.f && useAA) { 3248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi // Case when we end up drawing a solid AA rect 3258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi // Reset the start rect to draw this single solid rect 3268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi // but it requires to upload a new intervals uniform so we can mimic 3278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi // one giant dash 3288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi ptsRot[0].fX -= hasStartRect ? startAdj : 0; 3298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi ptsRot[1].fX += hasEndRect ? endAdj : 0; 3308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi startRect.set(ptsRot, 2); 3318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi startRect.outset(strokeAdj, halfSrcStroke); 3328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi hasStartRect = true; 3338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi hasEndRect = false; 3348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi lineDone = true; 3358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 3368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkPoint devicePts[2]; 3378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi vm.mapPoints(devicePts, ptsRot, 2); 3388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkScalar lineLength = SkPoint::Distance(devicePts[0], devicePts[1]); 3398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi if (hasCap) { 3408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi lineLength += 2.f * halfDevStroke; 3418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } 3428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi devIntervals[0] = lineLength; 3438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } 3448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi bool fullDash = devIntervals[1] > 0.f || useAA; 3458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi if (fullDash) { 3468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkPathEffect::DashInfo devInfo; 3478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi devInfo.fPhase = devPhase; 3488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi devInfo.fCount = 2; 3498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi devInfo.fIntervals = devIntervals; 3508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi GrPrimitiveEdgeType edgeType= useAA ? kFillAA_GrProcessorEdgeType : 3518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi kFillBW_GrProcessorEdgeType; 3528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi bool isRoundCap = SkPaint::kRound_Cap == cap; 3538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi GrDashingEffect::DashCap capType = isRoundCap ? GrDashingEffect::kRound_DashCap : 3548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi GrDashingEffect::kNonRound_DashCap; 3558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi drawState->setGeometryProcessor( 3568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi GrDashingEffect::Create(edgeType, devInfo, strokeWidth, capType))->unref(); 3578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 3588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi // Set up the vertex data for the line and start/end dashes 3598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi drawState->setVertexAttribs<gDashLineVertexAttribs>(SK_ARRAY_COUNT(gDashLineVertexAttribs), 3608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi sizeof(DashLineVertex)); 3618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } else { 3628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi // Set up the vertex data for the line and start/end dashes 3638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi drawState->setGeometryProcessor( 3648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi GrDefaultGeoProcFactory::CreateAndSetAttribs( 3658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi drawState, 3668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi GrDefaultGeoProcFactory::kPosition_GPType))->unref(); 3678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } 3688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 3698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi int totalRectCnt = 0; 3708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 3718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi totalRectCnt += !lineDone ? 1 : 0; 3728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi totalRectCnt += hasStartRect ? 1 : 0; 3738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi totalRectCnt += hasEndRect ? 1 : 0; 3748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 3758d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi GrDrawTarget::AutoReleaseGeometry geo(target, 3768d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi totalRectCnt * 4, 3778d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi drawState->getVertexStride(), 0); 3788d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi if (!geo.succeeded()) { 3798d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkDebugf("Failed to get space for vertices!\n"); 3808d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi return false; 3818d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } 3828d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 3838d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi int curVIdx = 0; 3848d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 3858d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi if (SkPaint::kRound_Cap == cap && 0 != srcStrokeWidth) { 3868d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi // need to adjust this for round caps to correctly set the dashPos attrib on vertices 3878d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi startOffset -= halfDevStroke; 3888d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } 3898d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 3908d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi // Draw interior part of dashed line 3918d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi if (!lineDone) { 3928d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkPoint devicePts[2]; 3938d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi vm.mapPoints(devicePts, ptsRot, 2); 3948d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkScalar lineLength = SkPoint::Distance(devicePts[0], devicePts[1]); 3958d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi if (hasCap) { 3968d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi lineLength += 2.f * halfDevStroke; 3978d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } 3988d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 3998d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkRect bounds; 4008d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi bounds.set(ptsRot[0].fX, ptsRot[0].fY, ptsRot[1].fX, ptsRot[1].fY); 4018d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi bounds.outset(bloatX + strokeAdj, bloatY + halfSrcStroke); 4028d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi if (fullDash) { 4038d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi DashLineVertex* verts = reinterpret_cast<DashLineVertex*>(geo.vertices()); 4048d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi setup_dashed_rect(bounds, verts, curVIdx, combinedMatrix, startOffset, devBloat, 4058d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi lineLength, halfDevStroke); 4068d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } else { 4078d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkPoint* verts = reinterpret_cast<SkPoint*>(geo.vertices()); 4088d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi setup_dashed_rect_pos(bounds, curVIdx, combinedMatrix, verts); 4098d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } 4108d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi curVIdx += 4; 4118d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } 4128d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 4138d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi if (hasStartRect) { 4148d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkASSERT(useAA); // so that we know bloatX and bloatY have been set 4158d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi startRect.outset(bloatX, bloatY); 4168d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi if (fullDash) { 4178d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi DashLineVertex* verts = reinterpret_cast<DashLineVertex*>(geo.vertices()); 4188d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi setup_dashed_rect(startRect, verts, curVIdx, combinedMatrix, startOffset, devBloat, 4198d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi devIntervals[0], halfDevStroke); 4208d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } else { 4218d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkPoint* verts = reinterpret_cast<SkPoint*>(geo.vertices()); 4228d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi setup_dashed_rect_pos(startRect, curVIdx, combinedMatrix, verts); 4238d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } 4248d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 4258d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi curVIdx += 4; 4268d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } 4278d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 4288d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi if (hasEndRect) { 4298d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkASSERT(useAA); // so that we know bloatX and bloatY have been set 4308d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi endRect.outset(bloatX, bloatY); 4318d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi if (fullDash) { 4328d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi DashLineVertex* verts = reinterpret_cast<DashLineVertex*>(geo.vertices()); 4338d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi setup_dashed_rect(endRect, verts, curVIdx, combinedMatrix, startOffset, devBloat, 4348d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi devIntervals[0], halfDevStroke); 4358d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } else { 4368d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkPoint* verts = reinterpret_cast<SkPoint*>(geo.vertices()); 4378d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi setup_dashed_rect_pos(endRect, curVIdx, combinedMatrix, verts); 4388d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } 4398d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 4408d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi } 4418d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 4428d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi target->setIndexSourceToBuffer(gpu->getContext()->getQuadIndexBuffer()); 4438d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi target->drawIndexedInstances(drawState, kTriangles_GrPrimitiveType, totalRectCnt, 4, 6); 4448d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi target->resetIndexSource(); 4458d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi return true; 4468d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi} 4478d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 4488d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi////////////////////////////////////////////////////////////////////////////// 4498d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 4508d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiclass GLDashingCircleEffect; 4518d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi/* 4528d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * This effect will draw a dotted line (defined as a dashed lined with round caps and no on 4538d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * interval). The radius of the dots is given by the strokeWidth and the spacing by the DashInfo. 4548d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * Both of the previous two parameters are in device space. This effect also requires the setting of 4558d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * a vec2 vertex attribute for the the four corners of the bounding rect. This attribute is the 4568d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * "dash position" of each vertex. In other words it is the vertex coords (in device space) if we 4578d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * transform the line to be horizontal, with the start of line at the origin then shifted to the 4588d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi * right by half the off interval. The line then goes in the positive x direction. 4598d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi */ 4608d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoiclass DashingCircleEffect : public GrGeometryProcessor { 4618d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoipublic: 4628d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi typedef SkPathEffect::DashInfo DashInfo; 4638d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 4648d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi static GrGeometryProcessor* Create(GrPrimitiveEdgeType edgeType, 4658d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi const DashInfo& info, 4668d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi SkScalar radius); 4678d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 4688d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi virtual ~DashingCircleEffect(); 4698d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 4708d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi static const char* Name() { return "DashingCircleEffect"; } 4718d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 4728d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi const GrShaderVar& inCoord() const { return fInCoord; } 4738d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi 4748d2b206a675ec20ea07100c35df34e65ee1e45e8Ruchi Kandoi GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; } 475 476 SkScalar getRadius() const { return fRadius; } 477 478 SkScalar getCenterX() const { return fCenterX; } 479 480 SkScalar getIntervalLength() const { return fIntervalLength; } 481 482 typedef GLDashingCircleEffect GLProcessor; 483 484 virtual const GrBackendGeometryProcessorFactory& getFactory() const SK_OVERRIDE; 485 486private: 487 DashingCircleEffect(GrPrimitiveEdgeType edgeType, const DashInfo& info, SkScalar radius); 488 489 virtual bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE; 490 491 virtual void onComputeInvariantOutput(GrInvariantOutput* inout) const SK_OVERRIDE; 492 493 GrPrimitiveEdgeType fEdgeType; 494 const GrShaderVar& fInCoord; 495 SkScalar fIntervalLength; 496 SkScalar fRadius; 497 SkScalar fCenterX; 498 499 GR_DECLARE_GEOMETRY_PROCESSOR_TEST; 500 501 typedef GrGeometryProcessor INHERITED; 502}; 503 504////////////////////////////////////////////////////////////////////////////// 505 506class GLDashingCircleEffect : public GrGLGeometryProcessor { 507public: 508 GLDashingCircleEffect(const GrBackendProcessorFactory&, const GrProcessor&); 509 510 virtual void emitCode(const EmitArgs&) SK_OVERRIDE; 511 512 static inline void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder*); 513 514 virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE; 515 516private: 517 GrGLProgramDataManager::UniformHandle fParamUniform; 518 SkScalar fPrevRadius; 519 SkScalar fPrevCenterX; 520 SkScalar fPrevIntervalLength; 521 typedef GrGLGeometryProcessor INHERITED; 522}; 523 524GLDashingCircleEffect::GLDashingCircleEffect(const GrBackendProcessorFactory& factory, 525 const GrProcessor&) 526 : INHERITED (factory) { 527 fPrevRadius = SK_ScalarMin; 528 fPrevCenterX = SK_ScalarMin; 529 fPrevIntervalLength = SK_ScalarMax; 530} 531 532void GLDashingCircleEffect::emitCode(const EmitArgs& args) { 533 const DashingCircleEffect& dce = args.fGP.cast<DashingCircleEffect>(); 534 const char *paramName; 535 // The param uniforms, xyz, refer to circle radius - 0.5, cicles center x coord, and 536 // the total interval length of the dash. 537 fParamUniform = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility, 538 kVec3f_GrSLType, 539 "params", 540 ¶mName); 541 542 GrGLVertToFrag v(kVec2f_GrSLType); 543 args.fPB->addVarying("Coord", &v); 544 545 GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder(); 546 vsBuilder->codeAppendf("\t%s = %s;\n", v.vsOut(), dce.inCoord().c_str()); 547 548 // setup position varying 549 vsBuilder->codeAppendf("%s = %s * vec3(%s, 1);", vsBuilder->glPosition(), vsBuilder->uViewM(), 550 vsBuilder->inPosition()); 551 552 // transforms all points so that we can compare them to our test circle 553 GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder(); 554 fsBuilder->codeAppendf("\t\tfloat xShifted = %s.x - floor(%s.x / %s.z) * %s.z;\n", 555 v.fsIn(), v.fsIn(), paramName, paramName); 556 fsBuilder->codeAppendf("\t\tvec2 fragPosShifted = vec2(xShifted, %s.y);\n", v.fsIn()); 557 fsBuilder->codeAppendf("\t\tvec2 center = vec2(%s.y, 0.0);\n", paramName); 558 fsBuilder->codeAppend("\t\tfloat dist = length(center - fragPosShifted);\n"); 559 if (GrProcessorEdgeTypeIsAA(dce.getEdgeType())) { 560 fsBuilder->codeAppendf("\t\tfloat diff = dist - %s.x;\n", paramName); 561 fsBuilder->codeAppend("\t\tdiff = 1.0 - diff;\n"); 562 fsBuilder->codeAppend("\t\tfloat alpha = clamp(diff, 0.0, 1.0);\n"); 563 } else { 564 fsBuilder->codeAppendf("\t\tfloat alpha = 1.0;\n"); 565 fsBuilder->codeAppendf("\t\talpha *= dist < %s.x + 0.5 ? 1.0 : 0.0;\n", paramName); 566 } 567 fsBuilder->codeAppendf("\t\t%s = %s;\n", args.fOutput, 568 (GrGLSLExpr4(args.fInput) * GrGLSLExpr1("alpha")).c_str()); 569} 570 571void GLDashingCircleEffect::setData(const GrGLProgramDataManager& pdman 572 , const GrProcessor& processor) { 573 const DashingCircleEffect& dce = processor.cast<DashingCircleEffect>(); 574 SkScalar radius = dce.getRadius(); 575 SkScalar centerX = dce.getCenterX(); 576 SkScalar intervalLength = dce.getIntervalLength(); 577 if (radius != fPrevRadius || centerX != fPrevCenterX || intervalLength != fPrevIntervalLength) { 578 pdman.set3f(fParamUniform, radius - 0.5f, centerX, intervalLength); 579 fPrevRadius = radius; 580 fPrevCenterX = centerX; 581 fPrevIntervalLength = intervalLength; 582 } 583} 584 585void GLDashingCircleEffect::GenKey(const GrProcessor& processor, const GrGLCaps&, 586 GrProcessorKeyBuilder* b) { 587 const DashingCircleEffect& dce = processor.cast<DashingCircleEffect>(); 588 b->add32(dce.getEdgeType()); 589} 590 591////////////////////////////////////////////////////////////////////////////// 592 593GrGeometryProcessor* DashingCircleEffect::Create(GrPrimitiveEdgeType edgeType, const DashInfo& info, 594 SkScalar radius) { 595 if (info.fCount != 2 || info.fIntervals[0] != 0) { 596 return NULL; 597 } 598 599 return SkNEW_ARGS(DashingCircleEffect, (edgeType, info, radius)); 600} 601 602DashingCircleEffect::~DashingCircleEffect() {} 603 604void DashingCircleEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const { 605 inout->mulByUnknownAlpha(); 606} 607 608const GrBackendGeometryProcessorFactory& DashingCircleEffect::getFactory() const { 609 return GrTBackendGeometryProcessorFactory<DashingCircleEffect>::getInstance(); 610} 611 612DashingCircleEffect::DashingCircleEffect(GrPrimitiveEdgeType edgeType, const DashInfo& info, 613 SkScalar radius) 614 : fEdgeType(edgeType) 615 , fInCoord(this->addVertexAttrib(GrShaderVar("inCoord", 616 kVec2f_GrSLType, 617 GrShaderVar::kAttribute_TypeModifier))) { 618 SkScalar onLen = info.fIntervals[0]; 619 SkScalar offLen = info.fIntervals[1]; 620 fIntervalLength = onLen + offLen; 621 fRadius = radius; 622 fCenterX = SkScalarHalf(offLen); 623} 624 625bool DashingCircleEffect::onIsEqual(const GrGeometryProcessor& other) const { 626 const DashingCircleEffect& dce = other.cast<DashingCircleEffect>(); 627 return (fEdgeType == dce.fEdgeType && 628 fIntervalLength == dce.fIntervalLength && 629 fRadius == dce.fRadius && 630 fCenterX == dce.fCenterX); 631} 632 633GR_DEFINE_GEOMETRY_PROCESSOR_TEST(DashingCircleEffect); 634 635GrGeometryProcessor* DashingCircleEffect::TestCreate(SkRandom* random, 636 GrContext*, 637 const GrDrawTargetCaps& caps, 638 GrTexture*[]) { 639 GrPrimitiveEdgeType edgeType = static_cast<GrPrimitiveEdgeType>(random->nextULessThan( 640 kGrProcessorEdgeTypeCnt)); 641 SkScalar strokeWidth = random->nextRangeScalar(0, 100.f); 642 DashInfo info; 643 info.fCount = 2; 644 SkAutoTArray<SkScalar> intervals(info.fCount); 645 info.fIntervals = intervals.get(); 646 info.fIntervals[0] = 0; 647 info.fIntervals[1] = random->nextRangeScalar(0, 10.f); 648 info.fPhase = random->nextRangeScalar(0, info.fIntervals[1]); 649 650 return DashingCircleEffect::Create(edgeType, info, strokeWidth); 651} 652 653////////////////////////////////////////////////////////////////////////////// 654 655class GLDashingLineEffect; 656 657/* 658 * This effect will draw a dashed line. The width of the dash is given by the strokeWidth and the 659 * length and spacing by the DashInfo. Both of the previous two parameters are in device space. 660 * This effect also requires the setting of a vec2 vertex attribute for the the four corners of the 661 * bounding rect. This attribute is the "dash position" of each vertex. In other words it is the 662 * vertex coords (in device space) if we transform the line to be horizontal, with the start of 663 * line at the origin then shifted to the right by half the off interval. The line then goes in the 664 * positive x direction. 665 */ 666class DashingLineEffect : public GrGeometryProcessor { 667public: 668 typedef SkPathEffect::DashInfo DashInfo; 669 670 static GrGeometryProcessor* Create(GrPrimitiveEdgeType edgeType, 671 const DashInfo& info, 672 SkScalar strokeWidth); 673 674 virtual ~DashingLineEffect(); 675 676 static const char* Name() { return "DashingEffect"; } 677 678 const GrShaderVar& inCoord() const { return fInCoord; } 679 680 GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; } 681 682 const SkRect& getRect() const { return fRect; } 683 684 SkScalar getIntervalLength() const { return fIntervalLength; } 685 686 typedef GLDashingLineEffect GLProcessor; 687 688 virtual const GrBackendGeometryProcessorFactory& getFactory() const SK_OVERRIDE; 689 690private: 691 DashingLineEffect(GrPrimitiveEdgeType edgeType, const DashInfo& info, SkScalar strokeWidth); 692 693 virtual bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE; 694 695 virtual void onComputeInvariantOutput(GrInvariantOutput* inout) const SK_OVERRIDE; 696 697 GrPrimitiveEdgeType fEdgeType; 698 const GrShaderVar& fInCoord; 699 SkRect fRect; 700 SkScalar fIntervalLength; 701 702 GR_DECLARE_GEOMETRY_PROCESSOR_TEST; 703 704 typedef GrGeometryProcessor INHERITED; 705}; 706 707////////////////////////////////////////////////////////////////////////////// 708 709class GLDashingLineEffect : public GrGLGeometryProcessor { 710public: 711 GLDashingLineEffect(const GrBackendProcessorFactory&, const GrProcessor&); 712 713 virtual void emitCode(const EmitArgs&) SK_OVERRIDE; 714 715 static inline void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder*); 716 717 virtual void setData(const GrGLProgramDataManager&, const GrProcessor&) SK_OVERRIDE; 718 719private: 720 GrGLProgramDataManager::UniformHandle fRectUniform; 721 GrGLProgramDataManager::UniformHandle fIntervalUniform; 722 SkRect fPrevRect; 723 SkScalar fPrevIntervalLength; 724 typedef GrGLGeometryProcessor INHERITED; 725}; 726 727GLDashingLineEffect::GLDashingLineEffect(const GrBackendProcessorFactory& factory, 728 const GrProcessor&) 729 : INHERITED (factory) { 730 fPrevRect.fLeft = SK_ScalarNaN; 731 fPrevIntervalLength = SK_ScalarMax; 732} 733 734void GLDashingLineEffect::emitCode(const EmitArgs& args) { 735 const DashingLineEffect& de = args.fGP.cast<DashingLineEffect>(); 736 const char *rectName; 737 // The rect uniform's xyzw refer to (left + 0.5, top + 0.5, right - 0.5, bottom - 0.5), 738 // respectively. 739 fRectUniform = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility, 740 kVec4f_GrSLType, 741 "rect", 742 &rectName); 743 const char *intervalName; 744 // The interval uniform's refers to the total length of the interval (on + off) 745 fIntervalUniform = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility, 746 kFloat_GrSLType, 747 "interval", 748 &intervalName); 749 750 GrGLVertToFrag v(kVec2f_GrSLType); 751 args.fPB->addVarying("Coord", &v); 752 GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder(); 753 vsBuilder->codeAppendf("\t%s = %s;\n", v.vsOut(), de.inCoord().c_str()); 754 755 // setup position varying 756 vsBuilder->codeAppendf("%s = %s * vec3(%s, 1);", vsBuilder->glPosition(), vsBuilder->uViewM(), 757 vsBuilder->inPosition()); 758 759 // transforms all points so that we can compare them to our test rect 760 GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder(); 761 fsBuilder->codeAppendf("\t\tfloat xShifted = %s.x - floor(%s.x / %s) * %s;\n", 762 v.fsIn(), v.fsIn(), intervalName, intervalName); 763 fsBuilder->codeAppendf("\t\tvec2 fragPosShifted = vec2(xShifted, %s.y);\n", v.fsIn()); 764 if (GrProcessorEdgeTypeIsAA(de.getEdgeType())) { 765 // The amount of coverage removed in x and y by the edges is computed as a pair of negative 766 // numbers, xSub and ySub. 767 fsBuilder->codeAppend("\t\tfloat xSub, ySub;\n"); 768 fsBuilder->codeAppendf("\t\txSub = min(fragPosShifted.x - %s.x, 0.0);\n", rectName); 769 fsBuilder->codeAppendf("\t\txSub += min(%s.z - fragPosShifted.x, 0.0);\n", rectName); 770 fsBuilder->codeAppendf("\t\tySub = min(fragPosShifted.y - %s.y, 0.0);\n", rectName); 771 fsBuilder->codeAppendf("\t\tySub += min(%s.w - fragPosShifted.y, 0.0);\n", rectName); 772 // Now compute coverage in x and y and multiply them to get the fraction of the pixel 773 // covered. 774 fsBuilder->codeAppendf("\t\tfloat alpha = (1.0 + max(xSub, -1.0)) * (1.0 + max(ySub, -1.0));\n"); 775 } else { 776 // Assuming the bounding geometry is tight so no need to check y values 777 fsBuilder->codeAppendf("\t\tfloat alpha = 1.0;\n"); 778 fsBuilder->codeAppendf("\t\talpha *= (fragPosShifted.x - %s.x) > -0.5 ? 1.0 : 0.0;\n", rectName); 779 fsBuilder->codeAppendf("\t\talpha *= (%s.z - fragPosShifted.x) >= -0.5 ? 1.0 : 0.0;\n", rectName); 780 } 781 fsBuilder->codeAppendf("\t\t%s = %s;\n", args.fOutput, 782 (GrGLSLExpr4(args.fInput) * GrGLSLExpr1("alpha")).c_str()); 783} 784 785void GLDashingLineEffect::setData(const GrGLProgramDataManager& pdman, 786 const GrProcessor& processor) { 787 const DashingLineEffect& de = processor.cast<DashingLineEffect>(); 788 const SkRect& rect = de.getRect(); 789 SkScalar intervalLength = de.getIntervalLength(); 790 if (rect != fPrevRect || intervalLength != fPrevIntervalLength) { 791 pdman.set4f(fRectUniform, rect.fLeft + 0.5f, rect.fTop + 0.5f, 792 rect.fRight - 0.5f, rect.fBottom - 0.5f); 793 pdman.set1f(fIntervalUniform, intervalLength); 794 fPrevRect = rect; 795 fPrevIntervalLength = intervalLength; 796 } 797} 798 799void GLDashingLineEffect::GenKey(const GrProcessor& processor, const GrGLCaps&, 800 GrProcessorKeyBuilder* b) { 801 const DashingLineEffect& de = processor.cast<DashingLineEffect>(); 802 b->add32(de.getEdgeType()); 803} 804 805////////////////////////////////////////////////////////////////////////////// 806 807GrGeometryProcessor* DashingLineEffect::Create(GrPrimitiveEdgeType edgeType, 808 const DashInfo& info, 809 SkScalar strokeWidth) { 810 if (info.fCount != 2) { 811 return NULL; 812 } 813 814 return SkNEW_ARGS(DashingLineEffect, (edgeType, info, strokeWidth)); 815} 816 817DashingLineEffect::~DashingLineEffect() {} 818 819void DashingLineEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const { 820 inout->mulByUnknownAlpha(); 821} 822 823const GrBackendGeometryProcessorFactory& DashingLineEffect::getFactory() const { 824 return GrTBackendGeometryProcessorFactory<DashingLineEffect>::getInstance(); 825} 826 827DashingLineEffect::DashingLineEffect(GrPrimitiveEdgeType edgeType, const DashInfo& info, 828 SkScalar strokeWidth) 829 : fEdgeType(edgeType) 830 , fInCoord(this->addVertexAttrib(GrShaderVar("inCoord", 831 kVec2f_GrSLType, 832 GrShaderVar::kAttribute_TypeModifier))) { 833 SkScalar onLen = info.fIntervals[0]; 834 SkScalar offLen = info.fIntervals[1]; 835 SkScalar halfOffLen = SkScalarHalf(offLen); 836 SkScalar halfStroke = SkScalarHalf(strokeWidth); 837 fIntervalLength = onLen + offLen; 838 fRect.set(halfOffLen, -halfStroke, halfOffLen + onLen, halfStroke); 839} 840 841bool DashingLineEffect::onIsEqual(const GrGeometryProcessor& other) const { 842 const DashingLineEffect& de = other.cast<DashingLineEffect>(); 843 return (fEdgeType == de.fEdgeType && 844 fRect == de.fRect && 845 fIntervalLength == de.fIntervalLength); 846} 847 848GR_DEFINE_GEOMETRY_PROCESSOR_TEST(DashingLineEffect); 849 850GrGeometryProcessor* DashingLineEffect::TestCreate(SkRandom* random, 851 GrContext*, 852 const GrDrawTargetCaps& caps, 853 GrTexture*[]) { 854 GrPrimitiveEdgeType edgeType = static_cast<GrPrimitiveEdgeType>(random->nextULessThan( 855 kGrProcessorEdgeTypeCnt)); 856 SkScalar strokeWidth = random->nextRangeScalar(0, 100.f); 857 DashInfo info; 858 info.fCount = 2; 859 SkAutoTArray<SkScalar> intervals(info.fCount); 860 info.fIntervals = intervals.get(); 861 info.fIntervals[0] = random->nextRangeScalar(0, 10.f); 862 info.fIntervals[1] = random->nextRangeScalar(0, 10.f); 863 info.fPhase = random->nextRangeScalar(0, info.fIntervals[0] + info.fIntervals[1]); 864 865 return DashingLineEffect::Create(edgeType, info, strokeWidth); 866} 867 868////////////////////////////////////////////////////////////////////////////// 869 870GrGeometryProcessor* GrDashingEffect::Create(GrPrimitiveEdgeType edgeType, 871 const SkPathEffect::DashInfo& info, 872 SkScalar strokeWidth, 873 GrDashingEffect::DashCap cap) { 874 switch (cap) { 875 case GrDashingEffect::kRound_DashCap: 876 return DashingCircleEffect::Create(edgeType, info, SkScalarHalf(strokeWidth)); 877 case GrDashingEffect::kNonRound_DashCap: 878 return DashingLineEffect::Create(edgeType, info, strokeWidth); 879 default: 880 SkFAIL("Unexpected dashed cap."); 881 } 882 return NULL; 883} 884