1 /*
2  * Copyright 2011 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 #ifndef SkEdgeBuilder_DEFINED
8 #define SkEdgeBuilder_DEFINED
9 
10 #include "SkArenaAlloc.h"
11 #include "SkRect.h"
12 #include "SkTDArray.h"
13 #include "SkEdge.h"
14 #include "SkAnalyticEdge.h"
15 
16 struct SkEdge;
17 struct SkAnalyticEdge;
18 class SkEdgeClipper;
19 class SkPath;
20 
21 class SkEdgeBuilder {
22 public:
23     enum EdgeType {
24         // Used in supersampling or non-AA scan coverter; it stores only integral y coordinates.
25         kEdge,
26 
27         // Used in Analytic AA scan converter; it uses SkFixed to store fractional y.
28         kAnalyticEdge,
29 
30         // Used in Delta AA scan converter; it's a super-light wrapper of SkPoint, which can then be
31         // used to construct SkAnalyticEdge (kAnalyticEdge) later. We use kBezier to save the memory
32         // allocation time (a SkBezier is much lighter than SkAnalyticEdge or SkEdge). Note that
33         // Delta AA only has to deal with one SkAnalyticEdge at a time (whereas Analytic AA has to
34         // deal with all SkAnalyticEdges at the same time). Thus for Delta AA, we only need to
35         // allocate memory for n SkBeziers and 1 SkAnalyticEdge. (Analytic AA need to allocate
36         // memory for n SkAnalyticEdges.)
37         kBezier
38     };
39 
40     // static constexpr int kEdgeSizes[3] = {sizeof(SkEdge), sizeof(SkAnalyticEdge), sizeof(SkBezier)};
41 
42     SkEdgeBuilder();
43 
44     // returns the number of built edges. The array of those edge pointers
45     // is returned from edgeList().
46     int build(const SkPath& path, const SkIRect* clip, int shiftUp, bool clipToTheRight,
47               EdgeType edgeType = kEdge);
48 
49     int build_edges(const SkPath& path, const SkIRect* shiftedClip,
50             int shiftEdgesUp, bool pathContainedInClip, EdgeType edgeType = kEdge);
51 
edgeList()52     SkEdge** edgeList() { return (SkEdge**)fEdgeList; }
analyticEdgeList()53     SkAnalyticEdge** analyticEdgeList() { return (SkAnalyticEdge**)fEdgeList; }
bezierList()54     SkBezier** bezierList() { return (SkBezier**)fEdgeList; }
55 
56 private:
57     enum Combine {
58         kNo_Combine,
59         kPartial_Combine,
60         kTotal_Combine
61     };
62 
63     Combine CombineVertical(const SkEdge* edge, SkEdge* last);
64     Combine CombineVertical(const SkAnalyticEdge* edge, SkAnalyticEdge* last);
65     Combine checkVertical(const SkEdge* edge, SkEdge** edgePtr);
66     Combine checkVertical(const SkAnalyticEdge* edge, SkAnalyticEdge** edgePtr);
67     bool vertical_line(const SkEdge* edge);
68     bool vertical_line(const SkAnalyticEdge* edge);
69 
70     SkSTArenaAlloc<512> fAlloc;
71     SkTDArray<void*>    fList;
72 
73     /*
74      *  If we're in general mode, we allcoate the pointers in fList, and this
75      *  will point at fList.begin(). If we're in polygon mode, fList will be
76      *  empty, as we will have preallocated room for the pointers in fAlloc's
77      *  block, and fEdgeList will point into that.
78      */
79     void**      fEdgeList;
80 
81     int         fShiftUp;
82     EdgeType    fEdgeType;
83 
84 public:
85     void addLine(const SkPoint pts[]);
86     void addQuad(const SkPoint pts[]);
87     void addCubic(const SkPoint pts[]);
88     void addClipper(SkEdgeClipper*);
89 
edgeType()90     EdgeType edgeType() const { return fEdgeType; }
91 
92     int buildPoly(const SkPath& path, const SkIRect* clip, int shiftUp, bool clipToTheRight);
93 
addPolyLine(SkPoint pts[],char * & edge,size_t edgeSize,char ** & edgePtr,int shiftUp)94     inline void addPolyLine(SkPoint pts[], char* &edge, size_t edgeSize, char** &edgePtr,
95             int shiftUp) {
96         if (fEdgeType == kBezier) {
97             if (((SkLine*)edge)->set(pts)) {
98                 *edgePtr++ = edge;
99                 edge += edgeSize;
100             }
101             return;
102         }
103         bool analyticAA = fEdgeType == kAnalyticEdge;
104         bool setLineResult = analyticAA ?
105                 ((SkAnalyticEdge*)edge)->setLine(pts[0], pts[1]) :
106                 ((SkEdge*)edge)->setLine(pts[0], pts[1], shiftUp);
107         if (setLineResult) {
108             Combine combine = analyticAA ?
109                     checkVertical((SkAnalyticEdge*)edge, (SkAnalyticEdge**)edgePtr) :
110                     checkVertical((SkEdge*)edge, (SkEdge**)edgePtr);
111             if (kNo_Combine == combine) {
112                 *edgePtr++ = edge;
113                 edge += edgeSize;
114             } else if (kTotal_Combine == combine) {
115                 --edgePtr;
116             }
117         }
118     }
119 };
120 
121 #endif
122