| /* | |
| * 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(SkPathBuilder* 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. | |
| // skbug.com/40039419 | |
| 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; | |
| } | |