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.
6 #include "core/paint/InlinePainter.h"
8 #include "core/paint/BoxPainter.h"
9 #include "core/paint/LineBoxListPainter.h"
10 #include "core/paint/ObjectPainter.h"
11 #include "core/rendering/GraphicsContextAnnotator.h"
12 #include "core/rendering/PaintInfo.h"
13 #include "core/rendering/RenderInline.h"
14 #include "core/rendering/RenderTheme.h"
15 #include "core/rendering/RootInlineBox.h"
16 #include "platform/geometry/LayoutPoint.h"
20 void InlinePainter::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
22 ANNOTATE_GRAPHICS_CONTEXT(paintInfo, &m_renderInline);
23 LineBoxListPainter(*m_renderInline.lineBoxes()).paint(&m_renderInline, paintInfo, paintOffset);
26 void InlinePainter::paintOutline(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
28 RenderStyle* styleToUse = m_renderInline.style();
29 if (!styleToUse->hasOutline())
32 if (styleToUse->outlineStyleIsAuto()) {
33 if (RenderTheme::theme().shouldDrawDefaultFocusRing(&m_renderInline)) {
34 // Only paint the focus ring by hand if the theme isn't able to draw the focus ring.
35 ObjectPainter(m_renderInline).paintFocusRing(paintInfo, paintOffset, styleToUse);
40 if (styleToUse->outlineStyle() == BNONE)
43 Vector<LayoutRect> rects;
45 rects.append(LayoutRect());
46 for (InlineFlowBox* curr = m_renderInline.firstLineBox(); curr; curr = curr->nextLineBox()) {
47 RootInlineBox& root = curr->root();
48 LayoutUnit top = std::max<LayoutUnit>(root.lineTop(), curr->logicalTop());
49 LayoutUnit bottom = std::min<LayoutUnit>(root.lineBottom(), curr->logicalBottom());
50 rects.append(LayoutRect(curr->x(), top, curr->logicalWidth(), bottom - top));
52 rects.append(LayoutRect());
54 Color outlineColor = m_renderInline.resolveColor(styleToUse, CSSPropertyOutlineColor);
55 bool useTransparencyLayer = outlineColor.hasAlpha();
57 GraphicsContext* graphicsContext = paintInfo.context;
58 if (useTransparencyLayer) {
59 graphicsContext->beginTransparencyLayer(static_cast<float>(outlineColor.alpha()) / 255);
60 outlineColor = Color(outlineColor.red(), outlineColor.green(), outlineColor.blue());
63 for (unsigned i = 1; i < rects.size() - 1; i++)
64 paintOutlineForLine(graphicsContext, paintOffset, rects.at(i - 1), rects.at(i), rects.at(i + 1), outlineColor);
66 if (useTransparencyLayer)
67 graphicsContext->endLayer();
70 void InlinePainter::paintOutlineForLine(GraphicsContext* graphicsContext, const LayoutPoint& paintOffset,
71 const LayoutRect& lastline, const LayoutRect& thisline, const LayoutRect& nextline, const Color outlineColor)
73 RenderStyle* styleToUse = m_renderInline.style();
74 int outlineWidth = styleToUse->outlineWidth();
75 EBorderStyle outlineStyle = styleToUse->outlineStyle();
77 bool antialias = BoxPainter::shouldAntialiasLines(graphicsContext);
79 int offset = m_renderInline.style()->outlineOffset();
81 LayoutRect box(LayoutPoint(paintOffset.x() + thisline.x() - offset, paintOffset.y() + thisline.y() - offset),
82 LayoutSize(thisline.width() + offset, thisline.height() + offset));
84 IntRect pixelSnappedBox = pixelSnappedIntRect(box);
85 if (pixelSnappedBox.width() < 0 || pixelSnappedBox.height() < 0)
87 IntRect pixelSnappedLastLine = pixelSnappedIntRect(paintOffset.x() + lastline.x(), 0, lastline.width(), 0);
88 IntRect pixelSnappedNextLine = pixelSnappedIntRect(paintOffset.x() + nextline.x(), 0, nextline.width(), 0);
91 ObjectPainter::drawLineForBoxSide(graphicsContext,
92 pixelSnappedBox.x() - outlineWidth,
93 pixelSnappedBox.y() - (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.maxX() - 1) <= thisline.x() ? outlineWidth : 0),
95 pixelSnappedBox.maxY() + (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.maxX() - 1) <= thisline.x() ? outlineWidth : 0),
97 outlineColor, outlineStyle,
98 (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.maxX() - 1) <= thisline.x() ? outlineWidth : -outlineWidth),
99 (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.maxX() - 1) <= thisline.x() ? outlineWidth : -outlineWidth),
103 ObjectPainter::drawLineForBoxSide(graphicsContext,
104 pixelSnappedBox.maxX(),
105 pixelSnappedBox.y() - (lastline.isEmpty() || lastline.maxX() < thisline.maxX() || (thisline.maxX() - 1) <= lastline.x() ? outlineWidth : 0),
106 pixelSnappedBox.maxX() + outlineWidth,
107 pixelSnappedBox.maxY() + (nextline.isEmpty() || nextline.maxX() <= thisline.maxX() || (thisline.maxX() - 1) <= nextline.x() ? outlineWidth : 0),
109 outlineColor, outlineStyle,
110 (lastline.isEmpty() || lastline.maxX() < thisline.maxX() || (thisline.maxX() - 1) <= lastline.x() ? outlineWidth : -outlineWidth),
111 (nextline.isEmpty() || nextline.maxX() <= thisline.maxX() || (thisline.maxX() - 1) <= nextline.x() ? outlineWidth : -outlineWidth),
114 if (thisline.x() < lastline.x()) {
115 ObjectPainter::drawLineForBoxSide(graphicsContext,
116 pixelSnappedBox.x() - outlineWidth,
117 pixelSnappedBox.y() - outlineWidth,
118 std::min(pixelSnappedBox.maxX() + outlineWidth, (lastline.isEmpty() ? 1000000 : pixelSnappedLastLine.x())),
120 BSTop, outlineColor, outlineStyle,
122 (!lastline.isEmpty() && paintOffset.x() + lastline.x() + 1 < pixelSnappedBox.maxX() + outlineWidth) ? -outlineWidth : outlineWidth,
126 if (lastline.maxX() < thisline.maxX()) {
127 ObjectPainter::drawLineForBoxSide(graphicsContext,
128 std::max(lastline.isEmpty() ? -1000000 : pixelSnappedLastLine.maxX(), pixelSnappedBox.x() - outlineWidth),
129 pixelSnappedBox.y() - outlineWidth,
130 pixelSnappedBox.maxX() + outlineWidth,
132 BSTop, outlineColor, outlineStyle,
133 (!lastline.isEmpty() && pixelSnappedBox.x() - outlineWidth < paintOffset.x() + lastline.maxX()) ? -outlineWidth : outlineWidth,
134 outlineWidth, antialias);
137 if (thisline.x() == thisline.maxX()) {
138 ObjectPainter::drawLineForBoxSide(graphicsContext,
139 pixelSnappedBox.x() - outlineWidth,
140 pixelSnappedBox.y() - outlineWidth,
141 pixelSnappedBox.maxX() + outlineWidth,
143 BSTop, outlineColor, outlineStyle,
150 if (thisline.x() < nextline.x()) {
151 ObjectPainter::drawLineForBoxSide(graphicsContext,
152 pixelSnappedBox.x() - outlineWidth,
153 pixelSnappedBox.maxY(),
154 std::min(pixelSnappedBox.maxX() + outlineWidth, !nextline.isEmpty() ? pixelSnappedNextLine.x() + 1 : 1000000),
155 pixelSnappedBox.maxY() + outlineWidth,
156 BSBottom, outlineColor, outlineStyle,
158 (!nextline.isEmpty() && paintOffset.x() + nextline.x() + 1 < pixelSnappedBox.maxX() + outlineWidth) ? -outlineWidth : outlineWidth,
162 if (nextline.maxX() < thisline.maxX()) {
163 ObjectPainter::drawLineForBoxSide(graphicsContext,
164 std::max(!nextline.isEmpty() ? pixelSnappedNextLine.maxX() : -1000000, pixelSnappedBox.x() - outlineWidth),
165 pixelSnappedBox.maxY(),
166 pixelSnappedBox.maxX() + outlineWidth,
167 pixelSnappedBox.maxY() + outlineWidth,
168 BSBottom, outlineColor, outlineStyle,
169 (!nextline.isEmpty() && pixelSnappedBox.x() - outlineWidth < paintOffset.x() + nextline.maxX()) ? -outlineWidth : outlineWidth,
170 outlineWidth, antialias);
173 if (thisline.x() == thisline.maxX()) {
174 ObjectPainter::drawLineForBoxSide(graphicsContext,
175 pixelSnappedBox.x() - outlineWidth,
176 pixelSnappedBox.maxY(),
177 pixelSnappedBox.maxX() + outlineWidth,
178 pixelSnappedBox.maxY() + outlineWidth,
179 BSBottom, outlineColor, outlineStyle,