Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2012 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 "SkStrokeRec.h"
      9 #include "SkPaintDefaults.h"
     10 
     11 // must be < 0, since ==0 means hairline, and >0 means normal stroke
     12 #define kStrokeRec_FillStyleWidth     (-SK_Scalar1)
     13 
     14 SkStrokeRec::SkStrokeRec(InitStyle s) {
     15     fResScale       = 1;
     16     fWidth          = (kFill_InitStyle == s) ? kStrokeRec_FillStyleWidth : 0;
     17     fMiterLimit     = SkPaintDefaults_MiterLimit;
     18     fCap            = SkPaint::kDefault_Cap;
     19     fJoin           = SkPaint::kDefault_Join;
     20     fStrokeAndFill  = false;
     21 }
     22 
     23 SkStrokeRec::SkStrokeRec(const SkPaint& paint, SkScalar resScale) {
     24     this->init(paint, paint.getStyle(), resScale);
     25 }
     26 
     27 SkStrokeRec::SkStrokeRec(const SkPaint& paint, SkPaint::Style styleOverride, SkScalar resScale) {
     28     this->init(paint, styleOverride, resScale);
     29 }
     30 
     31 void SkStrokeRec::init(const SkPaint& paint, SkPaint::Style style, SkScalar resScale) {
     32     fResScale = resScale;
     33 
     34     switch (style) {
     35         case SkPaint::kFill_Style:
     36             fWidth = kStrokeRec_FillStyleWidth;
     37             fStrokeAndFill = false;
     38             break;
     39         case SkPaint::kStroke_Style:
     40             fWidth = paint.getStrokeWidth();
     41             fStrokeAndFill = false;
     42             break;
     43         case SkPaint::kStrokeAndFill_Style:
     44             if (0 == paint.getStrokeWidth()) {
     45                 // hairline+fill == fill
     46                 fWidth = kStrokeRec_FillStyleWidth;
     47                 fStrokeAndFill = false;
     48             } else {
     49                 fWidth = paint.getStrokeWidth();
     50                 fStrokeAndFill = true;
     51             }
     52             break;
     53         default:
     54             SkDEBUGFAIL("unknown paint style");
     55             // fall back on just fill
     56             fWidth = kStrokeRec_FillStyleWidth;
     57             fStrokeAndFill = false;
     58             break;
     59     }
     60 
     61     // copy these from the paint, regardless of our "style"
     62     fMiterLimit = paint.getStrokeMiter();
     63     fCap        = paint.getStrokeCap();
     64     fJoin       = paint.getStrokeJoin();
     65 }
     66 
     67 SkStrokeRec::Style SkStrokeRec::getStyle() const {
     68     if (fWidth < 0) {
     69         return kFill_Style;
     70     } else if (0 == fWidth) {
     71         return kHairline_Style;
     72     } else {
     73         return fStrokeAndFill ? kStrokeAndFill_Style : kStroke_Style;
     74     }
     75 }
     76 
     77 void SkStrokeRec::setFillStyle() {
     78     fWidth = kStrokeRec_FillStyleWidth;
     79     fStrokeAndFill = false;
     80 }
     81 
     82 void SkStrokeRec::setHairlineStyle() {
     83     fWidth = 0;
     84     fStrokeAndFill = false;
     85 }
     86 
     87 void SkStrokeRec::setStrokeStyle(SkScalar width, bool strokeAndFill) {
     88     if (strokeAndFill && (0 == width)) {
     89         // hairline+fill == fill
     90         this->setFillStyle();
     91     } else {
     92         fWidth = width;
     93         fStrokeAndFill = strokeAndFill;
     94     }
     95 }
     96 
     97 #include "SkStroke.h"
     98 
     99 #ifdef SK_DEBUG
    100     // enables tweaking these values at runtime from SampleApp
    101     bool gDebugStrokerErrorSet = false;
    102     SkScalar gDebugStrokerError;
    103 #endif
    104 
    105 bool SkStrokeRec::applyToPath(SkPath* dst, const SkPath& src) const {
    106     if (fWidth <= 0) {  // hairline or fill
    107         return false;
    108     }
    109 
    110     SkStroke stroker;
    111     stroker.setCap((SkPaint::Cap)fCap);
    112     stroker.setJoin((SkPaint::Join)fJoin);
    113     stroker.setMiterLimit(fMiterLimit);
    114     stroker.setWidth(fWidth);
    115     stroker.setDoFill(fStrokeAndFill);
    116 #ifdef SK_DEBUG
    117     stroker.setResScale(gDebugStrokerErrorSet ? gDebugStrokerError : fResScale);
    118 #else
    119     stroker.setResScale(fResScale);
    120 #endif
    121     stroker.strokePath(src, dst);
    122     return true;
    123 }
    124 
    125 void SkStrokeRec::applyToPaint(SkPaint* paint) const {
    126     if (fWidth < 0) {  // fill
    127         paint->setStyle(SkPaint::kFill_Style);
    128         return;
    129     }
    130 
    131     paint->setStyle(fStrokeAndFill ? SkPaint::kStrokeAndFill_Style : SkPaint::kStroke_Style);
    132     paint->setStrokeWidth(fWidth);
    133     paint->setStrokeMiter(fMiterLimit);
    134     paint->setStrokeCap((SkPaint::Cap)fCap);
    135     paint->setStrokeJoin((SkPaint::Join)fJoin);
    136 }
    137 
    138 static inline SkScalar get_inflation_bounds(SkPaint::Join join,
    139                                             SkScalar strokeWidth,
    140                                             SkScalar miterLimit) {
    141     if (strokeWidth < 0) {  // fill
    142         return 0;
    143     } else if (0 == strokeWidth) {
    144         return SK_Scalar1;
    145     }
    146     // since we're stroked, outset the rect by the radius (and join type)
    147     SkScalar radius = SkScalarHalf(strokeWidth);
    148     if (SkPaint::kMiter_Join == join) {
    149         if (miterLimit > SK_Scalar1) {
    150             radius *= miterLimit;
    151         }
    152     }
    153     return radius;
    154 }
    155 
    156 SkScalar SkStrokeRec::getInflationRadius() const {
    157     return get_inflation_bounds((SkPaint::Join)fJoin, fWidth, fMiterLimit);
    158 }
    159 
    160 SkScalar SkStrokeRec::GetInflationRadius(const SkPaint& paint, SkPaint::Style style) {
    161     SkScalar width = SkPaint::kFill_Style == style ? -SK_Scalar1 : paint.getStrokeWidth();
    162     return get_inflation_bounds(paint.getStrokeJoin(), width, paint.getStrokeMiter());
    163 
    164 }
    165