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

Side by Side Diff: Source/core/paint/BoxPainter.cpp

Issue 559733005: Move painting code from RenderBoxModelObject into BoxPainter. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: gs 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
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "config.h" 5 #include "config.h"
6 #include "core/paint/BoxPainter.h" 6 #include "core/paint/BoxPainter.h"
7 7
8 #include "core/HTMLNames.h"
9 #include "core/frame/Settings.h"
10 #include "core/html/HTMLFrameOwnerElement.h"
11 #include "core/paint/BackgroundImageGeometry.h"
8 #include "core/paint/BoxDecorationData.h" 12 #include "core/paint/BoxDecorationData.h"
13 #include "core/rendering/ImageQualityController.h"
9 #include "core/rendering/PaintInfo.h" 14 #include "core/rendering/PaintInfo.h"
10 #include "core/rendering/RenderBox.h" 15 #include "core/rendering/RenderBox.h"
16 #include "core/rendering/RenderBoxModelObject.h"
11 #include "core/rendering/RenderLayer.h" 17 #include "core/rendering/RenderLayer.h"
12 #include "core/rendering/RenderTable.h" 18 #include "core/rendering/RenderTable.h"
13 #include "core/rendering/RenderTheme.h" 19 #include "core/rendering/RenderTheme.h"
14 #include "core/rendering/RenderView.h" 20 #include "core/rendering/RenderView.h"
21 #include "core/rendering/compositing/CompositedLayerMapping.h"
22 #include "core/rendering/style/ShadowList.h"
23 #include "platform/LengthFunctions.h"
15 #include "platform/geometry/LayoutPoint.h" 24 #include "platform/geometry/LayoutPoint.h"
16 #include "platform/graphics/GraphicsContextStateSaver.h" 25 #include "platform/graphics/GraphicsContextStateSaver.h"
17 26
18 namespace blink { 27 namespace blink {
19 28
20 void BoxPainter::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) 29 void BoxPainter::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
21 { 30 {
22 LayoutPoint adjustedPaintOffset = paintOffset + m_renderBox.location(); 31 LayoutPoint adjustedPaintOffset = paintOffset + m_renderBox.location();
23 // default implementation. Just pass paint through to the children 32 // default implementation. Just pass paint through to the children
24 PaintInfo childInfo(paintInfo); 33 PaintInfo childInfo(paintInfo);
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
150 GraphicsContext* context = paintInfo.context; 159 GraphicsContext* context = paintInfo.context;
151 if (!context) 160 if (!context)
152 shouldDrawBackgroundInSeparateBuffer = false; 161 shouldDrawBackgroundInSeparateBuffer = false;
153 162
154 bool skipBaseColor = false; 163 bool skipBaseColor = false;
155 if (shouldDrawBackgroundInSeparateBuffer) { 164 if (shouldDrawBackgroundInSeparateBuffer) {
156 bool isBaseColorVisible = !isBottomLayerOccluded && c.hasAlpha(); 165 bool isBaseColorVisible = !isBottomLayerOccluded && c.hasAlpha();
157 166
158 // Paint the document's base background color outside the transparency l ayer, 167 // Paint the document's base background color outside the transparency l ayer,
159 // so that the background images don't blend with this color: http://crb ug.com/389039. 168 // so that the background images don't blend with this color: http://crb ug.com/389039.
160 if (isBaseColorVisible && m_renderBox.isDocumentElementWithOpaqueBackgro und()) { 169 if (isBaseColorVisible && isDocumentElementWithOpaqueBackground(m_render Box)) {
161 m_renderBox.paintRootBackgroundColor(paintInfo, rect, Color()); 170 paintRootBackgroundColor(m_renderBox, paintInfo, rect, Color());
162 skipBaseColor = true; 171 skipBaseColor = true;
163 } 172 }
164 context->beginTransparencyLayer(1); 173 context->beginTransparencyLayer(1);
165 } 174 }
166 175
167 Vector<const FillLayer*>::const_reverse_iterator topLayer = layers.rend(); 176 Vector<const FillLayer*>::const_reverse_iterator topLayer = layers.rend();
168 for (Vector<const FillLayer*>::const_reverse_iterator it = layers.rbegin(); it != topLayer; ++it) 177 for (Vector<const FillLayer*>::const_reverse_iterator it = layers.rbegin(); it != topLayer; ++it)
169 paintFillLayer(paintInfo, c, **it, rect, bleedAvoidance, op, backgroundO bject, skipBaseColor); 178 paintFillLayer(paintInfo, c, **it, rect, bleedAvoidance, op, backgroundO bject, skipBaseColor);
170 179
171 if (shouldDrawBackgroundInSeparateBuffer) 180 if (shouldDrawBackgroundInSeparateBuffer)
172 context->endLayer(); 181 context->endLayer();
173 } 182 }
174 183
175 void BoxPainter::paintFillLayer(const PaintInfo& paintInfo, const Color& c, cons t FillLayer& fillLayer, const LayoutRect& rect, 184 void BoxPainter::paintFillLayer(const PaintInfo& paintInfo, const Color& c, cons t FillLayer& fillLayer, const LayoutRect& rect,
176 BackgroundBleedAvoidance bleedAvoidance, CompositeOperator op, RenderObject* backgroundObject, bool skipBaseColor) 185 BackgroundBleedAvoidance bleedAvoidance, CompositeOperator op, RenderObject* backgroundObject, bool skipBaseColor)
177 { 186 {
178 m_renderBox.paintFillLayerExtended(paintInfo, c, fillLayer, rect, bleedAvoid ance, 0, LayoutSize(), op, backgroundObject, skipBaseColor); 187 BoxPainter::paintFillLayerExtended(m_renderBox, paintInfo, c, fillLayer, rec t, bleedAvoidance, 0, LayoutSize(), op, backgroundObject, skipBaseColor);
188 }
189
190 void BoxPainter::applyBoxShadowForBackground(GraphicsContext* context, RenderObj ect& obj)
191 {
192 const ShadowList* shadowList = obj.style()->boxShadow();
193 ASSERT(shadowList);
194 for (size_t i = shadowList->shadows().size(); i--; ) {
195 const ShadowData& boxShadow = shadowList->shadows()[i];
196 if (boxShadow.style() != Normal)
197 continue;
198 FloatSize shadowOffset(boxShadow.x(), boxShadow.y());
199 context->setShadow(shadowOffset, boxShadow.blur(), boxShadow.color(),
200 DrawLooperBuilder::ShadowRespectsTransforms, DrawLooperBuilder::Shad owIgnoresAlpha);
201 return;
202 }
203 }
204
205 // FIXME: See crbug.com/382491. The use of getCTM in this context is incorrect b ecause the matrix returned does not
206 // include scales applied at raster time, such as the device zoom.
207 static LayoutRect shrinkRectByOnePixel(GraphicsContext* context, const LayoutRec t& rect)
208 {
209 LayoutRect shrunkRect = rect;
210 AffineTransform transform = context->getCTM();
211 shrunkRect.inflateX(-static_cast<LayoutUnit>(ceil(1 / transform.xScale())));
212 shrunkRect.inflateY(-static_cast<LayoutUnit>(ceil(1 / transform.yScale())));
213 return shrunkRect;
214 }
215
216 RoundedRect BoxPainter::getBackgroundRoundedRect(RenderObject& obj, const Layout Rect& borderRect, InlineFlowBox* box, LayoutUnit inlineBoxWidth, LayoutUnit inli neBoxHeight,
217 bool includeLogicalLeftEdge, bool includeLogicalRightEdge)
218 {
219 RoundedRect border = obj.style()->getRoundedBorderFor(borderRect, includeLog icalLeftEdge, includeLogicalRightEdge);
220 if (box && (box->nextLineBox() || box->prevLineBox())) {
221 RoundedRect segmentBorder = obj.style()->getRoundedBorderFor(LayoutRect( 0, 0, inlineBoxWidth, inlineBoxHeight), includeLogicalLeftEdge, includeLogicalRi ghtEdge);
222 border.setRadii(segmentBorder.radii());
223 }
224
225 return border;
226 }
227
228 RoundedRect BoxPainter::backgroundRoundedRectAdjustedForBleedAvoidance(RenderObj ect& obj, GraphicsContext* context, const LayoutRect& borderRect, BackgroundBlee dAvoidance bleedAvoidance, InlineFlowBox* box, const LayoutSize& boxSize, bool i ncludeLogicalLeftEdge, bool includeLogicalRightEdge)
229 {
230 if (bleedAvoidance == BackgroundBleedShrinkBackground) {
231 // We shrink the rectangle by one pixel on each side because the bleed i s one pixel maximum.
232 return BoxPainter::getBackgroundRoundedRect(obj, shrinkRectByOnePixel(co ntext, borderRect), box, boxSize.width(), boxSize.height(), includeLogicalLeftEd ge, includeLogicalRightEdge);
233 }
234 if (bleedAvoidance == BackgroundBleedBackgroundOverBorder)
235 return obj.style()->getRoundedInnerBorderFor(borderRect, includeLogicalL eftEdge, includeLogicalRightEdge);
236
237 return BoxPainter::getBackgroundRoundedRect(obj, borderRect, box, boxSize.wi dth(), boxSize.height(), includeLogicalLeftEdge, includeLogicalRightEdge);
238 }
239
240 void BoxPainter::clipRoundedInnerRect(GraphicsContext * context, const LayoutRec t& rect, const RoundedRect& clipRect)
241 {
242 if (clipRect.isRenderable()) {
243 context->clipRoundedRect(clipRect);
244 } else {
245 // We create a rounded rect for each of the corners and clip it, while m aking sure we clip opposing corners together.
246 if (!clipRect.radii().topLeft().isEmpty() || !clipRect.radii().bottomRig ht().isEmpty()) {
247 IntRect topCorner(clipRect.rect().x(), clipRect.rect().y(), rect.max X() - clipRect.rect().x(), rect.maxY() - clipRect.rect().y());
248 RoundedRect::Radii topCornerRadii;
249 topCornerRadii.setTopLeft(clipRect.radii().topLeft());
250 context->clipRoundedRect(RoundedRect(topCorner, topCornerRadii));
251
252 IntRect bottomCorner(rect.x(), rect.y(), clipRect.rect().maxX() - re ct.x(), clipRect.rect().maxY() - rect.y());
253 RoundedRect::Radii bottomCornerRadii;
254 bottomCornerRadii.setBottomRight(clipRect.radii().bottomRight());
255 context->clipRoundedRect(RoundedRect(bottomCorner, bottomCornerRadii ));
256 }
257
258 if (!clipRect.radii().topRight().isEmpty() || !clipRect.radii().bottomLe ft().isEmpty()) {
259 IntRect topCorner(rect.x(), clipRect.rect().y(), clipRect.rect().max X() - rect.x(), rect.maxY() - clipRect.rect().y());
260 RoundedRect::Radii topCornerRadii;
261 topCornerRadii.setTopRight(clipRect.radii().topRight());
262 context->clipRoundedRect(RoundedRect(topCorner, topCornerRadii));
263
264 IntRect bottomCorner(clipRect.rect().x(), rect.y(), rect.maxX() - cl ipRect.rect().x(), clipRect.rect().maxY() - rect.y());
265 RoundedRect::Radii bottomCornerRadii;
266 bottomCornerRadii.setBottomLeft(clipRect.radii().bottomLeft());
267 context->clipRoundedRect(RoundedRect(bottomCorner, bottomCornerRadii ));
268 }
269 }
270 }
271
272 void BoxPainter::paintFillLayerExtended(RenderBoxModelObject& obj, const PaintIn fo& paintInfo, const Color& color, const FillLayer& bgLayer, const LayoutRect& r ect,
273 BackgroundBleedAvoidance bleedAvoidance, InlineFlowBox* box, const LayoutSiz e& boxSize, CompositeOperator op, RenderObject* backgroundObject, bool skipBaseC olor)
274 {
275 GraphicsContext* context = paintInfo.context;
276 if (rect.isEmpty())
277 return;
278
279 bool includeLeftEdge = box ? box->includeLogicalLeftEdge() : true;
280 bool includeRightEdge = box ? box->includeLogicalRightEdge() : true;
281
282 bool hasRoundedBorder = obj.style()->hasBorderRadius() && (includeLeftEdge | | includeRightEdge);
283 bool clippedWithLocalScrolling = obj.hasOverflowClip() && bgLayer.attachment () == LocalBackgroundAttachment;
284 bool isBorderFill = bgLayer.clip() == BorderFillBox;
285 bool isDocumentElementRenderer = obj.isDocumentElement();
286 bool isBottomLayer = !bgLayer.next();
287
288 Color bgColor = color;
289 StyleImage* bgImage = bgLayer.image();
290 bool shouldPaintBackgroundImage = bgImage && bgImage->canRender(obj, obj.sty le()->effectiveZoom());
291
292 bool forceBackgroundToWhite = false;
293 if (obj.document().printing()) {
294 if (obj.style()->printColorAdjust() == PrintColorAdjustEconomy)
295 forceBackgroundToWhite = true;
296 if (obj.document().settings() && obj.document().settings()->shouldPrintB ackgrounds())
297 forceBackgroundToWhite = false;
298 }
299
300 // When printing backgrounds is disabled or using economy mode,
301 // change existing background colors and images to a solid white background.
302 // If there's no bg color or image, leave it untouched to avoid affecting tr ansparency.
303 // We don't try to avoid loading the background images, because this style f lag is only set
304 // when printing, and at that point we've already loaded the background imag es anyway. (To avoid
305 // loading the background images we'd have to do this check when applying st yles rather than
306 // while rendering.)
307 if (forceBackgroundToWhite) {
308 // Note that we can't reuse this variable below because the bgColor migh t be changed
309 bool shouldPaintBackgroundColor = isBottomLayer && bgColor.alpha();
310 if (shouldPaintBackgroundImage || shouldPaintBackgroundColor) {
311 bgColor = Color::white;
312 shouldPaintBackgroundImage = false;
313 }
314 }
315
316 bool colorVisible = bgColor.alpha();
317
318 // Fast path for drawing simple color backgrounds.
319 if (!isDocumentElementRenderer && !clippedWithLocalScrolling && !shouldPaint BackgroundImage && isBorderFill && isBottomLayer) {
320 if (!colorVisible)
321 return;
322
323 bool boxShadowShouldBeAppliedToBackground = obj.boxShadowShouldBeApplied ToBackground(bleedAvoidance, box);
324 GraphicsContextStateSaver shadowStateSaver(*context, boxShadowShouldBeAp pliedToBackground);
325 if (boxShadowShouldBeAppliedToBackground)
326 BoxPainter::applyBoxShadowForBackground(context, obj);
327
328 if (hasRoundedBorder && bleedAvoidance != BackgroundBleedClipBackground) {
329 RoundedRect border = backgroundRoundedRectAdjustedForBleedAvoidance( obj, context, rect, bleedAvoidance, box, boxSize, includeLeftEdge, includeRightE dge);
330 if (border.isRenderable()) {
331 context->fillRoundedRect(border, bgColor);
332 } else {
333 context->save();
334 clipRoundedInnerRect(context, rect, border);
335 context->fillRect(border.rect(), bgColor);
336 context->restore();
337 }
338 } else {
339 context->fillRect(pixelSnappedIntRect(rect), bgColor);
340 }
341
342 return;
343 }
344
345 // BorderFillBox radius clipping is taken care of by BackgroundBleedClipBack ground
346 bool clipToBorderRadius = hasRoundedBorder && !(isBorderFill && bleedAvoidan ce == BackgroundBleedClipBackground);
347 GraphicsContextStateSaver clipToBorderStateSaver(*context, clipToBorderRadiu s);
348 if (clipToBorderRadius) {
349 RoundedRect border = isBorderFill ? backgroundRoundedRectAdjustedForBlee dAvoidance(obj, context, rect, bleedAvoidance, box, boxSize, includeLeftEdge, in cludeRightEdge) : getBackgroundRoundedRect(obj, rect, box, boxSize.width(), boxS ize.height(), includeLeftEdge, includeRightEdge);
350
351 // Clip to the padding or content boxes as necessary.
352 if (bgLayer.clip() == ContentFillBox) {
353 border = obj.style()->getRoundedInnerBorderFor(border.rect(),
354 obj.paddingTop() + obj.borderTop(), obj.paddingBottom() + obj.bo rderBottom(),
355 obj.paddingLeft() + obj.borderLeft(), obj.paddingRight() + obj.b orderRight(), includeLeftEdge, includeRightEdge);
356 } else if (bgLayer.clip() == PaddingFillBox) {
357 border = obj.style()->getRoundedInnerBorderFor(border.rect(), includ eLeftEdge, includeRightEdge);
358 }
359
360 clipRoundedInnerRect(context, rect, border);
361 }
362
363 int bLeft = includeLeftEdge ? obj.borderLeft() : 0;
364 int bRight = includeRightEdge ? obj.borderRight() : 0;
365 LayoutUnit pLeft = includeLeftEdge ? obj.paddingLeft() : LayoutUnit();
366 LayoutUnit pRight = includeRightEdge ? obj.paddingRight() : LayoutUnit();
367
368 GraphicsContextStateSaver clipWithScrollingStateSaver(*context, clippedWithL ocalScrolling);
369 LayoutRect scrolledPaintRect = rect;
370 if (clippedWithLocalScrolling) {
371 // Clip to the overflow area.
372 RenderBox* thisBox = toRenderBox(&obj);
373 context->clip(thisBox->overflowClipRect(rect.location()));
374
375 // Adjust the paint rect to reflect a scrolled content box with borders at the ends.
376 IntSize offset = thisBox->scrolledContentOffset();
377 scrolledPaintRect.move(-offset);
378 scrolledPaintRect.setWidth(bLeft + thisBox->scrollWidth() + bRight);
379 scrolledPaintRect.setHeight(thisBox->borderTop() + thisBox->scrollHeight () + thisBox->borderBottom());
380 }
381
382 GraphicsContextStateSaver backgroundClipStateSaver(*context, false);
383 IntRect maskRect;
384
385 switch (bgLayer.clip()) {
386 case PaddingFillBox:
387 case ContentFillBox: {
388 if (clipToBorderRadius)
389 break;
390
391 // Clip to the padding or content boxes as necessary.
392 bool includePadding = bgLayer.clip() == ContentFillBox;
393 LayoutRect clipRect = LayoutRect(scrolledPaintRect.x() + bLeft + (includ ePadding ? pLeft : LayoutUnit()),
394 scrolledPaintRect.y() + obj.borderTop() + (includePadding ? obj.padd ingTop() : LayoutUnit()),
395 scrolledPaintRect.width() - bLeft - bRight - (includePadding ? pLeft + pRight : LayoutUnit()),
396 scrolledPaintRect.height() - obj.borderTop() - obj.borderBottom() - (includePadding ? obj.paddingTop() + obj.paddingBottom() : LayoutUnit()));
397 backgroundClipStateSaver.save();
398 context->clip(clipRect);
399
400 break;
401 }
402 case TextFillBox: {
403 // First figure out how big the mask has to be. It should be no bigger t han what we need
404 // to actually render, so we should intersect the dirty rect with the bo rder box of the background.
405 maskRect = pixelSnappedIntRect(rect);
406 maskRect.intersect(paintInfo.rect);
407
408 // We draw the background into a separate layer, to be later masked with yet another layer
409 // holding the text content.
410 backgroundClipStateSaver.save();
411 context->clip(maskRect);
412 context->beginTransparencyLayer(1);
413
414 break;
415 }
416 case BorderFillBox:
417 break;
418 default:
419 ASSERT_NOT_REACHED();
420 break;
421 }
422
423 // Paint the color first underneath all images, culled if background image o ccludes it.
424 // FIXME: In the bgLayer->hasFiniteBounds() case, we could improve the culli ng test
425 // by verifying whether the background image covers the entire layout rect.
426 if (isBottomLayer) {
427 IntRect backgroundRect(pixelSnappedIntRect(scrolledPaintRect));
428 bool boxShadowShouldBeAppliedToBackground = obj.boxShadowShouldBeApplied ToBackground(bleedAvoidance, box);
429 bool isOpaqueRoot = (isDocumentElementRenderer && !bgColor.hasAlpha()) | | isDocumentElementWithOpaqueBackground(obj);
430 if (boxShadowShouldBeAppliedToBackground || !shouldPaintBackgroundImage || !bgLayer.hasOpaqueImage(&obj) || !bgLayer.hasRepeatXY() || (isOpaqueRoot && ! toRenderBox(&obj)->height())) {
431 if (!boxShadowShouldBeAppliedToBackground)
432 backgroundRect.intersect(paintInfo.rect);
433
434 GraphicsContextStateSaver shadowStateSaver(*context, boxShadowShould BeAppliedToBackground);
435 if (boxShadowShouldBeAppliedToBackground)
436 BoxPainter::applyBoxShadowForBackground(context, obj);
437
438 if (isOpaqueRoot && !skipBaseColor) {
439 paintRootBackgroundColor(obj, paintInfo, rect, bgColor);
440 } else if (bgColor.alpha()) {
441 context->fillRect(backgroundRect, bgColor, context->compositeOpe ration());
442 }
443 }
444 }
445
446 // no progressive loading of the background image
447 if (shouldPaintBackgroundImage) {
448 BackgroundImageGeometry geometry;
449 calculateBackgroundImageGeometry(obj, paintInfo.paintContainer(), bgLaye r, scrolledPaintRect, geometry, backgroundObject);
450 geometry.clip(paintInfo.rect);
451 if (!geometry.destRect().isEmpty()) {
452 CompositeOperator compositeOp = op == CompositeSourceOver ? bgLayer. composite() : op;
453 RenderObject* clientForBackgroundImage = backgroundObject ? backgrou ndObject : &obj;
454 RefPtr<Image> image = bgImage->image(clientForBackgroundImage, geome try.tileSize());
455 InterpolationQuality interpolationQuality = chooseInterpolationQuali ty(obj, context, image.get(), &bgLayer, geometry.tileSize());
456 if (bgLayer.maskSourceType() == MaskLuminance)
457 context->setColorFilter(ColorFilterLuminanceToAlpha);
458 InterpolationQuality previousInterpolationQuality = context->imageIn terpolationQuality();
459 context->setImageInterpolationQuality(interpolationQuality);
460 context->drawTiledImage(image.get(), geometry.destRect(), geometry.r elativePhase(), geometry.tileSize(),
461 compositeOp, bgLayer.blendMode(), geometry.spaceSize());
462 context->setImageInterpolationQuality(previousInterpolationQuality);
463 }
464 }
465
466 if (bgLayer.clip() == TextFillBox) {
467 // Create the text mask layer.
468 context->setCompositeOperation(CompositeDestinationIn);
469 context->beginTransparencyLayer(1);
470
471 // FIXME: Workaround for https://code.google.com/p/skia/issues/detail?id =1291.
472 context->clearRect(maskRect);
473
474 // Now draw the text into the mask. We do this by painting using a speci al paint phase that signals to
475 // InlineTextBoxes that they should just add their contents to the clip.
476 PaintInfo info(context, maskRect, PaintPhaseTextClip, PaintBehaviorForce BlackText, 0);
477 context->setCompositeOperation(CompositeSourceOver);
478 if (box) {
479 RootInlineBox& root = box->root();
480 box->paint(info, LayoutPoint(scrolledPaintRect.x() - box->x(), scrol ledPaintRect.y() - box->y()), root.lineTop(), root.lineBottom());
481 } else {
482 LayoutSize localOffset = obj.isBox() ? toRenderBox(&obj)->locationOf fset() : LayoutSize();
483 obj.paint(info, scrolledPaintRect.location() - localOffset);
484 }
485
486 context->endLayer();
487 context->endLayer();
488 }
179 } 489 }
180 490
181 void BoxPainter::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffset) 491 void BoxPainter::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
182 { 492 {
183 if (!paintInfo.shouldPaintWithinRoot(&m_renderBox) || m_renderBox.style()->v isibility() != VISIBLE || paintInfo.phase != PaintPhaseMask) 493 if (!paintInfo.shouldPaintWithinRoot(&m_renderBox) || m_renderBox.style()->v isibility() != VISIBLE || paintInfo.phase != PaintPhaseMask)
184 return; 494 return;
185 495
186 LayoutRect paintRect = LayoutRect(paintOffset, m_renderBox.size()); 496 LayoutRect paintRect = LayoutRect(paintOffset, m_renderBox.size());
187 paintMaskImages(paintInfo, paintRect); 497 paintMaskImages(paintInfo, paintRect);
188 } 498 }
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
231 return; 541 return;
232 542
233 // We should never have this state in this function. A layer with a mask 543 // We should never have this state in this function. A layer with a mask
234 // should have always created its own backing if it became composited. 544 // should have always created its own backing if it became composited.
235 ASSERT(m_renderBox.layer()->compositingState() != HasOwnBackingButPaintsInto Ancestor); 545 ASSERT(m_renderBox.layer()->compositingState() != HasOwnBackingButPaintsInto Ancestor);
236 546
237 LayoutRect paintRect = LayoutRect(paintOffset, m_renderBox.size()); 547 LayoutRect paintRect = LayoutRect(paintOffset, m_renderBox.size());
238 paintInfo.context->fillRect(pixelSnappedIntRect(paintRect), Color::black); 548 paintInfo.context->fillRect(pixelSnappedIntRect(paintRect), Color::black);
239 } 549 }
240 550
551 void BoxPainter::paintRootBackgroundColor(RenderObject& obj, const PaintInfo& pa intInfo, const LayoutRect& rect, const Color& bgColor)
552 {
553 GraphicsContext* context = paintInfo.context;
554 if (rect.isEmpty())
555 return;
556
557 ASSERT(m_renderBox.isDocumentElement());
558
559 IntRect backgroundRect(pixelSnappedIntRect(rect));
560 backgroundRect.intersect(paintInfo.rect);
561
562 Color baseColor = obj.view()->frameView()->baseBackgroundColor();
563 bool shouldClearDocumentBackground = obj.document().settings() && obj.docume nt().settings()->shouldClearDocumentBackground();
564 CompositeOperator operation = shouldClearDocumentBackground ? CompositeCopy : context->compositeOperation();
565
566 // If we have an alpha go ahead and blend with the base background color.
567 if (baseColor.alpha()) {
568 if (bgColor.alpha())
569 baseColor = baseColor.blend(bgColor);
570 context->fillRect(backgroundRect, baseColor, operation);
571 } else if (bgColor.alpha()) {
572 context->fillRect(backgroundRect, bgColor, operation);
573 } else if (shouldClearDocumentBackground) {
574 context->clearRect(backgroundRect);
575 }
576 }
577
578 bool BoxPainter::isDocumentElementWithOpaqueBackground(RenderObject& obj)
579 {
580 if (!obj.isDocumentElement())
581 return false;
582
583 // The background is opaque only if we're the root document, since iframes w ith
584 // no background in the child document should show the parent's background.
585 bool isOpaque = true;
586 Element* ownerElement = obj.document().ownerElement();
587 if (ownerElement) {
588 if (!isHTMLFrameElement(*ownerElement)) {
589 // Locate the <body> element using the DOM. This is easier than tryi ng
590 // to crawl around a render tree with potential :before/:after conte nt and
591 // anonymous blocks created by inline <body> tags etc. We can locate the <body>
592 // render object very easily via the DOM.
593 HTMLElement* body = obj.document().body();
594 if (body) {
595 // Can't scroll a frameset document anyway.
596 isOpaque = body->hasTagName(HTMLNames::framesetTag);
597 } else {
598 // FIXME: SVG specific behavior should be in the SVG code.
599 // SVG documents and XML documents with SVG root nodes are trans parent.
600 isOpaque = !obj.document().hasSVGRootNode();
601 }
602 }
603 } else if (obj.view()->frameView()) {
604 isOpaque = !obj.view()->frameView()->isTransparent();
605 }
606
607 return isOpaque;
608 }
609
610 static inline int getSpace(int areaSize, int tileSize)
611 {
612 int numberOfTiles = areaSize / tileSize;
613 int space = -1;
614
615 if (numberOfTiles > 1)
616 space = lroundf((float)(areaSize - numberOfTiles * tileSize) / (numberOf Tiles - 1));
617
618 return space;
619 }
620
621 void BoxPainter::calculateBackgroundImageGeometry(RenderBoxModelObject& obj, con st RenderLayerModelObject* paintContainer, const FillLayer& fillLayer, const Lay outRect& paintRect,
622 BackgroundImageGeometry& geometry, RenderObject* backgroundObject)
623 {
624 LayoutUnit left = 0;
625 LayoutUnit top = 0;
626 IntSize positioningAreaSize;
627 IntRect snappedPaintRect = pixelSnappedIntRect(paintRect);
628
629 // Determine the background positioning area and set destRect to the backgro und painting area.
630 // destRect will be adjusted later if the background is non-repeating.
631 // FIXME: transforms spec says that fixed backgrounds behave like scroll ins ide transforms.
632 bool fixedAttachment = fillLayer.attachment() == FixedBackgroundAttachment;
633
634 if (RuntimeEnabledFeatures::fastMobileScrollingEnabled()) {
635 // As a side effect of an optimization to blit on scroll, we do not hono r the CSS
636 // property "background-attachment: fixed" because it may result in rend ering
637 // artifacts. Note, these artifacts only appear if we are blitting on sc roll of
638 // a page that has fixed background images.
639 fixedAttachment = false;
640 }
641
642 if (!fixedAttachment) {
643 geometry.setDestRect(snappedPaintRect);
644
645 LayoutUnit right = 0;
646 LayoutUnit bottom = 0;
647 // Scroll and Local.
648 if (fillLayer.origin() != BorderFillBox) {
649 left = obj.borderLeft();
650 right = obj.borderRight();
651 top = obj.borderTop();
652 bottom = obj.borderBottom();
653 if (fillLayer.origin() == ContentFillBox) {
654 left += obj.paddingLeft();
655 right += obj.paddingRight();
656 top += obj.paddingTop();
657 bottom += obj.paddingBottom();
658 }
659 }
660
661 // The background of the box generated by the root element covers the en tire canvas including
662 // its margins. Since those were added in already, we have to factor the m out when computing
663 // the background positioning area.
664 if (obj.isDocumentElement()) {
665 positioningAreaSize = pixelSnappedIntSize(toRenderBox(&obj)->size() - LayoutSize(left + right, top + bottom), toRenderBox(&obj)->location());
666 left += obj.marginLeft();
667 top += obj.marginTop();
668 } else {
669 positioningAreaSize = pixelSnappedIntSize(paintRect.size() - LayoutS ize(left + right, top + bottom), paintRect.location());
670 }
671 } else {
672 geometry.setHasNonLocalGeometry();
673
674 IntRect viewportRect = pixelSnappedIntRect(obj.viewRect());
675 if (fixedBackgroundPaintsInLocalCoordinates(obj))
676 viewportRect.setLocation(IntPoint());
677 else if (FrameView* frameView = obj.view()->frameView())
678 viewportRect.setLocation(IntPoint(frameView->scrollOffsetForFixedPos ition()));
679
680 if (paintContainer) {
681 IntPoint absoluteContainerOffset = roundedIntPoint(paintContainer->l ocalToAbsolute(FloatPoint()));
682 viewportRect.moveBy(-absoluteContainerOffset);
683 }
684
685 geometry.setDestRect(pixelSnappedIntRect(viewportRect));
686 positioningAreaSize = geometry.destRect().size();
687 }
688
689 const RenderObject* clientForBackgroundImage = backgroundObject ? background Object : &obj;
690 IntSize fillTileSize = calculateFillTileSize(obj, fillLayer, positioningArea Size);
691 fillLayer.image()->setContainerSizeForRenderer(clientForBackgroundImage, fil lTileSize, obj.style()->effectiveZoom());
692 geometry.setTileSize(fillTileSize);
693
694 EFillRepeat backgroundRepeatX = fillLayer.repeatX();
695 EFillRepeat backgroundRepeatY = fillLayer.repeatY();
696 int availableWidth = positioningAreaSize.width() - geometry.tileSize().width ();
697 int availableHeight = positioningAreaSize.height() - geometry.tileSize().hei ght();
698
699 LayoutUnit computedXPosition = roundedMinimumValueForLength(fillLayer.xPosit ion(), availableWidth);
700 if (backgroundRepeatX == RoundFill && positioningAreaSize.width() > 0 && fil lTileSize.width() > 0) {
701 long nrTiles = std::max(1l, lroundf((float)positioningAreaSize.width() / fillTileSize.width()));
702
703 if (fillLayer.size().size.height().isAuto() && backgroundRepeatY != Roun dFill) {
704 fillTileSize.setHeight(fillTileSize.height() * positioningAreaSize.w idth() / (nrTiles * fillTileSize.width()));
705 }
706
707 fillTileSize.setWidth(positioningAreaSize.width() / nrTiles);
708 geometry.setTileSize(fillTileSize);
709 geometry.setPhaseX(geometry.tileSize().width() ? geometry.tileSize().wid th() - roundToInt(computedXPosition + left) % geometry.tileSize().width() : 0);
710 geometry.setSpaceSize(IntSize());
711 }
712
713 LayoutUnit computedYPosition = roundedMinimumValueForLength(fillLayer.yPosit ion(), availableHeight);
714 if (backgroundRepeatY == RoundFill && positioningAreaSize.height() > 0 && fi llTileSize.height() > 0) {
715 long nrTiles = std::max(1l, lroundf((float)positioningAreaSize.height() / fillTileSize.height()));
716
717 if (fillLayer.size().size.width().isAuto() && backgroundRepeatX != Round Fill) {
718 fillTileSize.setWidth(fillTileSize.width() * positioningAreaSize.hei ght() / (nrTiles * fillTileSize.height()));
719 }
720
721 fillTileSize.setHeight(positioningAreaSize.height() / nrTiles);
722 geometry.setTileSize(fillTileSize);
723 geometry.setPhaseY(geometry.tileSize().height() ? geometry.tileSize().he ight() - roundToInt(computedYPosition + top) % geometry.tileSize().height() : 0) ;
724 geometry.setSpaceSize(IntSize());
725 }
726
727 if (backgroundRepeatX == RepeatFill) {
728 geometry.setPhaseX(geometry.tileSize().width() ? geometry.tileSize().wid th() - roundToInt(computedXPosition + left) % geometry.tileSize().width() : 0);
729 geometry.setSpaceSize(IntSize());
730 } else if (backgroundRepeatX == SpaceFill && fillTileSize.width() > 0) {
731 int space = getSpace(positioningAreaSize.width(), geometry.tileSize().wi dth());
732 int actualWidth = geometry.tileSize().width() + space;
733
734 if (space >= 0) {
735 computedXPosition = roundedMinimumValueForLength(Length(), available Width);
736 geometry.setSpaceSize(IntSize(space, 0));
737 geometry.setPhaseX(actualWidth ? actualWidth - roundToInt(computedXP osition + left) % actualWidth : 0);
738 } else {
739 backgroundRepeatX = NoRepeatFill;
740 }
741 }
742 if (backgroundRepeatX == NoRepeatFill) {
743 int xOffset = fillLayer.backgroundXOrigin() == RightEdge ? availableWidt h - computedXPosition : computedXPosition;
744 geometry.setNoRepeatX(left + xOffset);
745 geometry.setSpaceSize(IntSize(0, geometry.spaceSize().height()));
746 }
747
748 if (backgroundRepeatY == RepeatFill) {
749 geometry.setPhaseY(geometry.tileSize().height() ? geometry.tileSize().he ight() - roundToInt(computedYPosition + top) % geometry.tileSize().height() : 0) ;
750 geometry.setSpaceSize(IntSize(geometry.spaceSize().width(), 0));
751 } else if (backgroundRepeatY == SpaceFill && fillTileSize.height() > 0) {
752 int space = getSpace(positioningAreaSize.height(), geometry.tileSize().h eight());
753 int actualHeight = geometry.tileSize().height() + space;
754
755 if (space >= 0) {
756 computedYPosition = roundedMinimumValueForLength(Length(), available Height);
757 geometry.setSpaceSize(IntSize(geometry.spaceSize().width(), space));
758 geometry.setPhaseY(actualHeight ? actualHeight - roundToInt(computed YPosition + top) % actualHeight : 0);
759 } else {
760 backgroundRepeatY = NoRepeatFill;
761 }
762 }
763 if (backgroundRepeatY == NoRepeatFill) {
764 int yOffset = fillLayer.backgroundYOrigin() == BottomEdge ? availableHei ght - computedYPosition : computedYPosition;
765 geometry.setNoRepeatY(top + yOffset);
766 geometry.setSpaceSize(IntSize(geometry.spaceSize().width(), 0));
767 }
768
769 if (fixedAttachment)
770 geometry.useFixedAttachment(snappedPaintRect.location());
771
772 geometry.clip(snappedPaintRect);
773 geometry.setDestOrigin(geometry.destRect().location());
774 }
775
776 InterpolationQuality BoxPainter::chooseInterpolationQuality(RenderBoxModelObject & obj, GraphicsContext* context, Image* image, const void* layer, const LayoutSi ze& size)
777 {
778 return ImageQualityController::imageQualityController()->chooseInterpolation Quality(context, &obj, image, layer, size);
779 }
780
781 bool BoxPainter::fixedBackgroundPaintsInLocalCoordinates(RenderObject& obj)
782 {
783 if (!obj.isDocumentElement())
784 return false;
785
786 if (obj.view()->frameView() && obj.view()->frameView()->paintBehavior() & Pa intBehaviorFlattenCompositingLayers)
787 return false;
788
789 RenderLayer* rootLayer = obj.view()->layer();
790 if (!rootLayer || rootLayer->compositingState() == NotComposited)
791 return false;
792
793 return rootLayer->compositedLayerMapping()->backgroundLayerPaintsFixedRootBa ckground();
794 }
795
796 static inline void applySubPixelHeuristicForTileSize(LayoutSize& tileSize, const IntSize& positioningAreaSize)
797 {
798 tileSize.setWidth(positioningAreaSize.width() - tileSize.width() <= 1 ? tile Size.width().ceil() : tileSize.width().floor());
799 tileSize.setHeight(positioningAreaSize.height() - tileSize.height() <= 1 ? t ileSize.height().ceil() : tileSize.height().floor());
800 }
801
802 IntSize BoxPainter::calculateFillTileSize(RenderBoxModelObject& obj, const FillL ayer& fillLayer, const IntSize& positioningAreaSize)
803 {
804 StyleImage* image = fillLayer.image();
805 EFillSizeType type = fillLayer.size().type;
806
807 IntSize imageIntrinsicSize = obj.calculateImageIntrinsicDimensions(image, po sitioningAreaSize, RenderBoxModelObject::ScaleByEffectiveZoom);
808 imageIntrinsicSize.scale(1 / image->imageScaleFactor(), 1 / image->imageScal eFactor());
809 switch (type) {
810 case SizeLength: {
811 LayoutSize tileSize = positioningAreaSize;
812
813 Length layerWidth = fillLayer.size().size.width();
814 Length layerHeight = fillLayer.size().size.height();
815
816 if (layerWidth.isFixed())
817 tileSize.setWidth(layerWidth.value());
818 else if (layerWidth.isPercent())
819 tileSize.setWidth(valueForLength(layerWidth, positioningAreaSize.wid th()));
820
821 if (layerHeight.isFixed())
822 tileSize.setHeight(layerHeight.value());
823 else if (layerHeight.isPercent())
824 tileSize.setHeight(valueForLength(layerHeight, positioningAreaSize.h eight()));
825
826 applySubPixelHeuristicForTileSize(tileSize, positioningAreaSize);
827
828 // If one of the values is auto we have to use the appropriate
829 // scale to maintain our aspect ratio.
830 if (layerWidth.isAuto() && !layerHeight.isAuto()) {
831 if (imageIntrinsicSize.height())
832 tileSize.setWidth(imageIntrinsicSize.width() * tileSize.height() / imageIntrinsicSize.height());
833 } else if (!layerWidth.isAuto() && layerHeight.isAuto()) {
834 if (imageIntrinsicSize.width())
835 tileSize.setHeight(imageIntrinsicSize.height() * tileSize.width( ) / imageIntrinsicSize.width());
836 } else if (layerWidth.isAuto() && layerHeight.isAuto()) {
837 // If both width and height are auto, use the image's intrinsic size .
838 tileSize = imageIntrinsicSize;
839 }
840
841 tileSize.clampNegativeToZero();
842 return flooredIntSize(tileSize);
843 }
844 case SizeNone: {
845 // If both values are ‘auto’ then the intrinsic width and/or height of t he image should be used, if any.
846 if (!imageIntrinsicSize.isEmpty())
847 return imageIntrinsicSize;
848
849 // If the image has neither an intrinsic width nor an intrinsic height, its size is determined as for ‘contain’.
850 type = Contain;
851 }
852 case Contain:
853 case Cover: {
854 float horizontalScaleFactor = imageIntrinsicSize.width()
855 ? static_cast<float>(positioningAreaSize.width()) / imageIntrinsicSi ze.width() : 1;
856 float verticalScaleFactor = imageIntrinsicSize.height()
857 ? static_cast<float>(positioningAreaSize.height()) / imageIntrinsicS ize.height() : 1;
858 float scaleFactor = type == Contain ? std::min(horizontalScaleFactor, ve rticalScaleFactor) : std::max(horizontalScaleFactor, verticalScaleFactor);
859 return IntSize(std::max(1l, lround(imageIntrinsicSize.width() * scaleFac tor)), std::max(1l, lround(imageIntrinsicSize.height() * scaleFactor)));
860 }
861 }
862
863 ASSERT_NOT_REACHED();
864 return IntSize();
865 }
866
241 } // namespace blink 867 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698