• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "config.h"
6 #include "core/paint/ListMarkerPainter.h"
7 
8 #include "core/paint/BlockPainter.h"
9 #include "core/rendering/GraphicsContextAnnotator.h"
10 #include "core/rendering/PaintInfo.h"
11 #include "core/rendering/RenderListItem.h"
12 #include "core/rendering/RenderListMarker.h"
13 #include "core/rendering/TextRunConstructor.h"
14 #include "platform/geometry/LayoutPoint.h"
15 #include "platform/graphics/GraphicsContextStateSaver.h"
16 #include "wtf/unicode/CharacterNames.h"
17 
18 namespace blink {
19 
paint(PaintInfo & paintInfo,const LayoutPoint & paintOffset)20 void ListMarkerPainter::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
21 {
22     ANNOTATE_GRAPHICS_CONTEXT(paintInfo, &m_renderListMarker);
23 
24     if (paintInfo.phase != PaintPhaseForeground)
25         return;
26 
27     if (m_renderListMarker.style()->visibility() != VISIBLE)
28         return;
29 
30     LayoutPoint boxOrigin(paintOffset + m_renderListMarker.location());
31     LayoutRect overflowRect(m_renderListMarker.visualOverflowRect());
32     overflowRect.moveBy(boxOrigin);
33 
34     if (!paintInfo.rect.intersects(pixelSnappedIntRect(overflowRect)))
35         return;
36 
37     LayoutRect box(boxOrigin, m_renderListMarker.size());
38 
39     IntRect marker = m_renderListMarker.getRelativeMarkerRect();
40     marker.moveBy(roundedIntPoint(boxOrigin));
41 
42     GraphicsContext* context = paintInfo.context;
43 
44     if (m_renderListMarker.isImage()) {
45         context->drawImage(m_renderListMarker.image()->image(&m_renderListMarker, marker.size()).get(), marker);
46         if (m_renderListMarker.selectionState() != RenderObject::SelectionNone) {
47             LayoutRect selRect = m_renderListMarker.localSelectionRect();
48             selRect.moveBy(boxOrigin);
49             context->fillRect(pixelSnappedIntRect(selRect), m_renderListMarker.selectionBackgroundColor());
50         }
51         return;
52     }
53 
54     if (m_renderListMarker.selectionState() != RenderObject::SelectionNone) {
55         LayoutRect selRect = m_renderListMarker.localSelectionRect();
56         selRect.moveBy(boxOrigin);
57         context->fillRect(pixelSnappedIntRect(selRect), m_renderListMarker.selectionBackgroundColor());
58     }
59 
60     const Color color(m_renderListMarker.resolveColor(CSSPropertyColor));
61     context->setStrokeColor(color);
62     context->setStrokeStyle(SolidStroke);
63     context->setStrokeThickness(1.0f);
64     context->setFillColor(color);
65 
66     EListStyleType type = m_renderListMarker.style()->listStyleType();
67     switch (type) {
68     case Disc:
69         context->fillEllipse(marker);
70         return;
71     case Circle:
72         context->strokeEllipse(marker);
73         return;
74     case Square:
75         context->fillRect(marker);
76         return;
77     case NoneListStyle:
78         return;
79     case Afar:
80     case Amharic:
81     case AmharicAbegede:
82     case ArabicIndic:
83     case Armenian:
84     case BinaryListStyle:
85     case Bengali:
86     case Cambodian:
87     case CJKIdeographic:
88     case CjkEarthlyBranch:
89     case CjkHeavenlyStem:
90     case DecimalLeadingZero:
91     case DecimalListStyle:
92     case Devanagari:
93     case Ethiopic:
94     case EthiopicAbegede:
95     case EthiopicAbegedeAmEt:
96     case EthiopicAbegedeGez:
97     case EthiopicAbegedeTiEr:
98     case EthiopicAbegedeTiEt:
99     case EthiopicHalehameAaEr:
100     case EthiopicHalehameAaEt:
101     case EthiopicHalehameAmEt:
102     case EthiopicHalehameGez:
103     case EthiopicHalehameOmEt:
104     case EthiopicHalehameSidEt:
105     case EthiopicHalehameSoEt:
106     case EthiopicHalehameTiEr:
107     case EthiopicHalehameTiEt:
108     case EthiopicHalehameTig:
109     case Georgian:
110     case Gujarati:
111     case Gurmukhi:
112     case Hangul:
113     case HangulConsonant:
114     case Hebrew:
115     case Hiragana:
116     case HiraganaIroha:
117     case Kannada:
118     case Katakana:
119     case KatakanaIroha:
120     case Khmer:
121     case Lao:
122     case LowerAlpha:
123     case LowerArmenian:
124     case LowerGreek:
125     case LowerHexadecimal:
126     case LowerLatin:
127     case LowerNorwegian:
128     case LowerRoman:
129     case Malayalam:
130     case Mongolian:
131     case Myanmar:
132     case Octal:
133     case Oriya:
134     case Oromo:
135     case Persian:
136     case Sidama:
137     case Somali:
138     case Telugu:
139     case Thai:
140     case Tibetan:
141     case Tigre:
142     case TigrinyaEr:
143     case TigrinyaErAbegede:
144     case TigrinyaEt:
145     case TigrinyaEtAbegede:
146     case UpperAlpha:
147     case UpperArmenian:
148     case UpperGreek:
149     case UpperHexadecimal:
150     case UpperLatin:
151     case UpperNorwegian:
152     case UpperRoman:
153     case Urdu:
154     case Asterisks:
155     case Footnotes:
156         break;
157     }
158     if (m_renderListMarker.text().isEmpty())
159         return;
160 
161     const Font& font = m_renderListMarker.style()->font();
162     TextRun textRun = constructTextRun(&m_renderListMarker, font, m_renderListMarker.text(), m_renderListMarker.style());
163 
164     GraphicsContextStateSaver stateSaver(*context, false);
165     if (!m_renderListMarker.style()->isHorizontalWritingMode()) {
166         marker.moveBy(roundedIntPoint(-boxOrigin));
167         marker = marker.transposedRect();
168         marker.moveBy(IntPoint(roundToInt(box.x()), roundToInt(box.y() - m_renderListMarker.logicalHeight())));
169         stateSaver.save();
170         context->translate(marker.x(), marker.maxY());
171         context->rotate(static_cast<float>(deg2rad(90.)));
172         context->translate(-marker.x(), -marker.maxY());
173     }
174 
175     TextRunPaintInfo textRunPaintInfo(textRun);
176     textRunPaintInfo.bounds = marker;
177     IntPoint textOrigin = IntPoint(marker.x(), marker.y() + m_renderListMarker.style()->fontMetrics().ascent());
178 
179     if (type == Asterisks || type == Footnotes) {
180         context->drawText(font, textRunPaintInfo, textOrigin);
181     } else {
182         // Text is not arbitrary. We can judge whether it's RTL from the first character,
183         // and we only need to handle the direction RightToLeft for now.
184         bool textNeedsReversing = WTF::Unicode::direction(m_renderListMarker.text()[0]) == WTF::Unicode::RightToLeft;
185         StringBuilder reversedText;
186         if (textNeedsReversing) {
187             int length = m_renderListMarker.text().length();
188             reversedText.reserveCapacity(length);
189             for (int i = length - 1; i >= 0; --i)
190                 reversedText.append(m_renderListMarker.text()[i]);
191             ASSERT(reversedText.length() == reversedText.capacity());
192             textRun.setText(reversedText.toString());
193         }
194 
195         const UChar suffix = m_renderListMarker.listMarkerSuffix(type, m_renderListMarker.listItem()->value());
196         UChar suffixStr[2] = {
197             m_renderListMarker.style()->isLeftToRightDirection() ? suffix : ' ',
198             m_renderListMarker.style()->isLeftToRightDirection() ? ' ' : suffix
199         };
200         TextRun suffixRun = constructTextRun(&m_renderListMarker, font, suffixStr, 2, m_renderListMarker.style(), m_renderListMarker.style()->direction());
201         TextRunPaintInfo suffixRunInfo(suffixRun);
202         suffixRunInfo.bounds = marker;
203 
204         if (m_renderListMarker.style()->isLeftToRightDirection()) {
205             context->drawText(font, textRunPaintInfo, textOrigin);
206             context->drawText(font, suffixRunInfo, textOrigin + IntSize(font.width(textRun), 0));
207         } else {
208             context->drawText(font, suffixRunInfo, textOrigin);
209             context->drawText(font, textRunPaintInfo, textOrigin + IntSize(font.width(suffixRun), 0));
210         }
211     }
212 }
213 
214 } // namespace blink
215