Home | History | Annotate | Download | only in core
      1 #include "SkEdgeBuilder.h"
      2 #include "SkPath.h"
      3 #include "SkEdge.h"
      4 #include "SkEdgeClipper.h"
      5 #include "SkLineClipper.h"
      6 #include "SkGeometry.h"
      7 
      8 SkEdgeBuilder::SkEdgeBuilder() : fAlloc(16*1024) {}
      9 
     10 template <typename T> static T* typedAllocThrow(SkChunkAlloc& alloc) {
     11     return static_cast<T*>(alloc.allocThrow(sizeof(T)));
     12 }
     13 
     14 ///////////////////////////////////////////////////////////////////////////////
     15 
     16 void SkEdgeBuilder::addLine(const SkPoint pts[]) {
     17     SkEdge* edge = typedAllocThrow<SkEdge>(fAlloc);
     18     if (edge->setLine(pts[0], pts[1], NULL, fShiftUp)) {
     19         fList.push(edge);
     20     } else {
     21         // TODO: unallocate edge from storage...
     22     }
     23 }
     24 
     25 void SkEdgeBuilder::addQuad(const SkPoint pts[]) {
     26     SkQuadraticEdge* edge = typedAllocThrow<SkQuadraticEdge>(fAlloc);
     27     if (edge->setQuadratic(pts, fShiftUp)) {
     28         fList.push(edge);
     29     } else {
     30         // TODO: unallocate edge from storage...
     31     }
     32 }
     33 
     34 void SkEdgeBuilder::addCubic(const SkPoint pts[]) {
     35     SkCubicEdge* edge = typedAllocThrow<SkCubicEdge>(fAlloc);
     36     if (edge->setCubic(pts, NULL, fShiftUp)) {
     37         fList.push(edge);
     38     } else {
     39         // TODO: unallocate edge from storage...
     40     }
     41 }
     42 
     43 void SkEdgeBuilder::addClipper(SkEdgeClipper* clipper) {
     44     SkPoint      pts[4];
     45     SkPath::Verb verb;
     46 
     47     while ((verb = clipper->next(pts)) != SkPath::kDone_Verb) {
     48         switch (verb) {
     49             case SkPath::kLine_Verb:
     50                 this->addLine(pts);
     51                 break;
     52             case SkPath::kQuad_Verb:
     53                 this->addQuad(pts);
     54                 break;
     55             case SkPath::kCubic_Verb:
     56                 this->addCubic(pts);
     57                 break;
     58             default:
     59                 break;
     60         }
     61     }
     62 }
     63 
     64 ///////////////////////////////////////////////////////////////////////////////
     65 
     66 static void setShiftedClip(SkRect* dst, const SkIRect& src, int shift) {
     67     dst->set(SkIntToScalar(src.fLeft >> shift),
     68              SkIntToScalar(src.fTop >> shift),
     69              SkIntToScalar(src.fRight >> shift),
     70              SkIntToScalar(src.fBottom >> shift));
     71 }
     72 
     73 int SkEdgeBuilder::build(const SkPath& path, const SkIRect* iclip,
     74                          int shiftUp) {
     75     fAlloc.reset();
     76     fList.reset();
     77     fShiftUp = shiftUp;
     78 
     79     SkPath::Iter    iter(path, true);
     80     SkPoint         pts[4];
     81     SkPath::Verb    verb;
     82 
     83     if (iclip) {
     84         SkRect clip;
     85         setShiftedClip(&clip, *iclip, shiftUp);
     86         SkEdgeClipper clipper;
     87 
     88         while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
     89             switch (verb) {
     90                 case SkPath::kMove_Verb:
     91                 case SkPath::kClose_Verb:
     92                     // we ignore these, and just get the whole segment from
     93                     // the corresponding line/quad/cubic verbs
     94                     break;
     95                 case SkPath::kLine_Verb: {
     96                     SkPoint lines[SkLineClipper::kMaxPoints];
     97                     int lineCount = SkLineClipper::ClipLine(pts, clip, lines);
     98                     for (int i = 0; i < lineCount; i++) {
     99                         this->addLine(&lines[i]);
    100                     }
    101                     break;
    102                 }
    103                 case SkPath::kQuad_Verb:
    104                     if (clipper.clipQuad(pts, clip)) {
    105                         this->addClipper(&clipper);
    106                     }
    107                     break;
    108                 case SkPath::kCubic_Verb:
    109                     if (clipper.clipCubic(pts, clip)) {
    110                         this->addClipper(&clipper);
    111                     }
    112                     break;
    113                 default:
    114                     SkASSERT(!"unexpected verb");
    115                     break;
    116             }
    117         }
    118     } else {
    119         while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
    120             switch (verb) {
    121                 case SkPath::kMove_Verb:
    122                 case SkPath::kClose_Verb:
    123                     // we ignore these, and just get the whole segment from
    124                     // the corresponding line/quad/cubic verbs
    125                     break;
    126                 case SkPath::kLine_Verb:
    127                     this->addLine(pts);
    128                     break;
    129                 case SkPath::kQuad_Verb: {
    130                     SkPoint monoX[5];
    131                     int n = SkChopQuadAtYExtrema(pts, monoX);
    132                     for (int i = 0; i <= n; i++) {
    133                         this->addQuad(&monoX[i * 2]);
    134                     }
    135                     break;
    136                 }
    137                 case SkPath::kCubic_Verb: {
    138                     SkPoint monoY[10];
    139                     int n = SkChopCubicAtYExtrema(pts, monoY);
    140                     for (int i = 0; i <= n; i++) {
    141                         this->addCubic(&monoY[i * 3]);
    142                     }
    143                     break;
    144                 }
    145                 default:
    146                     SkASSERT(!"unexpected verb");
    147                     break;
    148             }
    149         }
    150     }
    151     return fList.count();
    152 }
    153 
    154 
    155