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