1 | /* |
2 | * Copyright (C) 2010, 2011 Nokia Corporation and/or its subsidiary(-ies) |
3 | * |
4 | * This library is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU Library General Public |
6 | * License as published by the Free Software Foundation; either |
7 | * version 2 of the License, or (at your option) any later version. |
8 | * |
9 | * This library is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | * Library General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU Library General Public License |
15 | * along with this library; see the file COPYING.LIB. If not, write to |
16 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
17 | * Boston, MA 02110-1301, USA. |
18 | * |
19 | */ |
20 | |
21 | #include "config.h" |
22 | #include "RenderDetailsMarker.h" |
23 | |
24 | #include "Element.h" |
25 | #include "GraphicsContext.h" |
26 | #include "HTMLDetailsElement.h" |
27 | #include "HTMLInputElement.h" |
28 | #include "HTMLNames.h" |
29 | #include "PaintInfo.h" |
30 | #include <wtf/IsoMallocInlines.h> |
31 | |
32 | namespace WebCore { |
33 | |
34 | using namespace HTMLNames; |
35 | |
36 | WTF_MAKE_ISO_ALLOCATED_IMPL(RenderDetailsMarker); |
37 | |
38 | RenderDetailsMarker::RenderDetailsMarker(DetailsMarkerControl& element, RenderStyle&& style) |
39 | : RenderBlockFlow(element, WTFMove(style)) |
40 | { |
41 | } |
42 | |
43 | static Path createPath(const FloatPoint* path) |
44 | { |
45 | Path result; |
46 | result.moveTo(FloatPoint(path[0].x(), path[0].y())); |
47 | for (int i = 1; i < 4; ++i) |
48 | result.addLineTo(FloatPoint(path[i].x(), path[i].y())); |
49 | return result; |
50 | } |
51 | |
52 | static Path createDownArrowPath() |
53 | { |
54 | FloatPoint points[4] = { FloatPoint(0.0f, 0.07f), FloatPoint(0.5f, 0.93f), FloatPoint(1.0f, 0.07f), FloatPoint(0.0f, 0.07f) }; |
55 | return createPath(points); |
56 | } |
57 | |
58 | static Path createUpArrowPath() |
59 | { |
60 | FloatPoint points[4] = { FloatPoint(0.0f, 0.93f), FloatPoint(0.5f, 0.07f), FloatPoint(1.0f, 0.93f), FloatPoint(0.0f, 0.93f) }; |
61 | return createPath(points); |
62 | } |
63 | |
64 | static Path createLeftArrowPath() |
65 | { |
66 | FloatPoint points[4] = { FloatPoint(1.0f, 0.0f), FloatPoint(0.14f, 0.5f), FloatPoint(1.0f, 1.0f), FloatPoint(1.0f, 0.0f) }; |
67 | return createPath(points); |
68 | } |
69 | |
70 | static Path createRightArrowPath() |
71 | { |
72 | FloatPoint points[4] = { FloatPoint(0.0f, 0.0f), FloatPoint(0.86f, 0.5f), FloatPoint(0.0f, 1.0f), FloatPoint(0.0f, 0.0f) }; |
73 | return createPath(points); |
74 | } |
75 | |
76 | RenderDetailsMarker::Orientation RenderDetailsMarker::orientation() const |
77 | { |
78 | switch (style().writingMode()) { |
79 | case TopToBottomWritingMode: |
80 | if (style().isLeftToRightDirection()) |
81 | return isOpen() ? Down : Right; |
82 | return isOpen() ? Down : Left; |
83 | case RightToLeftWritingMode: |
84 | if (style().isLeftToRightDirection()) |
85 | return isOpen() ? Left : Down; |
86 | return isOpen() ? Left : Up; |
87 | case LeftToRightWritingMode: |
88 | if (style().isLeftToRightDirection()) |
89 | return isOpen() ? Right : Down; |
90 | return isOpen() ? Right : Up; |
91 | case BottomToTopWritingMode: |
92 | if (style().isLeftToRightDirection()) |
93 | return isOpen() ? Up : Right; |
94 | return isOpen() ? Up : Left; |
95 | } |
96 | return Right; |
97 | } |
98 | |
99 | Path RenderDetailsMarker::getCanonicalPath() const |
100 | { |
101 | switch (orientation()) { |
102 | case Left: return createLeftArrowPath(); |
103 | case Right: return createRightArrowPath(); |
104 | case Up: return createUpArrowPath(); |
105 | case Down: return createDownArrowPath(); |
106 | } |
107 | |
108 | return Path(); |
109 | } |
110 | |
111 | Path RenderDetailsMarker::getPath(const LayoutPoint& origin) const |
112 | { |
113 | Path result = getCanonicalPath(); |
114 | result.transform(AffineTransform().scale(contentWidth(), contentHeight())); |
115 | result.translate(FloatSize(origin.x(), origin.y())); |
116 | return result; |
117 | } |
118 | |
119 | void RenderDetailsMarker::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) |
120 | { |
121 | if (paintInfo.phase != PaintPhase::Foreground || style().visibility() != Visibility::Visible) { |
122 | RenderBlockFlow::paint(paintInfo, paintOffset); |
123 | return; |
124 | } |
125 | |
126 | LayoutPoint boxOrigin(paintOffset + location()); |
127 | LayoutRect overflowRect(visualOverflowRect()); |
128 | overflowRect.moveBy(boxOrigin); |
129 | |
130 | if (!paintInfo.rect.intersects(snappedIntRect(overflowRect))) |
131 | return; |
132 | |
133 | const Color color(style().visitedDependentColorWithColorFilter(CSSPropertyColor)); |
134 | paintInfo.context().setStrokeColor(color); |
135 | paintInfo.context().setStrokeStyle(SolidStroke); |
136 | paintInfo.context().setStrokeThickness(1.0f); |
137 | paintInfo.context().setFillColor(color); |
138 | |
139 | boxOrigin.move(borderLeft() + paddingLeft(), borderTop() + paddingTop()); |
140 | paintInfo.context().fillPath(getPath(boxOrigin)); |
141 | } |
142 | |
143 | bool RenderDetailsMarker::isOpen() const |
144 | { |
145 | for (RenderObject* renderer = parent(); renderer; renderer = renderer->parent()) { |
146 | if (!renderer->node()) |
147 | continue; |
148 | if (is<HTMLDetailsElement>(*renderer->node())) |
149 | return !downcast<HTMLDetailsElement>(*renderer->node()).attributeWithoutSynchronization(openAttr).isNull(); |
150 | if (is<HTMLInputElement>(*renderer->node())) |
151 | return true; |
152 | } |
153 | |
154 | return false; |
155 | } |
156 | |
157 | } |
158 | |