Use is<>() / downcast<>() for Element
[WebKit-https.git] / Source / WebCore / rendering / RenderDetailsMarker.cpp
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 #if ENABLE(DETAILS_ELEMENT)
23 #include "RenderDetailsMarker.h"
24
25 #include "Element.h"
26 #include "GraphicsContext.h"
27 #include "HTMLDetailsElement.h"
28 #include "HTMLInputElement.h"
29 #include "HTMLNames.h"
30 #include "PaintInfo.h"
31
32 namespace WebCore {
33
34 using namespace HTMLNames;
35
36 RenderDetailsMarker::RenderDetailsMarker(DetailsMarkerControl& element, PassRef<RenderStyle> style)
37     : RenderBlockFlow(element, WTF::move(style))
38 {
39 }
40
41 static Path createPath(const FloatPoint* path)
42 {
43     Path result;
44     result.moveTo(FloatPoint(path[0].x(), path[0].y()));
45     for (int i = 1; i < 4; ++i)
46         result.addLineTo(FloatPoint(path[i].x(), path[i].y()));
47     return result;
48 }
49
50 static Path createDownArrowPath()
51 {
52     FloatPoint points[4] = { FloatPoint(0.0f, 0.07f), FloatPoint(0.5f, 0.93f), FloatPoint(1.0f, 0.07f), FloatPoint(0.0f, 0.07f) };
53     return createPath(points);
54 }
55
56 static Path createUpArrowPath()
57 {
58     FloatPoint points[4] = { FloatPoint(0.0f, 0.93f), FloatPoint(0.5f, 0.07f), FloatPoint(1.0f, 0.93f), FloatPoint(0.0f, 0.93f) };
59     return createPath(points);
60 }
61
62 static Path createLeftArrowPath()
63 {
64     FloatPoint points[4] = { FloatPoint(1.0f, 0.0f), FloatPoint(0.14f, 0.5f), FloatPoint(1.0f, 1.0f), FloatPoint(1.0f, 0.0f) };
65     return createPath(points);
66 }
67
68 static Path createRightArrowPath()
69 {
70     FloatPoint points[4] = { FloatPoint(0.0f, 0.0f), FloatPoint(0.86f, 0.5f), FloatPoint(0.0f, 1.0f), FloatPoint(0.0f, 0.0f) };
71     return createPath(points);
72 }
73
74 RenderDetailsMarker::Orientation RenderDetailsMarker::orientation() const
75 {
76     switch (style().writingMode()) {
77     case TopToBottomWritingMode:
78         if (style().isLeftToRightDirection())
79             return isOpen() ? Down : Right;
80         return isOpen() ? Down : Left;
81     case RightToLeftWritingMode:
82         if (style().isLeftToRightDirection())
83             return isOpen() ? Left : Down;
84         return isOpen() ? Left : Up;
85     case LeftToRightWritingMode:
86         if (style().isLeftToRightDirection())
87             return isOpen() ? Right : Down;
88         return isOpen() ? Right : Up;
89     case BottomToTopWritingMode:
90         if (style().isLeftToRightDirection())
91             return isOpen() ? Up : Right;
92         return isOpen() ? Up : Left;
93     }
94     return Right;
95 }
96
97 Path RenderDetailsMarker::getCanonicalPath() const
98 {
99     switch (orientation()) {
100     case Left: return createLeftArrowPath();
101     case Right: return createRightArrowPath();
102     case Up: return createUpArrowPath();
103     case Down: return createDownArrowPath();
104     }
105
106     return Path();
107 }
108
109 Path RenderDetailsMarker::getPath(const LayoutPoint& origin) const
110 {
111     Path result = getCanonicalPath();
112     result.transform(AffineTransform().scale(contentWidth(), contentHeight()));
113     result.translate(FloatSize(origin.x(), origin.y()));
114     return result;
115 }
116
117 void RenderDetailsMarker::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
118 {
119     if (paintInfo.phase != PaintPhaseForeground || style().visibility() != VISIBLE) {
120         RenderBlockFlow::paint(paintInfo, paintOffset);
121         return;
122     }
123
124     LayoutPoint boxOrigin(paintOffset + location());
125     LayoutRect overflowRect(visualOverflowRect());
126     overflowRect.moveBy(boxOrigin);
127     overflowRect.inflate(maximalOutlineSize(paintInfo.phase));
128
129     if (!paintInfo.rect.intersects(snappedIntRect(overflowRect)))
130         return;
131
132     const Color color(style().visitedDependentColor(CSSPropertyColor));
133     paintInfo.context->setStrokeColor(color, style().colorSpace());
134     paintInfo.context->setStrokeStyle(SolidStroke);
135     paintInfo.context->setStrokeThickness(1.0f);
136     paintInfo.context->setFillColor(color, style().colorSpace());
137
138     boxOrigin.move(borderLeft() + paddingLeft(), borderTop() + paddingTop());
139     paintInfo.context->fillPath(getPath(boxOrigin));
140 }
141
142 bool RenderDetailsMarker::isOpen() const
143 {
144     for (RenderObject* renderer = parent(); renderer; renderer = renderer->parent()) {
145         if (!renderer->node())
146             continue;
147         if (is<HTMLDetailsElement>(renderer->node()))
148             return !downcast<HTMLDetailsElement>(*renderer->node()).getAttribute(openAttr).isNull();
149         if (is<HTMLInputElement>(renderer->node()))
150             return true;
151     }
152
153     return false;
154 }
155
156 }
157
158 #endif