1/*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4 *           (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
5 *           (C) 2005, 2006 Samuel Weinig (sam.weinig@gmail.com)
6 * Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
7 * Copyright (C) 2010 Google Inc. All rights reserved.
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 * Library General Public License for more details.
18 *
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
21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
23 *
24 */
25
26#include "config.h"
27#include "core/rendering/RenderBoxModelObject.h"
28
29#include "core/page/scrolling/ScrollingConstraints.h"
30#include "core/rendering/ImageQualityController.h"
31#include "core/rendering/RenderBlock.h"
32#include "core/rendering/RenderFlowThread.h"
33#include "core/rendering/RenderGeometryMap.h"
34#include "core/rendering/RenderInline.h"
35#include "core/rendering/RenderLayer.h"
36#include "core/rendering/RenderObjectInlines.h"
37#include "core/rendering/RenderRegion.h"
38#include "core/rendering/RenderTextFragment.h"
39#include "core/rendering/RenderView.h"
40#include "core/rendering/compositing/CompositedLayerMapping.h"
41#include "core/rendering/compositing/RenderLayerCompositor.h"
42#include "core/rendering/style/BorderEdge.h"
43#include "core/rendering/style/ShadowList.h"
44#include "platform/LengthFunctions.h"
45#include "platform/geometry/TransformState.h"
46#include "platform/graphics/DrawLooperBuilder.h"
47#include "platform/graphics/GraphicsContextStateSaver.h"
48#include "platform/graphics/Path.h"
49#include "wtf/CurrentTime.h"
50
51namespace blink {
52
53// The HashMap for storing continuation pointers.
54// An inline can be split with blocks occuring in between the inline content.
55// When this occurs we need a pointer to the next object. We can basically be
56// split into a sequence of inlines and blocks. The continuation will either be
57// an anonymous block (that houses other blocks) or it will be an inline flow.
58// <b><i><p>Hello</p></i></b>. In this example the <i> will have a block as
59// its continuation but the <b> will just have an inline as its continuation.
60typedef WillBeHeapHashMap<RawPtrWillBeMember<const RenderBoxModelObject>, RawPtrWillBeMember<RenderBoxModelObject> > ContinuationMap;
61static OwnPtrWillBePersistent<ContinuationMap>* continuationMap = 0;
62
63// This HashMap is similar to the continuation map, but connects first-letter
64// renderers to their remaining text fragments.
65typedef WillBeHeapHashMap<RawPtrWillBeMember<const RenderBoxModelObject>, RawPtrWillBeMember<RenderTextFragment> > FirstLetterRemainingTextMap;
66static OwnPtrWillBePersistent<FirstLetterRemainingTextMap>* firstLetterRemainingTextMap = 0;
67
68void RenderBoxModelObject::setSelectionState(SelectionState state)
69{
70    if (state == SelectionInside && selectionState() != SelectionNone)
71        return;
72
73    if ((state == SelectionStart && selectionState() == SelectionEnd)
74        || (state == SelectionEnd && selectionState() == SelectionStart))
75        RenderObject::setSelectionState(SelectionBoth);
76    else
77        RenderObject::setSelectionState(state);
78
79    // FIXME: We should consider whether it is OK propagating to ancestor RenderInlines.
80    // This is a workaround for http://webkit.org/b/32123
81    // The containing block can be null in case of an orphaned tree.
82    RenderBlock* containingBlock = this->containingBlock();
83    if (containingBlock && !containingBlock->isRenderView())
84        containingBlock->setSelectionState(state);
85}
86
87void RenderBoxModelObject::contentChanged(ContentChangeType changeType)
88{
89    if (!hasLayer())
90        return;
91
92    layer()->contentChanged(changeType);
93}
94
95bool RenderBoxModelObject::hasAcceleratedCompositing() const
96{
97    return view()->compositor()->hasAcceleratedCompositing();
98}
99
100RenderBoxModelObject::RenderBoxModelObject(ContainerNode* node)
101    : RenderLayerModelObject(node)
102{
103}
104
105RenderBoxModelObject::~RenderBoxModelObject()
106{
107}
108
109void RenderBoxModelObject::willBeDestroyed()
110{
111    ImageQualityController::remove(this);
112
113    // A continuation of this RenderObject should be destroyed at subclasses.
114    ASSERT(!continuation());
115
116    // If this is a first-letter object with a remaining text fragment then the
117    // entry needs to be cleared from the map.
118    if (firstLetterRemainingText())
119        setFirstLetterRemainingText(0);
120
121    RenderLayerModelObject::willBeDestroyed();
122}
123
124bool RenderBoxModelObject::calculateHasBoxDecorations() const
125{
126    RenderStyle* styleToUse = style();
127    ASSERT(styleToUse);
128    return hasBackground() || styleToUse->hasBorder() || styleToUse->hasAppearance() || styleToUse->boxShadow();
129}
130
131void RenderBoxModelObject::updateFromStyle()
132{
133    RenderLayerModelObject::updateFromStyle();
134
135    RenderStyle* styleToUse = style();
136    setHasBoxDecorationBackground(calculateHasBoxDecorations());
137    setInline(styleToUse->isDisplayInlineType());
138    setPositionState(styleToUse->position());
139    setHorizontalWritingMode(styleToUse->isHorizontalWritingMode());
140}
141
142static LayoutSize accumulateInFlowPositionOffsets(const RenderObject* child)
143{
144    if (!child->isAnonymousBlock() || !child->isRelPositioned())
145        return LayoutSize();
146    LayoutSize offset;
147    RenderObject* p = toRenderBlock(child)->inlineElementContinuation();
148    while (p && p->isRenderInline()) {
149        if (p->isRelPositioned()) {
150            RenderInline* renderInline = toRenderInline(p);
151            offset += renderInline->offsetForInFlowPosition();
152        }
153        p = p->parent();
154    }
155    return offset;
156}
157
158bool RenderBoxModelObject::hasAutoHeightOrContainingBlockWithAutoHeight() const
159{
160    Length logicalHeightLength = style()->logicalHeight();
161    if (logicalHeightLength.isAuto())
162        return true;
163
164    // For percentage heights: The percentage is calculated with respect to the height of the generated box's
165    // containing block. If the height of the containing block is not specified explicitly (i.e., it depends
166    // on content height), and this element is not absolutely positioned, the value computes to 'auto'.
167    if (!logicalHeightLength.isPercent() || isOutOfFlowPositioned() || document().inQuirksMode())
168        return false;
169
170    // Anonymous block boxes are ignored when resolving percentage values that would refer to it:
171    // the closest non-anonymous ancestor box is used instead.
172    RenderBlock* cb = containingBlock();
173    while (cb->isAnonymous())
174        cb = cb->containingBlock();
175
176    // Matching RenderBox::percentageLogicalHeightIsResolvableFromBlock() by
177    // ignoring table cell's attribute value, where it says that table cells violate
178    // what the CSS spec says to do with heights. Basically we
179    // don't care if the cell specified a height or not.
180    if (cb->isTableCell())
181        return false;
182
183    // Match RenderBox::availableLogicalHeightUsing by special casing
184    // the render view. The available height is taken from the frame.
185    if (cb->isRenderView())
186        return false;
187
188    if (cb->isOutOfFlowPositioned() && !cb->style()->logicalTop().isAuto() && !cb->style()->logicalBottom().isAuto())
189        return false;
190
191    // If the height of the containing block computes to 'auto', then it hasn't been 'specified explicitly'.
192    return cb->hasAutoHeightOrContainingBlockWithAutoHeight();
193}
194
195LayoutSize RenderBoxModelObject::relativePositionOffset() const
196{
197    LayoutSize offset = accumulateInFlowPositionOffsets(this);
198
199    RenderBlock* containingBlock = this->containingBlock();
200
201    // Objects that shrink to avoid floats normally use available line width when computing containing block width.  However
202    // in the case of relative positioning using percentages, we can't do this.  The offset should always be resolved using the
203    // available width of the containing block.  Therefore we don't use containingBlockLogicalWidthForContent() here, but instead explicitly
204    // call availableWidth on our containing block.
205    if (!style()->left().isAuto()) {
206        if (!style()->right().isAuto() && !containingBlock->style()->isLeftToRightDirection())
207            offset.setWidth(-valueForLength(style()->right(), containingBlock->availableWidth()));
208        else
209            offset.expand(valueForLength(style()->left(), containingBlock->availableWidth()), 0);
210    } else if (!style()->right().isAuto()) {
211        offset.expand(-valueForLength(style()->right(), containingBlock->availableWidth()), 0);
212    }
213
214    // If the containing block of a relatively positioned element does not
215    // specify a height, a percentage top or bottom offset should be resolved as
216    // auto. An exception to this is if the containing block has the WinIE quirk
217    // where <html> and <body> assume the size of the viewport. In this case,
218    // calculate the percent offset based on this height.
219    // See <https://bugs.webkit.org/show_bug.cgi?id=26396>.
220    if (!style()->top().isAuto()
221        && (!containingBlock->hasAutoHeightOrContainingBlockWithAutoHeight()
222            || !style()->top().isPercent()
223            || containingBlock->stretchesToViewport()))
224        offset.expand(0, valueForLength(style()->top(), containingBlock->availableHeight()));
225
226    else if (!style()->bottom().isAuto()
227        && (!containingBlock->hasAutoHeightOrContainingBlockWithAutoHeight()
228            || !style()->bottom().isPercent()
229            || containingBlock->stretchesToViewport()))
230        offset.expand(0, -valueForLength(style()->bottom(), containingBlock->availableHeight()));
231
232    return offset;
233}
234
235LayoutPoint RenderBoxModelObject::adjustedPositionRelativeToOffsetParent(const LayoutPoint& startPoint) const
236{
237    // If the element is the HTML body element or doesn't have a parent
238    // return 0 and stop this algorithm.
239    if (isBody() || !parent())
240        return LayoutPoint();
241
242    LayoutPoint referencePoint = startPoint;
243    referencePoint.move(parent()->columnOffset(referencePoint));
244
245    // If the offsetParent of the element is null, or is the HTML body element,
246    // return the distance between the canvas origin and the left border edge
247    // of the element and stop this algorithm.
248    Element* element = offsetParent();
249    if (!element)
250        return referencePoint;
251
252    if (const RenderBoxModelObject* offsetParent = element->renderBoxModelObject()) {
253        if (offsetParent->isBox() && !offsetParent->isBody())
254            referencePoint.move(-toRenderBox(offsetParent)->borderLeft(), -toRenderBox(offsetParent)->borderTop());
255        if (!isOutOfFlowPositioned() || flowThreadContainingBlock()) {
256            if (isRelPositioned())
257                referencePoint.move(relativePositionOffset());
258
259            RenderObject* current;
260            for (current = parent(); current != offsetParent && current->parent(); current = current->parent()) {
261                // FIXME: What are we supposed to do inside SVG content?
262                if (!isOutOfFlowPositioned()) {
263                    if (current->isBox() && !current->isTableRow())
264                        referencePoint.moveBy(toRenderBox(current)->topLeftLocation());
265                    referencePoint.move(current->parent()->columnOffset(referencePoint));
266                }
267            }
268
269            if (offsetParent->isBox() && offsetParent->isBody() && !offsetParent->isPositioned())
270                referencePoint.moveBy(toRenderBox(offsetParent)->topLeftLocation());
271        }
272    }
273
274    return referencePoint;
275}
276
277LayoutSize RenderBoxModelObject::offsetForInFlowPosition() const
278{
279    return isRelPositioned() ? relativePositionOffset() : LayoutSize();
280}
281
282LayoutUnit RenderBoxModelObject::offsetLeft() const
283{
284    // Note that RenderInline and RenderBox override this to pass a different
285    // startPoint to adjustedPositionRelativeToOffsetParent.
286    return adjustedPositionRelativeToOffsetParent(LayoutPoint()).x();
287}
288
289LayoutUnit RenderBoxModelObject::offsetTop() const
290{
291    // Note that RenderInline and RenderBox override this to pass a different
292    // startPoint to adjustedPositionRelativeToOffsetParent.
293    return adjustedPositionRelativeToOffsetParent(LayoutPoint()).y();
294}
295
296int RenderBoxModelObject::pixelSnappedOffsetWidth() const
297{
298    return snapSizeToPixel(offsetWidth(), offsetLeft());
299}
300
301int RenderBoxModelObject::pixelSnappedOffsetHeight() const
302{
303    return snapSizeToPixel(offsetHeight(), offsetTop());
304}
305
306LayoutUnit RenderBoxModelObject::computedCSSPadding(const Length& padding) const
307{
308    LayoutUnit w = 0;
309    if (padding.isPercent())
310        w = containingBlockLogicalWidthForContent();
311    return minimumValueForLength(padding, w);
312}
313
314static inline int resolveWidthForRatio(int height, const FloatSize& intrinsicRatio)
315{
316    return ceilf(height * intrinsicRatio.width() / intrinsicRatio.height());
317}
318
319static inline int resolveHeightForRatio(int width, const FloatSize& intrinsicRatio)
320{
321    return ceilf(width * intrinsicRatio.height() / intrinsicRatio.width());
322}
323
324static inline IntSize resolveAgainstIntrinsicWidthOrHeightAndRatio(const IntSize& size, const FloatSize& intrinsicRatio, int useWidth, int useHeight)
325{
326    if (intrinsicRatio.isEmpty()) {
327        if (useWidth)
328            return IntSize(useWidth, size.height());
329        return IntSize(size.width(), useHeight);
330    }
331
332    if (useWidth)
333        return IntSize(useWidth, resolveHeightForRatio(useWidth, intrinsicRatio));
334    return IntSize(resolveWidthForRatio(useHeight, intrinsicRatio), useHeight);
335}
336
337static inline IntSize resolveAgainstIntrinsicRatio(const IntSize& size, const FloatSize& intrinsicRatio)
338{
339    // Two possible solutions: (size.width(), solutionHeight) or (solutionWidth, size.height())
340    // "... must be assumed to be the largest dimensions..." = easiest answer: the rect with the largest surface area.
341
342    int solutionWidth = resolveWidthForRatio(size.height(), intrinsicRatio);
343    int solutionHeight = resolveHeightForRatio(size.width(), intrinsicRatio);
344    if (solutionWidth <= size.width()) {
345        if (solutionHeight <= size.height()) {
346            // If both solutions fit, choose the one covering the larger area.
347            int areaOne = solutionWidth * size.height();
348            int areaTwo = size.width() * solutionHeight;
349            if (areaOne < areaTwo)
350                return IntSize(size.width(), solutionHeight);
351            return IntSize(solutionWidth, size.height());
352        }
353
354        // Only the first solution fits.
355        return IntSize(solutionWidth, size.height());
356    }
357
358    // Only the second solution fits, assert that.
359    ASSERT(solutionHeight <= size.height());
360    return IntSize(size.width(), solutionHeight);
361}
362
363IntSize RenderBoxModelObject::calculateImageIntrinsicDimensions(StyleImage* image, const IntSize& positioningAreaSize, ScaleByEffectiveZoomOrNot shouldScaleOrNot) const
364{
365    // A generated image without a fixed size, will always return the container size as intrinsic size.
366    if (image->isGeneratedImage() && image->usesImageContainerSize())
367        return IntSize(positioningAreaSize.width(), positioningAreaSize.height());
368
369    Length intrinsicWidth;
370    Length intrinsicHeight;
371    FloatSize intrinsicRatio;
372    image->computeIntrinsicDimensions(this, intrinsicWidth, intrinsicHeight, intrinsicRatio);
373
374    ASSERT(!intrinsicWidth.isPercent());
375    ASSERT(!intrinsicHeight.isPercent());
376
377    IntSize resolvedSize(intrinsicWidth.value(), intrinsicHeight.value());
378    IntSize minimumSize(resolvedSize.width() > 0 ? 1 : 0, resolvedSize.height() > 0 ? 1 : 0);
379    if (shouldScaleOrNot == ScaleByEffectiveZoom)
380        resolvedSize.scale(style()->effectiveZoom());
381    resolvedSize.clampToMinimumSize(minimumSize);
382
383    if (!resolvedSize.isEmpty())
384        return resolvedSize;
385
386    // If the image has one of either an intrinsic width or an intrinsic height:
387    // * and an intrinsic aspect ratio, then the missing dimension is calculated from the given dimension and the ratio.
388    // * and no intrinsic aspect ratio, then the missing dimension is assumed to be the size of the rectangle that
389    //   establishes the coordinate system for the 'background-position' property.
390    if (resolvedSize.width() > 0 || resolvedSize.height() > 0)
391        return resolveAgainstIntrinsicWidthOrHeightAndRatio(positioningAreaSize, intrinsicRatio, resolvedSize.width(), resolvedSize.height());
392
393    // If the image has no intrinsic dimensions and has an intrinsic ratio the dimensions must be assumed to be the
394    // largest dimensions at that ratio such that neither dimension exceeds the dimensions of the rectangle that
395    // establishes the coordinate system for the 'background-position' property.
396    if (!intrinsicRatio.isEmpty())
397        return resolveAgainstIntrinsicRatio(positioningAreaSize, intrinsicRatio);
398
399    // If the image has no intrinsic ratio either, then the dimensions must be assumed to be the rectangle that
400    // establishes the coordinate system for the 'background-position' property.
401    return positioningAreaSize;
402}
403
404bool RenderBoxModelObject::boxShadowShouldBeAppliedToBackground(BackgroundBleedAvoidance bleedAvoidance, InlineFlowBox* inlineFlowBox) const
405{
406    if (bleedAvoidance != BackgroundBleedNone)
407        return false;
408
409    if (style()->hasAppearance())
410        return false;
411
412    const ShadowList* shadowList = style()->boxShadow();
413    if (!shadowList)
414        return false;
415
416    bool hasOneNormalBoxShadow = false;
417    size_t shadowCount = shadowList->shadows().size();
418    for (size_t i = 0; i < shadowCount; ++i) {
419        const ShadowData& currentShadow = shadowList->shadows()[i];
420        if (currentShadow.style() != Normal)
421            continue;
422
423        if (hasOneNormalBoxShadow)
424            return false;
425        hasOneNormalBoxShadow = true;
426
427        if (currentShadow.spread())
428            return false;
429    }
430
431    if (!hasOneNormalBoxShadow)
432        return false;
433
434    Color backgroundColor = resolveColor(CSSPropertyBackgroundColor);
435    if (backgroundColor.hasAlpha())
436        return false;
437
438    const FillLayer* lastBackgroundLayer = &style()->backgroundLayers();
439    for (const FillLayer* next = lastBackgroundLayer->next(); next; next = lastBackgroundLayer->next())
440        lastBackgroundLayer = next;
441
442    if (lastBackgroundLayer->clip() != BorderFillBox)
443        return false;
444
445    if (lastBackgroundLayer->image() && style()->hasBorderRadius())
446        return false;
447
448    if (inlineFlowBox && !inlineFlowBox->boxShadowCanBeAppliedToBackground(*lastBackgroundLayer))
449        return false;
450
451    if (hasOverflowClip() && lastBackgroundLayer->attachment() == LocalBackgroundAttachment)
452        return false;
453
454    return true;
455}
456
457
458
459LayoutUnit RenderBoxModelObject::containingBlockLogicalWidthForContent() const
460{
461    return containingBlock()->availableLogicalWidth();
462}
463
464RenderBoxModelObject* RenderBoxModelObject::continuation() const
465{
466    if (!continuationMap)
467        return 0;
468    return (*continuationMap)->get(this);
469}
470
471void RenderBoxModelObject::setContinuation(RenderBoxModelObject* continuation)
472{
473    if (continuation) {
474        if (!continuationMap)
475            continuationMap = new OwnPtrWillBePersistent<ContinuationMap>(adoptPtrWillBeNoop(new ContinuationMap));
476        (*continuationMap)->set(this, continuation);
477    } else {
478        if (continuationMap)
479            (*continuationMap)->remove(this);
480    }
481}
482
483void RenderBoxModelObject::computeLayerHitTestRects(LayerHitTestRects& rects) const
484{
485    RenderLayerModelObject::computeLayerHitTestRects(rects);
486
487    // If there is a continuation then we need to consult it here, since this is
488    // the root of the tree walk and it wouldn't otherwise get picked up.
489    // Continuations should always be siblings in the tree, so any others should
490    // get picked up already by the tree walk.
491    if (continuation())
492        continuation()->computeLayerHitTestRects(rects);
493}
494
495RenderTextFragment* RenderBoxModelObject::firstLetterRemainingText() const
496{
497    if (!firstLetterRemainingTextMap)
498        return 0;
499    return (*firstLetterRemainingTextMap)->get(this);
500}
501
502void RenderBoxModelObject::setFirstLetterRemainingText(RenderTextFragment* remainingText)
503{
504    if (remainingText) {
505        if (!firstLetterRemainingTextMap)
506            firstLetterRemainingTextMap = new OwnPtrWillBePersistent<FirstLetterRemainingTextMap>(adoptPtrWillBeNoop(new FirstLetterRemainingTextMap));
507        (*firstLetterRemainingTextMap)->set(this, remainingText);
508    } else if (firstLetterRemainingTextMap) {
509        (*firstLetterRemainingTextMap)->remove(this);
510    }
511}
512
513LayoutRect RenderBoxModelObject::localCaretRectForEmptyElement(LayoutUnit width, LayoutUnit textIndentOffset)
514{
515    ASSERT(!slowFirstChild());
516
517    // FIXME: This does not take into account either :first-line or :first-letter
518    // However, as soon as some content is entered, the line boxes will be
519    // constructed and this kludge is not called any more. So only the caret size
520    // of an empty :first-line'd block is wrong. I think we can live with that.
521    RenderStyle* currentStyle = firstLineStyle();
522
523    enum CaretAlignment { alignLeft, alignRight, alignCenter };
524
525    CaretAlignment alignment = alignLeft;
526
527    switch (currentStyle->textAlign()) {
528    case LEFT:
529    case WEBKIT_LEFT:
530        break;
531    case CENTER:
532    case WEBKIT_CENTER:
533        alignment = alignCenter;
534        break;
535    case RIGHT:
536    case WEBKIT_RIGHT:
537        alignment = alignRight;
538        break;
539    case JUSTIFY:
540    case TASTART:
541        if (!currentStyle->isLeftToRightDirection())
542            alignment = alignRight;
543        break;
544    case TAEND:
545        if (currentStyle->isLeftToRightDirection())
546            alignment = alignRight;
547        break;
548    }
549
550    LayoutUnit x = borderLeft() + paddingLeft();
551    LayoutUnit maxX = width - borderRight() - paddingRight();
552
553    switch (alignment) {
554    case alignLeft:
555        if (currentStyle->isLeftToRightDirection())
556            x += textIndentOffset;
557        break;
558    case alignCenter:
559        x = (x + maxX) / 2;
560        if (currentStyle->isLeftToRightDirection())
561            x += textIndentOffset / 2;
562        else
563            x -= textIndentOffset / 2;
564        break;
565    case alignRight:
566        x = maxX - caretWidth;
567        if (!currentStyle->isLeftToRightDirection())
568            x -= textIndentOffset;
569        break;
570    }
571    x = std::min(x, std::max<LayoutUnit>(maxX - caretWidth, 0));
572
573    LayoutUnit height = style()->fontMetrics().height();
574    LayoutUnit verticalSpace = lineHeight(true, currentStyle->isHorizontalWritingMode() ? HorizontalLine : VerticalLine,  PositionOfInteriorLineBoxes) - height;
575    LayoutUnit y = paddingTop() + borderTop() + (verticalSpace / 2);
576    return currentStyle->isHorizontalWritingMode() ? LayoutRect(x, y, caretWidth, height) : LayoutRect(y, x, height, caretWidth);
577}
578
579void RenderBoxModelObject::mapAbsoluteToLocalPoint(MapCoordinatesFlags mode, TransformState& transformState) const
580{
581    RenderObject* o = container();
582    if (!o)
583        return;
584
585    if (o->isRenderFlowThread())
586        transformState.move(o->columnOffset(LayoutPoint(transformState.mappedPoint())));
587
588    o->mapAbsoluteToLocalPoint(mode, transformState);
589
590    LayoutSize containerOffset = offsetFromContainer(o, LayoutPoint());
591
592    if (!style()->hasOutOfFlowPosition() && o->hasColumns()) {
593        RenderBlock* block = toRenderBlock(o);
594        LayoutPoint point(roundedLayoutPoint(transformState.mappedPoint()));
595        point -= containerOffset;
596        block->adjustForColumnRect(containerOffset, point);
597    }
598
599    bool preserve3D = mode & UseTransforms && (o->style()->preserves3D() || style()->preserves3D());
600    if (mode & UseTransforms && shouldUseTransformFromContainer(o)) {
601        TransformationMatrix t;
602        getTransformFromContainer(o, containerOffset, t);
603        transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
604    } else
605        transformState.move(containerOffset.width(), containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
606}
607
608const RenderObject* RenderBoxModelObject::pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const
609{
610    ASSERT(ancestorToStopAt != this);
611
612    bool ancestorSkipped;
613    RenderObject* container = this->container(ancestorToStopAt, &ancestorSkipped);
614    if (!container)
615        return 0;
616
617    bool isInline = isRenderInline();
618    bool isFixedPos = !isInline && style()->position() == FixedPosition;
619    bool hasTransform = !isInline && hasLayer() && layer()->transform();
620
621    LayoutSize adjustmentForSkippedAncestor;
622    if (ancestorSkipped) {
623        // There can't be a transform between paintInvalidationContainer and o, because transforms create containers, so it should be safe
624        // to just subtract the delta between the ancestor and o.
625        adjustmentForSkippedAncestor = -ancestorToStopAt->offsetFromAncestorContainer(container);
626    }
627
628    bool offsetDependsOnPoint = false;
629    LayoutSize containerOffset = offsetFromContainer(container, LayoutPoint(), &offsetDependsOnPoint);
630
631    bool preserve3D = container->style()->preserves3D() || style()->preserves3D();
632    if (shouldUseTransformFromContainer(container)) {
633        TransformationMatrix t;
634        getTransformFromContainer(container, containerOffset, t);
635        t.translateRight(adjustmentForSkippedAncestor.width().toFloat(), adjustmentForSkippedAncestor.height().toFloat());
636        geometryMap.push(this, t, preserve3D, offsetDependsOnPoint, isFixedPos, hasTransform);
637    } else {
638        containerOffset += adjustmentForSkippedAncestor;
639        geometryMap.push(this, containerOffset, preserve3D, offsetDependsOnPoint, isFixedPos, hasTransform);
640    }
641
642    return ancestorSkipped ? ancestorToStopAt : container;
643}
644
645void RenderBoxModelObject::moveChildTo(RenderBoxModelObject* toBoxModelObject, RenderObject* child, RenderObject* beforeChild, bool fullRemoveInsert)
646{
647    // We assume that callers have cleared their positioned objects list for child moves (!fullRemoveInsert) so the
648    // positioned renderer maps don't become stale. It would be too slow to do the map lookup on each call.
649    ASSERT(!fullRemoveInsert || !isRenderBlock() || !toRenderBlock(this)->hasPositionedObjects());
650
651    ASSERT(this == child->parent());
652    ASSERT(!beforeChild || toBoxModelObject == beforeChild->parent());
653    if (fullRemoveInsert && (toBoxModelObject->isRenderBlock() || toBoxModelObject->isRenderInline())) {
654        // Takes care of adding the new child correctly if toBlock and fromBlock
655        // have different kind of children (block vs inline).
656        toBoxModelObject->addChild(virtualChildren()->removeChildNode(this, child), beforeChild);
657    } else
658        toBoxModelObject->virtualChildren()->insertChildNode(toBoxModelObject, virtualChildren()->removeChildNode(this, child, fullRemoveInsert), beforeChild, fullRemoveInsert);
659}
660
661void RenderBoxModelObject::moveChildrenTo(RenderBoxModelObject* toBoxModelObject, RenderObject* startChild, RenderObject* endChild, RenderObject* beforeChild, bool fullRemoveInsert)
662{
663    // This condition is rarely hit since this function is usually called on
664    // anonymous blocks which can no longer carry positioned objects (see r120761)
665    // or when fullRemoveInsert is false.
666    if (fullRemoveInsert && isRenderBlock()) {
667        RenderBlock* block = toRenderBlock(this);
668        block->removePositionedObjects(0);
669        if (block->isRenderBlockFlow())
670            toRenderBlockFlow(block)->removeFloatingObjects();
671    }
672
673    ASSERT(!beforeChild || toBoxModelObject == beforeChild->parent());
674    for (RenderObject* child = startChild; child && child != endChild; ) {
675        // Save our next sibling as moveChildTo will clear it.
676        RenderObject* nextSibling = child->nextSibling();
677        moveChildTo(toBoxModelObject, child, beforeChild, fullRemoveInsert);
678        child = nextSibling;
679    }
680}
681
682} // namespace blink
683