Home | History | Annotate | Download | only in rendering
      1 /*
      2  * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org)
      3  *           (C) 1999 Antti Koivisto (koivisto (at) kde.org)
      4  *           (C) 2005 Allan Sandfeld Jensen (kde (at) carewolf.com)
      5  *           (C) 2005, 2006 Samuel Weinig (sam.weinig (at) 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 
     51 namespace 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.
     60 typedef WillBeHeapHashMap<RawPtrWillBeMember<const RenderBoxModelObject>, RawPtrWillBeMember<RenderBoxModelObject> > ContinuationMap;
     61 static 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.
     65 typedef WillBeHeapHashMap<RawPtrWillBeMember<const RenderBoxModelObject>, RawPtrWillBeMember<RenderTextFragment> > FirstLetterRemainingTextMap;
     66 static OwnPtrWillBePersistent<FirstLetterRemainingTextMap>* firstLetterRemainingTextMap = 0;
     67 
     68 void 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 
     87 void RenderBoxModelObject::contentChanged(ContentChangeType changeType)
     88 {
     89     if (!hasLayer())
     90         return;
     91 
     92     layer()->contentChanged(changeType);
     93 }
     94 
     95 bool RenderBoxModelObject::hasAcceleratedCompositing() const
     96 {
     97     return view()->compositor()->hasAcceleratedCompositing();
     98 }
     99 
    100 RenderBoxModelObject::RenderBoxModelObject(ContainerNode* node)
    101     : RenderLayerModelObject(node)
    102 {
    103 }
    104 
    105 RenderBoxModelObject::~RenderBoxModelObject()
    106 {
    107 }
    108 
    109 void 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 
    124 bool RenderBoxModelObject::calculateHasBoxDecorations() const
    125 {
    126     RenderStyle* styleToUse = style();
    127     ASSERT(styleToUse);
    128     return hasBackground() || styleToUse->hasBorder() || styleToUse->hasAppearance() || styleToUse->boxShadow();
    129 }
    130 
    131 void 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 
    142 static 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 
    158 bool 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 
    195 LayoutSize 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 
    235 LayoutPoint 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 
    277 LayoutSize RenderBoxModelObject::offsetForInFlowPosition() const
    278 {
    279     return isRelPositioned() ? relativePositionOffset() : LayoutSize();
    280 }
    281 
    282 LayoutUnit 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 
    289 LayoutUnit 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 
    296 int RenderBoxModelObject::pixelSnappedOffsetWidth() const
    297 {
    298     return snapSizeToPixel(offsetWidth(), offsetLeft());
    299 }
    300 
    301 int RenderBoxModelObject::pixelSnappedOffsetHeight() const
    302 {
    303     return snapSizeToPixel(offsetHeight(), offsetTop());
    304 }
    305 
    306 LayoutUnit 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 
    314 static inline int resolveWidthForRatio(int height, const FloatSize& intrinsicRatio)
    315 {
    316     return ceilf(height * intrinsicRatio.width() / intrinsicRatio.height());
    317 }
    318 
    319 static inline int resolveHeightForRatio(int width, const FloatSize& intrinsicRatio)
    320 {
    321     return ceilf(width * intrinsicRatio.height() / intrinsicRatio.width());
    322 }
    323 
    324 static 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 
    337 static 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 
    363 IntSize 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 
    404 bool 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 
    459 LayoutUnit RenderBoxModelObject::containingBlockLogicalWidthForContent() const
    460 {
    461     return containingBlock()->availableLogicalWidth();
    462 }
    463 
    464 RenderBoxModelObject* RenderBoxModelObject::continuation() const
    465 {
    466     if (!continuationMap)
    467         return 0;
    468     return (*continuationMap)->get(this);
    469 }
    470 
    471 void 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 
    483 void 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 
    495 RenderTextFragment* RenderBoxModelObject::firstLetterRemainingText() const
    496 {
    497     if (!firstLetterRemainingTextMap)
    498         return 0;
    499     return (*firstLetterRemainingTextMap)->get(this);
    500 }
    501 
    502 void 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 
    513 LayoutRect 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 
    579 void 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 
    608 const 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 
    645 void 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 
    661 void 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