123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647 |
- /*
- * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
- * (C) 1999 Antti Koivisto (koivisto@kde.org)
- * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
- #include "config.h"
- #include "RenderInline.h"
- #include "Chrome.h"
- #include "FloatQuad.h"
- #include "GraphicsContext.h"
- #include "HitTestResult.h"
- #include "InlineTextBox.h"
- #include "Page.h"
- #include "RenderArena.h"
- #include "RenderBlock.h"
- #include "RenderFlowThread.h"
- #include "RenderFullScreen.h"
- #include "RenderGeometryMap.h"
- #include "RenderLayer.h"
- #include "RenderTheme.h"
- #include "RenderView.h"
- #include "StyleInheritedData.h"
- #include "TransformState.h"
- #include "VisiblePosition.h"
- #if ENABLE(DASHBOARD_SUPPORT) || ENABLE(DRAGGABLE_REGION)
- #include "Frame.h"
- #endif
- using namespace std;
- namespace WebCore {
- RenderInline::RenderInline(Element* element)
- : RenderBoxModelObject(element)
- , m_alwaysCreateLineBoxes(false)
- {
- setChildrenInline(true);
- }
- RenderInline* RenderInline::createAnonymous(Document* document)
- {
- RenderInline* renderer = new (document->renderArena()) RenderInline(0);
- renderer->setDocumentForAnonymous(document);
- return renderer;
- }
- void RenderInline::willBeDestroyed()
- {
- #if !ASSERT_DISABLED
- // Make sure we do not retain "this" in the continuation outline table map of our containing blocks.
- if (parent() && style()->visibility() == VISIBLE && hasOutline()) {
- bool containingBlockPaintsContinuationOutline = continuation() || isInlineElementContinuation();
- if (containingBlockPaintsContinuationOutline) {
- if (RenderBlock* cb = containingBlock()) {
- if (RenderBlock* cbCb = cb->containingBlock())
- ASSERT(!cbCb->paintsContinuationOutline(this));
- }
- }
- }
- #endif
- // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will
- // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise.
- children()->destroyLeftoverChildren();
- // Destroy our continuation before anything other than anonymous children.
- // The reason we don't destroy it before anonymous children is that they may
- // have continuations of their own that are anonymous children of our continuation.
- RenderBoxModelObject* continuation = this->continuation();
- if (continuation) {
- continuation->destroy();
- setContinuation(0);
- }
-
- if (!documentBeingDestroyed()) {
- if (firstLineBox()) {
- // We can't wait for RenderBoxModelObject::destroy to clear the selection,
- // because by then we will have nuked the line boxes.
- // FIXME: The FrameSelection should be responsible for this when it
- // is notified of DOM mutations.
- if (isSelectionBorder())
- view()->clearSelection();
- // If line boxes are contained inside a root, that means we're an inline.
- // In that case, we need to remove all the line boxes so that the parent
- // lines aren't pointing to deleted children. If the first line box does
- // not have a parent that means they are either already disconnected or
- // root lines that can just be destroyed without disconnecting.
- if (firstLineBox()->parent()) {
- for (InlineFlowBox* box = firstLineBox(); box; box = box->nextLineBox())
- box->remove();
- }
- } else if (parent())
- parent()->dirtyLinesFromChangedChild(this);
- }
- m_lineBoxes.deleteLineBoxes(renderArena());
- RenderBoxModelObject::willBeDestroyed();
- }
- RenderInline* RenderInline::inlineElementContinuation() const
- {
- RenderBoxModelObject* continuation = this->continuation();
- if (!continuation)
- return nullptr;
- if (continuation->isRenderInline())
- return toRenderInline(continuation);
- return continuation->isRenderBlock() ? toRenderBlock(continuation)->inlineElementContinuation() : nullptr;
- }
- void RenderInline::updateFromStyle()
- {
- RenderBoxModelObject::updateFromStyle();
- setInline(true); // Needed for run-ins, since run-in is considered a block display type.
- // FIXME: Support transforms and reflections on inline flows someday.
- setHasTransform(false);
- setHasReflection(false);
- }
- static RenderObject* inFlowPositionedInlineAncestor(RenderObject* p)
- {
- while (p && p->isRenderInline()) {
- if (p->isInFlowPositioned())
- return p;
- p = p->parent();
- }
- return 0;
- }
- static void updateStyleOfAnonymousBlockContinuations(RenderObject* box, const RenderStyle* newStyle, const RenderStyle* oldStyle)
- {
- for (;box && box->isAnonymousBlock(); box = box->nextSibling()) {
- if (box->style()->position() == newStyle->position())
- continue;
-
- if (!box->isRenderBlock())
- break; // We're done if we ever encounter something other than a RenderBlock.
- RenderBlock* block = toRenderBlock(box);
- if (!block->isAnonymousBlockContinuation())
- break; // We're done if we ever encounter something other than a continuation RenderBlock.
-
- // If we are no longer in-flow positioned but our descendant block(s) still have an in-flow positioned ancestor then
- // their containing anonymous block should keep its in-flow positioning.
- RenderInline* cont = toRenderBlock(box)->inlineElementContinuation();
- if (oldStyle->hasInFlowPosition() && inFlowPositionedInlineAncestor(cont))
- continue;
- RefPtr<RenderStyle> blockStyle = RenderStyle::createAnonymousStyleWithDisplay(block->style(), BLOCK);
- blockStyle->setPosition(newStyle->position());
- block->setStyle(blockStyle);
- }
- }
- void RenderInline::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
- {
- RenderBoxModelObject::styleDidChange(diff, oldStyle);
- // Ensure that all of the split inlines pick up the new style. We
- // only do this if we're an inline, since we don't want to propagate
- // a block's style to the other inlines.
- // e.g., <font>foo <h4>goo</h4> moo</font>. The <font> inlines before
- // and after the block share the same style, but the block doesn't
- // need to pass its style on to anyone else.
- RenderStyle* newStyle = style();
- RenderInline* continuation = inlineElementContinuation();
- for (RenderInline* currCont = continuation; currCont; currCont = currCont->inlineElementContinuation()) {
- RenderBoxModelObject* nextCont = currCont->continuation();
- currCont->setContinuation(0);
- currCont->setStyle(newStyle);
- currCont->setContinuation(nextCont);
- }
- // If an inline's in-flow positioning has changed then any descendant blocks will need to change their in-flow positioning accordingly.
- // Do this by updating the position of the descendant blocks' containing anonymous blocks - there may be more than one.
- if (continuation && oldStyle && newStyle->position() != oldStyle->position()
- && (newStyle->hasInFlowPosition() || oldStyle->hasInFlowPosition())) {
- // If any descendant blocks exist then they will be in the next anonymous block and its siblings.
- RenderObject* block = containingBlock()->nextSibling();
- ASSERT(block && block->isAnonymousBlock());
- updateStyleOfAnonymousBlockContinuations(block, newStyle, oldStyle);
- }
- if (!m_alwaysCreateLineBoxes) {
- bool alwaysCreateLineBoxes = hasSelfPaintingLayer() || hasBoxDecorations() || newStyle->hasPadding() || newStyle->hasMargin() || hasOutline();
- if (oldStyle && alwaysCreateLineBoxes) {
- dirtyLineBoxes(false);
- setNeedsLayout(true);
- }
- m_alwaysCreateLineBoxes = alwaysCreateLineBoxes;
- }
- }
- void RenderInline::updateAlwaysCreateLineBoxes(bool fullLayout)
- {
- // Once we have been tainted once, just assume it will happen again. This way effects like hover highlighting that change the
- // background color will only cause a layout on the first rollover.
- if (m_alwaysCreateLineBoxes)
- return;
- RenderStyle* parentStyle = parent()->style();
- RenderInline* parentRenderInline = parent()->isRenderInline() ? toRenderInline(parent()) : 0;
- bool checkFonts = document()->inNoQuirksMode();
- RenderFlowThread* flowThread = flowThreadContainingBlock();
- bool alwaysCreateLineBoxes = (parentRenderInline && parentRenderInline->alwaysCreateLineBoxes())
- || (parentRenderInline && parentStyle->verticalAlign() != BASELINE)
- || style()->verticalAlign() != BASELINE
- || style()->textEmphasisMark() != TextEmphasisMarkNone
- || (checkFonts && (!parentStyle->font().fontMetrics().hasIdenticalAscentDescentAndLineGap(style()->font().fontMetrics())
- || parentStyle->lineHeight() != style()->lineHeight()))
- || (flowThread && flowThread->hasRegionsWithStyling());
- if (!alwaysCreateLineBoxes && checkFonts && document()->styleSheetCollection()->usesFirstLineRules()) {
- // Have to check the first line style as well.
- parentStyle = parent()->style(true);
- RenderStyle* childStyle = style(true);
- alwaysCreateLineBoxes = !parentStyle->font().fontMetrics().hasIdenticalAscentDescentAndLineGap(childStyle->font().fontMetrics())
- || childStyle->verticalAlign() != BASELINE
- || parentStyle->lineHeight() != childStyle->lineHeight();
- }
- if (alwaysCreateLineBoxes) {
- if (!fullLayout)
- dirtyLineBoxes(false);
- m_alwaysCreateLineBoxes = true;
- }
- }
- LayoutRect RenderInline::localCaretRect(InlineBox* inlineBox, int, LayoutUnit* extraWidthToEndOfLine)
- {
- if (firstChild()) {
- // This condition is possible if the RenderInline is at an editing boundary,
- // i.e. the VisiblePosition is:
- // <RenderInline editingBoundary=true>|<RenderText> </RenderText></RenderInline>
- // FIXME: need to figure out how to make this return a valid rect, note that
- // there are no line boxes created in the above case.
- return LayoutRect();
- }
- ASSERT_UNUSED(inlineBox, !inlineBox);
- if (extraWidthToEndOfLine)
- *extraWidthToEndOfLine = 0;
- LayoutRect caretRect = localCaretRectForEmptyElement(borderAndPaddingWidth(), 0);
- if (InlineBox* firstBox = firstLineBox())
- caretRect.moveBy(roundedLayoutPoint(firstBox->topLeft()));
- return caretRect;
- }
- void RenderInline::addChild(RenderObject* newChild, RenderObject* beforeChild)
- {
- if (continuation())
- return addChildToContinuation(newChild, beforeChild);
- return addChildIgnoringContinuation(newChild, beforeChild);
- }
- static RenderBoxModelObject* nextContinuation(RenderObject* renderer)
- {
- if (renderer->isInline() && !renderer->isReplaced())
- return toRenderInline(renderer)->continuation();
- return toRenderBlock(renderer)->inlineElementContinuation();
- }
- RenderBoxModelObject* RenderInline::continuationBefore(RenderObject* beforeChild)
- {
- if (beforeChild && beforeChild->parent() == this)
- return this;
- RenderBoxModelObject* curr = nextContinuation(this);
- RenderBoxModelObject* nextToLast = this;
- RenderBoxModelObject* last = this;
- while (curr) {
- if (beforeChild && beforeChild->parent() == curr) {
- if (curr->firstChild() == beforeChild)
- return last;
- return curr;
- }
- nextToLast = last;
- last = curr;
- curr = nextContinuation(curr);
- }
- if (!beforeChild && !last->firstChild())
- return nextToLast;
- return last;
- }
- void RenderInline::addChildIgnoringContinuation(RenderObject* newChild, RenderObject* beforeChild)
- {
- // Make sure we don't append things after :after-generated content if we have it.
- if (!beforeChild && isAfterContent(lastChild()))
- beforeChild = lastChild();
- if (!newChild->isInline() && !newChild->isFloatingOrOutOfFlowPositioned()) {
- // We are placing a block inside an inline. We have to perform a split of this
- // inline into continuations. This involves creating an anonymous block box to hold
- // |newChild|. We then make that block box a continuation of this inline. We take all of
- // the children after |beforeChild| and put them in a clone of this object.
- RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(style(), BLOCK);
-
- // If inside an inline affected by in-flow positioning the block needs to be affected by it too.
- // Giving the block a layer like this allows it to collect the x/y offsets from inline parents later.
- if (RenderObject* positionedAncestor = inFlowPositionedInlineAncestor(this))
- newStyle->setPosition(positionedAncestor->style()->position());
- RenderBlock* newBox = RenderBlock::createAnonymous(document());
- newBox->setStyle(newStyle.release());
- RenderBoxModelObject* oldContinuation = continuation();
- setContinuation(newBox);
- splitFlow(beforeChild, newBox, newChild, oldContinuation);
- return;
- }
- RenderBoxModelObject::addChild(newChild, beforeChild);
- newChild->setNeedsLayoutAndPrefWidthsRecalc();
- }
- RenderInline* RenderInline::clone() const
- {
- RenderInline* cloneInline = new (renderArena()) RenderInline(node());
- cloneInline->setStyle(style());
- cloneInline->setFlowThreadState(flowThreadState());
- return cloneInline;
- }
- void RenderInline::splitInlines(RenderBlock* fromBlock, RenderBlock* toBlock,
- RenderBlock* middleBlock,
- RenderObject* beforeChild, RenderBoxModelObject* oldCont)
- {
- // Create a clone of this inline.
- RenderInline* cloneInline = clone();
- cloneInline->setContinuation(oldCont);
- #if ENABLE(FULLSCREEN_API)
- // If we're splitting the inline containing the fullscreened element,
- // |beforeChild| may be the renderer for the fullscreened element. However,
- // that renderer is wrapped in a RenderFullScreen, so |this| is not its
- // parent. Since the splitting logic expects |this| to be the parent, set
- // |beforeChild| to be the RenderFullScreen.
- const Element* fullScreenElement = document()->webkitCurrentFullScreenElement();
- if (fullScreenElement && beforeChild && beforeChild->node() == fullScreenElement)
- beforeChild = document()->fullScreenRenderer();
- #endif
- // Now take all of the children from beforeChild to the end and remove
- // them from |this| and place them in the clone.
- RenderObject* o = beforeChild;
- while (o) {
- RenderObject* tmp = o;
- o = tmp->nextSibling();
- cloneInline->addChildIgnoringContinuation(children()->removeChildNode(this, tmp), 0);
- tmp->setNeedsLayoutAndPrefWidthsRecalc();
- }
- // Hook |clone| up as the continuation of the middle block.
- middleBlock->setContinuation(cloneInline);
- // We have been reparented and are now under the fromBlock. We need
- // to walk up our inline parent chain until we hit the containing block.
- // Once we hit the containing block we're done.
- RenderBoxModelObject* curr = toRenderBoxModelObject(parent());
- RenderBoxModelObject* currChild = this;
-
- // FIXME: Because splitting is O(n^2) as tags nest pathologically, we cap the depth at which we're willing to clone.
- // There will eventually be a better approach to this problem that will let us nest to a much
- // greater depth (see bugzilla bug 13430) but for now we have a limit. This *will* result in
- // incorrect rendering, but the alternative is to hang forever.
- unsigned splitDepth = 1;
- const unsigned cMaxSplitDepth = 200;
- while (curr && curr != fromBlock) {
- ASSERT(curr->isRenderInline());
- if (splitDepth < cMaxSplitDepth) {
- // Create a new clone.
- RenderInline* cloneChild = cloneInline;
- cloneInline = toRenderInline(curr)->clone();
- // Insert our child clone as the first child.
- cloneInline->addChildIgnoringContinuation(cloneChild, 0);
- // Hook the clone up as a continuation of |curr|.
- RenderInline* inlineCurr = toRenderInline(curr);
- oldCont = inlineCurr->continuation();
- inlineCurr->setContinuation(cloneInline);
- cloneInline->setContinuation(oldCont);
- // Now we need to take all of the children starting from the first child
- // *after* currChild and append them all to the clone.
- o = currChild->nextSibling();
- while (o) {
- RenderObject* tmp = o;
- o = tmp->nextSibling();
- cloneInline->addChildIgnoringContinuation(inlineCurr->children()->removeChildNode(curr, tmp), 0);
- tmp->setNeedsLayoutAndPrefWidthsRecalc();
- }
- }
-
- // Keep walking up the chain.
- currChild = curr;
- curr = toRenderBoxModelObject(curr->parent());
- splitDepth++;
- }
- // Now we are at the block level. We need to put the clone into the toBlock.
- toBlock->children()->appendChildNode(toBlock, cloneInline);
- // Now take all the children after currChild and remove them from the fromBlock
- // and put them in the toBlock.
- o = currChild->nextSibling();
- while (o) {
- RenderObject* tmp = o;
- o = tmp->nextSibling();
- toBlock->children()->appendChildNode(toBlock, fromBlock->children()->removeChildNode(fromBlock, tmp));
- }
- }
- void RenderInline::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox,
- RenderObject* newChild, RenderBoxModelObject* oldCont)
- {
- RenderBlock* pre = 0;
- RenderBlock* block = containingBlock();
-
- // Delete our line boxes before we do the inline split into continuations.
- block->deleteLineBoxTree();
-
- bool madeNewBeforeBlock = false;
- if (block->isAnonymousBlock() && (!block->parent() || !block->parent()->createsAnonymousWrapper())) {
- // We can reuse this block and make it the preBlock of the next continuation.
- pre = block;
- pre->removePositionedObjects(0);
- pre->removeFloatingObjects();
- block = block->containingBlock();
- } else {
- // No anonymous block available for use. Make one.
- pre = block->createAnonymousBlock();
- madeNewBeforeBlock = true;
- }
- RenderBlock* post = toRenderBlock(pre->createAnonymousBoxWithSameTypeAs(block));
- RenderObject* boxFirst = madeNewBeforeBlock ? block->firstChild() : pre->nextSibling();
- if (madeNewBeforeBlock)
- block->children()->insertChildNode(block, pre, boxFirst);
- block->children()->insertChildNode(block, newBlockBox, boxFirst);
- block->children()->insertChildNode(block, post, boxFirst);
- block->setChildrenInline(false);
-
- if (madeNewBeforeBlock) {
- RenderObject* o = boxFirst;
- while (o) {
- RenderObject* no = o;
- o = no->nextSibling();
- pre->children()->appendChildNode(pre, block->children()->removeChildNode(block, no));
- no->setNeedsLayoutAndPrefWidthsRecalc();
- }
- }
- splitInlines(pre, post, newBlockBox, beforeChild, oldCont);
- // We already know the newBlockBox isn't going to contain inline kids, so avoid wasting
- // time in makeChildrenNonInline by just setting this explicitly up front.
- newBlockBox->setChildrenInline(false);
- // We delayed adding the newChild until now so that the |newBlockBox| would be fully
- // connected, thus allowing newChild access to a renderArena should it need
- // to wrap itself in additional boxes (e.g., table construction).
- newBlockBox->addChild(newChild);
- // Always just do a full layout in order to ensure that line boxes (especially wrappers for images)
- // get deleted properly. Because objects moves from the pre block into the post block, we want to
- // make new line boxes instead of leaving the old line boxes around.
- pre->setNeedsLayoutAndPrefWidthsRecalc();
- block->setNeedsLayoutAndPrefWidthsRecalc();
- post->setNeedsLayoutAndPrefWidthsRecalc();
- }
- void RenderInline::addChildToContinuation(RenderObject* newChild, RenderObject* beforeChild)
- {
- RenderBoxModelObject* flow = continuationBefore(beforeChild);
- ASSERT(!beforeChild || beforeChild->parent()->isRenderBlock() || beforeChild->parent()->isRenderInline());
- RenderBoxModelObject* beforeChildParent = 0;
- if (beforeChild)
- beforeChildParent = toRenderBoxModelObject(beforeChild->parent());
- else {
- RenderBoxModelObject* cont = nextContinuation(flow);
- if (cont)
- beforeChildParent = cont;
- else
- beforeChildParent = flow;
- }
- if (newChild->isFloatingOrOutOfFlowPositioned())
- return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
- // A continuation always consists of two potential candidates: an inline or an anonymous
- // block box holding block children.
- bool childInline = newChild->isInline();
- bool bcpInline = beforeChildParent->isInline();
- bool flowInline = flow->isInline();
- if (flow == beforeChildParent)
- return flow->addChildIgnoringContinuation(newChild, beforeChild);
- else {
- // The goal here is to match up if we can, so that we can coalesce and create the
- // minimal # of continuations needed for the inline.
- if (childInline == bcpInline)
- return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
- else if (flowInline == childInline)
- return flow->addChildIgnoringContinuation(newChild, 0); // Just treat like an append.
- else
- return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
- }
- }
- void RenderInline::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
- {
- m_lineBoxes.paint(this, paintInfo, paintOffset);
- }
- template<typename GeneratorContext>
- void RenderInline::generateLineBoxRects(GeneratorContext& yield) const
- {
- if (!alwaysCreateLineBoxes())
- generateCulledLineBoxRects(yield, this);
- else if (InlineFlowBox* curr = firstLineBox()) {
- for (; curr; curr = curr->nextLineBox())
- yield(FloatRect(curr->topLeft(), curr->size()));
- } else
- yield(FloatRect());
- }
- template<typename GeneratorContext>
- void RenderInline::generateCulledLineBoxRects(GeneratorContext& yield, const RenderInline* container) const
- {
- if (!culledInlineFirstLineBox()) {
- yield(FloatRect());
- return;
- }
- bool isHorizontal = style()->isHorizontalWritingMode();
- for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
- if (curr->isFloatingOrOutOfFlowPositioned())
- continue;
-
- // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
- // direction (aligned to the root box's baseline).
- if (curr->isBox()) {
- RenderBox* currBox = toRenderBox(curr);
- if (currBox->inlineBoxWrapper()) {
- RootInlineBox* rootBox = currBox->inlineBoxWrapper()->root();
- int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
- int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
- if (isHorizontal)
- yield(FloatRect(currBox->inlineBoxWrapper()->x() - currBox->marginLeft(), logicalTop, currBox->width() + currBox->marginWidth(), logicalHeight));
- else
- yield(FloatRect(logicalTop, currBox->inlineBoxWrapper()->y() - currBox->marginTop(), logicalHeight, currBox->height() + currBox->marginHeight()));
- }
- } else if (curr->isRenderInline()) {
- // If the child doesn't need line boxes either, then we can recur.
- RenderInline* currInline = toRenderInline(curr);
- if (!currInline->alwaysCreateLineBoxes())
- currInline->generateCulledLineBoxRects(yield, container);
- else {
- for (InlineFlowBox* childLine = currInline->firstLineBox(); childLine; childLine = childLine->nextLineBox()) {
- RootInlineBox* rootBox = childLine->root();
- int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
- int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
- if (isHorizontal)
- yield(FloatRect(childLine->x() - childLine->marginLogicalLeft(),
- logicalTop,
- childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight(),
- logicalHeight));
- else
- yield(FloatRect(logicalTop,
- childLine->y() - childLine->marginLogicalLeft(),
- logicalHeight,
- childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight()));
- }
- }
- } else if (curr->isText()) {
- RenderText* currText = toRenderText(curr);
- for (InlineTextBox* childText = currText->firstTextBox(); childText; childText = childText->nextTextBox()) {
- RootInlineBox* rootBox = childText->root();
- int logicalTop = rootBox->logicalTop() + (rootBox->renderer()->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent() - container->style(rootBox->isFirstLineStyle())->font().fontMetrics().ascent());
- int logicalHeight = container->style(rootBox->isFirstLineStyle())->font().fontMetrics().height();
- if (isHorizontal)
- yield(FloatRect(childText->x(), logicalTop, childText->logicalWidth(), logicalHeight));
- else
- yield(FloatRect(logicalTop, childText->y(), logicalHeight, childText->logicalWidth()));
- }
- }
- }
- }
- namespace {
- class AbsoluteRectsGeneratorContext {
- public:
- AbsoluteRectsGeneratorContext(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset)
- : m_rects(rects)
- , m_accumulatedOffset(accumulatedOffset) { }
- void operator()(const FloatRect& rect)
- {
- IntRect intRect = enclosingIntRect(rect);
- intRect.move(m_accumulatedOffset.x(), m_accumulatedOffset.y());
- m_rects.append(intRect);
- }
- private:
- Vector<IntRect>& m_rects;
- const LayoutPoint& m_accumulatedOffset;
- };
- } // unnamed namespace
- void RenderInline::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const
- {
- AbsoluteRectsGeneratorContext context(rects, accumulatedOffset);
- generateLineBoxRects(context);
- if (continuation()) {
- if (continuation()->isBox()) {
- RenderBox* box = toRenderBox(continuation());
- continuation()->absoluteRects(rects, toLayoutPoint(accumulatedOffset - containingBlock()->location() + box->locationOffset()));
- } else
- continuation()->absoluteRects(rects, toLayoutPoint(accumulatedOffset - containingBlock()->location()));
- }
- }
- namespace {
- class AbsoluteQuadsGeneratorContext {
- public:
- AbsoluteQuadsGeneratorContext(const RenderInline* renderer, Vector<FloatQuad>& quads)
- : m_quads(quads)
- , m_geometryMap()
- {
- m_geometryMap.pushMappingsToAncestor(renderer, 0);
- }
- void operator()(const FloatRect& rect)
- {
- m_quads.append(m_geometryMap.absoluteRect(rect));
- }
- private:
- Vector<FloatQuad>& m_quads;
- RenderGeometryMap m_geometryMap;
- };
- } // unnamed namespace
- void RenderInline::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
- {
- AbsoluteQuadsGeneratorContext context(this, quads);
- generateLineBoxRects(context);
- if (continuation())
- continuation()->absoluteQuads(quads, wasFixed);
- }
- LayoutUnit RenderInline::offsetLeft() const
- {
- LayoutPoint topLeft;
- if (InlineBox* firstBox = firstLineBoxIncludingCulling())
- topLeft = flooredLayoutPoint(firstBox->topLeft());
- return adjustedPositionRelativeToOffsetParent(topLeft).x();
- }
- LayoutUnit RenderInline::offsetTop() const
- {
- LayoutPoint topLeft;
- if (InlineBox* firstBox = firstLineBoxIncludingCulling())
- topLeft = flooredLayoutPoint(firstBox->topLeft());
- return adjustedPositionRelativeToOffsetParent(topLeft).y();
- }
- static LayoutUnit computeMargin(const RenderInline* renderer, const Length& margin)
- {
- if (margin.isAuto())
- return 0;
- if (margin.isFixed())
- return margin.value();
- if (margin.isPercent())
- return minimumValueForLength(margin, max<LayoutUnit>(0, renderer->containingBlock()->availableLogicalWidth()));
- if (margin.isViewportPercentage())
- return valueForLength(margin, 0, renderer->view());
- return 0;
- }
- LayoutUnit RenderInline::marginLeft() const
- {
- return computeMargin(this, style()->marginLeft());
- }
- LayoutUnit RenderInline::marginRight() const
- {
- return computeMargin(this, style()->marginRight());
- }
- LayoutUnit RenderInline::marginTop() const
- {
- return computeMargin(this, style()->marginTop());
- }
- LayoutUnit RenderInline::marginBottom() const
- {
- return computeMargin(this, style()->marginBottom());
- }
- LayoutUnit RenderInline::marginStart(const RenderStyle* otherStyle) const
- {
- return computeMargin(this, style()->marginStartUsing(otherStyle ? otherStyle : style()));
- }
- LayoutUnit RenderInline::marginEnd(const RenderStyle* otherStyle) const
- {
- return computeMargin(this, style()->marginEndUsing(otherStyle ? otherStyle : style()));
- }
- LayoutUnit RenderInline::marginBefore(const RenderStyle* otherStyle) const
- {
- return computeMargin(this, style()->marginBeforeUsing(otherStyle ? otherStyle : style()));
- }
- LayoutUnit RenderInline::marginAfter(const RenderStyle* otherStyle) const
- {
- return computeMargin(this, style()->marginAfterUsing(otherStyle ? otherStyle : style()));
- }
- const char* RenderInline::renderName() const
- {
- if (isRelPositioned())
- return "RenderInline (relative positioned)";
- if (isStickyPositioned())
- return "RenderInline (sticky positioned)";
- // FIXME: Temporary hack while the new generated content system is being implemented.
- if (isPseudoElement())
- return "RenderInline (generated)";
- if (isAnonymous())
- return "RenderInline (generated)";
- if (isRunIn())
- return "RenderInline (run-in)";
- return "RenderInline";
- }
- bool RenderInline::nodeAtPoint(const HitTestRequest& request, HitTestResult& result,
- const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
- {
- return m_lineBoxes.hitTest(this, request, result, locationInContainer, accumulatedOffset, hitTestAction);
- }
- namespace {
- class HitTestCulledInlinesGeneratorContext {
- public:
- HitTestCulledInlinesGeneratorContext(Region& region, const HitTestLocation& location) : m_intersected(false), m_region(region), m_location(location) { }
- void operator()(const FloatRect& rect)
- {
- m_intersected = m_intersected || m_location.intersects(rect);
- m_region.unite(enclosingIntRect(rect));
- }
- bool intersected() const { return m_intersected; }
- private:
- bool m_intersected;
- Region& m_region;
- const HitTestLocation& m_location;
- };
- } // unnamed namespace
- bool RenderInline::hitTestCulledInline(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset)
- {
- ASSERT(result.isRectBasedTest() && !alwaysCreateLineBoxes());
- if (!visibleToHitTesting())
- return false;
- HitTestLocation tmpLocation(locationInContainer, -toLayoutSize(accumulatedOffset));
- Region regionResult;
- HitTestCulledInlinesGeneratorContext context(regionResult, tmpLocation);
- generateCulledLineBoxRects(context, this);
- if (context.intersected()) {
- updateHitTestResult(result, tmpLocation.point());
- // We can not use addNodeToRectBasedTestResult to determine if we fully enclose the hit-test area
- // because it can only handle rectangular targets.
- result.addNodeToRectBasedTestResult(node(), request, locationInContainer);
- return regionResult.contains(tmpLocation.boundingBox());
- }
- return false;
- }
- VisiblePosition RenderInline::positionForPoint(const LayoutPoint& point)
- {
- // FIXME: Does not deal with relative or sticky positioned inlines (should it?)
- RenderBlock* cb = containingBlock();
- if (firstLineBox()) {
- // This inline actually has a line box. We must have clicked in the border/padding of one of these boxes. We
- // should try to find a result by asking our containing block.
- return cb->positionForPoint(point);
- }
- // Translate the coords from the pre-anonymous block to the post-anonymous block.
- LayoutPoint parentBlockPoint = cb->location() + point;
- RenderBoxModelObject* c = continuation();
- while (c) {
- RenderBox* contBlock = c->isInline() ? c->containingBlock() : toRenderBlock(c);
- if (c->isInline() || c->firstChild())
- return c->positionForPoint(parentBlockPoint - contBlock->locationOffset());
- c = toRenderBlock(c)->inlineElementContinuation();
- }
-
- return RenderBoxModelObject::positionForPoint(point);
- }
- namespace {
- class LinesBoundingBoxGeneratorContext {
- public:
- LinesBoundingBoxGeneratorContext(FloatRect& rect) : m_rect(rect) { }
- void operator()(const FloatRect& rect)
- {
- m_rect.uniteIfNonZero(rect);
- }
- private:
- FloatRect& m_rect;
- };
- } // unnamed namespace
- IntRect RenderInline::linesBoundingBox() const
- {
- if (!alwaysCreateLineBoxes()) {
- ASSERT(!firstLineBox());
- FloatRect floatResult;
- LinesBoundingBoxGeneratorContext context(floatResult);
- generateCulledLineBoxRects(context, this);
- return enclosingIntRect(floatResult);
- }
- IntRect result;
-
- // See <rdar://problem/5289721>, for an unknown reason the linked list here is sometimes inconsistent, first is non-zero and last is zero. We have been
- // unable to reproduce this at all (and consequently unable to figure ot why this is happening). The assert will hopefully catch the problem in debug
- // builds and help us someday figure out why. We also put in a redundant check of lastLineBox() to avoid the crash for now.
- ASSERT(!firstLineBox() == !lastLineBox()); // Either both are null or both exist.
- if (firstLineBox() && lastLineBox()) {
- // Return the width of the minimal left side and the maximal right side.
- float logicalLeftSide = 0;
- float logicalRightSide = 0;
- for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
- if (curr == firstLineBox() || curr->logicalLeft() < logicalLeftSide)
- logicalLeftSide = curr->logicalLeft();
- if (curr == firstLineBox() || curr->logicalRight() > logicalRightSide)
- logicalRightSide = curr->logicalRight();
- }
-
- bool isHorizontal = style()->isHorizontalWritingMode();
-
- float x = isHorizontal ? logicalLeftSide : firstLineBox()->x();
- float y = isHorizontal ? firstLineBox()->y() : logicalLeftSide;
- float width = isHorizontal ? logicalRightSide - logicalLeftSide : lastLineBox()->logicalBottom() - x;
- float height = isHorizontal ? lastLineBox()->logicalBottom() - y : logicalRightSide - logicalLeftSide;
- result = enclosingIntRect(FloatRect(x, y, width, height));
- }
- return result;
- }
- InlineBox* RenderInline::culledInlineFirstLineBox() const
- {
- for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
- if (curr->isFloatingOrOutOfFlowPositioned())
- continue;
-
- // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
- // direction (aligned to the root box's baseline).
- if (curr->isBox())
- return toRenderBox(curr)->inlineBoxWrapper();
- if (curr->isRenderInline()) {
- RenderInline* currInline = toRenderInline(curr);
- InlineBox* result = currInline->firstLineBoxIncludingCulling();
- if (result)
- return result;
- } else if (curr->isText()) {
- RenderText* currText = toRenderText(curr);
- if (currText->firstTextBox())
- return currText->firstTextBox();
- }
- }
- return 0;
- }
- InlineBox* RenderInline::culledInlineLastLineBox() const
- {
- for (RenderObject* curr = lastChild(); curr; curr = curr->previousSibling()) {
- if (curr->isFloatingOrOutOfFlowPositioned())
- continue;
-
- // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block
- // direction (aligned to the root box's baseline).
- if (curr->isBox())
- return toRenderBox(curr)->inlineBoxWrapper();
- if (curr->isRenderInline()) {
- RenderInline* currInline = toRenderInline(curr);
- InlineBox* result = currInline->lastLineBoxIncludingCulling();
- if (result)
- return result;
- } else if (curr->isText()) {
- RenderText* currText = toRenderText(curr);
- if (currText->lastTextBox())
- return currText->lastTextBox();
- }
- }
- return 0;
- }
- LayoutRect RenderInline::culledInlineVisualOverflowBoundingBox() const
- {
- FloatRect floatResult;
- LinesBoundingBoxGeneratorContext context(floatResult);
- generateCulledLineBoxRects(context, this);
- LayoutRect result(enclosingLayoutRect(floatResult));
- bool isHorizontal = style()->isHorizontalWritingMode();
- for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
- if (curr->isFloatingOrOutOfFlowPositioned())
- continue;
-
- // For overflow we just have to propagate by hand and recompute it all.
- if (curr->isBox()) {
- RenderBox* currBox = toRenderBox(curr);
- if (!currBox->hasSelfPaintingLayer() && currBox->inlineBoxWrapper()) {
- LayoutRect logicalRect = currBox->logicalVisualOverflowRectForPropagation(style());
- if (isHorizontal) {
- logicalRect.moveBy(currBox->location());
- result.uniteIfNonZero(logicalRect);
- } else {
- logicalRect.moveBy(currBox->location());
- result.uniteIfNonZero(logicalRect.transposedRect());
- }
- }
- } else if (curr->isRenderInline()) {
- // If the child doesn't need line boxes either, then we can recur.
- RenderInline* currInline = toRenderInline(curr);
- if (!currInline->alwaysCreateLineBoxes())
- result.uniteIfNonZero(currInline->culledInlineVisualOverflowBoundingBox());
- else if (!currInline->hasSelfPaintingLayer())
- result.uniteIfNonZero(currInline->linesVisualOverflowBoundingBox());
- } else if (curr->isText()) {
- // FIXME; Overflow from text boxes is lost. We will need to cache this information in
- // InlineTextBoxes.
- RenderText* currText = toRenderText(curr);
- result.uniteIfNonZero(currText->linesVisualOverflowBoundingBox());
- }
- }
- return result;
- }
- LayoutRect RenderInline::linesVisualOverflowBoundingBox() const
- {
- if (!alwaysCreateLineBoxes())
- return culledInlineVisualOverflowBoundingBox();
- if (!firstLineBox() || !lastLineBox())
- return LayoutRect();
- // Return the width of the minimal left side and the maximal right side.
- LayoutUnit logicalLeftSide = LayoutUnit::max();
- LayoutUnit logicalRightSide = LayoutUnit::min();
- for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
- logicalLeftSide = min(logicalLeftSide, curr->logicalLeftVisualOverflow());
- logicalRightSide = max(logicalRightSide, curr->logicalRightVisualOverflow());
- }
- RootInlineBox* firstRootBox = firstLineBox()->root();
- RootInlineBox* lastRootBox = lastLineBox()->root();
-
- LayoutUnit logicalTop = firstLineBox()->logicalTopVisualOverflow(firstRootBox->lineTop());
- LayoutUnit logicalWidth = logicalRightSide - logicalLeftSide;
- LayoutUnit logicalHeight = lastLineBox()->logicalBottomVisualOverflow(lastRootBox->lineBottom()) - logicalTop;
-
- LayoutRect rect(logicalLeftSide, logicalTop, logicalWidth, logicalHeight);
- if (!style()->isHorizontalWritingMode())
- rect = rect.transposedRect();
- return rect;
- }
- LayoutRect RenderInline::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const
- {
- // Only run-ins are allowed in here during layout.
- ASSERT(!view() || !view()->layoutStateEnabled() || isRunIn());
- if (!firstLineBoxIncludingCulling() && !continuation())
- return LayoutRect();
- LayoutRect repaintRect(linesVisualOverflowBoundingBox());
- bool hitRepaintContainer = false;
- // We need to add in the in-flow position offsets of any inlines (including us) up to our
- // containing block.
- RenderBlock* cb = containingBlock();
- for (const RenderObject* inlineFlow = this; inlineFlow && inlineFlow->isRenderInline() && inlineFlow != cb;
- inlineFlow = inlineFlow->parent()) {
- if (inlineFlow == repaintContainer) {
- hitRepaintContainer = true;
- break;
- }
- if (inlineFlow->style()->hasInFlowPosition() && inlineFlow->hasLayer())
- repaintRect.move(toRenderInline(inlineFlow)->layer()->paintOffset());
- }
- LayoutUnit outlineSize = style()->outlineSize();
- repaintRect.inflate(outlineSize);
- if (hitRepaintContainer || !cb)
- return repaintRect;
- if (cb->hasColumns())
- cb->adjustRectForColumns(repaintRect);
- if (cb->hasOverflowClip())
- cb->applyCachedClipAndScrollOffsetForRepaint(repaintRect);
- cb->computeRectForRepaint(repaintContainer, repaintRect);
- if (outlineSize) {
- for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
- if (!curr->isText())
- repaintRect.unite(curr->rectWithOutlineForRepaint(repaintContainer, outlineSize));
- }
- if (continuation() && !continuation()->isInline() && continuation()->parent())
- repaintRect.unite(continuation()->rectWithOutlineForRepaint(repaintContainer, outlineSize));
- }
- return repaintRect;
- }
- LayoutRect RenderInline::rectWithOutlineForRepaint(const RenderLayerModelObject* repaintContainer, LayoutUnit outlineWidth) const
- {
- LayoutRect r(RenderBoxModelObject::rectWithOutlineForRepaint(repaintContainer, outlineWidth));
- for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
- if (!curr->isText())
- r.unite(curr->rectWithOutlineForRepaint(repaintContainer, outlineWidth));
- }
- return r;
- }
- void RenderInline::computeRectForRepaint(const RenderLayerModelObject* repaintContainer, LayoutRect& rect, bool fixed) const
- {
- if (RenderView* v = view()) {
- // LayoutState is only valid for root-relative repainting
- if (v->layoutStateEnabled() && !repaintContainer) {
- LayoutState* layoutState = v->layoutState();
- if (style()->hasInFlowPosition() && layer())
- rect.move(layer()->paintOffset());
- rect.move(layoutState->m_paintOffset);
- if (layoutState->m_clipped)
- rect.intersect(layoutState->m_clipRect);
- return;
- }
- }
- if (repaintContainer == this)
- return;
- bool containerSkipped;
- RenderObject* o = container(repaintContainer, &containerSkipped);
- if (!o)
- return;
- LayoutPoint topLeft = rect.location();
- if (o->isBlockFlow() && !style()->hasOutOfFlowPosition()) {
- RenderBlock* cb = toRenderBlock(o);
- if (cb->hasColumns()) {
- LayoutRect repaintRect(topLeft, rect.size());
- cb->adjustRectForColumns(repaintRect);
- topLeft = repaintRect.location();
- rect = repaintRect;
- }
- }
- if (style()->hasInFlowPosition() && layer()) {
- // Apply the in-flow position offset when invalidating a rectangle. The layer
- // is translated, but the render box isn't, so we need to do this to get the
- // right dirty rect. Since this is called from RenderObject::setStyle, the relative or sticky position
- // flag on the RenderObject has been cleared, so use the one on the style().
- topLeft += layer()->paintOffset();
- }
-
- // FIXME: We ignore the lightweight clipping rect that controls use, since if |o| is in mid-layout,
- // its controlClipRect will be wrong. For overflow clip we use the values cached by the layer.
- rect.setLocation(topLeft);
- if (o->hasOverflowClip()) {
- RenderBox* containerBox = toRenderBox(o);
- containerBox->applyCachedClipAndScrollOffsetForRepaint(rect);
- if (rect.isEmpty())
- return;
- }
- if (containerSkipped) {
- // If the repaintContainer is below o, then we need to map the rect into repaintContainer's coordinates.
- LayoutSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
- rect.move(-containerOffset);
- return;
- }
-
- o->computeRectForRepaint(repaintContainer, rect, fixed);
- }
- LayoutSize RenderInline::offsetFromContainer(RenderObject* container, const LayoutPoint& point, bool* offsetDependsOnPoint) const
- {
- ASSERT(container == this->container());
-
- LayoutSize offset;
- if (isInFlowPositioned())
- offset += offsetForInFlowPosition();
- container->adjustForColumns(offset, point);
- if (container->hasOverflowClip())
- offset -= toRenderBox(container)->scrolledContentOffset();
- if (offsetDependsOnPoint)
- *offsetDependsOnPoint = container->hasColumns()
- || (container->isBox() && container->style()->isFlippedBlocksWritingMode())
- || container->isRenderFlowThread();
- return offset;
- }
- void RenderInline::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed) const
- {
- if (repaintContainer == this)
- return;
- if (RenderView *v = view()) {
- if (v->layoutStateEnabled() && !repaintContainer) {
- LayoutState* layoutState = v->layoutState();
- LayoutSize offset = layoutState->m_paintOffset;
- if (style()->hasInFlowPosition() && layer())
- offset += layer()->paintOffset();
- transformState.move(offset);
- return;
- }
- }
- bool containerSkipped;
- RenderObject* o = container(repaintContainer, &containerSkipped);
- if (!o)
- return;
- if (mode & ApplyContainerFlip && o->isBox()) {
- if (o->style()->isFlippedBlocksWritingMode()) {
- IntPoint centerPoint = roundedIntPoint(transformState.mappedPoint());
- transformState.move(toRenderBox(o)->flipForWritingModeIncludingColumns(centerPoint) - centerPoint);
- }
- mode &= ~ApplyContainerFlip;
- }
- LayoutSize containerOffset = offsetFromContainer(o, roundedLayoutPoint(transformState.mappedPoint()));
- bool preserve3D = mode & UseTransforms && (o->style()->preserves3D() || style()->preserves3D());
- if (mode & UseTransforms && shouldUseTransformFromContainer(o)) {
- TransformationMatrix t;
- getTransformFromContainer(o, containerOffset, t);
- transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
- } else
- transformState.move(containerOffset.width(), containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
- if (containerSkipped) {
- // There can't be a transform between repaintContainer and o, because transforms create containers, so it should be safe
- // to just subtract the delta between the repaintContainer and o.
- LayoutSize containerOffset = repaintContainer->offsetFromAncestorContainer(o);
- transformState.move(-containerOffset.width(), -containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
- return;
- }
- o->mapLocalToContainer(repaintContainer, transformState, mode, wasFixed);
- }
- const RenderObject* RenderInline::pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const
- {
- ASSERT(ancestorToStopAt != this);
- bool ancestorSkipped;
- RenderObject* container = this->container(ancestorToStopAt, &ancestorSkipped);
- if (!container)
- return 0;
- LayoutSize adjustmentForSkippedAncestor;
- if (ancestorSkipped) {
- // There can't be a transform between repaintContainer and o, because transforms create containers, so it should be safe
- // to just subtract the delta between the ancestor and o.
- adjustmentForSkippedAncestor = -ancestorToStopAt->offsetFromAncestorContainer(container);
- }
- bool offsetDependsOnPoint = false;
- LayoutSize containerOffset = offsetFromContainer(container, LayoutPoint(), &offsetDependsOnPoint);
- bool preserve3D = container->style()->preserves3D() || style()->preserves3D();
- if (shouldUseTransformFromContainer(container)) {
- TransformationMatrix t;
- getTransformFromContainer(container, containerOffset, t);
- t.translateRight(adjustmentForSkippedAncestor.width(), adjustmentForSkippedAncestor.height()); // FIXME: right?
- geometryMap.push(this, t, preserve3D, offsetDependsOnPoint);
- } else {
- containerOffset += adjustmentForSkippedAncestor;
- geometryMap.push(this, containerOffset, preserve3D, offsetDependsOnPoint);
- }
-
- return ancestorSkipped ? ancestorToStopAt : container;
- }
- void RenderInline::updateDragState(bool dragOn)
- {
- RenderBoxModelObject::updateDragState(dragOn);
- if (continuation())
- continuation()->updateDragState(dragOn);
- }
- void RenderInline::childBecameNonInline(RenderObject* child)
- {
- // We have to split the parent flow.
- RenderBlock* newBox = containingBlock()->createAnonymousBlock();
- RenderBoxModelObject* oldContinuation = continuation();
- setContinuation(newBox);
- RenderObject* beforeChild = child->nextSibling();
- children()->removeChildNode(this, child);
- splitFlow(beforeChild, newBox, child, oldContinuation);
- }
- void RenderInline::updateHitTestResult(HitTestResult& result, const LayoutPoint& point)
- {
- if (result.innerNode())
- return;
- Node* n = node();
- LayoutPoint localPoint(point);
- if (n) {
- if (isInlineElementContinuation()) {
- // We're in the continuation of a split inline. Adjust our local point to be in the coordinate space
- // of the principal renderer's containing block. This will end up being the innerNonSharedNode.
- RenderBlock* firstBlock = n->renderer()->containingBlock();
-
- // Get our containing block.
- RenderBox* block = containingBlock();
- localPoint.moveBy(block->location() - firstBlock->locationOffset());
- }
- result.setInnerNode(n);
- if (!result.innerNonSharedNode())
- result.setInnerNonSharedNode(n);
- result.setLocalPoint(localPoint);
- }
- }
- void RenderInline::dirtyLineBoxes(bool fullLayout)
- {
- if (fullLayout) {
- m_lineBoxes.deleteLineBoxes(renderArena());
- return;
- }
- if (!alwaysCreateLineBoxes()) {
- // We have to grovel into our children in order to dirty the appropriate lines.
- for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
- if (curr->isFloatingOrOutOfFlowPositioned())
- continue;
- if (curr->isBox() && !curr->needsLayout()) {
- RenderBox* currBox = toRenderBox(curr);
- if (currBox->inlineBoxWrapper())
- currBox->inlineBoxWrapper()->root()->markDirty();
- } else if (!curr->selfNeedsLayout()) {
- if (curr->isRenderInline()) {
- RenderInline* currInline = toRenderInline(curr);
- for (InlineFlowBox* childLine = currInline->firstLineBox(); childLine; childLine = childLine->nextLineBox())
- childLine->root()->markDirty();
- } else if (curr->isText()) {
- RenderText* currText = toRenderText(curr);
- for (InlineTextBox* childText = currText->firstTextBox(); childText; childText = childText->nextTextBox())
- childText->root()->markDirty();
- }
- }
- }
- } else
- m_lineBoxes.dirtyLineBoxes();
- }
- void RenderInline::deleteLineBoxTree()
- {
- m_lineBoxes.deleteLineBoxTree(renderArena());
- }
- InlineFlowBox* RenderInline::createInlineFlowBox()
- {
- return new (renderArena()) InlineFlowBox(this);
- }
- InlineFlowBox* RenderInline::createAndAppendInlineFlowBox()
- {
- setAlwaysCreateLineBoxes();
- InlineFlowBox* flowBox = createInlineFlowBox();
- m_lineBoxes.appendLineBox(flowBox);
- return flowBox;
- }
- LayoutUnit RenderInline::lineHeight(bool firstLine, LineDirectionMode /*direction*/, LinePositionMode /*linePositionMode*/) const
- {
- if (firstLine && document()->styleSheetCollection()->usesFirstLineRules()) {
- RenderStyle* s = style(firstLine);
- if (s != style())
- return s->computedLineHeight(view());
- }
- return style()->computedLineHeight(view());
- }
- int RenderInline::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
- {
- const FontMetrics& fontMetrics = style(firstLine)->fontMetrics();
- return fontMetrics.ascent(baselineType) + (lineHeight(firstLine, direction, linePositionMode) - fontMetrics.height()) / 2;
- }
- LayoutSize RenderInline::offsetForInFlowPositionedInline(const RenderBox* child) const
- {
- // FIXME: This function isn't right with mixed writing modes.
- ASSERT(isInFlowPositioned());
- if (!isInFlowPositioned())
- return LayoutSize();
- // When we have an enclosing relpositioned inline, we need to add in the offset of the first line
- // box from the rest of the content, but only in the cases where we know we're positioned
- // relative to the inline itself.
- LayoutSize logicalOffset;
- LayoutUnit inlinePosition;
- LayoutUnit blockPosition;
- if (firstLineBox()) {
- inlinePosition = roundedLayoutUnit(firstLineBox()->logicalLeft());
- blockPosition = firstLineBox()->logicalTop();
- } else {
- inlinePosition = layer()->staticInlinePosition();
- blockPosition = layer()->staticBlockPosition();
- }
- if (!child->style()->hasStaticInlinePosition(style()->isHorizontalWritingMode()))
- logicalOffset.setWidth(inlinePosition);
- // This is not terribly intuitive, but we have to match other browsers. Despite being a block display type inside
- // an inline, we still keep our x locked to the left of the relative positioned inline. Arguably the correct
- // behavior would be to go flush left to the block that contains the inline, but that isn't what other browsers
- // do.
- else if (!child->style()->isOriginalDisplayInlineType())
- // Avoid adding in the left border/padding of the containing block twice. Subtract it out.
- logicalOffset.setWidth(inlinePosition - child->containingBlock()->borderAndPaddingLogicalLeft());
- if (!child->style()->hasStaticBlockPosition(style()->isHorizontalWritingMode()))
- logicalOffset.setHeight(blockPosition);
- return style()->isHorizontalWritingMode() ? logicalOffset : logicalOffset.transposedSize();
- }
- void RenderInline::imageChanged(WrappedImagePtr, const IntRect*)
- {
- if (!parent())
- return;
-
- // FIXME: We can do better.
- repaint();
- }
- void RenderInline::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset)
- {
- AbsoluteRectsGeneratorContext context(rects, additionalOffset);
- generateLineBoxRects(context);
- for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
- if (!curr->isText() && !curr->isListMarker()) {
- FloatPoint pos(additionalOffset);
- // FIXME: This doesn't work correctly with transforms.
- if (curr->hasLayer())
- pos = curr->localToAbsolute();
- else if (curr->isBox())
- pos.move(toRenderBox(curr)->locationOffset());
- curr->addFocusRingRects(rects, flooredIntPoint(pos));
- }
- }
- if (continuation()) {
- if (continuation()->isInline())
- continuation()->addFocusRingRects(rects, flooredLayoutPoint(additionalOffset + continuation()->containingBlock()->location() - containingBlock()->location()));
- else
- continuation()->addFocusRingRects(rects, flooredLayoutPoint(additionalOffset + toRenderBox(continuation())->location() - containingBlock()->location()));
- }
- }
- void RenderInline::paintOutline(GraphicsContext* graphicsContext, const LayoutPoint& paintOffset)
- {
- if (!hasOutline())
- return;
-
- RenderStyle* styleToUse = style();
- if (styleToUse->outlineStyleIsAuto() || hasOutlineAnnotation()) {
- if (!theme()->supportsFocusRing(styleToUse)) {
- // Only paint the focus ring by hand if the theme isn't able to draw the focus ring.
- paintFocusRing(graphicsContext, paintOffset, styleToUse);
- }
- }
- if (graphicsContext->paintingDisabled())
- return;
- if (styleToUse->outlineStyleIsAuto() || styleToUse->outlineStyle() == BNONE)
- return;
- Vector<LayoutRect> rects;
- rects.append(LayoutRect());
- for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) {
- RootInlineBox* root = curr->root();
- LayoutUnit top = max<LayoutUnit>(root->lineTop(), curr->logicalTop());
- LayoutUnit bottom = min<LayoutUnit>(root->lineBottom(), curr->logicalBottom());
- rects.append(LayoutRect(curr->x(), top, curr->logicalWidth(), bottom - top));
- }
- rects.append(LayoutRect());
- Color outlineColor = styleToUse->visitedDependentColor(CSSPropertyOutlineColor);
- bool useTransparencyLayer = outlineColor.hasAlpha();
- if (useTransparencyLayer) {
- graphicsContext->beginTransparencyLayer(static_cast<float>(outlineColor.alpha()) / 255);
- outlineColor = Color(outlineColor.red(), outlineColor.green(), outlineColor.blue());
- }
- for (unsigned i = 1; i < rects.size() - 1; i++)
- paintOutlineForLine(graphicsContext, paintOffset, rects.at(i - 1), rects.at(i), rects.at(i + 1), outlineColor);
- if (useTransparencyLayer)
- graphicsContext->endTransparencyLayer();
- }
- void RenderInline::paintOutlineForLine(GraphicsContext* graphicsContext, const LayoutPoint& paintOffset,
- const LayoutRect& lastline, const LayoutRect& thisline, const LayoutRect& nextline,
- const Color outlineColor)
- {
- RenderStyle* styleToUse = style();
- int outlineWidth = styleToUse->outlineWidth();
- EBorderStyle outlineStyle = styleToUse->outlineStyle();
- bool antialias = shouldAntialiasLines(graphicsContext);
- int offset = style()->outlineOffset();
- LayoutRect box(LayoutPoint(paintOffset.x() + thisline.x() - offset, paintOffset.y() + thisline.y() - offset),
- LayoutSize(thisline.width() + offset, thisline.height() + offset));
- IntRect pixelSnappedBox = pixelSnappedIntRect(box);
- IntRect pixelSnappedLastLine = pixelSnappedIntRect(paintOffset.x() + lastline.x(), 0, lastline.width(), 0);
- IntRect pixelSnappedNextLine = pixelSnappedIntRect(paintOffset.x() + nextline.x(), 0, nextline.width(), 0);
-
- // left edge
- drawLineForBoxSide(graphicsContext,
- pixelSnappedBox.x() - outlineWidth,
- pixelSnappedBox.y() - (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.maxX() - 1) <= thisline.x() ? outlineWidth : 0),
- pixelSnappedBox.x(),
- pixelSnappedBox.maxY() + (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.maxX() - 1) <= thisline.x() ? outlineWidth : 0),
- BSLeft,
- outlineColor, outlineStyle,
- (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.maxX() - 1) <= thisline.x() ? outlineWidth : -outlineWidth),
- (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.maxX() - 1) <= thisline.x() ? outlineWidth : -outlineWidth),
- antialias);
-
- // right edge
- drawLineForBoxSide(graphicsContext,
- pixelSnappedBox.maxX(),
- pixelSnappedBox.y() - (lastline.isEmpty() || lastline.maxX() < thisline.maxX() || (thisline.maxX() - 1) <= lastline.x() ? outlineWidth : 0),
- pixelSnappedBox.maxX() + outlineWidth,
- pixelSnappedBox.maxY() + (nextline.isEmpty() || nextline.maxX() <= thisline.maxX() || (thisline.maxX() - 1) <= nextline.x() ? outlineWidth : 0),
- BSRight,
- outlineColor, outlineStyle,
- (lastline.isEmpty() || lastline.maxX() < thisline.maxX() || (thisline.maxX() - 1) <= lastline.x() ? outlineWidth : -outlineWidth),
- (nextline.isEmpty() || nextline.maxX() <= thisline.maxX() || (thisline.maxX() - 1) <= nextline.x() ? outlineWidth : -outlineWidth),
- antialias);
- // upper edge
- if (thisline.x() < lastline.x())
- drawLineForBoxSide(graphicsContext,
- pixelSnappedBox.x() - outlineWidth,
- pixelSnappedBox.y() - outlineWidth,
- min(pixelSnappedBox.maxX() + outlineWidth, (lastline.isEmpty() ? 1000000 : pixelSnappedLastLine.x())),
- pixelSnappedBox.y(),
- BSTop, outlineColor, outlineStyle,
- outlineWidth,
- (!lastline.isEmpty() && paintOffset.x() + lastline.x() + 1 < pixelSnappedBox.maxX() + outlineWidth) ? -outlineWidth : outlineWidth,
- antialias);
-
- if (lastline.maxX() < thisline.maxX())
- drawLineForBoxSide(graphicsContext,
- max(lastline.isEmpty() ? -1000000 : pixelSnappedLastLine.maxX(), pixelSnappedBox.x() - outlineWidth),
- pixelSnappedBox.y() - outlineWidth,
- pixelSnappedBox.maxX() + outlineWidth,
- pixelSnappedBox.y(),
- BSTop, outlineColor, outlineStyle,
- (!lastline.isEmpty() && pixelSnappedBox.x() - outlineWidth < paintOffset.x() + lastline.maxX()) ? -outlineWidth : outlineWidth,
- outlineWidth, antialias);
- if (thisline.x() == thisline.maxX())
- drawLineForBoxSide(graphicsContext,
- pixelSnappedBox.x() - outlineWidth,
- pixelSnappedBox.y() - outlineWidth,
- pixelSnappedBox.maxX() + outlineWidth,
- pixelSnappedBox.y(),
- BSTop, outlineColor, outlineStyle,
- outlineWidth,
- outlineWidth,
- antialias);
- // lower edge
- if (thisline.x() < nextline.x())
- drawLineForBoxSide(graphicsContext,
- pixelSnappedBox.x() - outlineWidth,
- pixelSnappedBox.maxY(),
- min(pixelSnappedBox.maxX() + outlineWidth, !nextline.isEmpty() ? pixelSnappedNextLine.x() + 1 : 1000000),
- pixelSnappedBox.maxY() + outlineWidth,
- BSBottom, outlineColor, outlineStyle,
- outlineWidth,
- (!nextline.isEmpty() && paintOffset.x() + nextline.x() + 1 < pixelSnappedBox.maxX() + outlineWidth) ? -outlineWidth : outlineWidth,
- antialias);
-
- if (nextline.maxX() < thisline.maxX())
- drawLineForBoxSide(graphicsContext,
- max(!nextline.isEmpty() ? pixelSnappedNextLine.maxX() : -1000000, pixelSnappedBox.x() - outlineWidth),
- pixelSnappedBox.maxY(),
- pixelSnappedBox.maxX() + outlineWidth,
- pixelSnappedBox.maxY() + outlineWidth,
- BSBottom, outlineColor, outlineStyle,
- (!nextline.isEmpty() && pixelSnappedBox.x() - outlineWidth < paintOffset.x() + nextline.maxX()) ? -outlineWidth : outlineWidth,
- outlineWidth, antialias);
- if (thisline.x() == thisline.maxX())
- drawLineForBoxSide(graphicsContext,
- pixelSnappedBox.x() - outlineWidth,
- pixelSnappedBox.maxY(),
- pixelSnappedBox.maxX() + outlineWidth,
- pixelSnappedBox.maxY() + outlineWidth,
- BSBottom, outlineColor, outlineStyle,
- outlineWidth,
- outlineWidth,
- antialias);
- }
- #if ENABLE(DASHBOARD_SUPPORT) || ENABLE(DRAGGABLE_REGION)
- void RenderInline::addAnnotatedRegions(Vector<AnnotatedRegionValue>& regions)
- {
- // Convert the style regions to absolute coordinates.
- if (style()->visibility() != VISIBLE)
- return;
- #if ENABLE(DASHBOARD_SUPPORT)
- const Vector<StyleDashboardRegion>& styleRegions = style()->dashboardRegions();
- unsigned i, count = styleRegions.size();
- for (i = 0; i < count; i++) {
- StyleDashboardRegion styleRegion = styleRegions[i];
- LayoutRect linesBoundingBox = this->linesBoundingBox();
- LayoutUnit w = linesBoundingBox.width();
- LayoutUnit h = linesBoundingBox.height();
- AnnotatedRegionValue region;
- region.label = styleRegion.label;
- region.bounds = LayoutRect(linesBoundingBox.x() + styleRegion.offset.left().value(),
- linesBoundingBox.y() + styleRegion.offset.top().value(),
- w - styleRegion.offset.left().value() - styleRegion.offset.right().value(),
- h - styleRegion.offset.top().value() - styleRegion.offset.bottom().value());
- region.type = styleRegion.type;
- RenderObject* container = containingBlock();
- if (!container)
- container = this;
- region.clip = region.bounds;
- container->computeAbsoluteRepaintRect(region.clip);
- if (region.clip.height() < 0) {
- region.clip.setHeight(0);
- region.clip.setWidth(0);
- }
- FloatPoint absPos = container->localToAbsolute();
- region.bounds.setX(absPos.x() + region.bounds.x());
- region.bounds.setY(absPos.y() + region.bounds.y());
- regions.append(region);
- }
- #else // ENABLE(DRAGGABLE_REGION)
- if (style()->getDraggableRegionMode() == DraggableRegionNone)
- return;
- AnnotatedRegionValue region;
- region.draggable = style()->getDraggableRegionMode() == DraggableRegionDrag;
- region.bounds = linesBoundingBox();
- RenderObject* container = containingBlock();
- if (!container)
- container = this;
- FloatPoint absPos = container->localToAbsolute();
- region.bounds.setX(absPos.x() + region.bounds.x());
- region.bounds.setY(absPos.y() + region.bounds.y());
-
- regions.append(region);
- #endif
- }
- #endif
- } // namespace WebCore
|