| /* | 
 |  * Copyright 2012 Google Inc. | 
 |  * | 
 |  * Use of this source code is governed by a BSD-style license that can be | 
 |  * found in the LICENSE file. | 
 |  */ | 
 |  | 
 | #include "include/core/SkStrokeRec.h" | 
 |  | 
 | #include "src/core/SkPaintDefaults.h" | 
 | #include "src/core/SkStroke.h" | 
 |  | 
 | #include <algorithm> | 
 |  | 
 | // must be < 0, since ==0 means hairline, and >0 means normal stroke | 
 | #define kStrokeRec_FillStyleWidth     (-SK_Scalar1) | 
 |  | 
 | SkStrokeRec::SkStrokeRec(InitStyle s) { | 
 |     fResScale       = 1; | 
 |     fWidth          = (kFill_InitStyle == s) ? kStrokeRec_FillStyleWidth : 0; | 
 |     fMiterLimit     = SkPaintDefaults_MiterLimit; | 
 |     fCap            = SkPaint::kDefault_Cap; | 
 |     fJoin           = SkPaint::kDefault_Join; | 
 |     fStrokeAndFill  = false; | 
 | } | 
 |  | 
 | SkStrokeRec::SkStrokeRec(const SkPaint& paint, SkScalar resScale) { | 
 |     this->init(paint, paint.getStyle(), resScale); | 
 | } | 
 |  | 
 | SkStrokeRec::SkStrokeRec(const SkPaint& paint, SkPaint::Style styleOverride, SkScalar resScale) { | 
 |     this->init(paint, styleOverride, resScale); | 
 | } | 
 |  | 
 | void SkStrokeRec::init(const SkPaint& paint, SkPaint::Style style, SkScalar resScale) { | 
 |     fResScale = resScale; | 
 |  | 
 |     switch (style) { | 
 |         case SkPaint::kFill_Style: | 
 |             fWidth = kStrokeRec_FillStyleWidth; | 
 |             fStrokeAndFill = false; | 
 |             break; | 
 |         case SkPaint::kStroke_Style: | 
 |             fWidth = paint.getStrokeWidth(); | 
 |             fStrokeAndFill = false; | 
 |             break; | 
 |         case SkPaint::kStrokeAndFill_Style: | 
 |             if (0 == paint.getStrokeWidth()) { | 
 |                 // hairline+fill == fill | 
 |                 fWidth = kStrokeRec_FillStyleWidth; | 
 |                 fStrokeAndFill = false; | 
 |             } else { | 
 |                 fWidth = paint.getStrokeWidth(); | 
 |                 fStrokeAndFill = true; | 
 |             } | 
 |             break; | 
 |         default: | 
 |             SkDEBUGFAIL("unknown paint style"); | 
 |             // fall back on just fill | 
 |             fWidth = kStrokeRec_FillStyleWidth; | 
 |             fStrokeAndFill = false; | 
 |             break; | 
 |     } | 
 |  | 
 |     // copy these from the paint, regardless of our "style" | 
 |     fMiterLimit = paint.getStrokeMiter(); | 
 |     fCap        = paint.getStrokeCap(); | 
 |     fJoin       = paint.getStrokeJoin(); | 
 | } | 
 |  | 
 | SkStrokeRec::Style SkStrokeRec::getStyle() const { | 
 |     if (fWidth < 0) { | 
 |         return kFill_Style; | 
 |     } else if (0 == fWidth) { | 
 |         return kHairline_Style; | 
 |     } else { | 
 |         return fStrokeAndFill ? kStrokeAndFill_Style : kStroke_Style; | 
 |     } | 
 | } | 
 |  | 
 | void SkStrokeRec::setFillStyle() { | 
 |     fWidth = kStrokeRec_FillStyleWidth; | 
 |     fStrokeAndFill = false; | 
 | } | 
 |  | 
 | void SkStrokeRec::setHairlineStyle() { | 
 |     fWidth = 0; | 
 |     fStrokeAndFill = false; | 
 | } | 
 |  | 
 | void SkStrokeRec::setStrokeStyle(SkScalar width, bool strokeAndFill) { | 
 |     if (strokeAndFill && (0 == width)) { | 
 |         // hairline+fill == fill | 
 |         this->setFillStyle(); | 
 |     } else { | 
 |         fWidth = width; | 
 |         fStrokeAndFill = strokeAndFill; | 
 |     } | 
 | } | 
 |  | 
 | #ifdef SK_DEBUG | 
 |     // enables tweaking these values at runtime from Viewer | 
 |     bool gDebugStrokerErrorSet = false; | 
 |     SkScalar gDebugStrokerError; | 
 | #endif | 
 |  | 
 | bool SkStrokeRec::applyToPath(SkPath* dst, const SkPath& src) const { | 
 |     if (fWidth <= 0) {  // hairline or fill | 
 |         return false; | 
 |     } | 
 |  | 
 |     SkStroke stroker; | 
 |     stroker.setCap((SkPaint::Cap)fCap); | 
 |     stroker.setJoin((SkPaint::Join)fJoin); | 
 |     stroker.setMiterLimit(fMiterLimit); | 
 |     stroker.setWidth(fWidth); | 
 |     stroker.setDoFill(fStrokeAndFill); | 
 | #ifdef SK_DEBUG | 
 |     stroker.setResScale(gDebugStrokerErrorSet ? gDebugStrokerError : fResScale); | 
 | #else | 
 |     stroker.setResScale(fResScale); | 
 | #endif | 
 |     stroker.strokePath(src, dst); | 
 |     return true; | 
 | } | 
 |  | 
 | void SkStrokeRec::applyToPaint(SkPaint* paint) const { | 
 |     if (fWidth < 0) {  // fill | 
 |         paint->setStyle(SkPaint::kFill_Style); | 
 |         return; | 
 |     } | 
 |  | 
 |     paint->setStyle(fStrokeAndFill ? SkPaint::kStrokeAndFill_Style : SkPaint::kStroke_Style); | 
 |     paint->setStrokeWidth(fWidth); | 
 |     paint->setStrokeMiter(fMiterLimit); | 
 |     paint->setStrokeCap((SkPaint::Cap)fCap); | 
 |     paint->setStrokeJoin((SkPaint::Join)fJoin); | 
 | } | 
 |  | 
 | SkScalar SkStrokeRec::getInflationRadius() const { | 
 |     return GetInflationRadius((SkPaint::Join)fJoin, fMiterLimit, (SkPaint::Cap)fCap, fWidth); | 
 | } | 
 |  | 
 | SkScalar SkStrokeRec::GetInflationRadius(const SkPaint& paint, SkPaint::Style style) { | 
 |     SkScalar width = SkPaint::kFill_Style == style ? -SK_Scalar1 : paint.getStrokeWidth(); | 
 |     return GetInflationRadius(paint.getStrokeJoin(), paint.getStrokeMiter(), paint.getStrokeCap(), | 
 |                               width); | 
 |  | 
 | } | 
 |  | 
 | SkScalar SkStrokeRec::GetInflationRadius(SkPaint::Join join, SkScalar miterLimit, SkPaint::Cap cap, | 
 |                                          SkScalar strokeWidth) { | 
 |     if (strokeWidth < 0) {  // fill | 
 |         return 0; | 
 |     } else if (0 == strokeWidth) { | 
 |         // FIXME: We need a "matrixScale" parameter here in order to properly handle hairlines. | 
 |         // Their with is determined in device space, unlike other strokes. | 
 |         // http://skbug.com/8157 | 
 |         return SK_Scalar1; | 
 |     } | 
 |  | 
 |     // since we're stroked, outset the rect by the radius (and join type, caps) | 
 |     SkScalar multiplier = SK_Scalar1; | 
 |     if (SkPaint::kMiter_Join == join) { | 
 |         multiplier = std::max(multiplier, miterLimit); | 
 |     } | 
 |     if (SkPaint::kSquare_Cap == cap) { | 
 |         multiplier = std::max(multiplier, SK_ScalarSqrt2); | 
 |     } | 
 |     return strokeWidth/2 * multiplier; | 
 | } | 
 |  |