1/* 2 * Copyright 2014 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "GrGLPathRange.h" 9#include "GrGLPath.h" 10#include "GrGLPathRendering.h" 11#include "GrGLGpu.h" 12 13GrGLPathRange::GrGLPathRange(GrGLGpu* gpu, PathGenerator* pathGenerator, const GrStyle& style) 14 : INHERITED(gpu, pathGenerator), 15 fStyle(style), 16 fBasePathID(gpu->glPathRendering()->genPaths(this->getNumPaths())), 17 fGpuMemorySize(0) { 18 this->init(); 19 this->registerWithCache(SkBudgeted::kYes); 20} 21 22GrGLPathRange::GrGLPathRange(GrGLGpu* gpu, 23 GrGLuint basePathID, 24 int numPaths, 25 size_t gpuMemorySize, 26 const GrStyle& style) 27 : INHERITED(gpu, numPaths), 28 fStyle(style), 29 fBasePathID(basePathID), 30 fGpuMemorySize(gpuMemorySize) { 31 this->init(); 32 this->registerWithCache(SkBudgeted::kYes); 33} 34 35void GrGLPathRange::init() { 36 const SkStrokeRec& stroke = fStyle.strokeRec(); 37 // Must force fill: 38 // * dashing: NVPR stroke dashing is different to Skia. 39 // * end caps: NVPR stroking degenerate contours with end caps is different to Skia. 40 bool forceFill = fStyle.pathEffect() || 41 (stroke.needToApply() && stroke.getCap() != SkPaint::kButt_Cap); 42 43 if (forceFill) { 44 fShouldStroke = false; 45 fShouldFill = true; 46 } else { 47 fShouldStroke = stroke.needToApply(); 48 fShouldFill = stroke.isFillStyle() || 49 stroke.getStyle() == SkStrokeRec::kStrokeAndFill_Style; 50 } 51} 52 53void GrGLPathRange::onInitPath(int index, const SkPath& origSkPath) const { 54 GrGLGpu* gpu = static_cast<GrGLGpu*>(this->getGpu()); 55 if (nullptr == gpu) { 56 return; 57 } 58 // Make sure the path at this index hasn't been initted already. 59 SkDEBUGCODE( 60 GrGLboolean isPath; 61 GR_GL_CALL_RET(gpu->glInterface(), isPath, IsPath(fBasePathID + index))); 62 SkASSERT(GR_GL_FALSE == isPath); 63 64 if (origSkPath.isEmpty()) { 65 GrGLPath::InitPathObjectEmptyPath(gpu, fBasePathID + index); 66 } else if (fShouldStroke) { 67 GrGLPath::InitPathObjectPathData(gpu, fBasePathID + index, origSkPath); 68 GrGLPath::InitPathObjectStroke(gpu, fBasePathID + index, fStyle.strokeRec()); 69 } else { 70 const SkPath* skPath = &origSkPath; 71 SkTLazy<SkPath> tmpPath; 72 if (!fStyle.isSimpleFill()) { 73 SkStrokeRec::InitStyle fill; 74 // The path effect must be applied to the path. However, if a path effect is present, 75 // we must convert all the paths to fills. The path effect application may leave 76 // simple paths as strokes but converts other paths to fills. 77 // Thus we must stroke the strokes here, so that all paths in the 78 // path range are using the same style. 79 if (!fStyle.applyToPath(tmpPath.init(), &fill, *skPath, SK_Scalar1)) { 80 return; 81 } 82 // We shouldn't have allowed hairlines or arbitrary path effect styles to get here 83 // so after application we better have a filled path. 84 SkASSERT(SkStrokeRec::kFill_InitStyle == fill); 85 skPath = tmpPath.get(); 86 87 } 88 GrGLPath::InitPathObjectPathData(gpu, fBasePathID + index, *skPath); 89 } 90 // TODO: Use a better approximation for the individual path sizes. 91 fGpuMemorySize += 100; 92} 93 94void GrGLPathRange::onRelease() { 95 SkASSERT(this->getGpu()); 96 97 if (0 != fBasePathID) { 98 static_cast<GrGLGpu*>(this->getGpu())->glPathRendering()->deletePaths(fBasePathID, 99 this->getNumPaths()); 100 fBasePathID = 0; 101 } 102 103 INHERITED::onRelease(); 104} 105 106void GrGLPathRange::onAbandon() { 107 fBasePathID = 0; 108 109 INHERITED::onAbandon(); 110} 111