1521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)// Copyright (C) 2013 Google Inc. All rights reserved.
2521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)//
3521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)// Redistribution and use in source and binary forms, with or without
4521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)// modification, are permitted provided that the following conditions are
5521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)// met:
6521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)//
7521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)//    * Redistributions of source code must retain the above copyright
8521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)// notice, this list of conditions and the following disclaimer.
9521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)//    * Redistributions in binary form must reproduce the above
10521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)// copyright notice, this list of conditions and the following disclaimer
11521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)// in the documentation and/or other materials provided with the
12521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)// distribution.
13521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)//    * Neither the name of Google Inc. nor the names of its
14521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)// contributors may be used to endorse or promote products derived from
15521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)// this software without specific prior written permission.
16521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)//
17521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)
29521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)#include "config.h"
30a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)#include "platform/graphics/StrokeData.h"
311e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include "wtf/OwnPtr.h"
321e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include "wtf/PassOwnPtr.h"
33521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)
34c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)namespace blink {
35521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)
36521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)static const int dashRatio = 3; // Ratio of the length of a dash to its width.
37521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)
38521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)void StrokeData::setLineDash(const DashArray& dashes, float dashOffset)
39521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles){
40521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    // FIXME: This is lifted directly off SkiaSupport, lines 49-74
41521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    // so it is not guaranteed to work correctly.
42521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    size_t dashLength = dashes.size();
43521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    if (!dashLength) {
44521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)        // If no dash is set, revert to solid stroke
45521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)        // FIXME: do we need to set NoStroke in some cases?
46521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)        m_style = SolidStroke;
477757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        m_dash.clear();
48521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)        return;
49521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    }
50521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)
51521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    size_t count = !(dashLength % 2) ? dashLength : dashLength * 2;
521e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)    OwnPtr<SkScalar[]> intervals = adoptArrayPtr(new SkScalar[count]);
53521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)
54521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    for (unsigned i = 0; i < count; i++)
55521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)        intervals[i] = dashes[i % dashLength];
56521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)
5710f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch    m_dash = adoptRef(SkDashPathEffect::Create(intervals.get(), count, dashOffset));
58521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)}
59521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)
60d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)void StrokeData::setupPaint(SkPaint* paint, int length) const
61521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles){
62521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    paint->setStyle(SkPaint::kStroke_Style);
63d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    paint->setStrokeWidth(SkFloatToScalar(m_thickness));
64521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    paint->setStrokeCap(m_lineCap);
65521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    paint->setStrokeJoin(m_lineJoin);
66521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    paint->setStrokeMiter(SkFloatToScalar(m_miterLimit));
67521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)
68d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    setupPaintDashPathEffect(paint, length);
69d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)}
70d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
71d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)void StrokeData::setupPaintDashPathEffect(SkPaint* paint, int length) const
72d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles){
73d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    float width = m_thickness;
74521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    if (m_dash) {
757757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch        paint->setPathEffect(m_dash.get());
76521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    } else {
77521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)        switch (m_style) {
78521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)        case NoStroke:
79521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)        case SolidStroke:
80521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)        case DoubleStroke:
81521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)        case WavyStroke: // FIXME: https://code.google.com/p/chromium/issues/detail?id=229574
82d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            paint->setPathEffect(0);
83d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            return;
84521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)        case DashedStroke:
85521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)            width = dashRatio * width;
86521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)            // Fall through.
87521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)        case DottedStroke:
88521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)            // Truncate the width, since we don't want fuzzy dots or dashes.
89521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)            int dashLength = static_cast<int>(width);
90521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)            // Subtract off the endcaps, since they're rendered separately.
91521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)            int distance = length - 2 * static_cast<int>(m_thickness);
92521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)            int phase = 1;
93521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)            if (dashLength > 1) {
94521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)                // Determine how many dashes or dots we should have.
95521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)                int numDashes = distance / dashLength;
96521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)                int remainder = distance % dashLength;
97521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)                // Adjust the phase to center the dashes within the line.
98521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)                if (numDashes % 2) {
99521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)                    // Odd: shift right a full dash, minus half the remainder.
100521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)                    phase = dashLength - remainder / 2;
101521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)                } else {
102521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)                    // Even: shift right half a dash, minus half the remainder.
103521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)                    phase = (dashLength - remainder) / 2;
104521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)                }
105521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)            }
106521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)            SkScalar dashLengthSk = SkIntToScalar(dashLength);
107521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)            SkScalar intervals[2] = { dashLengthSk, dashLengthSk };
10810f88d5669dbd969c059d61ba09fa37dd72ac559Ben Murdoch            RefPtr<SkDashPathEffect> pathEffect = adoptRef(SkDashPathEffect::Create(intervals, 2, SkIntToScalar(phase)));
1097757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch            paint->setPathEffect(pathEffect.get());
110521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)        }
111521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    }
112521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)}
113521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)
114e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)} // namespace blink
115