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 |