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

Side by Side Diff: Source/core/rendering/RenderBox.cpp

Issue 550363004: Factor painting code out of RenderBox into a new class called BoxPainter. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: fix 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « Source/core/rendering/RenderBox.h ('k') | Source/core/rendering/RenderBoxModelObject.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org) 3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com) 4 * (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
5 * (C) 2005, 2006 Samuel Weinig (sam.weinig@gmail.com) 5 * (C) 2005, 2006 Samuel Weinig (sam.weinig@gmail.com)
6 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserv ed. 6 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserv ed.
7 * Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved. 7 * Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved.
8 * 8 *
9 * This library is free software; you can redistribute it and/or 9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public 10 * modify it under the terms of the GNU Library General Public
(...skipping 22 matching lines...) Expand all
33 #include "core/frame/FrameView.h" 33 #include "core/frame/FrameView.h"
34 #include "core/frame/LocalFrame.h" 34 #include "core/frame/LocalFrame.h"
35 #include "core/frame/PinchViewport.h" 35 #include "core/frame/PinchViewport.h"
36 #include "core/frame/Settings.h" 36 #include "core/frame/Settings.h"
37 #include "core/html/HTMLElement.h" 37 #include "core/html/HTMLElement.h"
38 #include "core/html/HTMLFrameElementBase.h" 38 #include "core/html/HTMLFrameElementBase.h"
39 #include "core/html/HTMLFrameOwnerElement.h" 39 #include "core/html/HTMLFrameOwnerElement.h"
40 #include "core/page/AutoscrollController.h" 40 #include "core/page/AutoscrollController.h"
41 #include "core/page/EventHandler.h" 41 #include "core/page/EventHandler.h"
42 #include "core/page/Page.h" 42 #include "core/page/Page.h"
43 #include "core/paint/BoxPainter.h"
43 #include "core/rendering/HitTestResult.h" 44 #include "core/rendering/HitTestResult.h"
44 #include "core/rendering/PaintInfo.h" 45 #include "core/rendering/PaintInfo.h"
45 #include "core/rendering/RenderDeprecatedFlexibleBox.h" 46 #include "core/rendering/RenderDeprecatedFlexibleBox.h"
46 #include "core/rendering/RenderFlexibleBox.h" 47 #include "core/rendering/RenderFlexibleBox.h"
47 #include "core/rendering/RenderGeometryMap.h" 48 #include "core/rendering/RenderGeometryMap.h"
48 #include "core/rendering/RenderGrid.h" 49 #include "core/rendering/RenderGrid.h"
49 #include "core/rendering/RenderInline.h" 50 #include "core/rendering/RenderInline.h"
50 #include "core/rendering/RenderLayer.h" 51 #include "core/rendering/RenderLayer.h"
51 #include "core/rendering/RenderListBox.h" 52 #include "core/rendering/RenderListBox.h"
52 #include "core/rendering/RenderListMarker.h" 53 #include "core/rendering/RenderListMarker.h"
53 #include "core/rendering/RenderTableCell.h" 54 #include "core/rendering/RenderTableCell.h"
54 #include "core/rendering/RenderTheme.h"
55 #include "core/rendering/RenderView.h" 55 #include "core/rendering/RenderView.h"
56 #include "core/rendering/compositing/RenderLayerCompositor.h" 56 #include "core/rendering/compositing/RenderLayerCompositor.h"
57 #include "platform/LengthFunctions.h" 57 #include "platform/LengthFunctions.h"
58 #include "platform/geometry/FloatQuad.h" 58 #include "platform/geometry/FloatQuad.h"
59 #include "platform/geometry/TransformState.h" 59 #include "platform/geometry/TransformState.h"
60 #include "platform/graphics/GraphicsContextStateSaver.h"
61 #include <algorithm> 60 #include <algorithm>
62 #include <math.h> 61 #include <math.h>
63 62
64 namespace blink { 63 namespace blink {
65 64
66 using namespace HTMLNames; 65 using namespace HTMLNames;
67 66
68 // Used by flexible boxes when flexing this element and by table cells. 67 // Used by flexible boxes when flexing this element and by table cells.
69 typedef WTF::HashMap<const RenderBox*, LayoutUnit> OverrideSizeMap; 68 typedef WTF::HashMap<const RenderBox*, LayoutUnit> OverrideSizeMap;
70 69
(...skipping 998 matching lines...) Expand 10 before | Expand all | Expand 10 after
1069 boundsRect.moveBy(adjustedLocation); 1068 boundsRect.moveBy(adjustedLocation);
1070 if (visibleToHitTestRequest(request) && action == HitTestForeground && locat ionInContainer.intersects(boundsRect)) { 1069 if (visibleToHitTestRequest(request) && action == HitTestForeground && locat ionInContainer.intersects(boundsRect)) {
1071 updateHitTestResult(result, locationInContainer.point() - toLayoutSize(a djustedLocation)); 1070 updateHitTestResult(result, locationInContainer.point() - toLayoutSize(a djustedLocation));
1072 if (!result.addNodeToRectBasedTestResult(node(), request, locationInCont ainer, boundsRect)) 1071 if (!result.addNodeToRectBasedTestResult(node(), request, locationInCont ainer, boundsRect))
1073 return true; 1072 return true;
1074 } 1073 }
1075 1074
1076 return false; 1075 return false;
1077 } 1076 }
1078 1077
1079 // --------------------- painting stuff -------------------------------
1080
1081 void RenderBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) 1078 void RenderBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
1082 { 1079 {
1083 LayoutPoint adjustedPaintOffset = paintOffset + location(); 1080 BoxPainter(*this).paint(paintInfo, paintOffset);
1084 // default implementation. Just pass paint through to the children
1085 PaintInfo childInfo(paintInfo);
1086 childInfo.updatePaintingRootForChildren(this);
1087 for (RenderObject* child = slowFirstChild(); child; child = child->nextSibli ng())
1088 child->paint(childInfo, adjustedPaintOffset);
1089 } 1081 }
1090 1082
1091 void RenderBox::paintRootBoxFillLayers(const PaintInfo& paintInfo)
1092 {
1093 if (paintInfo.skipRootBackground())
1094 return;
1095
1096 RenderObject* rootBackgroundRenderer = rendererForRootBackground();
1097
1098 const FillLayer& bgLayer = rootBackgroundRenderer->style()->backgroundLayers ();
1099 Color bgColor = rootBackgroundRenderer->resolveColor(CSSPropertyBackgroundCo lor);
1100
1101 paintFillLayers(paintInfo, bgColor, bgLayer, view()->backgroundRect(this), B ackgroundBleedNone, CompositeSourceOver, rootBackgroundRenderer);
1102 }
1103
1104 BackgroundBleedAvoidance RenderBox::determineBackgroundBleedAvoidance(GraphicsCo ntext* context, const BoxDecorationData& boxDecorationData) const
1105 {
1106 if (!boxDecorationData.hasBackground || !boxDecorationData.hasBorder || !sty le()->hasBorderRadius() || canRenderBorderImage())
1107 return BackgroundBleedNone;
1108
1109 // FIXME: See crbug.com/382491. getCTM does not accurately reflect the scale at the time content is
1110 // rasterized, and should not be relied on to make decisions about bleeding.
1111 AffineTransform ctm = context->getCTM();
1112 FloatSize contextScaling(static_cast<float>(ctm.xScale()), static_cast<float >(ctm.yScale()));
1113
1114 // Because RoundedRect uses IntRect internally the inset applied by the
1115 // BackgroundBleedShrinkBackground strategy cannot be less than one integer
1116 // layout coordinate, even with subpixel layout enabled. To take that into
1117 // account, we clamp the contextScaling to 1.0 for the following test so
1118 // that borderObscuresBackgroundEdge can only return true if the border
1119 // widths are greater than 2 in both layout coordinates and screen
1120 // coordinates.
1121 // This precaution will become obsolete if RoundedRect is ever promoted to
1122 // a sub-pixel representation.
1123 if (contextScaling.width() > 1)
1124 contextScaling.setWidth(1);
1125 if (contextScaling.height() > 1)
1126 contextScaling.setHeight(1);
1127
1128 if (borderObscuresBackgroundEdge(contextScaling))
1129 return BackgroundBleedShrinkBackground;
1130 if (!boxDecorationData.hasAppearance && borderObscuresBackground() && backgr oundHasOpaqueTopLayer())
1131 return BackgroundBleedBackgroundOverBorder;
1132
1133 return BackgroundBleedClipBackground;
1134 }
1135 1083
1136 void RenderBox::paintBoxDecorationBackground(PaintInfo& paintInfo, const LayoutP oint& paintOffset) 1084 void RenderBox::paintBoxDecorationBackground(PaintInfo& paintInfo, const LayoutP oint& paintOffset)
1137 { 1085 {
1138 if (!paintInfo.shouldPaintWithinRoot(this)) 1086 BoxPainter(*this).paintBoxDecorationBackground(paintInfo, paintOffset);
1139 return;
1140
1141 LayoutRect paintRect = borderBoxRect();
1142 paintRect.moveBy(paintOffset);
1143 paintBoxDecorationBackgroundWithRect(paintInfo, paintOffset, paintRect);
1144 } 1087 }
1145 1088
1146 void RenderBox::paintBoxDecorationBackgroundWithRect(PaintInfo& paintInfo, const LayoutPoint& paintOffset, const LayoutRect& paintRect)
1147 {
1148 RenderStyle* style = this->style();
1149 BoxDecorationData boxDecorationData(*style);
1150 BackgroundBleedAvoidance bleedAvoidance = determineBackgroundBleedAvoidance( paintInfo.context, boxDecorationData);
1151
1152 // FIXME: Should eventually give the theme control over whether the box shad ow should paint, since controls could have
1153 // custom shadows of their own.
1154 if (!boxShadowShouldBeAppliedToBackground(bleedAvoidance))
1155 paintBoxShadow(paintInfo, paintRect, style, Normal);
1156
1157 GraphicsContextStateSaver stateSaver(*paintInfo.context, false);
1158 if (bleedAvoidance == BackgroundBleedClipBackground) {
1159 stateSaver.save();
1160 RoundedRect border = style->getRoundedBorderFor(paintRect);
1161 paintInfo.context->clipRoundedRect(border);
1162 }
1163
1164 // If we have a native theme appearance, paint that before painting our back ground.
1165 // The theme will tell us whether or not we should also paint the CSS backgr ound.
1166 IntRect snappedPaintRect(pixelSnappedIntRect(paintRect));
1167 bool themePainted = boxDecorationData.hasAppearance && !RenderTheme::theme() .paint(this, paintInfo, snappedPaintRect);
1168 if (!themePainted) {
1169 if (bleedAvoidance == BackgroundBleedBackgroundOverBorder)
1170 paintBorder(paintInfo, paintRect, style, bleedAvoidance);
1171
1172 paintBackground(paintInfo, paintRect, boxDecorationData.backgroundColor, bleedAvoidance);
1173
1174 if (boxDecorationData.hasAppearance)
1175 RenderTheme::theme().paintDecorations(this, paintInfo, snappedPaintR ect);
1176 }
1177 paintBoxShadow(paintInfo, paintRect, style, Inset);
1178
1179 // The theme will tell us whether or not we should also paint the CSS border .
1180 if (boxDecorationData.hasBorder && bleedAvoidance != BackgroundBleedBackgrou ndOverBorder && (!boxDecorationData.hasAppearance || (!themePainted && RenderThe me::theme().paintBorderOnly(this, paintInfo, snappedPaintRect))) && !(isTable() && toRenderTable(this)->collapseBorders()))
1181 paintBorder(paintInfo, paintRect, style, bleedAvoidance);
1182 }
1183
1184 void RenderBox::paintBackground(const PaintInfo& paintInfo, const LayoutRect& pa intRect, const Color& backgroundColor, BackgroundBleedAvoidance bleedAvoidance)
1185 {
1186 if (isDocumentElement()) {
1187 paintRootBoxFillLayers(paintInfo);
1188 return;
1189 }
1190 if (isBody() && skipBodyBackground(this))
1191 return;
1192 if (boxDecorationBackgroundIsKnownToBeObscured())
1193 return;
1194 paintFillLayers(paintInfo, backgroundColor, style()->backgroundLayers(), pai ntRect, bleedAvoidance);
1195 }
1196 1089
1197 bool RenderBox::getBackgroundPaintedExtent(LayoutRect& paintedExtent) const 1090 bool RenderBox::getBackgroundPaintedExtent(LayoutRect& paintedExtent) const
1198 { 1091 {
1199 ASSERT(hasBackground()); 1092 ASSERT(hasBackground());
1200 LayoutRect backgroundRect = pixelSnappedIntRect(borderBoxRect()); 1093 LayoutRect backgroundRect = pixelSnappedIntRect(borderBoxRect());
1201 1094
1202 Color backgroundColor = resolveColor(CSSPropertyBackgroundColor); 1095 Color backgroundColor = resolveColor(CSSPropertyBackgroundColor);
1203 if (backgroundColor.alpha()) { 1096 if (backgroundColor.alpha()) {
1204 paintedExtent = backgroundRect; 1097 paintedExtent = backgroundRect;
1205 return true; 1098 return true;
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after
1349 Color bgColor = resolveColor(CSSPropertyBackgroundColor); 1242 Color bgColor = resolveColor(CSSPropertyBackgroundColor);
1350 if (bgColor.alpha() == 255) 1243 if (bgColor.alpha() == 255)
1351 return true; 1244 return true;
1352 } 1245 }
1353 1246
1354 return false; 1247 return false;
1355 } 1248 }
1356 1249
1357 void RenderBox::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffset) 1250 void RenderBox::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
1358 { 1251 {
1359 if (!paintInfo.shouldPaintWithinRoot(this) || style()->visibility() != VISIB LE || paintInfo.phase != PaintPhaseMask) 1252 BoxPainter(*this).paintMask(paintInfo, paintOffset);
1360 return;
1361
1362 LayoutRect paintRect = LayoutRect(paintOffset, size());
1363 paintMaskImages(paintInfo, paintRect);
1364 } 1253 }
1365 1254
1366 void RenderBox::paintClippingMask(PaintInfo& paintInfo, const LayoutPoint& paint Offset) 1255 void RenderBox::paintClippingMask(PaintInfo& paintInfo, const LayoutPoint& paint Offset)
1367 { 1256 {
1368 if (!paintInfo.shouldPaintWithinRoot(this) || style()->visibility() != VISIB LE || paintInfo.phase != PaintPhaseClippingMask) 1257 BoxPainter(*this).paintClippingMask(paintInfo, paintOffset);
1369 return;
1370
1371 if (!layer() || layer()->compositingState() != PaintsIntoOwnBacking)
1372 return;
1373
1374 // We should never have this state in this function. A layer with a mask
1375 // should have always created its own backing if it became composited.
1376 ASSERT(layer()->compositingState() != HasOwnBackingButPaintsIntoAncestor);
1377
1378 LayoutRect paintRect = LayoutRect(paintOffset, size());
1379 paintInfo.context->fillRect(pixelSnappedIntRect(paintRect), Color::black);
1380 }
1381
1382 void RenderBox::paintMaskImages(const PaintInfo& paintInfo, const LayoutRect& pa intRect)
1383 {
1384 // Figure out if we need to push a transparency layer to render our mask.
1385 bool pushTransparencyLayer = false;
1386 bool compositedMask = hasLayer() && layer()->hasCompositedMask();
1387 bool flattenCompositingLayers = view()->frameView() && view()->frameView()-> paintBehavior() & PaintBehaviorFlattenCompositingLayers;
1388 CompositeOperator compositeOp = CompositeSourceOver;
1389
1390 bool allMaskImagesLoaded = true;
1391
1392 if (!compositedMask || flattenCompositingLayers) {
1393 pushTransparencyLayer = true;
1394 StyleImage* maskBoxImage = style()->maskBoxImage().image();
1395 const FillLayer& maskLayers = style()->maskLayers();
1396
1397 // Don't render a masked element until all the mask images have loaded, to prevent a flash of unmasked content.
1398 if (maskBoxImage)
1399 allMaskImagesLoaded &= maskBoxImage->isLoaded();
1400
1401 allMaskImagesLoaded &= maskLayers.imagesAreLoaded();
1402
1403 paintInfo.context->setCompositeOperation(CompositeDestinationIn);
1404 paintInfo.context->beginTransparencyLayer(1);
1405 compositeOp = CompositeSourceOver;
1406 }
1407
1408 if (allMaskImagesLoaded) {
1409 paintFillLayers(paintInfo, Color::transparent, style()->maskLayers(), pa intRect, BackgroundBleedNone, compositeOp);
1410 paintNinePieceImage(paintInfo.context, paintRect, style(), style()->mask BoxImage(), compositeOp);
1411 }
1412
1413 if (pushTransparencyLayer)
1414 paintInfo.context->endLayer();
1415 }
1416
1417 void RenderBox::paintFillLayers(const PaintInfo& paintInfo, const Color& c, cons t FillLayer& fillLayer, const LayoutRect& rect,
1418 BackgroundBleedAvoidance bleedAvoidance, CompositeOperator op, RenderObject* backgroundObject)
1419 {
1420 Vector<const FillLayer*, 8> layers;
1421 const FillLayer* curLayer = &fillLayer;
1422 bool shouldDrawBackgroundInSeparateBuffer = false;
1423 bool isBottomLayerOccluded = false;
1424 while (curLayer) {
1425 layers.append(curLayer);
1426 // Stop traversal when an opaque layer is encountered.
1427 // FIXME : It would be possible for the following occlusion culling test to be more aggressive
1428 // on layers with no repeat by testing whether the image covers the layo ut rect.
1429 // Testing that here would imply duplicating a lot of calculations that are currently done in
1430 // RenderBoxModelObject::paintFillLayerExtended. A more efficient soluti on might be to move
1431 // the layer recursion into paintFillLayerExtended, or to compute the la yer geometry here
1432 // and pass it down.
1433
1434 if (!shouldDrawBackgroundInSeparateBuffer && curLayer->blendMode() != We bBlendModeNormal)
1435 shouldDrawBackgroundInSeparateBuffer = true;
1436
1437 // The clipOccludesNextLayers condition must be evaluated first to avoid short-circuiting.
1438 if (curLayer->clipOccludesNextLayers(curLayer == &fillLayer) && curLayer ->hasOpaqueImage(this) && curLayer->image()->canRender(*this, style()->effective Zoom()) && curLayer->hasRepeatXY() && curLayer->blendMode() == WebBlendModeNorma l && !boxShadowShouldBeAppliedToBackground(bleedAvoidance))
1439 break;
1440 curLayer = curLayer->next();
1441 }
1442
1443 if (layers.size() > 0 && (**layers.rbegin()).next())
1444 isBottomLayerOccluded = true;
1445
1446 GraphicsContext* context = paintInfo.context;
1447 if (!context)
1448 shouldDrawBackgroundInSeparateBuffer = false;
1449
1450 bool skipBaseColor = false;
1451 if (shouldDrawBackgroundInSeparateBuffer) {
1452 bool isBaseColorVisible = !isBottomLayerOccluded && c.hasAlpha();
1453
1454 // Paint the document's base background color outside the transparency l ayer,
1455 // so that the background images don't blend with this color: http://crb ug.com/389039.
1456 if (isBaseColorVisible && isDocumentElementWithOpaqueBackground()) {
1457 paintRootBackgroundColor(paintInfo, rect, Color());
1458 skipBaseColor = true;
1459 }
1460 context->beginTransparencyLayer(1);
1461 }
1462
1463 Vector<const FillLayer*>::const_reverse_iterator topLayer = layers.rend();
1464 for (Vector<const FillLayer*>::const_reverse_iterator it = layers.rbegin(); it != topLayer; ++it)
1465 paintFillLayer(paintInfo, c, **it, rect, bleedAvoidance, op, backgroundO bject, skipBaseColor);
1466
1467 if (shouldDrawBackgroundInSeparateBuffer)
1468 context->endLayer();
1469 }
1470
1471 void RenderBox::paintFillLayer(const PaintInfo& paintInfo, const Color& c, const FillLayer& fillLayer, const LayoutRect& rect,
1472 BackgroundBleedAvoidance bleedAvoidance, CompositeOperator op, RenderObject* backgroundObject, bool skipBaseColor)
1473 {
1474 paintFillLayerExtended(paintInfo, c, fillLayer, rect, bleedAvoidance, 0, Lay outSize(), op, backgroundObject, skipBaseColor);
1475 } 1258 }
1476 1259
1477 void RenderBox::imageChanged(WrappedImagePtr image, const IntRect*) 1260 void RenderBox::imageChanged(WrappedImagePtr image, const IntRect*)
1478 { 1261 {
1479 if (!parent()) 1262 if (!parent())
1480 return; 1263 return;
1481 1264
1482 AllowPaintInvalidationScope scoper(frameView()); 1265 AllowPaintInvalidationScope scoper(frameView());
1483 1266
1484 if ((style()->borderImage().image() && style()->borderImage().image()->data( ) == image) || 1267 if ((style()->borderImage().image() && style()->borderImage().image()->data( ) == image) ||
(...skipping 3251 matching lines...) Expand 10 before | Expand all | Expand 10 after
4736 // PreviousBorderBoxSize is only valid when there is background or box decor ations. 4519 // PreviousBorderBoxSize is only valid when there is background or box decor ations.
4737 ASSERT(style()->hasBackground() || style()->hasBoxDecorations()); 4520 ASSERT(style()->hasBackground() || style()->hasBoxDecorations());
4738 4521
4739 if (m_rareData && m_rareData->m_previousBorderBoxSize.width() != -1) 4522 if (m_rareData && m_rareData->m_previousBorderBoxSize.width() != -1)
4740 return m_rareData->m_previousBorderBoxSize; 4523 return m_rareData->m_previousBorderBoxSize;
4741 4524
4742 // We didn't save the old border box size because it was the same as the siz e of oldBounds. 4525 // We didn't save the old border box size because it was the same as the siz e of oldBounds.
4743 return previousBoundsSize; 4526 return previousBoundsSize;
4744 } 4527 }
4745 4528
4746 RenderBox::BoxDecorationData::BoxDecorationData(const RenderStyle& style)
4747 {
4748 backgroundColor = style.visitedDependentColor(CSSPropertyBackgroundColor);
4749 hasBackground = backgroundColor.alpha() || style.hasBackgroundImage();
4750 ASSERT(hasBackground == style.hasBackground());
4751 hasBorder = style.hasBorder();
4752 hasAppearance = style.hasAppearance();
4753 }
4754
4755 } // namespace blink 4529 } // namespace blink
OLDNEW
« no previous file with comments | « Source/core/rendering/RenderBox.h ('k') | Source/core/rendering/RenderBoxModelObject.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698