Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(823)

Unified Diff: Source/core/paint/ObjectPainter.cpp

Issue 591613003: Move painting code from RenderObject into a new ObjectPainter class. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Merge again. Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/core/paint/ObjectPainter.h ('k') | Source/core/rendering/RenderInline.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/core/paint/ObjectPainter.cpp
diff --git a/Source/core/paint/ObjectPainter.cpp b/Source/core/paint/ObjectPainter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9663588702297dae5dbfeb990067034263ed236c
--- /dev/null
+++ b/Source/core/paint/ObjectPainter.cpp
@@ -0,0 +1,349 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "config.h"
+#include "core/paint/ObjectPainter.h"
+
+#include "core/rendering/PaintInfo.h"
+#include "core/rendering/RenderObject.h"
+#include "core/rendering/RenderTheme.h"
+#include "core/rendering/style/RenderStyle.h"
+#include "platform/geometry/LayoutPoint.h"
+#include "platform/graphics/GraphicsContextStateSaver.h"
+
+namespace blink {
+
+void ObjectPainter::paintFocusRing(PaintInfo& paintInfo, const LayoutPoint& paintOffset, RenderStyle* style)
+{
+ Vector<LayoutRect> focusRingRects;
+ m_renderObject.addFocusRingRects(focusRingRects, paintOffset, paintInfo.paintContainer());
+ ASSERT(style->outlineStyleIsAuto());
+ Vector<IntRect> focusRingIntRects;
+ for (size_t i = 0; i < focusRingRects.size(); ++i)
+ focusRingIntRects.append(pixelSnappedIntRect(focusRingRects[i]));
+ paintInfo.context->drawFocusRing(focusRingIntRects, style->outlineWidth(), style->outlineOffset(), m_renderObject.resolveColor(style, CSSPropertyOutlineColor));
+}
+
+void ObjectPainter::paintOutline(PaintInfo& paintInfo, const LayoutRect& paintRect)
+{
+ RenderStyle* styleToUse = m_renderObject.style();
+ if (!styleToUse->hasOutline())
+ return;
+
+ LayoutUnit outlineWidth = styleToUse->outlineWidth();
+
+ int outlineOffset = styleToUse->outlineOffset();
+
+ if (styleToUse->outlineStyleIsAuto()) {
+ if (RenderTheme::theme().shouldDrawDefaultFocusRing(&m_renderObject)) {
+ // Only paint the focus ring by hand if the theme isn't able to draw the focus ring.
+ paintFocusRing(paintInfo, paintRect.location(), styleToUse);
+ }
+ return;
+ }
+
+ if (styleToUse->outlineStyle() == BNONE)
+ return;
+
+ IntRect inner = pixelSnappedIntRect(paintRect);
+ inner.inflate(outlineOffset);
+
+ IntRect outer = pixelSnappedIntRect(inner);
+ outer.inflate(outlineWidth);
+
+ // FIXME: This prevents outlines from painting inside the object. See bug 12042
+ if (outer.isEmpty())
+ return;
+
+ EBorderStyle outlineStyle = styleToUse->outlineStyle();
+ Color outlineColor = m_renderObject.resolveColor(styleToUse, CSSPropertyOutlineColor);
+
+ GraphicsContext* graphicsContext = paintInfo.context;
+ bool useTransparencyLayer = outlineColor.hasAlpha();
+ if (useTransparencyLayer) {
+ if (outlineStyle == SOLID) {
+ Path path;
+ path.addRect(outer);
+ path.addRect(inner);
+ graphicsContext->setFillRule(RULE_EVENODD);
+ graphicsContext->setFillColor(outlineColor);
+ graphicsContext->fillPath(path);
+ return;
+ }
+ graphicsContext->beginTransparencyLayer(static_cast<float>(outlineColor.alpha()) / 255);
+ outlineColor = Color(outlineColor.red(), outlineColor.green(), outlineColor.blue());
+ }
+
+ int leftOuter = outer.x();
+ int leftInner = inner.x();
+ int rightOuter = outer.maxX();
+ int rightInner = inner.maxX();
+ int topOuter = outer.y();
+ int topInner = inner.y();
+ int bottomOuter = outer.maxY();
+ int bottomInner = inner.maxY();
+
+ drawLineForBoxSide(graphicsContext, leftOuter, topOuter, leftInner, bottomOuter, BSLeft, outlineColor, outlineStyle, outlineWidth, outlineWidth);
+ drawLineForBoxSide(graphicsContext, leftOuter, topOuter, rightOuter, topInner, BSTop, outlineColor, outlineStyle, outlineWidth, outlineWidth);
+ drawLineForBoxSide(graphicsContext, rightInner, topOuter, rightOuter, bottomOuter, BSRight, outlineColor, outlineStyle, outlineWidth, outlineWidth);
+ drawLineForBoxSide(graphicsContext, leftOuter, bottomInner, rightOuter, bottomOuter, BSBottom, outlineColor, outlineStyle, outlineWidth, outlineWidth);
+
+ if (useTransparencyLayer)
+ graphicsContext->endLayer();
+}
+
+void ObjectPainter::drawLineForBoxSide(GraphicsContext* graphicsContext, int x1, int y1, int x2, int y2,
+ BoxSide side, Color color, EBorderStyle style,
+ int adjacentWidth1, int adjacentWidth2, bool antialias)
+{
+ int thickness;
+ int length;
+ if (side == BSTop || side == BSBottom) {
+ thickness = y2 - y1;
+ length = x2 - x1;
+ } else {
+ thickness = x2 - x1;
+ length = y2 - y1;
+ }
+
+ // FIXME: We really would like this check to be an ASSERT as we don't want to draw empty borders. However
+ // nothing guarantees that the following recursive calls to drawLineForBoxSide will have non-null dimensions.
+ if (!thickness || !length)
+ return;
+
+ if (style == DOUBLE && thickness < 3)
+ style = SOLID;
+
+ switch (style) {
+ case BNONE:
+ case BHIDDEN:
+ return;
+ case DOTTED:
+ case DASHED:
+ drawDashedOrDottedBoxSide(graphicsContext, x1, y1, x2, y2, side,
+ color, thickness, style, antialias);
+ break;
+ case DOUBLE:
+ drawDoubleBoxSide(graphicsContext, x1, y1, x2, y2, length, side, color,
+ thickness, adjacentWidth1, adjacentWidth2, antialias);
+ break;
+ case RIDGE:
+ case GROOVE:
+ drawRidgeOrGrooveBoxSide(graphicsContext, x1, y1, x2, y2, side, color,
+ style, adjacentWidth1, adjacentWidth2, antialias);
+ break;
+ case INSET:
+ // FIXME: Maybe we should lighten the colors on one side like Firefox.
+ // https://bugs.webkit.org/show_bug.cgi?id=58608
+ if (side == BSTop || side == BSLeft)
+ color = color.dark();
+ // fall through
+ case OUTSET:
+ if (style == OUTSET && (side == BSBottom || side == BSRight))
+ color = color.dark();
+ // fall through
+ case SOLID:
+ drawSolidBoxSide(graphicsContext, x1, y1, x2, y2, side, color, adjacentWidth1, adjacentWidth2, antialias);
+ break;
+ }
+}
+
+void ObjectPainter::drawDashedOrDottedBoxSide(GraphicsContext* graphicsContext, int x1, int y1, int x2, int y2,
+ BoxSide side, Color color, int thickness, EBorderStyle style, bool antialias)
+{
+ if (thickness <= 0)
+ return;
+
+ bool wasAntialiased = graphicsContext->shouldAntialias();
+ StrokeStyle oldStrokeStyle = graphicsContext->strokeStyle();
+ graphicsContext->setShouldAntialias(antialias);
+ graphicsContext->setStrokeColor(color);
+ graphicsContext->setStrokeThickness(thickness);
+ graphicsContext->setStrokeStyle(style == DASHED ? DashedStroke : DottedStroke);
+
+ switch (side) {
+ case BSBottom:
+ case BSTop:
+ graphicsContext->drawLine(IntPoint(x1, (y1 + y2) / 2), IntPoint(x2, (y1 + y2) / 2));
+ break;
+ case BSRight:
+ case BSLeft:
+ graphicsContext->drawLine(IntPoint((x1 + x2) / 2, y1), IntPoint((x1 + x2) / 2, y2));
+ break;
+ }
+ graphicsContext->setShouldAntialias(wasAntialiased);
+ graphicsContext->setStrokeStyle(oldStrokeStyle);
+}
+
+void ObjectPainter::drawDoubleBoxSide(GraphicsContext* graphicsContext, int x1, int y1, int x2, int y2,
+ int length, BoxSide side, Color color, int thickness, int adjacentWidth1, int adjacentWidth2, bool antialias)
+{
+ int thirdOfThickness = (thickness + 1) / 3;
+ ASSERT(thirdOfThickness);
+
+ if (!adjacentWidth1 && !adjacentWidth2) {
+ StrokeStyle oldStrokeStyle = graphicsContext->strokeStyle();
+ graphicsContext->setStrokeStyle(NoStroke);
+ graphicsContext->setFillColor(color);
+
+ bool wasAntialiased = graphicsContext->shouldAntialias();
+ graphicsContext->setShouldAntialias(antialias);
+
+ switch (side) {
+ case BSTop:
+ case BSBottom:
+ graphicsContext->drawRect(IntRect(x1, y1, length, thirdOfThickness));
+ graphicsContext->drawRect(IntRect(x1, y2 - thirdOfThickness, length, thirdOfThickness));
+ break;
+ case BSLeft:
+ case BSRight:
+ // FIXME: Why do we offset the border by 1 in this case but not the other one?
+ if (length > 1) {
+ graphicsContext->drawRect(IntRect(x1, y1 + 1, thirdOfThickness, length - 1));
+ graphicsContext->drawRect(IntRect(x2 - thirdOfThickness, y1 + 1, thirdOfThickness, length - 1));
+ }
+ break;
+ }
+
+ graphicsContext->setShouldAntialias(wasAntialiased);
+ graphicsContext->setStrokeStyle(oldStrokeStyle);
+ return;
+ }
+
+ int adjacent1BigThird = ((adjacentWidth1 > 0) ? adjacentWidth1 + 1 : adjacentWidth1 - 1) / 3;
+ int adjacent2BigThird = ((adjacentWidth2 > 0) ? adjacentWidth2 + 1 : adjacentWidth2 - 1) / 3;
+
+ switch (side) {
+ case BSTop:
+ drawLineForBoxSide(graphicsContext, x1 + std::max((-adjacentWidth1 * 2 + 1) / 3, 0),
+ y1, x2 - std::max((-adjacentWidth2 * 2 + 1) / 3, 0), y1 + thirdOfThickness,
+ side, color, SOLID, adjacent1BigThird, adjacent2BigThird, antialias);
+ drawLineForBoxSide(graphicsContext, x1 + std::max((adjacentWidth1 * 2 + 1) / 3, 0),
+ y2 - thirdOfThickness, x2 - std::max((adjacentWidth2 * 2 + 1) / 3, 0), y2,
+ side, color, SOLID, adjacent1BigThird, adjacent2BigThird, antialias);
+ break;
+ case BSLeft:
+ drawLineForBoxSide(graphicsContext, x1, y1 + std::max((-adjacentWidth1 * 2 + 1) / 3, 0),
+ x1 + thirdOfThickness, y2 - std::max((-adjacentWidth2 * 2 + 1) / 3, 0),
+ side, color, SOLID, adjacent1BigThird, adjacent2BigThird, antialias);
+ drawLineForBoxSide(graphicsContext, x2 - thirdOfThickness, y1 + std::max((adjacentWidth1 * 2 + 1) / 3, 0),
+ x2, y2 - std::max((adjacentWidth2 * 2 + 1) / 3, 0),
+ side, color, SOLID, adjacent1BigThird, adjacent2BigThird, antialias);
+ break;
+ case BSBottom:
+ drawLineForBoxSide(graphicsContext, x1 + std::max((adjacentWidth1 * 2 + 1) / 3, 0),
+ y1, x2 - std::max((adjacentWidth2 * 2 + 1) / 3, 0), y1 + thirdOfThickness,
+ side, color, SOLID, adjacent1BigThird, adjacent2BigThird, antialias);
+ drawLineForBoxSide(graphicsContext, x1 + std::max((-adjacentWidth1 * 2 + 1) / 3, 0),
+ y2 - thirdOfThickness, x2 - std::max((-adjacentWidth2 * 2 + 1) / 3, 0), y2,
+ side, color, SOLID, adjacent1BigThird, adjacent2BigThird, antialias);
+ break;
+ case BSRight:
+ drawLineForBoxSide(graphicsContext, x1, y1 + std::max((adjacentWidth1 * 2 + 1) / 3, 0),
+ x1 + thirdOfThickness, y2 - std::max((adjacentWidth2 * 2 + 1) / 3, 0),
+ side, color, SOLID, adjacent1BigThird, adjacent2BigThird, antialias);
+ drawLineForBoxSide(graphicsContext, x2 - thirdOfThickness, y1 + std::max((-adjacentWidth1 * 2 + 1) / 3, 0),
+ x2, y2 - std::max((-adjacentWidth2 * 2 + 1) / 3, 0),
+ side, color, SOLID, adjacent1BigThird, adjacent2BigThird, antialias);
+ break;
+ default:
+ break;
+ }
+}
+
+void ObjectPainter::drawRidgeOrGrooveBoxSide(GraphicsContext* graphicsContext, int x1, int y1, int x2, int y2,
+ BoxSide side, Color color, EBorderStyle style, int adjacentWidth1, int adjacentWidth2, bool antialias)
+{
+ EBorderStyle s1;
+ EBorderStyle s2;
+ if (style == GROOVE) {
+ s1 = INSET;
+ s2 = OUTSET;
+ } else {
+ s1 = OUTSET;
+ s2 = INSET;
+ }
+
+ int adjacent1BigHalf = ((adjacentWidth1 > 0) ? adjacentWidth1 + 1 : adjacentWidth1 - 1) / 2;
+ int adjacent2BigHalf = ((adjacentWidth2 > 0) ? adjacentWidth2 + 1 : adjacentWidth2 - 1) / 2;
+
+ switch (side) {
+ case BSTop:
+ drawLineForBoxSide(graphicsContext, x1 + std::max(-adjacentWidth1, 0) / 2, y1, x2 - std::max(-adjacentWidth2, 0) / 2, (y1 + y2 + 1) / 2,
+ side, color, s1, adjacent1BigHalf, adjacent2BigHalf, antialias);
+ drawLineForBoxSide(graphicsContext, x1 + std::max(adjacentWidth1 + 1, 0) / 2, (y1 + y2 + 1) / 2, x2 - std::max(adjacentWidth2 + 1, 0) / 2, y2,
+ side, color, s2, adjacentWidth1 / 2, adjacentWidth2 / 2, antialias);
+ break;
+ case BSLeft:
+ drawLineForBoxSide(graphicsContext, x1, y1 + std::max(-adjacentWidth1, 0) / 2, (x1 + x2 + 1) / 2, y2 - std::max(-adjacentWidth2, 0) / 2,
+ side, color, s1, adjacent1BigHalf, adjacent2BigHalf, antialias);
+ drawLineForBoxSide(graphicsContext, (x1 + x2 + 1) / 2, y1 + std::max(adjacentWidth1 + 1, 0) / 2, x2, y2 - std::max(adjacentWidth2 + 1, 0) / 2,
+ side, color, s2, adjacentWidth1 / 2, adjacentWidth2 / 2, antialias);
+ break;
+ case BSBottom:
+ drawLineForBoxSide(graphicsContext, x1 + std::max(adjacentWidth1, 0) / 2, y1, x2 - std::max(adjacentWidth2, 0) / 2, (y1 + y2 + 1) / 2,
+ side, color, s2, adjacent1BigHalf, adjacent2BigHalf, antialias);
+ drawLineForBoxSide(graphicsContext, x1 + std::max(-adjacentWidth1 + 1, 0) / 2, (y1 + y2 + 1) / 2, x2 - std::max(-adjacentWidth2 + 1, 0) / 2, y2,
+ side, color, s1, adjacentWidth1 / 2, adjacentWidth2 / 2, antialias);
+ break;
+ case BSRight:
+ drawLineForBoxSide(graphicsContext, x1, y1 + std::max(adjacentWidth1, 0) / 2, (x1 + x2 + 1) / 2, y2 - std::max(adjacentWidth2, 0) / 2,
+ side, color, s2, adjacent1BigHalf, adjacent2BigHalf, antialias);
+ drawLineForBoxSide(graphicsContext, (x1 + x2 + 1) / 2, y1 + std::max(-adjacentWidth1 + 1, 0) / 2, x2, y2 - std::max(-adjacentWidth2 + 1, 0) / 2,
+ side, color, s1, adjacentWidth1 / 2, adjacentWidth2 / 2, antialias);
+ break;
+ }
+}
+
+void ObjectPainter::drawSolidBoxSide(GraphicsContext* graphicsContext, int x1, int y1, int x2, int y2,
+ BoxSide side, Color color, int adjacentWidth1, int adjacentWidth2, bool antialias)
+{
+ StrokeStyle oldStrokeStyle = graphicsContext->strokeStyle();
+ graphicsContext->setStrokeStyle(NoStroke);
+ graphicsContext->setFillColor(color);
+ ASSERT(x2 >= x1);
+ ASSERT(y2 >= y1);
+ if (!adjacentWidth1 && !adjacentWidth2) {
+ // Turn off antialiasing to match the behavior of drawConvexPolygon();
+ // this matters for rects in transformed contexts.
+ bool wasAntialiased = graphicsContext->shouldAntialias();
+ graphicsContext->setShouldAntialias(antialias);
+ graphicsContext->drawRect(IntRect(x1, y1, x2 - x1, y2 - y1));
+ graphicsContext->setShouldAntialias(wasAntialiased);
+ graphicsContext->setStrokeStyle(oldStrokeStyle);
+ return;
+ }
+ FloatPoint quad[4];
+ switch (side) {
+ case BSTop:
+ quad[0] = FloatPoint(x1 + std::max(-adjacentWidth1, 0), y1);
+ quad[1] = FloatPoint(x1 + std::max(adjacentWidth1, 0), y2);
+ quad[2] = FloatPoint(x2 - std::max(adjacentWidth2, 0), y2);
+ quad[3] = FloatPoint(x2 - std::max(-adjacentWidth2, 0), y1);
+ break;
+ case BSBottom:
+ quad[0] = FloatPoint(x1 + std::max(adjacentWidth1, 0), y1);
+ quad[1] = FloatPoint(x1 + std::max(-adjacentWidth1, 0), y2);
+ quad[2] = FloatPoint(x2 - std::max(-adjacentWidth2, 0), y2);
+ quad[3] = FloatPoint(x2 - std::max(adjacentWidth2, 0), y1);
+ break;
+ case BSLeft:
+ quad[0] = FloatPoint(x1, y1 + std::max(-adjacentWidth1, 0));
+ quad[1] = FloatPoint(x1, y2 - std::max(-adjacentWidth2, 0));
+ quad[2] = FloatPoint(x2, y2 - std::max(adjacentWidth2, 0));
+ quad[3] = FloatPoint(x2, y1 + std::max(adjacentWidth1, 0));
+ break;
+ case BSRight:
+ quad[0] = FloatPoint(x1, y1 + std::max(adjacentWidth1, 0));
+ quad[1] = FloatPoint(x1, y2 - std::max(adjacentWidth2, 0));
+ quad[2] = FloatPoint(x2, y2 - std::max(-adjacentWidth2, 0));
+ quad[3] = FloatPoint(x2, y1 + std::max(-adjacentWidth1, 0));
+ break;
+ }
+
+ graphicsContext->drawConvexPolygon(4, quad, antialias);
+ graphicsContext->setStrokeStyle(oldStrokeStyle);
+}
+
+} // namespace blink
« no previous file with comments | « Source/core/paint/ObjectPainter.h ('k') | Source/core/rendering/RenderInline.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698