15f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com/*
25f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com * Copyright 2012 Google Inc.
35f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com *
45f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com * Use of this source code is governed by a BSD-style license that can be
55f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com * found in the LICENSE file.
65f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com */
75f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com
85f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com#include "SkStrokeRec.h"
95f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com#include "SkPaintDefaults.h"
105f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com
115f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com// must be < 0, since ==0 means hairline, and >0 means normal stroke
125f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com#define kStrokeRec_FillStyleWidth     (-SK_Scalar1)
135f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com
145f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.comSkStrokeRec::SkStrokeRec(InitStyle s) {
1505d9044de4f1c6e791df66a425638752daac4c6breed    fResScale       = 1;
165f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com    fWidth          = (kFill_InitStyle == s) ? kStrokeRec_FillStyleWidth : 0;
175f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com    fMiterLimit     = SkPaintDefaults_MiterLimit;
185f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com    fCap            = SkPaint::kDefault_Cap;
195f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com    fJoin           = SkPaint::kDefault_Join;
205f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com    fStrokeAndFill  = false;
215f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com}
225f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com
2305d9044de4f1c6e791df66a425638752daac4c6breedSkStrokeRec::SkStrokeRec(const SkPaint& paint, SkScalar resScale) {
2405d9044de4f1c6e791df66a425638752daac4c6breed    this->init(paint, paint.getStyle(), resScale);
25e61c411c1258a323a010558c08de3d9f8d170dcaegdaniel}
26e61c411c1258a323a010558c08de3d9f8d170dcaegdaniel
2705d9044de4f1c6e791df66a425638752daac4c6breedSkStrokeRec::SkStrokeRec(const SkPaint& paint, SkPaint::Style styleOverride, SkScalar resScale) {
2805d9044de4f1c6e791df66a425638752daac4c6breed    this->init(paint, styleOverride, resScale);
29e61c411c1258a323a010558c08de3d9f8d170dcaegdaniel}
30e61c411c1258a323a010558c08de3d9f8d170dcaegdaniel
3105d9044de4f1c6e791df66a425638752daac4c6breedvoid SkStrokeRec::init(const SkPaint& paint, SkPaint::Style style, SkScalar resScale) {
3205d9044de4f1c6e791df66a425638752daac4c6breed    fResScale = resScale;
3305d9044de4f1c6e791df66a425638752daac4c6breed
34e61c411c1258a323a010558c08de3d9f8d170dcaegdaniel    switch (style) {
355f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com        case SkPaint::kFill_Style:
365f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com            fWidth = kStrokeRec_FillStyleWidth;
375f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com            fStrokeAndFill = false;
385f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com            break;
395f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com        case SkPaint::kStroke_Style:
405f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com            fWidth = paint.getStrokeWidth();
415f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com            fStrokeAndFill = false;
425f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com            break;
435f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com        case SkPaint::kStrokeAndFill_Style:
445f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com            if (0 == paint.getStrokeWidth()) {
455f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com                // hairline+fill == fill
465f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com                fWidth = kStrokeRec_FillStyleWidth;
475f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com                fStrokeAndFill = false;
485f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com            } else {
495f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com                fWidth = paint.getStrokeWidth();
505f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com                fStrokeAndFill = true;
515f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com            }
525f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com            break;
535f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com        default:
54330313a8a8343876ee596da39da06a5d69badd9cmtklein@google.com            SkDEBUGFAIL("unknown paint style");
555f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com            // fall back on just fill
565f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com            fWidth = kStrokeRec_FillStyleWidth;
575f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com            fStrokeAndFill = false;
585f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com            break;
595f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com    }
605f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com
615f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com    // copy these from the paint, regardless of our "style"
625f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com    fMiterLimit = paint.getStrokeMiter();
635f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com    fCap        = paint.getStrokeCap();
645f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com    fJoin       = paint.getStrokeJoin();
655f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com}
665f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com
675f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.comSkStrokeRec::Style SkStrokeRec::getStyle() const {
685f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com    if (fWidth < 0) {
695f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com        return kFill_Style;
705f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com    } else if (0 == fWidth) {
715f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com        return kHairline_Style;
725f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com    } else {
735f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com        return fStrokeAndFill ? kStrokeAndFill_Style : kStroke_Style;
745f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com    }
755f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com}
765f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com
775f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.comvoid SkStrokeRec::setFillStyle() {
785f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com    fWidth = kStrokeRec_FillStyleWidth;
795f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com    fStrokeAndFill = false;
805f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com}
815f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com
825f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.comvoid SkStrokeRec::setHairlineStyle() {
835f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com    fWidth = 0;
845f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com    fStrokeAndFill = false;
855f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com}
865f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com
875f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.comvoid SkStrokeRec::setStrokeStyle(SkScalar width, bool strokeAndFill) {
885f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com    if (strokeAndFill && (0 == width)) {
895f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com        // hairline+fill == fill
905f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com        this->setFillStyle();
915f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com    } else {
925f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com        fWidth = width;
935f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com        fStrokeAndFill = strokeAndFill;
945f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com    }
955f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com}
965f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com
975f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com#include "SkStroke.h"
985f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com
999d524f22bfde5dc3dc8f48e1be39bdebd3bb0304halcanary#ifdef SK_DEBUG
10004e4d08556750ff6be4576a4cd4925964c63376fcaryclark    // enables tweaking these values at runtime from SampleApp
10104e4d08556750ff6be4576a4cd4925964c63376fcaryclark    bool gDebugStrokerErrorSet = false;
10204e4d08556750ff6be4576a4cd4925964c63376fcaryclark    SkScalar gDebugStrokerError;
10304e4d08556750ff6be4576a4cd4925964c63376fcaryclark#endif
10404e4d08556750ff6be4576a4cd4925964c63376fcaryclark
1055f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.combool SkStrokeRec::applyToPath(SkPath* dst, const SkPath& src) const {
1065f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com    if (fWidth <= 0) {  // hairline or fill
1075f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com        return false;
1085f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com    }
1095f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com
1105f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com    SkStroke stroker;
111897c9937636c2287bb217c76da9a56afb43050acjvanverth    stroker.setCap((SkPaint::Cap)fCap);
112897c9937636c2287bb217c76da9a56afb43050acjvanverth    stroker.setJoin((SkPaint::Join)fJoin);
1135f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com    stroker.setMiterLimit(fMiterLimit);
1145f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com    stroker.setWidth(fWidth);
1155f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com    stroker.setDoFill(fStrokeAndFill);
116a76b7a3b04bc0e937921a1eb38d713c619e60e4ecaryclark#ifdef SK_DEBUG
11704e4d08556750ff6be4576a4cd4925964c63376fcaryclark    stroker.setResScale(gDebugStrokerErrorSet ? gDebugStrokerError : fResScale);
11804e4d08556750ff6be4576a4cd4925964c63376fcaryclark#else
11905d9044de4f1c6e791df66a425638752daac4c6breed    stroker.setResScale(fResScale);
120feff7d2d7719f52c7ea52db156003e609002bf04caryclark#endif
1215f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com    stroker.strokePath(src, dst);
1225f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com    return true;
1235f74cf8c49701f514b69dc6f1a8b5c0ffd78af0asugoi@google.com}
12420b373cf3116905fc5ca1928c9b504851335ca43cdalton
12520b373cf3116905fc5ca1928c9b504851335ca43cdaltonvoid SkStrokeRec::applyToPaint(SkPaint* paint) const {
12620b373cf3116905fc5ca1928c9b504851335ca43cdalton    if (fWidth < 0) {  // fill
12720b373cf3116905fc5ca1928c9b504851335ca43cdalton        paint->setStyle(SkPaint::kFill_Style);
12820b373cf3116905fc5ca1928c9b504851335ca43cdalton        return;
12920b373cf3116905fc5ca1928c9b504851335ca43cdalton    }
13020b373cf3116905fc5ca1928c9b504851335ca43cdalton
13120b373cf3116905fc5ca1928c9b504851335ca43cdalton    paint->setStyle(fStrokeAndFill ? SkPaint::kStrokeAndFill_Style : SkPaint::kStroke_Style);
13220b373cf3116905fc5ca1928c9b504851335ca43cdalton    paint->setStrokeWidth(fWidth);
13320b373cf3116905fc5ca1928c9b504851335ca43cdalton    paint->setStrokeMiter(fMiterLimit);
134897c9937636c2287bb217c76da9a56afb43050acjvanverth    paint->setStrokeCap((SkPaint::Cap)fCap);
135897c9937636c2287bb217c76da9a56afb43050acjvanverth    paint->setStrokeJoin((SkPaint::Join)fJoin);
13620b373cf3116905fc5ca1928c9b504851335ca43cdalton}
1375668648e875abe0a064caabef432ade4745deb89bsalomon
1385668648e875abe0a064caabef432ade4745deb89bsalomonstatic inline SkScalar get_inflation_bounds(SkPaint::Join join,
1395668648e875abe0a064caabef432ade4745deb89bsalomon                                            SkScalar strokeWidth,
1405668648e875abe0a064caabef432ade4745deb89bsalomon                                            SkScalar miterLimit) {
1415668648e875abe0a064caabef432ade4745deb89bsalomon    if (strokeWidth < 0) {  // fill
1425668648e875abe0a064caabef432ade4745deb89bsalomon        return 0;
1435668648e875abe0a064caabef432ade4745deb89bsalomon    } else if (0 == strokeWidth) {
1445668648e875abe0a064caabef432ade4745deb89bsalomon        return SK_Scalar1;
1455668648e875abe0a064caabef432ade4745deb89bsalomon    }
1465668648e875abe0a064caabef432ade4745deb89bsalomon    // since we're stroked, outset the rect by the radius (and join type)
1475668648e875abe0a064caabef432ade4745deb89bsalomon    SkScalar radius = SkScalarHalf(strokeWidth);
1485668648e875abe0a064caabef432ade4745deb89bsalomon    if (SkPaint::kMiter_Join == join) {
1495668648e875abe0a064caabef432ade4745deb89bsalomon        if (miterLimit > SK_Scalar1) {
150a99b6ceff92183b424634f2e7276b9ea1d59e69dMike Reed            radius *= miterLimit;
1515668648e875abe0a064caabef432ade4745deb89bsalomon        }
1525668648e875abe0a064caabef432ade4745deb89bsalomon    }
1535668648e875abe0a064caabef432ade4745deb89bsalomon    return radius;
1545668648e875abe0a064caabef432ade4745deb89bsalomon}
1555668648e875abe0a064caabef432ade4745deb89bsalomon
1565668648e875abe0a064caabef432ade4745deb89bsalomonSkScalar SkStrokeRec::getInflationRadius() const {
1575668648e875abe0a064caabef432ade4745deb89bsalomon    return get_inflation_bounds((SkPaint::Join)fJoin, fWidth, fMiterLimit);
1585668648e875abe0a064caabef432ade4745deb89bsalomon}
1595668648e875abe0a064caabef432ade4745deb89bsalomon
1605668648e875abe0a064caabef432ade4745deb89bsalomonSkScalar SkStrokeRec::GetInflationRadius(const SkPaint& paint, SkPaint::Style style) {
1615668648e875abe0a064caabef432ade4745deb89bsalomon    SkScalar width = SkPaint::kFill_Style == style ? -SK_Scalar1 : paint.getStrokeWidth();
1625668648e875abe0a064caabef432ade4745deb89bsalomon    return get_inflation_bounds(paint.getStrokeJoin(), width, paint.getStrokeMiter());
1635668648e875abe0a064caabef432ade4745deb89bsalomon
1645668648e875abe0a064caabef432ade4745deb89bsalomon}
165