| OLD | NEW |
| 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 Apple Inc. All rights reserved. | 6 * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. |
| 7 * Copyright (C) 2010 Google Inc. All rights reserved. | 7 * Copyright (C) 2010 Google Inc. 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 |
| 11 * License as published by the Free Software Foundation; either | 11 * License as published by the Free Software Foundation; either |
| 12 * version 2 of the License, or (at your option) any later version. | 12 * version 2 of the License, or (at your option) any later version. |
| 13 * | 13 * |
| 14 * This library is distributed in the hope that it will be useful, | 14 * This library is distributed in the hope that it will be useful, |
| 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 17 * Library General Public License for more details. | 17 * Library General Public License for more details. |
| 18 * | 18 * |
| 19 * You should have received a copy of the GNU Library General Public License | 19 * You should have received a copy of the GNU Library General Public License |
| 20 * along with this library; see the file COPYING.LIB. If not, write to | 20 * along with this library; see the file COPYING.LIB. If not, write to |
| 21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | 21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| 22 * Boston, MA 02110-1301, USA. | 22 * Boston, MA 02110-1301, USA. |
| 23 * | 23 * |
| 24 */ | 24 */ |
| 25 | 25 |
| 26 #include "config.h" | 26 #include "config.h" |
| 27 #include "core/rendering/RenderBoxModelObject.h" | 27 #include "core/rendering/RenderBoxModelObject.h" |
| 28 | 28 |
| 29 #include "core/HTMLNames.h" | |
| 30 #include "core/frame/Settings.h" | |
| 31 #include "core/html/HTMLFrameOwnerElement.h" | |
| 32 #include "core/page/scrolling/ScrollingConstraints.h" | 29 #include "core/page/scrolling/ScrollingConstraints.h" |
| 33 #include "core/rendering/ImageQualityController.h" | 30 #include "core/rendering/ImageQualityController.h" |
| 34 #include "core/rendering/RenderBlock.h" | 31 #include "core/rendering/RenderBlock.h" |
| 35 #include "core/rendering/RenderFlowThread.h" | 32 #include "core/rendering/RenderFlowThread.h" |
| 36 #include "core/rendering/RenderGeometryMap.h" | 33 #include "core/rendering/RenderGeometryMap.h" |
| 37 #include "core/rendering/RenderInline.h" | 34 #include "core/rendering/RenderInline.h" |
| 38 #include "core/rendering/RenderLayer.h" | 35 #include "core/rendering/RenderLayer.h" |
| 39 #include "core/rendering/RenderObjectInlines.h" | 36 #include "core/rendering/RenderObjectInlines.h" |
| 40 #include "core/rendering/RenderRegion.h" | 37 #include "core/rendering/RenderRegion.h" |
| 41 #include "core/rendering/RenderTextFragment.h" | 38 #include "core/rendering/RenderTextFragment.h" |
| 42 #include "core/rendering/RenderView.h" | 39 #include "core/rendering/RenderView.h" |
| 43 #include "core/rendering/compositing/CompositedLayerMapping.h" | 40 #include "core/rendering/compositing/CompositedLayerMapping.h" |
| 44 #include "core/rendering/compositing/RenderLayerCompositor.h" | 41 #include "core/rendering/compositing/RenderLayerCompositor.h" |
| 45 #include "core/rendering/style/BorderEdge.h" | 42 #include "core/rendering/style/BorderEdge.h" |
| 46 #include "core/rendering/style/ShadowList.h" | 43 #include "core/rendering/style/ShadowList.h" |
| 47 #include "platform/LengthFunctions.h" | 44 #include "platform/LengthFunctions.h" |
| 48 #include "platform/geometry/TransformState.h" | 45 #include "platform/geometry/TransformState.h" |
| 49 #include "platform/graphics/DrawLooperBuilder.h" | 46 #include "platform/graphics/DrawLooperBuilder.h" |
| 50 #include "platform/graphics/GraphicsContextStateSaver.h" | 47 #include "platform/graphics/GraphicsContextStateSaver.h" |
| 51 #include "platform/graphics/Path.h" | 48 #include "platform/graphics/Path.h" |
| 52 #include "wtf/CurrentTime.h" | 49 #include "wtf/CurrentTime.h" |
| 53 | 50 |
| 54 namespace blink { | 51 namespace blink { |
| 55 | 52 |
| 56 using namespace HTMLNames; | |
| 57 | |
| 58 // The HashMap for storing continuation pointers. | 53 // The HashMap for storing continuation pointers. |
| 59 // An inline can be split with blocks occuring in between the inline content. | 54 // An inline can be split with blocks occuring in between the inline content. |
| 60 // When this occurs we need a pointer to the next object. We can basically be | 55 // When this occurs we need a pointer to the next object. We can basically be |
| 61 // split into a sequence of inlines and blocks. The continuation will either be | 56 // split into a sequence of inlines and blocks. The continuation will either be |
| 62 // an anonymous block (that houses other blocks) or it will be an inline flow. | 57 // an anonymous block (that houses other blocks) or it will be an inline flow. |
| 63 // <b><i><p>Hello</p></i></b>. In this example the <i> will have a block as | 58 // <b><i><p>Hello</p></i></b>. In this example the <i> will have a block as |
| 64 // its continuation but the <b> will just have an inline as its continuation. | 59 // its continuation but the <b> will just have an inline as its continuation. |
| 65 typedef WillBeHeapHashMap<RawPtrWillBeMember<const RenderBoxModelObject>, RawPtr
WillBeMember<RenderBoxModelObject> > ContinuationMap; | 60 typedef WillBeHeapHashMap<RawPtrWillBeMember<const RenderBoxModelObject>, RawPtr
WillBeMember<RenderBoxModelObject> > ContinuationMap; |
| 66 static OwnPtrWillBePersistent<ContinuationMap>* continuationMap = 0; | 61 static OwnPtrWillBePersistent<ContinuationMap>* continuationMap = 0; |
| 67 | 62 |
| (...skipping 27 matching lines...) Expand all Loading... |
| 95 return; | 90 return; |
| 96 | 91 |
| 97 layer()->contentChanged(changeType); | 92 layer()->contentChanged(changeType); |
| 98 } | 93 } |
| 99 | 94 |
| 100 bool RenderBoxModelObject::hasAcceleratedCompositing() const | 95 bool RenderBoxModelObject::hasAcceleratedCompositing() const |
| 101 { | 96 { |
| 102 return view()->compositor()->hasAcceleratedCompositing(); | 97 return view()->compositor()->hasAcceleratedCompositing(); |
| 103 } | 98 } |
| 104 | 99 |
| 105 InterpolationQuality RenderBoxModelObject::chooseInterpolationQuality(GraphicsCo
ntext* context, Image* image, const void* layer, const LayoutSize& size) | |
| 106 { | |
| 107 return ImageQualityController::imageQualityController()->chooseInterpolation
Quality(context, this, image, layer, size); | |
| 108 } | |
| 109 | |
| 110 RenderBoxModelObject::RenderBoxModelObject(ContainerNode* node) | 100 RenderBoxModelObject::RenderBoxModelObject(ContainerNode* node) |
| 111 : RenderLayerModelObject(node) | 101 : RenderLayerModelObject(node) |
| 112 { | 102 { |
| 113 } | 103 } |
| 114 | 104 |
| 115 RenderBoxModelObject::~RenderBoxModelObject() | 105 RenderBoxModelObject::~RenderBoxModelObject() |
| 116 { | 106 { |
| 117 } | 107 } |
| 118 | 108 |
| 119 void RenderBoxModelObject::willBeDestroyed() | 109 void RenderBoxModelObject::willBeDestroyed() |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 195 if (cb->isRenderView()) | 185 if (cb->isRenderView()) |
| 196 return false; | 186 return false; |
| 197 | 187 |
| 198 if (cb->isOutOfFlowPositioned() && !cb->style()->logicalTop().isAuto() && !c
b->style()->logicalBottom().isAuto()) | 188 if (cb->isOutOfFlowPositioned() && !cb->style()->logicalTop().isAuto() && !c
b->style()->logicalBottom().isAuto()) |
| 199 return false; | 189 return false; |
| 200 | 190 |
| 201 // If the height of the containing block computes to 'auto', then it hasn't
been 'specified explicitly'. | 191 // If the height of the containing block computes to 'auto', then it hasn't
been 'specified explicitly'. |
| 202 return cb->hasAutoHeightOrContainingBlockWithAutoHeight(); | 192 return cb->hasAutoHeightOrContainingBlockWithAutoHeight(); |
| 203 } | 193 } |
| 204 | 194 |
| 205 bool RenderBoxModelObject::isDocumentElementWithOpaqueBackground() const | |
| 206 { | |
| 207 if (!isDocumentElement()) | |
| 208 return false; | |
| 209 | |
| 210 // The background is opaque only if we're the root document, since iframes w
ith | |
| 211 // no background in the child document should show the parent's background. | |
| 212 bool isOpaque = true; | |
| 213 Element* ownerElement = document().ownerElement(); | |
| 214 if (ownerElement) { | |
| 215 if (!isHTMLFrameElement(*ownerElement)) { | |
| 216 // Locate the <body> element using the DOM. This is easier than tryi
ng | |
| 217 // to crawl around a render tree with potential :before/:after conte
nt and | |
| 218 // anonymous blocks created by inline <body> tags etc. We can locate
the <body> | |
| 219 // render object very easily via the DOM. | |
| 220 HTMLElement* body = document().body(); | |
| 221 if (body) { | |
| 222 // Can't scroll a frameset document anyway. | |
| 223 isOpaque = body->hasTagName(framesetTag); | |
| 224 } else { | |
| 225 // FIXME: SVG specific behavior should be in the SVG code. | |
| 226 // SVG documents and XML documents with SVG root nodes are trans
parent. | |
| 227 isOpaque = !document().hasSVGRootNode(); | |
| 228 } | |
| 229 } | |
| 230 } else if (view()->frameView()) { | |
| 231 isOpaque = !view()->frameView()->isTransparent(); | |
| 232 } | |
| 233 | |
| 234 return isOpaque; | |
| 235 } | |
| 236 | |
| 237 void RenderBoxModelObject::paintRootBackgroundColor(const PaintInfo& paintInfo,
const LayoutRect& rect, const Color& bgColor) | |
| 238 { | |
| 239 GraphicsContext* context = paintInfo.context; | |
| 240 if (rect.isEmpty()) | |
| 241 return; | |
| 242 | |
| 243 ASSERT(isDocumentElement()); | |
| 244 | |
| 245 IntRect backgroundRect(pixelSnappedIntRect(rect)); | |
| 246 backgroundRect.intersect(paintInfo.rect); | |
| 247 | |
| 248 Color baseColor = view()->frameView()->baseBackgroundColor(); | |
| 249 bool shouldClearDocumentBackground = document().settings() && document().set
tings()->shouldClearDocumentBackground(); | |
| 250 CompositeOperator operation = shouldClearDocumentBackground ? CompositeCopy
: context->compositeOperation(); | |
| 251 | |
| 252 // If we have an alpha go ahead and blend with the base background color. | |
| 253 if (baseColor.alpha()) { | |
| 254 if (bgColor.alpha()) | |
| 255 baseColor = baseColor.blend(bgColor); | |
| 256 context->fillRect(backgroundRect, baseColor, operation); | |
| 257 } else if (bgColor.alpha()) { | |
| 258 context->fillRect(backgroundRect, bgColor, operation); | |
| 259 } else if (shouldClearDocumentBackground) { | |
| 260 context->clearRect(backgroundRect); | |
| 261 } | |
| 262 } | |
| 263 | |
| 264 LayoutSize RenderBoxModelObject::relativePositionOffset() const | 195 LayoutSize RenderBoxModelObject::relativePositionOffset() const |
| 265 { | 196 { |
| 266 LayoutSize offset = accumulateInFlowPositionOffsets(this); | 197 LayoutSize offset = accumulateInFlowPositionOffsets(this); |
| 267 | 198 |
| 268 RenderBlock* containingBlock = this->containingBlock(); | 199 RenderBlock* containingBlock = this->containingBlock(); |
| 269 | 200 |
| 270 // Objects that shrink to avoid floats normally use available line width whe
n computing containing block width. However | 201 // Objects that shrink to avoid floats normally use available line width whe
n computing containing block width. However |
| 271 // in the case of relative positioning using percentages, we can't do this.
The offset should always be resolved using the | 202 // in the case of relative positioning using percentages, we can't do this.
The offset should always be resolved using the |
| 272 // available width of the containing block. Therefore we don't use containi
ngBlockLogicalWidthForContent() here, but instead explicitly | 203 // available width of the containing block. Therefore we don't use containi
ngBlockLogicalWidthForContent() here, but instead explicitly |
| 273 // call availableWidth on our containing block. | 204 // call availableWidth on our containing block. |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 373 } | 304 } |
| 374 | 305 |
| 375 LayoutUnit RenderBoxModelObject::computedCSSPadding(const Length& padding) const | 306 LayoutUnit RenderBoxModelObject::computedCSSPadding(const Length& padding) const |
| 376 { | 307 { |
| 377 LayoutUnit w = 0; | 308 LayoutUnit w = 0; |
| 378 if (padding.isPercent()) | 309 if (padding.isPercent()) |
| 379 w = containingBlockLogicalWidthForContent(); | 310 w = containingBlockLogicalWidthForContent(); |
| 380 return minimumValueForLength(padding, w); | 311 return minimumValueForLength(padding, w); |
| 381 } | 312 } |
| 382 | 313 |
| 383 RoundedRect RenderBoxModelObject::getBackgroundRoundedRect(const LayoutRect& bor
derRect, InlineFlowBox* box, LayoutUnit inlineBoxWidth, LayoutUnit inlineBoxHeig
ht, | |
| 384 bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const | |
| 385 { | |
| 386 RoundedRect border = style()->getRoundedBorderFor(borderRect, includeLogical
LeftEdge, includeLogicalRightEdge); | |
| 387 if (box && (box->nextLineBox() || box->prevLineBox())) { | |
| 388 RoundedRect segmentBorder = style()->getRoundedBorderFor(LayoutRect(0, 0
, inlineBoxWidth, inlineBoxHeight), includeLogicalLeftEdge, includeLogicalRightE
dge); | |
| 389 border.setRadii(segmentBorder.radii()); | |
| 390 } | |
| 391 | |
| 392 return border; | |
| 393 } | |
| 394 | |
| 395 void RenderBoxModelObject::clipRoundedInnerRect(GraphicsContext * context, const
LayoutRect& rect, const RoundedRect& clipRect) | |
| 396 { | |
| 397 if (clipRect.isRenderable()) | |
| 398 context->clipRoundedRect(clipRect); | |
| 399 else { | |
| 400 // We create a rounded rect for each of the corners and clip it, while m
aking sure we clip opposing corners together. | |
| 401 if (!clipRect.radii().topLeft().isEmpty() || !clipRect.radii().bottomRig
ht().isEmpty()) { | |
| 402 IntRect topCorner(clipRect.rect().x(), clipRect.rect().y(), rect.max
X() - clipRect.rect().x(), rect.maxY() - clipRect.rect().y()); | |
| 403 RoundedRect::Radii topCornerRadii; | |
| 404 topCornerRadii.setTopLeft(clipRect.radii().topLeft()); | |
| 405 context->clipRoundedRect(RoundedRect(topCorner, topCornerRadii)); | |
| 406 | |
| 407 IntRect bottomCorner(rect.x(), rect.y(), clipRect.rect().maxX() - re
ct.x(), clipRect.rect().maxY() - rect.y()); | |
| 408 RoundedRect::Radii bottomCornerRadii; | |
| 409 bottomCornerRadii.setBottomRight(clipRect.radii().bottomRight()); | |
| 410 context->clipRoundedRect(RoundedRect(bottomCorner, bottomCornerRadii
)); | |
| 411 } | |
| 412 | |
| 413 if (!clipRect.radii().topRight().isEmpty() || !clipRect.radii().bottomLe
ft().isEmpty()) { | |
| 414 IntRect topCorner(rect.x(), clipRect.rect().y(), clipRect.rect().max
X() - rect.x(), rect.maxY() - clipRect.rect().y()); | |
| 415 RoundedRect::Radii topCornerRadii; | |
| 416 topCornerRadii.setTopRight(clipRect.radii().topRight()); | |
| 417 context->clipRoundedRect(RoundedRect(topCorner, topCornerRadii)); | |
| 418 | |
| 419 IntRect bottomCorner(clipRect.rect().x(), rect.y(), rect.maxX() - cl
ipRect.rect().x(), clipRect.rect().maxY() - rect.y()); | |
| 420 RoundedRect::Radii bottomCornerRadii; | |
| 421 bottomCornerRadii.setBottomLeft(clipRect.radii().bottomLeft()); | |
| 422 context->clipRoundedRect(RoundedRect(bottomCorner, bottomCornerRadii
)); | |
| 423 } | |
| 424 } | |
| 425 } | |
| 426 | |
| 427 // FIXME: See crbug.com/382491. The use of getCTM in this context is incorrect b
ecause the matrix returned does not | 314 // FIXME: See crbug.com/382491. The use of getCTM in this context is incorrect b
ecause the matrix returned does not |
| 428 // include scales applied at raster time, such as the device zoom. | 315 // include scales applied at raster time, such as the device zoom. |
| 429 static LayoutRect shrinkRectByOnePixel(GraphicsContext* context, const LayoutRec
t& rect) | 316 static LayoutRect shrinkRectByOnePixel(GraphicsContext* context, const LayoutRec
t& rect) |
| 430 { | 317 { |
| 431 LayoutRect shrunkRect = rect; | 318 LayoutRect shrunkRect = rect; |
| 432 AffineTransform transform = context->getCTM(); | 319 AffineTransform transform = context->getCTM(); |
| 433 shrunkRect.inflateX(-static_cast<LayoutUnit>(ceil(1 / transform.xScale()))); | 320 shrunkRect.inflateX(-static_cast<LayoutUnit>(ceil(1 / transform.xScale()))); |
| 434 shrunkRect.inflateY(-static_cast<LayoutUnit>(ceil(1 / transform.yScale()))); | 321 shrunkRect.inflateY(-static_cast<LayoutUnit>(ceil(1 / transform.yScale()))); |
| 435 return shrunkRect; | 322 return shrunkRect; |
| 436 } | 323 } |
| 437 | 324 |
| 438 LayoutRect RenderBoxModelObject::borderInnerRectAdjustedForBleedAvoidance(Graphi
csContext* context, const LayoutRect& rect, BackgroundBleedAvoidance bleedAvoida
nce) const | 325 LayoutRect RenderBoxModelObject::borderInnerRectAdjustedForBleedAvoidance(Graphi
csContext* context, const LayoutRect& rect, BackgroundBleedAvoidance bleedAvoida
nce) const |
| 439 { | 326 { |
| 440 // We shrink the rectangle by one pixel on each side to make it fully overla
p the anti-aliased background border | 327 // We shrink the rectangle by one pixel on each side to make it fully overla
p the anti-aliased background border |
| 441 return (bleedAvoidance == BackgroundBleedBackgroundOverBorder) ? shrinkRectB
yOnePixel(context, rect) : rect; | 328 return (bleedAvoidance == BackgroundBleedBackgroundOverBorder) ? shrinkRectB
yOnePixel(context, rect) : rect; |
| 442 } | 329 } |
| 443 | 330 |
| 444 RoundedRect RenderBoxModelObject::backgroundRoundedRectAdjustedForBleedAvoidance
(GraphicsContext* context, const LayoutRect& borderRect, BackgroundBleedAvoidanc
e bleedAvoidance, InlineFlowBox* box, const LayoutSize& boxSize, bool includeLog
icalLeftEdge, bool includeLogicalRightEdge) const | |
| 445 { | |
| 446 if (bleedAvoidance == BackgroundBleedShrinkBackground) { | |
| 447 // We shrink the rectangle by one pixel on each side because the bleed i
s one pixel maximum. | |
| 448 return getBackgroundRoundedRect(shrinkRectByOnePixel(context, borderRect
), box, boxSize.width(), boxSize.height(), includeLogicalLeftEdge, includeLogica
lRightEdge); | |
| 449 } | |
| 450 if (bleedAvoidance == BackgroundBleedBackgroundOverBorder) | |
| 451 return style()->getRoundedInnerBorderFor(borderRect, includeLogicalLeftE
dge, includeLogicalRightEdge); | |
| 452 | |
| 453 return getBackgroundRoundedRect(borderRect, box, boxSize.width(), boxSize.he
ight(), includeLogicalLeftEdge, includeLogicalRightEdge); | |
| 454 } | |
| 455 | |
| 456 static void applyBoxShadowForBackground(GraphicsContext* context, const RenderOb
ject* renderer) | |
| 457 { | |
| 458 const ShadowList* shadowList = renderer->style()->boxShadow(); | |
| 459 ASSERT(shadowList); | |
| 460 for (size_t i = shadowList->shadows().size(); i--; ) { | |
| 461 const ShadowData& boxShadow = shadowList->shadows()[i]; | |
| 462 if (boxShadow.style() != Normal) | |
| 463 continue; | |
| 464 FloatSize shadowOffset(boxShadow.x(), boxShadow.y()); | |
| 465 context->setShadow(shadowOffset, boxShadow.blur(), boxShadow.color(), | |
| 466 DrawLooperBuilder::ShadowRespectsTransforms, DrawLooperBuilder::Shad
owIgnoresAlpha); | |
| 467 return; | |
| 468 } | |
| 469 } | |
| 470 | |
| 471 void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, co
nst Color& color, const FillLayer& bgLayer, const LayoutRect& rect, | |
| 472 BackgroundBleedAvoidance bleedAvoidance, InlineFlowBox* box, const LayoutSiz
e& boxSize, CompositeOperator op, RenderObject* backgroundObject, bool skipBaseC
olor) | |
| 473 { | |
| 474 GraphicsContext* context = paintInfo.context; | |
| 475 if (rect.isEmpty()) | |
| 476 return; | |
| 477 | |
| 478 bool includeLeftEdge = box ? box->includeLogicalLeftEdge() : true; | |
| 479 bool includeRightEdge = box ? box->includeLogicalRightEdge() : true; | |
| 480 | |
| 481 bool hasRoundedBorder = style()->hasBorderRadius() && (includeLeftEdge || in
cludeRightEdge); | |
| 482 bool clippedWithLocalScrolling = hasOverflowClip() && bgLayer.attachment() =
= LocalBackgroundAttachment; | |
| 483 bool isBorderFill = bgLayer.clip() == BorderFillBox; | |
| 484 bool isDocumentElementRenderer = this->isDocumentElement(); | |
| 485 bool isBottomLayer = !bgLayer.next(); | |
| 486 | |
| 487 Color bgColor = color; | |
| 488 StyleImage* bgImage = bgLayer.image(); | |
| 489 bool shouldPaintBackgroundImage = bgImage && bgImage->canRender(*this, style
()->effectiveZoom()); | |
| 490 | |
| 491 bool forceBackgroundToWhite = false; | |
| 492 if (document().printing()) { | |
| 493 if (style()->printColorAdjust() == PrintColorAdjustEconomy) | |
| 494 forceBackgroundToWhite = true; | |
| 495 if (document().settings() && document().settings()->shouldPrintBackgroun
ds()) | |
| 496 forceBackgroundToWhite = false; | |
| 497 } | |
| 498 | |
| 499 // When printing backgrounds is disabled or using economy mode, | |
| 500 // change existing background colors and images to a solid white background. | |
| 501 // If there's no bg color or image, leave it untouched to avoid affecting tr
ansparency. | |
| 502 // We don't try to avoid loading the background images, because this style f
lag is only set | |
| 503 // when printing, and at that point we've already loaded the background imag
es anyway. (To avoid | |
| 504 // loading the background images we'd have to do this check when applying st
yles rather than | |
| 505 // while rendering.) | |
| 506 if (forceBackgroundToWhite) { | |
| 507 // Note that we can't reuse this variable below because the bgColor migh
t be changed | |
| 508 bool shouldPaintBackgroundColor = isBottomLayer && bgColor.alpha(); | |
| 509 if (shouldPaintBackgroundImage || shouldPaintBackgroundColor) { | |
| 510 bgColor = Color::white; | |
| 511 shouldPaintBackgroundImage = false; | |
| 512 } | |
| 513 } | |
| 514 | |
| 515 bool colorVisible = bgColor.alpha(); | |
| 516 | |
| 517 // Fast path for drawing simple color backgrounds. | |
| 518 if (!isDocumentElementRenderer && !clippedWithLocalScrolling && !shouldPaint
BackgroundImage && isBorderFill && isBottomLayer) { | |
| 519 if (!colorVisible) | |
| 520 return; | |
| 521 | |
| 522 bool boxShadowShouldBeAppliedToBackground = this->boxShadowShouldBeAppli
edToBackground(bleedAvoidance, box); | |
| 523 GraphicsContextStateSaver shadowStateSaver(*context, boxShadowShouldBeAp
pliedToBackground); | |
| 524 if (boxShadowShouldBeAppliedToBackground) | |
| 525 applyBoxShadowForBackground(context, this); | |
| 526 | |
| 527 if (hasRoundedBorder && bleedAvoidance != BackgroundBleedClipBackground)
{ | |
| 528 RoundedRect border = backgroundRoundedRectAdjustedForBleedAvoidance(
context, rect, bleedAvoidance, box, boxSize, includeLeftEdge, includeRightEdge); | |
| 529 if (border.isRenderable()) | |
| 530 context->fillRoundedRect(border, bgColor); | |
| 531 else { | |
| 532 context->save(); | |
| 533 clipRoundedInnerRect(context, rect, border); | |
| 534 context->fillRect(border.rect(), bgColor); | |
| 535 context->restore(); | |
| 536 } | |
| 537 } else { | |
| 538 context->fillRect(pixelSnappedIntRect(rect), bgColor); | |
| 539 } | |
| 540 | |
| 541 return; | |
| 542 } | |
| 543 | |
| 544 // BorderFillBox radius clipping is taken care of by BackgroundBleedClipBack
ground | |
| 545 bool clipToBorderRadius = hasRoundedBorder && !(isBorderFill && bleedAvoidan
ce == BackgroundBleedClipBackground); | |
| 546 GraphicsContextStateSaver clipToBorderStateSaver(*context, clipToBorderRadiu
s); | |
| 547 if (clipToBorderRadius) { | |
| 548 RoundedRect border = isBorderFill ? backgroundRoundedRectAdjustedForBlee
dAvoidance(context, rect, bleedAvoidance, box, boxSize, includeLeftEdge, include
RightEdge) : getBackgroundRoundedRect(rect, box, boxSize.width(), boxSize.height
(), includeLeftEdge, includeRightEdge); | |
| 549 | |
| 550 // Clip to the padding or content boxes as necessary. | |
| 551 if (bgLayer.clip() == ContentFillBox) { | |
| 552 border = style()->getRoundedInnerBorderFor(border.rect(), | |
| 553 paddingTop() + borderTop(), paddingBottom() + borderBottom(), pa
ddingLeft() + borderLeft(), paddingRight() + borderRight(), includeLeftEdge, inc
ludeRightEdge); | |
| 554 } else if (bgLayer.clip() == PaddingFillBox) | |
| 555 border = style()->getRoundedInnerBorderFor(border.rect(), includeLef
tEdge, includeRightEdge); | |
| 556 | |
| 557 clipRoundedInnerRect(context, rect, border); | |
| 558 } | |
| 559 | |
| 560 int bLeft = includeLeftEdge ? borderLeft() : 0; | |
| 561 int bRight = includeRightEdge ? borderRight() : 0; | |
| 562 LayoutUnit pLeft = includeLeftEdge ? paddingLeft() : LayoutUnit(); | |
| 563 LayoutUnit pRight = includeRightEdge ? paddingRight() : LayoutUnit(); | |
| 564 | |
| 565 GraphicsContextStateSaver clipWithScrollingStateSaver(*context, clippedWithL
ocalScrolling); | |
| 566 LayoutRect scrolledPaintRect = rect; | |
| 567 if (clippedWithLocalScrolling) { | |
| 568 // Clip to the overflow area. | |
| 569 RenderBox* thisBox = toRenderBox(this); | |
| 570 context->clip(thisBox->overflowClipRect(rect.location())); | |
| 571 | |
| 572 // Adjust the paint rect to reflect a scrolled content box with borders
at the ends. | |
| 573 IntSize offset = thisBox->scrolledContentOffset(); | |
| 574 scrolledPaintRect.move(-offset); | |
| 575 scrolledPaintRect.setWidth(bLeft + thisBox->scrollWidth() + bRight); | |
| 576 scrolledPaintRect.setHeight(borderTop() + thisBox->scrollHeight() + bord
erBottom()); | |
| 577 } | |
| 578 | |
| 579 GraphicsContextStateSaver backgroundClipStateSaver(*context, false); | |
| 580 IntRect maskRect; | |
| 581 | |
| 582 switch (bgLayer.clip()) { | |
| 583 case PaddingFillBox: | |
| 584 case ContentFillBox: { | |
| 585 if (clipToBorderRadius) | |
| 586 break; | |
| 587 | |
| 588 // Clip to the padding or content boxes as necessary. | |
| 589 bool includePadding = bgLayer.clip() == ContentFillBox; | |
| 590 LayoutRect clipRect = LayoutRect(scrolledPaintRect.x() + bLeft + (includ
ePadding ? pLeft : LayoutUnit()), | |
| 591 scrolledPaintRect.y() + borderTop() + (includePadding ? paddingTop()
: LayoutUnit()), | |
| 592 scrolledPaintRect.width() - bLeft - bRight - (includePadding ? pLeft
+ pRight : LayoutUnit()), | |
| 593 scrolledPaintRect.height() - borderTop() - borderBottom() - (include
Padding ? paddingTop() + paddingBottom() : LayoutUnit())); | |
| 594 backgroundClipStateSaver.save(); | |
| 595 context->clip(clipRect); | |
| 596 | |
| 597 break; | |
| 598 } | |
| 599 case TextFillBox: { | |
| 600 // First figure out how big the mask has to be. It should be no bigger
than what we need | |
| 601 // to actually render, so we should intersect the dirty rect with the bo
rder box of the background. | |
| 602 maskRect = pixelSnappedIntRect(rect); | |
| 603 maskRect.intersect(paintInfo.rect); | |
| 604 | |
| 605 // We draw the background into a separate layer, to be later masked with
yet another layer | |
| 606 // holding the text content. | |
| 607 backgroundClipStateSaver.save(); | |
| 608 context->clip(maskRect); | |
| 609 context->beginTransparencyLayer(1); | |
| 610 | |
| 611 break; | |
| 612 } | |
| 613 case BorderFillBox: | |
| 614 break; | |
| 615 default: | |
| 616 ASSERT_NOT_REACHED(); | |
| 617 break; | |
| 618 } | |
| 619 | |
| 620 // Paint the color first underneath all images, culled if background image o
ccludes it. | |
| 621 // FIXME: In the bgLayer->hasFiniteBounds() case, we could improve the culli
ng test | |
| 622 // by verifying whether the background image covers the entire layout rect. | |
| 623 if (isBottomLayer) { | |
| 624 IntRect backgroundRect(pixelSnappedIntRect(scrolledPaintRect)); | |
| 625 bool boxShadowShouldBeAppliedToBackground = this->boxShadowShouldBeAppli
edToBackground(bleedAvoidance, box); | |
| 626 bool isOpaqueRoot = (isDocumentElementRenderer && !bgColor.hasAlpha()) |
| isDocumentElementWithOpaqueBackground(); | |
| 627 if (boxShadowShouldBeAppliedToBackground || !shouldPaintBackgroundImage
|| !bgLayer.hasOpaqueImage(this) || !bgLayer.hasRepeatXY() || (isOpaqueRoot && !
toRenderBox(this)->height())) { | |
| 628 if (!boxShadowShouldBeAppliedToBackground) | |
| 629 backgroundRect.intersect(paintInfo.rect); | |
| 630 | |
| 631 GraphicsContextStateSaver shadowStateSaver(*context, boxShadowShould
BeAppliedToBackground); | |
| 632 if (boxShadowShouldBeAppliedToBackground) | |
| 633 applyBoxShadowForBackground(context, this); | |
| 634 | |
| 635 if (isOpaqueRoot && !skipBaseColor) { | |
| 636 paintRootBackgroundColor(paintInfo, rect, bgColor); | |
| 637 } else if (bgColor.alpha()) { | |
| 638 context->fillRect(backgroundRect, bgColor, context->compositeOpe
ration()); | |
| 639 } | |
| 640 } | |
| 641 } | |
| 642 | |
| 643 // no progressive loading of the background image | |
| 644 if (shouldPaintBackgroundImage) { | |
| 645 BackgroundImageGeometry geometry; | |
| 646 calculateBackgroundImageGeometry(paintInfo.paintContainer(), bgLayer, sc
rolledPaintRect, geometry, backgroundObject); | |
| 647 geometry.clip(paintInfo.rect); | |
| 648 if (!geometry.destRect().isEmpty()) { | |
| 649 CompositeOperator compositeOp = op == CompositeSourceOver ? bgLayer.
composite() : op; | |
| 650 RenderObject* clientForBackgroundImage = backgroundObject ? backgrou
ndObject : this; | |
| 651 RefPtr<Image> image = bgImage->image(clientForBackgroundImage, geome
try.tileSize()); | |
| 652 InterpolationQuality interpolationQuality = chooseInterpolationQuali
ty(context, image.get(), &bgLayer, geometry.tileSize()); | |
| 653 if (bgLayer.maskSourceType() == MaskLuminance) | |
| 654 context->setColorFilter(ColorFilterLuminanceToAlpha); | |
| 655 InterpolationQuality previousInterpolationQuality = context->imageIn
terpolationQuality(); | |
| 656 context->setImageInterpolationQuality(interpolationQuality); | |
| 657 context->drawTiledImage(image.get(), geometry.destRect(), geometry.r
elativePhase(), geometry.tileSize(), | |
| 658 compositeOp, bgLayer.blendMode(), geometry.spaceSize()); | |
| 659 context->setImageInterpolationQuality(previousInterpolationQuality); | |
| 660 } | |
| 661 } | |
| 662 | |
| 663 if (bgLayer.clip() == TextFillBox) { | |
| 664 // Create the text mask layer. | |
| 665 context->setCompositeOperation(CompositeDestinationIn); | |
| 666 context->beginTransparencyLayer(1); | |
| 667 | |
| 668 // FIXME: Workaround for https://code.google.com/p/skia/issues/detail?id
=1291. | |
| 669 context->clearRect(maskRect); | |
| 670 | |
| 671 // Now draw the text into the mask. We do this by painting using a speci
al paint phase that signals to | |
| 672 // InlineTextBoxes that they should just add their contents to the clip. | |
| 673 PaintInfo info(context, maskRect, PaintPhaseTextClip, PaintBehaviorForce
BlackText, 0); | |
| 674 context->setCompositeOperation(CompositeSourceOver); | |
| 675 if (box) { | |
| 676 RootInlineBox& root = box->root(); | |
| 677 box->paint(info, LayoutPoint(scrolledPaintRect.x() - box->x(), scrol
ledPaintRect.y() - box->y()), root.lineTop(), root.lineBottom()); | |
| 678 } else { | |
| 679 LayoutSize localOffset = isBox() ? toRenderBox(this)->locationOffset
() : LayoutSize(); | |
| 680 paint(info, scrolledPaintRect.location() - localOffset); | |
| 681 } | |
| 682 | |
| 683 context->endLayer(); | |
| 684 context->endLayer(); | |
| 685 } | |
| 686 } | |
| 687 | |
| 688 static inline int resolveWidthForRatio(int height, const FloatSize& intrinsicRat
io) | 331 static inline int resolveWidthForRatio(int height, const FloatSize& intrinsicRat
io) |
| 689 { | 332 { |
| 690 return ceilf(height * intrinsicRatio.width() / intrinsicRatio.height()); | 333 return ceilf(height * intrinsicRatio.width() / intrinsicRatio.height()); |
| 691 } | 334 } |
| 692 | 335 |
| 693 static inline int resolveHeightForRatio(int width, const FloatSize& intrinsicRat
io) | 336 static inline int resolveHeightForRatio(int width, const FloatSize& intrinsicRat
io) |
| 694 { | 337 { |
| 695 return ceilf(width * intrinsicRatio.height() / intrinsicRatio.width()); | 338 return ceilf(width * intrinsicRatio.height() / intrinsicRatio.width()); |
| 696 } | 339 } |
| 697 | 340 |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 768 // largest dimensions at that ratio such that neither dimension exceeds the
dimensions of the rectangle that | 411 // largest dimensions at that ratio such that neither dimension exceeds the
dimensions of the rectangle that |
| 769 // establishes the coordinate system for the 'background-position' property. | 412 // establishes the coordinate system for the 'background-position' property. |
| 770 if (!intrinsicRatio.isEmpty()) | 413 if (!intrinsicRatio.isEmpty()) |
| 771 return resolveAgainstIntrinsicRatio(positioningAreaSize, intrinsicRatio)
; | 414 return resolveAgainstIntrinsicRatio(positioningAreaSize, intrinsicRatio)
; |
| 772 | 415 |
| 773 // If the image has no intrinsic ratio either, then the dimensions must be a
ssumed to be the rectangle that | 416 // If the image has no intrinsic ratio either, then the dimensions must be a
ssumed to be the rectangle that |
| 774 // establishes the coordinate system for the 'background-position' property. | 417 // establishes the coordinate system for the 'background-position' property. |
| 775 return positioningAreaSize; | 418 return positioningAreaSize; |
| 776 } | 419 } |
| 777 | 420 |
| 778 static inline void applySubPixelHeuristicForTileSize(LayoutSize& tileSize, const
IntSize& positioningAreaSize) | |
| 779 { | |
| 780 tileSize.setWidth(positioningAreaSize.width() - tileSize.width() <= 1 ? tile
Size.width().ceil() : tileSize.width().floor()); | |
| 781 tileSize.setHeight(positioningAreaSize.height() - tileSize.height() <= 1 ? t
ileSize.height().ceil() : tileSize.height().floor()); | |
| 782 } | |
| 783 | |
| 784 IntSize RenderBoxModelObject::calculateFillTileSize(const FillLayer& fillLayer,
const IntSize& positioningAreaSize) const | |
| 785 { | |
| 786 StyleImage* image = fillLayer.image(); | |
| 787 EFillSizeType type = fillLayer.size().type; | |
| 788 | |
| 789 IntSize imageIntrinsicSize = calculateImageIntrinsicDimensions(image, positi
oningAreaSize, ScaleByEffectiveZoom); | |
| 790 imageIntrinsicSize.scale(1 / image->imageScaleFactor(), 1 / image->imageScal
eFactor()); | |
| 791 switch (type) { | |
| 792 case SizeLength: { | |
| 793 LayoutSize tileSize = positioningAreaSize; | |
| 794 | |
| 795 Length layerWidth = fillLayer.size().size.width(); | |
| 796 Length layerHeight = fillLayer.size().size.height(); | |
| 797 | |
| 798 if (layerWidth.isFixed()) | |
| 799 tileSize.setWidth(layerWidth.value()); | |
| 800 else if (layerWidth.isPercent()) | |
| 801 tileSize.setWidth(valueForLength(layerWidth, positioningAreaSize
.width())); | |
| 802 | |
| 803 if (layerHeight.isFixed()) | |
| 804 tileSize.setHeight(layerHeight.value()); | |
| 805 else if (layerHeight.isPercent()) | |
| 806 tileSize.setHeight(valueForLength(layerHeight, positioningAreaSi
ze.height())); | |
| 807 | |
| 808 applySubPixelHeuristicForTileSize(tileSize, positioningAreaSize); | |
| 809 | |
| 810 // If one of the values is auto we have to use the appropriate | |
| 811 // scale to maintain our aspect ratio. | |
| 812 if (layerWidth.isAuto() && !layerHeight.isAuto()) { | |
| 813 if (imageIntrinsicSize.height()) | |
| 814 tileSize.setWidth(imageIntrinsicSize.width() * tileSize.heig
ht() / imageIntrinsicSize.height()); | |
| 815 } else if (!layerWidth.isAuto() && layerHeight.isAuto()) { | |
| 816 if (imageIntrinsicSize.width()) | |
| 817 tileSize.setHeight(imageIntrinsicSize.height() * tileSize.wi
dth() / imageIntrinsicSize.width()); | |
| 818 } else if (layerWidth.isAuto() && layerHeight.isAuto()) { | |
| 819 // If both width and height are auto, use the image's intrinsic
size. | |
| 820 tileSize = imageIntrinsicSize; | |
| 821 } | |
| 822 | |
| 823 tileSize.clampNegativeToZero(); | |
| 824 return flooredIntSize(tileSize); | |
| 825 } | |
| 826 case SizeNone: { | |
| 827 // If both values are ‘auto’ then the intrinsic width and/or height
of the image should be used, if any. | |
| 828 if (!imageIntrinsicSize.isEmpty()) | |
| 829 return imageIntrinsicSize; | |
| 830 | |
| 831 // If the image has neither an intrinsic width nor an intrinsic heig
ht, its size is determined as for ‘contain’. | |
| 832 type = Contain; | |
| 833 } | |
| 834 case Contain: | |
| 835 case Cover: { | |
| 836 float horizontalScaleFactor = imageIntrinsicSize.width() | |
| 837 ? static_cast<float>(positioningAreaSize.width()) / imageIntrins
icSize.width() : 1; | |
| 838 float verticalScaleFactor = imageIntrinsicSize.height() | |
| 839 ? static_cast<float>(positioningAreaSize.height()) / imageIntrin
sicSize.height() : 1; | |
| 840 float scaleFactor = type == Contain ? std::min(horizontalScaleFactor
, verticalScaleFactor) : std::max(horizontalScaleFactor, verticalScaleFactor); | |
| 841 return IntSize(std::max(1l, lround(imageIntrinsicSize.width() * scal
eFactor)), std::max(1l, lround(imageIntrinsicSize.height() * scaleFactor))); | |
| 842 } | |
| 843 } | |
| 844 | |
| 845 ASSERT_NOT_REACHED(); | |
| 846 return IntSize(); | |
| 847 } | |
| 848 | |
| 849 void RenderBoxModelObject::BackgroundImageGeometry::setNoRepeatX(int xOffset) | |
| 850 { | |
| 851 m_destRect.move(std::max(xOffset, 0), 0); | |
| 852 m_phase.setX(-std::min(xOffset, 0)); | |
| 853 m_destRect.setWidth(m_tileSize.width() + std::min(xOffset, 0)); | |
| 854 } | |
| 855 void RenderBoxModelObject::BackgroundImageGeometry::setNoRepeatY(int yOffset) | |
| 856 { | |
| 857 m_destRect.move(0, std::max(yOffset, 0)); | |
| 858 m_phase.setY(-std::min(yOffset, 0)); | |
| 859 m_destRect.setHeight(m_tileSize.height() + std::min(yOffset, 0)); | |
| 860 } | |
| 861 | |
| 862 void RenderBoxModelObject::BackgroundImageGeometry::useFixedAttachment(const Int
Point& attachmentPoint) | |
| 863 { | |
| 864 IntPoint alignedPoint = attachmentPoint; | |
| 865 m_phase.move(std::max(alignedPoint.x() - m_destRect.x(), 0), std::max(aligne
dPoint.y() - m_destRect.y(), 0)); | |
| 866 } | |
| 867 | |
| 868 void RenderBoxModelObject::BackgroundImageGeometry::clip(const IntRect& clipRect
) | |
| 869 { | |
| 870 m_destRect.intersect(clipRect); | |
| 871 } | |
| 872 | |
| 873 IntPoint RenderBoxModelObject::BackgroundImageGeometry::relativePhase() const | |
| 874 { | |
| 875 IntPoint phase = m_phase; | |
| 876 phase += m_destRect.location() - m_destOrigin; | |
| 877 return phase; | |
| 878 } | |
| 879 | |
| 880 bool RenderBoxModelObject::fixedBackgroundPaintsInLocalCoordinates() const | |
| 881 { | |
| 882 if (!isDocumentElement()) | |
| 883 return false; | |
| 884 | |
| 885 if (view()->frameView() && view()->frameView()->paintBehavior() & PaintBehav
iorFlattenCompositingLayers) | |
| 886 return false; | |
| 887 | |
| 888 RenderLayer* rootLayer = view()->layer(); | |
| 889 if (!rootLayer || rootLayer->compositingState() == NotComposited) | |
| 890 return false; | |
| 891 | |
| 892 return rootLayer->compositedLayerMapping()->backgroundLayerPaintsFixedRootBa
ckground(); | |
| 893 } | |
| 894 | |
| 895 static inline int getSpace(int areaSize, int tileSize) | |
| 896 { | |
| 897 int numberOfTiles = areaSize / tileSize; | |
| 898 int space = -1; | |
| 899 | |
| 900 if (numberOfTiles > 1) | |
| 901 space = lroundf((float)(areaSize - numberOfTiles * tileSize) / (numberOf
Tiles - 1)); | |
| 902 | |
| 903 return space; | |
| 904 } | |
| 905 | |
| 906 void RenderBoxModelObject::calculateBackgroundImageGeometry(const RenderLayerMod
elObject* paintContainer, const FillLayer& fillLayer, const LayoutRect& paintRec
t, | |
| 907 BackgroundImageGeometry& geometry, RenderObject* backgroundObject) const | |
| 908 { | |
| 909 LayoutUnit left = 0; | |
| 910 LayoutUnit top = 0; | |
| 911 IntSize positioningAreaSize; | |
| 912 IntRect snappedPaintRect = pixelSnappedIntRect(paintRect); | |
| 913 | |
| 914 // Determine the background positioning area and set destRect to the backgro
und painting area. | |
| 915 // destRect will be adjusted later if the background is non-repeating. | |
| 916 // FIXME: transforms spec says that fixed backgrounds behave like scroll ins
ide transforms. | |
| 917 bool fixedAttachment = fillLayer.attachment() == FixedBackgroundAttachment; | |
| 918 | |
| 919 if (RuntimeEnabledFeatures::fastMobileScrollingEnabled()) { | |
| 920 // As a side effect of an optimization to blit on scroll, we do not hono
r the CSS | |
| 921 // property "background-attachment: fixed" because it may result in rend
ering | |
| 922 // artifacts. Note, these artifacts only appear if we are blitting on sc
roll of | |
| 923 // a page that has fixed background images. | |
| 924 fixedAttachment = false; | |
| 925 } | |
| 926 | |
| 927 if (!fixedAttachment) { | |
| 928 geometry.setDestRect(snappedPaintRect); | |
| 929 | |
| 930 LayoutUnit right = 0; | |
| 931 LayoutUnit bottom = 0; | |
| 932 // Scroll and Local. | |
| 933 if (fillLayer.origin() != BorderFillBox) { | |
| 934 left = borderLeft(); | |
| 935 right = borderRight(); | |
| 936 top = borderTop(); | |
| 937 bottom = borderBottom(); | |
| 938 if (fillLayer.origin() == ContentFillBox) { | |
| 939 left += paddingLeft(); | |
| 940 right += paddingRight(); | |
| 941 top += paddingTop(); | |
| 942 bottom += paddingBottom(); | |
| 943 } | |
| 944 } | |
| 945 | |
| 946 // The background of the box generated by the root element covers the en
tire canvas including | |
| 947 // its margins. Since those were added in already, we have to factor the
m out when computing | |
| 948 // the background positioning area. | |
| 949 if (isDocumentElement()) { | |
| 950 positioningAreaSize = pixelSnappedIntSize(toRenderBox(this)->size()
- LayoutSize(left + right, top + bottom), toRenderBox(this)->location()); | |
| 951 left += marginLeft(); | |
| 952 top += marginTop(); | |
| 953 } else | |
| 954 positioningAreaSize = pixelSnappedIntSize(paintRect.size() - LayoutS
ize(left + right, top + bottom), paintRect.location()); | |
| 955 } else { | |
| 956 geometry.setHasNonLocalGeometry(); | |
| 957 | |
| 958 IntRect viewportRect = pixelSnappedIntRect(viewRect()); | |
| 959 if (fixedBackgroundPaintsInLocalCoordinates()) | |
| 960 viewportRect.setLocation(IntPoint()); | |
| 961 else if (FrameView* frameView = view()->frameView()) | |
| 962 viewportRect.setLocation(IntPoint(frameView->scrollOffsetForFixedPos
ition())); | |
| 963 | |
| 964 if (paintContainer) { | |
| 965 IntPoint absoluteContainerOffset = roundedIntPoint(paintContainer->l
ocalToAbsolute(FloatPoint())); | |
| 966 viewportRect.moveBy(-absoluteContainerOffset); | |
| 967 } | |
| 968 | |
| 969 geometry.setDestRect(pixelSnappedIntRect(viewportRect)); | |
| 970 positioningAreaSize = geometry.destRect().size(); | |
| 971 } | |
| 972 | |
| 973 const RenderObject* clientForBackgroundImage = backgroundObject ? background
Object : this; | |
| 974 IntSize fillTileSize = calculateFillTileSize(fillLayer, positioningAreaSize)
; | |
| 975 fillLayer.image()->setContainerSizeForRenderer(clientForBackgroundImage, fil
lTileSize, style()->effectiveZoom()); | |
| 976 geometry.setTileSize(fillTileSize); | |
| 977 | |
| 978 EFillRepeat backgroundRepeatX = fillLayer.repeatX(); | |
| 979 EFillRepeat backgroundRepeatY = fillLayer.repeatY(); | |
| 980 int availableWidth = positioningAreaSize.width() - geometry.tileSize().width
(); | |
| 981 int availableHeight = positioningAreaSize.height() - geometry.tileSize().hei
ght(); | |
| 982 | |
| 983 LayoutUnit computedXPosition = roundedMinimumValueForLength(fillLayer.xPosit
ion(), availableWidth); | |
| 984 if (backgroundRepeatX == RoundFill && positioningAreaSize.width() > 0 && fil
lTileSize.width() > 0) { | |
| 985 long nrTiles = std::max(1l, lroundf((float)positioningAreaSize.width() /
fillTileSize.width())); | |
| 986 | |
| 987 if (fillLayer.size().size.height().isAuto() && backgroundRepeatY != Roun
dFill) { | |
| 988 fillTileSize.setHeight(fillTileSize.height() * positioningAreaSize.w
idth() / (nrTiles * fillTileSize.width())); | |
| 989 } | |
| 990 | |
| 991 fillTileSize.setWidth(positioningAreaSize.width() / nrTiles); | |
| 992 geometry.setTileSize(fillTileSize); | |
| 993 geometry.setPhaseX(geometry.tileSize().width() ? geometry.tileSize().wid
th() - roundToInt(computedXPosition + left) % geometry.tileSize().width() : 0); | |
| 994 geometry.setSpaceSize(IntSize()); | |
| 995 } | |
| 996 | |
| 997 LayoutUnit computedYPosition = roundedMinimumValueForLength(fillLayer.yPosit
ion(), availableHeight); | |
| 998 if (backgroundRepeatY == RoundFill && positioningAreaSize.height() > 0 && fi
llTileSize.height() > 0) { | |
| 999 long nrTiles = std::max(1l, lroundf((float)positioningAreaSize.height()
/ fillTileSize.height())); | |
| 1000 | |
| 1001 if (fillLayer.size().size.width().isAuto() && backgroundRepeatX != Round
Fill) { | |
| 1002 fillTileSize.setWidth(fillTileSize.width() * positioningAreaSize.hei
ght() / (nrTiles * fillTileSize.height())); | |
| 1003 } | |
| 1004 | |
| 1005 fillTileSize.setHeight(positioningAreaSize.height() / nrTiles); | |
| 1006 geometry.setTileSize(fillTileSize); | |
| 1007 geometry.setPhaseY(geometry.tileSize().height() ? geometry.tileSize().he
ight() - roundToInt(computedYPosition + top) % geometry.tileSize().height() : 0)
; | |
| 1008 geometry.setSpaceSize(IntSize()); | |
| 1009 } | |
| 1010 | |
| 1011 if (backgroundRepeatX == RepeatFill) { | |
| 1012 geometry.setPhaseX(geometry.tileSize().width() ? geometry.tileSize().wid
th() - roundToInt(computedXPosition + left) % geometry.tileSize().width() : 0); | |
| 1013 geometry.setSpaceSize(IntSize()); | |
| 1014 } else if (backgroundRepeatX == SpaceFill && fillTileSize.width() > 0) { | |
| 1015 int space = getSpace(positioningAreaSize.width(), geometry.tileSize().wi
dth()); | |
| 1016 int actualWidth = geometry.tileSize().width() + space; | |
| 1017 | |
| 1018 if (space >= 0) { | |
| 1019 computedXPosition = roundedMinimumValueForLength(Length(), available
Width); | |
| 1020 geometry.setSpaceSize(IntSize(space, 0)); | |
| 1021 geometry.setPhaseX(actualWidth ? actualWidth - roundToInt(computedXP
osition + left) % actualWidth : 0); | |
| 1022 } else { | |
| 1023 backgroundRepeatX = NoRepeatFill; | |
| 1024 } | |
| 1025 } | |
| 1026 if (backgroundRepeatX == NoRepeatFill) { | |
| 1027 int xOffset = fillLayer.backgroundXOrigin() == RightEdge ? availableWidt
h - computedXPosition : computedXPosition; | |
| 1028 geometry.setNoRepeatX(left + xOffset); | |
| 1029 geometry.setSpaceSize(IntSize(0, geometry.spaceSize().height())); | |
| 1030 } | |
| 1031 | |
| 1032 if (backgroundRepeatY == RepeatFill) { | |
| 1033 geometry.setPhaseY(geometry.tileSize().height() ? geometry.tileSize().he
ight() - roundToInt(computedYPosition + top) % geometry.tileSize().height() : 0)
; | |
| 1034 geometry.setSpaceSize(IntSize(geometry.spaceSize().width(), 0)); | |
| 1035 } else if (backgroundRepeatY == SpaceFill && fillTileSize.height() > 0) { | |
| 1036 int space = getSpace(positioningAreaSize.height(), geometry.tileSize().h
eight()); | |
| 1037 int actualHeight = geometry.tileSize().height() + space; | |
| 1038 | |
| 1039 if (space >= 0) { | |
| 1040 computedYPosition = roundedMinimumValueForLength(Length(), available
Height); | |
| 1041 geometry.setSpaceSize(IntSize(geometry.spaceSize().width(), space)); | |
| 1042 geometry.setPhaseY(actualHeight ? actualHeight - roundToInt(computed
YPosition + top) % actualHeight : 0); | |
| 1043 } else { | |
| 1044 backgroundRepeatY = NoRepeatFill; | |
| 1045 } | |
| 1046 } | |
| 1047 if (backgroundRepeatY == NoRepeatFill) { | |
| 1048 int yOffset = fillLayer.backgroundYOrigin() == BottomEdge ? availableHei
ght - computedYPosition : computedYPosition; | |
| 1049 geometry.setNoRepeatY(top + yOffset); | |
| 1050 geometry.setSpaceSize(IntSize(geometry.spaceSize().width(), 0)); | |
| 1051 } | |
| 1052 | |
| 1053 if (fixedAttachment) | |
| 1054 geometry.useFixedAttachment(snappedPaintRect.location()); | |
| 1055 | |
| 1056 geometry.clip(snappedPaintRect); | |
| 1057 geometry.setDestOrigin(geometry.destRect().location()); | |
| 1058 } | |
| 1059 | |
| 1060 static LayoutUnit computeBorderImageSide(const BorderImageLength& borderSlice, L
ayoutUnit borderSide, LayoutUnit imageSide, LayoutUnit boxExtent) | 421 static LayoutUnit computeBorderImageSide(const BorderImageLength& borderSlice, L
ayoutUnit borderSide, LayoutUnit imageSide, LayoutUnit boxExtent) |
| 1061 { | 422 { |
| 1062 if (borderSlice.isNumber()) | 423 if (borderSlice.isNumber()) |
| 1063 return borderSlice.number() * borderSide; | 424 return borderSlice.number() * borderSide; |
| 1064 if (borderSlice.length().isAuto()) | 425 if (borderSlice.length().isAuto()) |
| 1065 return imageSide; | 426 return imageSide; |
| 1066 return valueForLength(borderSlice.length(), boxExtent); | 427 return valueForLength(borderSlice.length(), boxExtent); |
| 1067 } | 428 } |
| 1068 | 429 |
| 1069 bool RenderBoxModelObject::paintNinePieceImage(GraphicsContext* graphicsContext,
const LayoutRect& rect, const RenderStyle* style, | 430 bool RenderBoxModelObject::paintNinePieceImage(GraphicsContext* graphicsContext,
const LayoutRect& rect, const RenderStyle* style, |
| (...skipping 1534 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2604 ASSERT(!beforeChild || toBoxModelObject == beforeChild->parent()); | 1965 ASSERT(!beforeChild || toBoxModelObject == beforeChild->parent()); |
| 2605 for (RenderObject* child = startChild; child && child != endChild; ) { | 1966 for (RenderObject* child = startChild; child && child != endChild; ) { |
| 2606 // Save our next sibling as moveChildTo will clear it. | 1967 // Save our next sibling as moveChildTo will clear it. |
| 2607 RenderObject* nextSibling = child->nextSibling(); | 1968 RenderObject* nextSibling = child->nextSibling(); |
| 2608 moveChildTo(toBoxModelObject, child, beforeChild, fullRemoveInsert); | 1969 moveChildTo(toBoxModelObject, child, beforeChild, fullRemoveInsert); |
| 2609 child = nextSibling; | 1970 child = nextSibling; |
| 2610 } | 1971 } |
| 2611 } | 1972 } |
| 2612 | 1973 |
| 2613 } // namespace blink | 1974 } // namespace blink |
| OLD | NEW |