void InlineBox::attachLine() { m_extracted = false; if (m_renderer->isBox()) toRenderBox(m_renderer)->setInlineBoxWrapper(this); }
void RootInlineBox::setLineBreakInfo(RenderObject* obj, unsigned breakPos, const BidiStatus& status) { // When setting lineBreakObj, the RenderObject must not be a RenderInline // with no line boxes, otherwise all sorts of invariants are broken later. // This has security implications because if the RenderObject does not // point to at least one line box, then that RenderInline can be deleted // later without resetting the lineBreakObj, leading to use-after-free. ASSERT_WITH_SECURITY_IMPLICATION(!obj || obj->isText() || !(obj->isRenderInline() && obj->isBox() && !toRenderBox(obj)->inlineBoxWrapper())); m_lineBreakObj = obj; m_lineBreakPos = breakPos; m_lineBreakBidiStatusEor = status.eor; m_lineBreakBidiStatusLastStrong = status.lastStrong; m_lineBreakBidiStatusLast = status.last; m_lineBreakContext = status.context; }
void InlineBox::extractLine() { m_extracted = true; if (m_renderer->isBox()) toRenderBox(m_renderer)->setInlineBoxWrapper(0); }
void RenderLayerClipper::calculateRects(const ClipRectsContext& context, const LayoutRect& paintDirtyRect, LayoutRect& layerBounds, ClipRect& backgroundRect, ClipRect& foregroundRect, ClipRect& outlineRect, const LayoutPoint* offsetFromRoot) const { bool isClippingRoot = m_renderer.layer() == context.rootLayer; if (!isClippingRoot && m_renderer.layer()->parent()) { backgroundRect = backgroundClipRect(context); backgroundRect.move(roundedIntSize(context.subPixelAccumulation)); backgroundRect.intersect(paintDirtyRect); } else { backgroundRect = paintDirtyRect; } foregroundRect = backgroundRect; outlineRect = backgroundRect; LayoutPoint offset; if (offsetFromRoot) offset = *offsetFromRoot; else m_renderer.layer()->convertToLayerCoords(context.rootLayer, offset); layerBounds = LayoutRect(offset, m_renderer.layer()->size()); // Update the clip rects that will be passed to child layers. if (m_renderer.hasOverflowClip()) { // This layer establishes a clip of some kind. if (!isClippingRoot || context.respectOverflowClip == RespectOverflowClip) { foregroundRect.intersect(toRenderBox(m_renderer).overflowClipRect(offset, context.scrollbarRelevancy)); if (m_renderer.style()->hasBorderRadius()) foregroundRect.setHasRadius(true); } // If we establish an overflow clip at all, then go ahead and make sure our background // rect is intersected with our layer's bounds including our visual overflow, // since any visual overflow like box-shadow or border-outset is not clipped by overflow:auto/hidden. if (toRenderBox(m_renderer).hasVisualOverflow()) { // FIXME: Perhaps we should be propagating the borderbox as the clip rect for children, even though // we may need to inflate our clip specifically for shadows or outsets. // FIXME: Does not do the right thing with CSS regions yet, since we don't yet factor in the // individual region boxes as overflow. LayoutRect layerBoundsWithVisualOverflow = toRenderBox(m_renderer).visualOverflowRect(); toRenderBox(m_renderer).flipForWritingMode(layerBoundsWithVisualOverflow); // Layers are in physical coordinates, so the overflow has to be flipped. layerBoundsWithVisualOverflow.moveBy(offset); if (!isClippingRoot || context.respectOverflowClip == RespectOverflowClip) backgroundRect.intersect(layerBoundsWithVisualOverflow); } else { LayoutRect bounds = toRenderBox(m_renderer).borderBoxRect(); bounds.moveBy(offset); if (!isClippingRoot || context.respectOverflowClip == RespectOverflowClip) backgroundRect.intersect(bounds); } } // CSS clip (different than clipping due to overflow) can clip to any box, even if it falls outside of the border box. if (m_renderer.hasClip()) { // Clip applies to *us* as well, so go ahead and update the damageRect. LayoutRect newPosClip = toRenderBox(m_renderer).clipRect(offset); backgroundRect.intersect(newPosClip); foregroundRect.intersect(newPosClip); outlineRect.intersect(newPosClip); } }
RenderObject* RenderObjectChildList::removeChildNode(RenderObject* owner, RenderObject* oldChild, bool fullRemove) { ASSERT(oldChild->parent() == owner); // So that we'll get the appropriate dirty bit set (either that a normal flow child got yanked or // that a positioned child got yanked). We also repaint, so that the area exposed when the child // disappears gets repainted properly. if (!owner->documentBeingDestroyed() && fullRemove && oldChild->m_everHadLayout) { oldChild->setNeedsLayoutAndPrefWidthsRecalc(); oldChild->repaint(); } // If we have a line box wrapper, delete it. if (oldChild->isBox()) toRenderBox(oldChild)->deleteLineBoxWrapper(); if (!owner->documentBeingDestroyed() && fullRemove) { // if we remove visible child from an invisible parent, we don't know the layer visibility any more RenderLayer* layer = 0; if (owner->style()->visibility() != VISIBLE && oldChild->style()->visibility() == VISIBLE && !oldChild->hasLayer()) { layer = owner->enclosingLayer(); layer->dirtyVisibleContentStatus(); } // Keep our layer hierarchy updated. if (oldChild->firstChild() || oldChild->hasLayer()) { if (!layer) layer = owner->enclosingLayer(); oldChild->removeLayers(layer); } // renumber ordered lists if (oldChild->isListItem()) updateListMarkerNumbers(oldChild->nextSibling()); if (oldChild->isPositioned() && owner->childrenInline()) owner->dirtyLinesFromChangedChild(oldChild); } // If oldChild is the start or end of the selection, then clear the selection to // avoid problems of invalid pointers. // FIXME: The SelectionController should be responsible for this when it // is notified of DOM mutations. if (!owner->documentBeingDestroyed() && oldChild->isSelectionBorder()) owner->view()->clearSelection(); // remove the child if (oldChild->previousSibling()) oldChild->previousSibling()->setNextSibling(oldChild->nextSibling()); if (oldChild->nextSibling()) oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling()); if (firstChild() == oldChild) setFirstChild(oldChild->nextSibling()); if (lastChild() == oldChild) setLastChild(oldChild->previousSibling()); oldChild->setPreviousSibling(0); oldChild->setNextSibling(0); oldChild->setParent(0); if (AXObjectCache::accessibilityEnabled()) owner->document()->axObjectCache()->childrenChanged(owner); return oldChild; }
void RenderView::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint&) { if (!paintInfo.shouldPaintWithinRoot(*this)) return; // Check to see if we are enclosed by a layer that requires complex painting rules. If so, we cannot blit // when scrolling, and we need to use slow repaints. Examples of layers that require this are transparent layers, // layers with reflections, or transformed layers. // FIXME: This needs to be dynamic. We should be able to go back to blitting if we ever stop being inside // a transform, transparency layer, etc. Element* elt; for (elt = document().ownerElement(); elt && elt->renderer(); elt = elt->document().ownerElement()) { RenderLayer* layer = elt->renderer()->enclosingLayer(); if (layer->cannotBlitToWindow()) { frameView().setCannotBlitToWindow(); break; } #if USE(ACCELERATED_COMPOSITING) if (RenderLayer* compositingLayer = layer->enclosingCompositingLayerForRepaint()) { if (!compositingLayer->backing()->paintsIntoWindow()) { frameView().setCannotBlitToWindow(); break; } } #endif } if (document().ownerElement()) return; if (paintInfo.skipRootBackground()) return; bool rootFillsViewport = false; bool rootObscuresBackground = false; Element* documentElement = document().documentElement(); if (RenderElement* rootRenderer = documentElement ? documentElement->renderer() : 0) { // The document element's renderer is currently forced to be a block, but may not always be. RenderBox* rootBox = rootRenderer->isBox() ? toRenderBox(rootRenderer) : 0; rootFillsViewport = rootBox && !rootBox->x() && !rootBox->y() && rootBox->width() >= width() && rootBox->height() >= height(); rootObscuresBackground = rendererObscuresBackground(rootRenderer); } Page* page = document().page(); float pageScaleFactor = page ? page->pageScaleFactor() : 1; // If painting will entirely fill the view, no need to fill the background. if (rootFillsViewport && rootObscuresBackground && pageScaleFactor >= 1) return; // This code typically only executes if the root element's visibility has been set to hidden, // if there is a transform on the <html>, or if there is a page scale factor less than 1. // Only fill with the base background color (typically white) if we're the root document, // since iframes/frames with no background in the child document should show the parent's background. if (frameView().isTransparent()) // FIXME: This needs to be dynamic. We should be able to go back to blitting if we ever stop being transparent. frameView().setCannotBlitToWindow(); // The parent must show behind the child. else { Color baseColor = frameView().baseBackgroundColor(); if (baseColor.alpha()) { CompositeOperator previousOperator = paintInfo.context->compositeOperation(); paintInfo.context->setCompositeOperation(CompositeCopy); paintInfo.context->fillRect(paintInfo.rect, baseColor, style()->colorSpace()); paintInfo.context->setCompositeOperation(previousOperator); } else paintInfo.context->clearRect(paintInfo.rect); } }
void InlineBox::attachLine() { m_bitfields.setExtracted(false); if (m_renderer->isBox()) toRenderBox(m_renderer)->setInlineBoxWrapper(this); }
void RenderLineBoxList::dirtyLinesFromChangedChild(RenderObject* container, RenderObject* child) { if (!container->parent() || (container->isRenderBlock() && (container->selfNeedsLayout() || !container->isBlockFlow()))) return; // If we have no first line box, then just bail early. if (!firstLineBox()) { // For an empty inline, go ahead and propagate the check up to our parent, unless the parent // is already dirty. if (container->isInline() && !container->parent()->selfNeedsLayout()) container->parent()->dirtyLinesFromChangedChild(container); return; } // Try to figure out which line box we belong in. First try to find a previous // line box by examining our siblings. If we didn't find a line box, then use our // parent's first line box. RootInlineBox* box = 0; RenderObject* curr = 0; for (curr = child->previousSibling(); curr; curr = curr->previousSibling()) { if (curr->isFloatingOrPositioned()) continue; if (curr->isReplaced()) { InlineBox* wrapper = toRenderBox(curr)->inlineBoxWrapper(); if (wrapper) box = wrapper->root(); } else if (curr->isText()) { InlineTextBox* textBox = toRenderText(curr)->lastTextBox(); if (textBox) box = textBox->root(); } else if (curr->isRenderInline()) { InlineFlowBox* flowBox = toRenderInline(curr)->lastLineBox(); if (flowBox) box = flowBox->root(); } if (box) break; } if (!box) box = firstLineBox()->root(); // If we found a line box, then dirty it. if (box) { RootInlineBox* adjacentBox; box->markDirty(); // dirty the adjacent lines that might be affected // NOTE: we dirty the previous line because RootInlineBox objects cache // the address of the first object on the next line after a BR, which we may be // invalidating here. For more info, see how RenderBlock::layoutInlineChildren // calls setLineBreakInfo with the result of findNextLineBreak. findNextLineBreak, // despite the name, actually returns the first RenderObject after the BR. // <rdar://problem/3849947> "Typing after pasting line does not appear until after window resize." adjacentBox = box->prevRootBox(); if (adjacentBox) adjacentBox->markDirty(); if (child->isBR() || (curr && curr->isBR())) { adjacentBox = box->nextRootBox(); if (adjacentBox) adjacentBox->markDirty(); } } }
void InlineBox::deleteLine(RenderArena* arena) { if (!m_bitfields.extracted() && m_renderer.isBox()) toRenderBox(renderer()).setInlineBoxWrapper(0); destroy(arena); }
RenderObject* RenderObjectChildList::removeChildNode(RenderObject* owner, RenderObject* oldChild, bool fullRemove) { ASSERT(oldChild->parent() == owner); // So that we'll get the appropriate dirty bit set (either that a normal flow child got yanked or // that a positioned child got yanked). We also repaint, so that the area exposed when the child // disappears gets repainted properly. if (!owner->documentBeingDestroyed() && fullRemove && oldChild->everHadLayout()) { oldChild->setNeedsLayoutAndPrefWidthsRecalc(); if (oldChild->isBody()) owner->view()->repaint(); else oldChild->repaint(); } // If we have a line box wrapper, delete it. if (oldChild->isBox()) toRenderBox(oldChild)->deleteLineBoxWrapper(); if (!owner->documentBeingDestroyed() && fullRemove) { // if we remove visible child from an invisible parent, we don't know the layer visibility any more RenderLayer* layer = 0; if (owner->style()->visibility() != VISIBLE && oldChild->style()->visibility() == VISIBLE && !oldChild->hasLayer()) { if ((layer = owner->enclosingLayer())) layer->dirtyVisibleContentStatus(); } // Keep our layer hierarchy updated. if (oldChild->firstChild() || oldChild->hasLayer()) { if (!layer) layer = owner->enclosingLayer(); oldChild->removeLayers(layer); } if (oldChild->isListItem()) toRenderListItem(oldChild)->updateListMarkerNumbers(); if (oldChild->isPositioned() && owner->childrenInline()) owner->dirtyLinesFromChangedChild(oldChild); if (oldChild->isRenderRegion()) toRenderRegion(oldChild)->detachRegion(); if (oldChild->inRenderFlowThread() && oldChild->isBox()) { oldChild->enclosingRenderFlowThread()->removeRenderBoxRegionInfo(toRenderBox(oldChild)); if (oldChild->canHaveRegionStyle()) oldChild->enclosingRenderFlowThread()->clearRenderBoxCustomStyle(toRenderBox(oldChild)); } if (RenderNamedFlowThread* containerFlowThread = renderNamedFlowThreadContainer(owner)) containerFlowThread->removeFlowChild(oldChild); #if ENABLE(SVG) // Update cached boundaries in SVG renderers, if a child is removed. owner->setNeedsBoundariesUpdate(); #endif } // If oldChild is the start or end of the selection, then clear the selection to // avoid problems of invalid pointers. // FIXME: The FrameSelection should be responsible for this when it // is notified of DOM mutations. if (!owner->documentBeingDestroyed() && oldChild->isSelectionBorder()) owner->view()->clearSelection(); // remove the child if (oldChild->previousSibling()) oldChild->previousSibling()->setNextSibling(oldChild->nextSibling()); if (oldChild->nextSibling()) oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling()); if (firstChild() == oldChild) setFirstChild(oldChild->nextSibling()); if (lastChild() == oldChild) setLastChild(oldChild->previousSibling()); oldChild->setPreviousSibling(0); oldChild->setNextSibling(0); oldChild->setParent(0); RenderCounter::rendererRemovedFromTree(oldChild); RenderQuote::rendererRemovedFromTree(oldChild); if (AXObjectCache::accessibilityEnabled()) owner->document()->axObjectCache()->childrenChanged(owner); return oldChild; }
void HTMLPlugInImageElement::subframeLoaderWillCreatePlugIn(const KURL& url) { if (!document()->page() || !document()->page()->settings()->plugInSnapshottingEnabled()) return; bool inMainFrame = document()->frame() == document()->page()->mainFrame(); if (document()->isPluginDocument() && inMainFrame) { LOG(Plugins, "%p Plug-in document in main frame", this); return; } if (ScriptController::processingUserGesture()) { LOG(Plugins, "%p Script is processing user gesture, set to play", this); return; } if (m_createdDuringUserGesture) { LOG(Plugins, "%p Plug-in was created when processing user gesture, set to play", this); return; } double lastKnownUserGestureTimestamp = document()->lastHandledUserGestureTimestamp(); if (!inMainFrame && document()->page()->mainFrame() && document()->page()->mainFrame()->document()) lastKnownUserGestureTimestamp = std::max(lastKnownUserGestureTimestamp, document()->page()->mainFrame()->document()->lastHandledUserGestureTimestamp()); if (currentTime() - lastKnownUserGestureTimestamp < autostartSoonAfterUserGestureThreshold) { LOG(Plugins, "%p Plug-in was created shortly after a user gesture, set to play", this); return; } RenderBox* renderEmbeddedObject = toRenderBox(renderer()); Length styleWidth = renderEmbeddedObject->style()->width(); Length styleHeight = renderEmbeddedObject->style()->height(); LayoutRect contentBoxRect = renderEmbeddedObject->contentBoxRect(); int contentWidth = contentBoxRect.width(); int contentHeight = contentBoxRect.height(); int contentArea = contentWidth * contentHeight; IntSize visibleViewSize = document()->frame()->view()->visibleSize(); int visibleArea = visibleViewSize.width() * visibleViewSize.height(); if (inMainFrame && styleWidth.isPercent() && (styleWidth.percent() == 100) && styleHeight.isPercent() && (styleHeight.percent() == 100) && (static_cast<float>(contentArea) / visibleArea > sizingFullPageAreaRatioThreshold)) { LOG(Plugins, "%p Plug-in is top level full page, set to play", this); return; } if (contentWidth <= sizingTinyDimensionThreshold || contentHeight <= sizingTinyDimensionThreshold) { LOG(Plugins, "%p Plug-in is %dx%d, set to play", this, contentWidth, contentHeight); return; } if (!document()->page() || !document()->page()->plugInClient()) { setDisplayState(WaitingForSnapshot); return; } LOG(Plugins, "%p Plug-in URL: %s", this, m_url.utf8().data()); LOG(Plugins, " loaded URL: %s", url.string().utf8().data()); m_plugInOriginHash = PlugInOriginHash::hash(this, url); if (m_plugInOriginHash && document()->page()->plugInClient()->isAutoStartOrigin(m_plugInOriginHash)) { LOG(Plugins, "%p Plug-in hash %x is auto-start, set to play", this, m_plugInOriginHash); return; } LOG(Plugins, "%p Plug-in hash %x is %dx%d, origin is not auto-start, set to wait for snapshot", this, m_plugInOriginHash, contentWidth, contentHeight); // We may have got to this point by restarting a snapshotted plug-in, in which case we don't want to // reset the display state. if (displayState() != RestartingWithPendingMouseClick && displayState() != Restarting) setDisplayState(WaitingForSnapshot); }
void RenderMultiColumnFlowThread::flowThreadDescendantInserted(RenderObject* descendant) { if (gShiftingSpanner || m_beingEvacuated || descendant->isInFlowRenderFlowThread()) return; RenderObject* subtreeRoot = descendant; for (; descendant; descendant = (descendant ? descendant->nextInPreOrder(subtreeRoot) : nullptr)) { if (descendant->isRenderMultiColumnSpannerPlaceholder()) { // A spanner's placeholder has been inserted. The actual spanner renderer is moved from // where it would otherwise occur (if it weren't a spanner) to becoming a sibling of the // column sets. RenderMultiColumnSpannerPlaceholder* placeholder = toRenderMultiColumnSpannerPlaceholder(descendant); if (placeholder->flowThread() != this) { // This isn't our spanner! It shifted here from an ancestor multicolumn block. It's going to end up // becoming our spanner instead, but for it to do that we first have to nuke the original spanner, // and get the spanner content back into this flow thread. RenderBox* spanner = placeholder->spanner(); // Get info for the move of the original content back into our flow thread. RenderBoxModelObject* placeholderParent = toRenderBoxModelObject(placeholder->parent()); // We have to nuke the placeholder, since the ancestor already lost the mapping to it when // we shifted the placeholder down into this flow thread. RenderObject* placeholderNextSibling = placeholderParent->removeChild(*placeholder); // Get the ancestor multicolumn flow thread to clean up its mess. RenderBlockFlow* ancestorBlock = toRenderBlockFlow(spanner->parent()); ancestorBlock->multiColumnFlowThread()->flowThreadRelativeWillBeRemoved(spanner); // Now move the original content into our flow thread. It will end up calling flowThreadDescendantInserted // on the new content only, and everything will get set up properly. ancestorBlock->moveChildTo(placeholderParent, spanner, placeholderNextSibling, true); // Advance descendant. descendant = placeholderNextSibling; // If the spanner was the subtree root, then we're done, since there is nothing else left to insert. if (!descendant) return; // Now that we have done this, we can continue past the spanning content, since we advanced // descendant already. if (descendant) descendant = descendant->previousInPreOrder(subtreeRoot); continue; } ASSERT(!m_spannerMap.get(placeholder->spanner())); m_spannerMap.add(placeholder->spanner(), placeholder); ASSERT(!placeholder->firstChild()); // There should be no children here, but if there are, we ought to skip them. continue; } RenderBlockFlow* multicolContainer = multiColumnBlockFlow(); RenderObject* nextRendererInFlowThread = descendant->nextInPreOrderAfterChildren(this); RenderObject* insertBeforeMulticolChild = nullptr; if (isValidColumnSpanner(this, descendant)) { // This is a spanner (column-span:all). Such renderers are moved from where they would // otherwise occur in the render tree to becoming a direct child of the multicol container, // so that they live among the column sets. This simplifies the layout implementation, and // basically just relies on regular block layout done by the RenderBlockFlow that // establishes the multicol container. RenderBlockFlow* container = toRenderBlockFlow(descendant->parent()); RenderMultiColumnSet* setToSplit = nullptr; if (nextRendererInFlowThread) { setToSplit = findSetRendering(descendant); if (setToSplit) { setToSplit->setNeedsLayout(); insertBeforeMulticolChild = setToSplit->nextSibling(); } } // Moving a spanner's renderer so that it becomes a sibling of the column sets requires us // to insert an anonymous placeholder in the tree where the spanner's renderer otherwise // would have been. This is needed for a two reasons: We need a way of separating inline // content before and after the spanner, so that it becomes separate line boxes. Secondly, // this placeholder serves as a break point for column sets, so that, when encountered, we // end flowing one column set and move to the next one. RenderMultiColumnSpannerPlaceholder* placeholder = RenderMultiColumnSpannerPlaceholder::createAnonymous(this, toRenderBox(descendant), &container->style()); container->addChild(placeholder, descendant->nextSibling()); container->removeChild(*descendant); // This is a guard to stop an ancestor flow thread from processing the spanner. gShiftingSpanner = true; multicolContainer->RenderBlock::addChild(descendant, insertBeforeMulticolChild); gShiftingSpanner = false; // The spanner has now been moved out from the flow thread, but we don't want to // examine its children anyway. They are all part of the spanner and shouldn't trigger // creation of column sets or anything like that. Continue at its original position in // the tree, i.e. where the placeholder was just put. if (subtreeRoot == descendant) subtreeRoot = placeholder; descendant = placeholder; } else { // This is regular multicol content, i.e. not part of a spanner. if (nextRendererInFlowThread && nextRendererInFlowThread->isRenderMultiColumnSpannerPlaceholder()) { // Inserted right before a spanner. Is there a set for us there? RenderMultiColumnSpannerPlaceholder* placeholder = toRenderMultiColumnSpannerPlaceholder(nextRendererInFlowThread); if (RenderObject* previous = placeholder->spanner()->previousSibling()) { if (previous->isRenderMultiColumnSet()) continue; // There's already a set there. Nothing to do. } insertBeforeMulticolChild = placeholder->spanner(); } else if (RenderMultiColumnSet* lastSet = lastMultiColumnSet()) { // This child is not an immediate predecessor of a spanner, which means that if this // child precedes a spanner at all, there has to be a column set created for us there // already. If it doesn't precede any spanner at all, on the other hand, we need a // column set at the end of the multicol container. We don't really check here if the // child inserted precedes any spanner or not (as that's an expensive operation). Just // make sure we have a column set at the end. It's no big deal if it remains unused. if (!lastSet->nextSibling()) continue; } } // Need to create a new column set when there's no set already created. We also always insert // another column set after a spanner. Even if it turns out that there are no renderers // following the spanner, there may be bottom margins there, which take up space. RenderMultiColumnSet* newSet = new RenderMultiColumnSet(*this, RenderStyle::createAnonymousStyleWithDisplay(&multicolContainer->style(), BLOCK)); newSet->initializeStyle(); multicolContainer->RenderBlock::addChild(newSet, insertBeforeMulticolChild); invalidateRegions(); // We cannot handle immediate column set siblings at the moment (and there's no need for // it, either). There has to be at least one spanner separating them. ASSERT(!previousColumnSetOrSpannerSiblingOf(newSet) || !previousColumnSetOrSpannerSiblingOf(newSet)->isRenderMultiColumnSet()); ASSERT(!nextColumnSetOrSpannerSiblingOf(newSet) || !nextColumnSetOrSpannerSiblingOf(newSet)->isRenderMultiColumnSet()); } }
RenderObject* RenderMultiColumnFlowThread::resolveMovedChild(RenderObject* child) const { if (child->style().columnSpan() != ColumnSpanAll || !child->isBox()) { // We only need to resolve for column spanners. return child; } // The renderer for the actual DOM node that establishes a spanner is moved from its original // location in the render tree to becoming a sibling of the column sets. In other words, it's // moved out from the flow thread (and becomes a sibling of it). When we for instance want to // create and insert a renderer for the sibling node immediately preceding the spanner, we need // to map that spanner renderer to the spanner's placeholder, which is where the new inserted // renderer belongs. if (RenderMultiColumnSpannerPlaceholder* placeholder = findColumnSpannerPlaceholder(toRenderBox(child))) return placeholder; // This is an invalid spanner, or its placeholder hasn't been created yet. This happens when // moving an entire subtree into the flow thread, when we are processing the insertion of this // spanner's preceding sibling, and we obviously haven't got as far as processing this spanner // yet. return child; }
void RenderLayerClipper::calculateClipRects(const ClipRectsContext& clipRectsContext, ClipRects& clipRects) const { if (!m_renderer->layer()->parent()) { // The root layer's clip rect is always infinite. clipRects.reset(PaintInfo::infiniteRect()); return; } ClipRectsType clipRectsType = clipRectsContext.clipRectsType; bool useCached = clipRectsType != TemporaryClipRects; // For transformed layers, the root layer was shifted to be us, so there is no need to // examine the parent. We want to cache clip rects with us as the root. RenderLayer* parentLayer = clipRectsContext.rootLayer != m_renderer->layer() ? m_renderer->layer()->parent() : 0; // Ensure that our parent's clip has been calculated so that we can examine the values. if (parentLayer) { if (useCached && parentLayer->clipper().clipRects(clipRectsContext)) { clipRects = *parentLayer->clipper().clipRects(clipRectsContext); } else { ClipRectsContext parentContext(clipRectsContext); parentContext.overlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize; // FIXME: why? parentLayer->clipper().calculateClipRects(parentContext, clipRects); } } else { clipRects.reset(PaintInfo::infiniteRect()); } // A fixed object is essentially the root of its containing block hierarchy, so when // we encounter such an object, we reset our clip rects to the fixedClipRect. if (m_renderer->style()->position() == FixedPosition) { clipRects.setPosClipRect(clipRects.fixedClipRect()); clipRects.setOverflowClipRect(clipRects.fixedClipRect()); clipRects.setFixed(true); } else if (m_renderer->style()->hasInFlowPosition()) { clipRects.setPosClipRect(clipRects.overflowClipRect()); } else if (m_renderer->style()->position() == AbsolutePosition) { clipRects.setOverflowClipRect(clipRects.posClipRect()); } // Update the clip rects that will be passed to child layers. if ((m_renderer->hasOverflowClip() && (clipRectsContext.respectOverflowClip == RespectOverflowClip || m_renderer->layer() != clipRectsContext.rootLayer)) || m_renderer->hasClip()) { // This layer establishes a clip of some kind. // This offset cannot use convertToLayerCoords, because sometimes our rootLayer may be across // some transformed layer boundary, for example, in the RenderLayerCompositor overlapMap, where // clipRects are needed in view space. LayoutPoint offset; offset = roundedLayoutPoint(m_renderer->localToContainerPoint(FloatPoint(), clipRectsContext.rootLayer->renderer())); RenderView* view = m_renderer->view(); ASSERT(view); if (view && clipRects.fixed() && clipRectsContext.rootLayer->renderer() == view) { offset -= view->frameView()->scrollOffsetForFixedPosition(); } if (m_renderer->hasOverflowClip()) { ClipRect newOverflowClip = toRenderBox(m_renderer)->overflowClipRect(offset, clipRectsContext.overlayScrollbarSizeRelevancy); if (m_renderer->style()->hasBorderRadius()) newOverflowClip.setHasRadius(true); clipRects.setOverflowClipRect(intersection(newOverflowClip, clipRects.overflowClipRect())); if (m_renderer->isPositioned()) clipRects.setPosClipRect(intersection(newOverflowClip, clipRects.posClipRect())); } if (m_renderer->hasClip()) { LayoutRect newPosClip = toRenderBox(m_renderer)->clipRect(offset); clipRects.setPosClipRect(intersection(newPosClip, clipRects.posClipRect())); clipRects.setOverflowClipRect(intersection(newPosClip, clipRects.overflowClipRect())); clipRects.setFixedClipRect(intersection(newPosClip, clipRects.fixedClipRect())); } } }
LayoutPoint RenderFlowThread::adjustedPositionRelativeToOffsetParent(const RenderBoxModelObject& boxModelObject, const LayoutPoint& startPoint) { LayoutPoint referencePoint = startPoint; // FIXME: This needs to be adapted for different writing modes inside the flow thread. RenderMultiColumnSet* startColumnSet = columnSetAtBlockOffset(referencePoint.y()); if (startColumnSet) { // Take into account the offset coordinates of the columnSet. RenderObject* currObject = startColumnSet; RenderObject* currOffsetParentRenderer; Element* currOffsetParentElement; while ((currOffsetParentElement = currObject->offsetParent()) && (currOffsetParentRenderer = currOffsetParentElement->renderer())) { if (currObject->isBoxModelObject()) referencePoint.move(toRenderBoxModelObject(currObject)->offsetLeft(), toRenderBoxModelObject(currObject)->offsetTop()); // Since we're looking for the offset relative to the body, we must also // take into consideration the borders of the columnSet's offsetParent. if (currOffsetParentRenderer->isBox() && !currOffsetParentRenderer->isBody()) referencePoint.move(toRenderBox(currOffsetParentRenderer)->borderLeft(), toRenderBox(currOffsetParentRenderer)->borderTop()); currObject = currOffsetParentRenderer; } // We need to check if any of this box's containing blocks start in a different columnSet // and if so, drop the object's top position (which was computed relative to its containing block // and is no longer valid) and recompute it using the columnSet in which it flows as reference. bool wasComputedRelativeToOtherRegion = false; const RenderBlock* objContainingBlock = boxModelObject.containingBlock(); while (objContainingBlock) { // Check if this object is in a different columnSet. RenderMultiColumnSet* parentStartRegion = 0; RenderMultiColumnSet* parentEndRegion = 0; getRegionRangeForBox(objContainingBlock, parentStartRegion, parentEndRegion); if (parentStartRegion && parentStartRegion != startColumnSet) { wasComputedRelativeToOtherRegion = true; break; } objContainingBlock = objContainingBlock->containingBlock(); } if (wasComputedRelativeToOtherRegion) { // Get the logical top coordinate of the current object. LayoutUnit top = 0; if (boxModelObject.isRenderBlock()) { top = toRenderBlock(&boxModelObject)->offsetFromLogicalTopOfFirstPage(); } else { if (boxModelObject.containingBlock()) top = boxModelObject.containingBlock()->offsetFromLogicalTopOfFirstPage(); if (boxModelObject.isBox()) top += toRenderBox(&boxModelObject)->topLeftLocation().y(); else if (boxModelObject.isRenderInline()) top -= toRenderInline(&boxModelObject)->borderTop(); } // Get the logical top of the columnSet this object starts in // and compute the object's top, relative to the columnSet's top. LayoutUnit regionLogicalTop = startColumnSet->pageLogicalTopForOffset(top); LayoutUnit topRelativeToRegion = top - regionLogicalTop; referencePoint.setY(startColumnSet->offsetTop() + topRelativeToRegion); // Since the top has been overriden, check if the // relative positioning must be reconsidered. if (boxModelObject.isRelPositioned()) referencePoint.move(0, boxModelObject.relativePositionOffset().height()); } // Since we're looking for the offset relative to the body, we must also // take into consideration the borders of the columnSet. referencePoint.move(startColumnSet->borderLeft(), startColumnSet->borderTop()); } return referencePoint; }
void HTMLPlugInImageElement::subframeLoaderWillCreatePlugIn(const KURL& url) { LOG(Plugins, "%p Plug-in URL: %s", this, m_url.utf8().data()); LOG(Plugins, " Loaded URL: %s", url.string().utf8().data()); m_loadedUrl = url; if (!document()->page() || !document()->page()->settings()->plugInSnapshottingEnabled()) return; if (displayState() == Restarting) { setDisplayState(Playing); LOG(Plugins, "%p Plug-in is explicitly restarting", this); return; } if (displayState() == RestartingWithPendingMouseClick) { LOG(Plugins, "%p Plug-in is explicitly restarting but also waiting for a click", this); return; } bool inMainFrame = document()->frame() == document()->page()->mainFrame(); if (document()->isPluginDocument() && inMainFrame) { LOG(Plugins, "%p Plug-in document in main frame", this); return; } if (ScriptController::processingUserGesture()) { LOG(Plugins, "%p Script is currently processing user gesture, set to play", this); return; } if (m_createdDuringUserGesture) { LOG(Plugins, "%p Plug-in was created when processing user gesture, set to play", this); return; } double lastKnownUserGestureTimestamp = document()->lastHandledUserGestureTimestamp(); if (!inMainFrame && document()->page()->mainFrame() && document()->page()->mainFrame()->document()) lastKnownUserGestureTimestamp = std::max(lastKnownUserGestureTimestamp, document()->page()->mainFrame()->document()->lastHandledUserGestureTimestamp()); if (currentTime() - lastKnownUserGestureTimestamp < autostartSoonAfterUserGestureThreshold) { LOG(Plugins, "%p Plug-in was created shortly after a user gesture, set to play", this); return; } RenderBox* renderEmbeddedObject = toRenderBox(renderer()); Length styleWidth = renderEmbeddedObject->style()->width(); Length styleHeight = renderEmbeddedObject->style()->height(); LayoutRect contentBoxRect = renderEmbeddedObject->contentBoxRect(); int contentWidth = contentBoxRect.width(); int contentHeight = contentBoxRect.height(); int contentArea = contentWidth * contentHeight; IntSize visibleViewSize = document()->frame()->view()->visibleSize(); int visibleArea = visibleViewSize.width() * visibleViewSize.height(); if (inMainFrame && styleWidth.isPercent() && (styleWidth.percent() == 100) && styleHeight.isPercent() && (styleHeight.percent() == 100) && (static_cast<float>(contentArea) / visibleArea > sizingFullPageAreaRatioThreshold)) { LOG(Plugins, "%p Plug-in is top level full page, set to play", this); return; } if (contentWidth <= sizingTinyDimensionThreshold || contentHeight <= sizingTinyDimensionThreshold) { LOG(Plugins, "%p Plug-in is very small %dx%d, set to play", this, contentWidth, contentHeight); return; } if (!document()->page()->plugInClient()) { setDisplayState(WaitingForSnapshot); return; } if (document()->page()->plugInClient()->shouldAutoStartFromOrigin(document()->page()->mainFrame()->document()->baseURL().host(), url.host(), loadedMimeType())) { LOG(Plugins, "%p Plug-in from (%s, %s) is marked to auto-start, set to play", this, document()->page()->mainFrame()->document()->baseURL().host().utf8().data(), url.host().utf8().data()); return; } LOG(Plugins, "%p Plug-in from (%s, %s) is not auto-start, sized at %dx%d, set to wait for snapshot", this, document()->page()->mainFrame()->document()->baseURL().host().utf8().data(), url.host().utf8().data(), contentWidth, contentHeight); setDisplayState(WaitingForSnapshot); }
void RenderFlowThread::removeFlowChildInfo(RenderObject* child) { if (child->isBox()) removeRenderBoxRegionInfo(toRenderBox(child)); clearRenderObjectCustomStyle(child); }
void RenderLineBoxList::dirtyLinesFromChangedChild(RenderObject* container, RenderObject* child) { if (!container->parent() || (container->isRenderBlock() && (container->selfNeedsLayout() || !container->isBlockFlow()))) return; RenderInline* inlineContainer = container->isRenderInline() ? toRenderInline(container) : 0; InlineBox* firstBox = inlineContainer ? inlineContainer->firstLineBoxIncludingCulling() : firstLineBox(); // If we have no first line box, then just bail early. if (!firstBox) { // For an empty inline, go ahead and propagate the check up to our parent, unless the parent // is already dirty. if (container->isInline() && !container->ancestorLineBoxDirty()) { container->parent()->dirtyLinesFromChangedChild(container); container->setAncestorLineBoxDirty(); // Mark the container to avoid dirtying the same lines again across multiple destroy() calls of the same subtree. } return; } // Try to figure out which line box we belong in. First try to find a previous // line box by examining our siblings. If we didn't find a line box, then use our // parent's first line box. RootInlineBox* box = 0; RenderObject* curr = 0; for (curr = child->previousSibling(); curr; curr = curr->previousSibling()) { if (curr->isFloatingOrOutOfFlowPositioned()) continue; if (curr->isReplaced()) { InlineBox* wrapper = toRenderBox(curr)->inlineBoxWrapper(); if (wrapper) box = wrapper->root(); } else if (curr->isText()) { InlineTextBox* textBox = toRenderText(curr)->lastTextBox(); if (textBox) box = textBox->root(); } else if (curr->isRenderInline()) { InlineBox* lastSiblingBox = toRenderInline(curr)->lastLineBoxIncludingCulling(); if (lastSiblingBox) box = lastSiblingBox->root(); } if (box) break; } if (!box) { if (inlineContainer && !inlineContainer->alwaysCreateLineBoxes()) { // https://bugs.webkit.org/show_bug.cgi?id=60778 // We may have just removed a <br> with no line box that was our first child. In this case // we won't find a previous sibling, but firstBox can be pointing to a following sibling. // This isn't good enough, since we won't locate the root line box that encloses the removed // <br>. We have to just over-invalidate a bit and go up to our parent. if (!inlineContainer->ancestorLineBoxDirty()) { inlineContainer->parent()->dirtyLinesFromChangedChild(inlineContainer); inlineContainer->setAncestorLineBoxDirty(); // Mark the container to avoid dirtying the same lines again across multiple destroy() calls of the same subtree. } return; } box = firstBox->root(); } // If we found a line box, then dirty it. if (box) { RootInlineBox* adjacentBox; box->markDirty(); // dirty the adjacent lines that might be affected // NOTE: we dirty the previous line because RootInlineBox objects cache // the address of the first object on the next line after a BR, which we may be // invalidating here. For more info, see how RenderBlock::layoutInlineChildren // calls setLineBreakInfo with the result of findNextLineBreak. findNextLineBreak, // despite the name, actually returns the first RenderObject after the BR. // <rdar://problem/3849947> "Typing after pasting line does not appear until after window resize." adjacentBox = box->prevRootBox(); if (adjacentBox) adjacentBox->markDirty(); adjacentBox = box->nextRootBox(); // If |child| has been inserted before the first element in the linebox, but after collapsed leading // space, the search for |child|'s linebox will go past the leading space to the previous linebox and select that // one as |box|. If we hit that situation here, dirty the |box| actually containing the child too. bool insertedAfterLeadingSpace = box->lineBreakObj() == child->previousSibling(); if (adjacentBox && (adjacentBox->lineBreakObj() == child || child->isBR() || (curr && curr->isBR()) || insertedAfterLeadingSpace)) adjacentBox->markDirty(); } }
void InlineBox::extractLine() { m_bitfields.setExtracted(true); if (m_renderer->isBox()) toRenderBox(m_renderer)->setInlineBoxWrapper(0); }
void RenderLineBoxList::dirtyLinesFromChangedChild(RenderObject* container, RenderObject* child) { if (!container->parent() || (container->isRenderBlock() && (container->selfNeedsLayout() || !container->isRenderParagraph()))) return; RenderInline* inlineContainer = container->isRenderInline() ? toRenderInline(container) : 0; InlineBox* firstBox = inlineContainer ? inlineContainer->firstLineBoxIncludingCulling() : firstLineBox(); // If we have no first line box, then just bail early. if (!firstBox) { // For an empty inline, go ahead and propagate the check up to our parent, unless the parent // is already dirty. if (container->isInline() && !container->ancestorLineBoxDirty()) { container->parent()->dirtyLinesFromChangedChild(container); container->setAncestorLineBoxDirty(); // Mark the container to avoid dirtying the same lines again across multiple destroy() calls of the same subtree. } return; } // Try to figure out which line box we belong in. First try to find a previous // line box by examining our siblings. If we didn't find a line box, then use our // parent's first line box. RootInlineBox* box = 0; RenderObject* curr = 0; ListHashSet<RenderObject*, 16> potentialLineBreakObjects; potentialLineBreakObjects.add(child); for (curr = child->previousSibling(); curr; curr = curr->previousSibling()) { potentialLineBreakObjects.add(curr); if (curr->isFloatingOrOutOfFlowPositioned()) continue; if (curr->isReplaced()) { InlineBox* wrapper = toRenderBox(curr)->inlineBoxWrapper(); if (wrapper) box = &wrapper->root(); } else if (curr->isText()) { InlineTextBox* textBox = toRenderText(curr)->lastTextBox(); if (textBox) box = &textBox->root(); } else if (curr->isRenderInline()) { InlineBox* lastSiblingBox = toRenderInline(curr)->lastLineBoxIncludingCulling(); if (lastSiblingBox) box = &lastSiblingBox->root(); } if (box) break; } if (!box) { if (inlineContainer && !inlineContainer->alwaysCreateLineBoxes()) { // https://bugs.webkit.org/show_bug.cgi?id=60778 // We may have just removed a <br> with no line box that was our first child. In this case // we won't find a previous sibling, but firstBox can be pointing to a following sibling. // This isn't good enough, since we won't locate the root line box that encloses the removed // <br>. We have to just over-invalidate a bit and go up to our parent. if (!inlineContainer->ancestorLineBoxDirty()) { inlineContainer->parent()->dirtyLinesFromChangedChild(inlineContainer); inlineContainer->setAncestorLineBoxDirty(); // Mark the container to avoid dirtying the same lines again across multiple destroy() calls of the same subtree. } return; } box = &firstBox->root(); } // If we found a line box, then dirty it. if (box) { RootInlineBox* adjacentBox; box->markDirty(); // dirty the adjacent lines that might be affected // NOTE: we dirty the previous line because RootInlineBox objects cache // the address of the first object on the next line after a BR, which we may be // invalidating here. For more info, see how RenderParagraph::layoutChildren // calls setLineBreakInfo with the result of findNextLineBreak. findNextLineBreak, // despite the name, actually returns the first RenderObject after the BR. // <rdar://problem/3849947> "Typing after pasting line does not appear until after window resize." adjacentBox = box->prevRootBox(); if (adjacentBox) adjacentBox->markDirty(); adjacentBox = box->nextRootBox(); // If |child| or any of its immediately previous siblings with culled lineboxes is the object after a line-break in |box| or the linebox after it // then that means |child| actually sits on the linebox after |box| (or is its line-break object) and so we need to dirty it as well. if (adjacentBox && (potentialLineBreakObjects.contains(box->lineBreakObj()) || potentialLineBreakObjects.contains(adjacentBox->lineBreakObj()) || isIsolated(container->style()->unicodeBidi()))) adjacentBox->markDirty(); } }
void RenderNamedFlowThread::getRanges(Vector<RefPtr<Range> >& rangeObjects, const RenderRegion* region) const { LayoutUnit logicalTopForRegion; LayoutUnit logicalBottomForRegion; // extend the first region top to contain everything up to its logical height if (region->isFirstRegion()) logicalTopForRegion = LayoutUnit::min(); else logicalTopForRegion = region->logicalTopForFlowThreadContent(); // extend the last region to contain everything above its y() if (region->isLastRegion()) logicalBottomForRegion = LayoutUnit::max(); else logicalBottomForRegion = region->logicalBottomForFlowThreadContent(); Vector<Node*> nodes; // eliminate the contentNodes that are descendants of other contentNodes for (NamedFlowContentNodes::const_iterator it = contentNodes().begin(); it != contentNodes().end(); ++it) { Node* node = *it; if (!isContainedInNodes(nodes, node)) nodes.append(node); } for (size_t i = 0; i < nodes.size(); i++) { Node* contentNode = nodes.at(i); if (!contentNode->renderer()) continue; RefPtr<Range> range = Range::create(contentNode->document()); bool foundStartPosition = false; bool startsAboveRegion = true; bool endsBelowRegion = true; bool skipOverOutsideNodes = false; Node* lastEndNode = 0; for (Node* node = contentNode; node; node = NodeTraversal::next(node, contentNode)) { RenderObject* renderer = node->renderer(); if (!renderer) continue; LayoutRect boundingBox; if (renderer->isRenderInline()) boundingBox = toRenderInline(renderer)->linesBoundingBox(); else if (renderer->isText()) boundingBox = toRenderText(renderer)->linesBoundingBox(); else { boundingBox = toRenderBox(renderer)->frameRect(); if (toRenderBox(renderer)->isRelPositioned()) boundingBox.move(toRenderBox(renderer)->relativePositionLogicalOffset()); } LayoutUnit offsetTop = renderer->containingBlock()->offsetFromLogicalTopOfFirstPage(); const LayoutPoint logicalOffsetFromTop(isHorizontalWritingMode() ? LayoutUnit() : offsetTop, isHorizontalWritingMode() ? offsetTop : LayoutUnit()); boundingBox.moveBy(logicalOffsetFromTop); LayoutUnit logicalTopForRenderer = region->logicalTopOfFlowThreadContentRect(boundingBox); LayoutUnit logicalBottomForRenderer = region->logicalBottomOfFlowThreadContentRect(boundingBox); // if the bounding box of the current element doesn't intersect the region box // close the current range only if the start element began inside the region, // otherwise just move the start position after this node and keep skipping them until we found a proper start position. if (!boxIntersectsRegion(logicalTopForRenderer, logicalBottomForRenderer, logicalTopForRegion, logicalBottomForRegion)) { if (foundStartPosition) { if (!startsAboveRegion) { if (range->intersectsNode(node, IGNORE_EXCEPTION)) range->setEndBefore(node, IGNORE_EXCEPTION); rangeObjects.append(range->cloneRange(IGNORE_EXCEPTION)); range = Range::create(contentNode->document()); startsAboveRegion = true; } else skipOverOutsideNodes = true; } if (skipOverOutsideNodes) range->setStartAfter(node, IGNORE_EXCEPTION); foundStartPosition = false; continue; } // start position if (logicalTopForRenderer < logicalTopForRegion && startsAboveRegion) { if (renderer->isText()) { // Text crosses region top // for Text elements, just find the last textbox that is contained inside the region and use its start() offset as start position RenderText* textRenderer = toRenderText(renderer); for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) { if (offsetTop + box->logicalBottom() < logicalTopForRegion) continue; range->setStart(Position(toText(node), box->start())); startsAboveRegion = false; break; } } else { // node crosses region top // for all elements, except Text, just set the start position to be before their children startsAboveRegion = true; range->setStart(Position(node, Position::PositionIsBeforeChildren)); } } else { // node starts inside region // for elements that start inside the region, set the start position to be before them. If we found one, we will just skip the others until // the range is closed. if (startsAboveRegion) { startsAboveRegion = false; range->setStartBefore(node, IGNORE_EXCEPTION); } } skipOverOutsideNodes = false; foundStartPosition = true; // end position if (logicalBottomForRegion < logicalBottomForRenderer && (endsBelowRegion || (!endsBelowRegion && !node->isDescendantOf(lastEndNode)))) { // for Text elements, just find just find the last textbox that is contained inside the region and use its start()+len() offset as end position if (renderer->isText()) { // Text crosses region bottom RenderText* textRenderer = toRenderText(renderer); InlineTextBox* lastBox = 0; for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) { if ((offsetTop + box->logicalTop()) < logicalBottomForRegion) { lastBox = box; continue; } ASSERT(lastBox); if (lastBox) range->setEnd(Position(toText(node), lastBox->start() + lastBox->len())); break; } endsBelowRegion = false; lastEndNode = node; } else { // node crosses region bottom // for all elements, except Text, just set the start position to be after their children range->setEnd(Position(node, Position::PositionIsAfterChildren)); endsBelowRegion = true; lastEndNode = node; } } else { // node ends inside region // for elements that ends inside the region, set the end position to be after them // allow this end position to be changed only by other elements that are not descendants of the current end node if (endsBelowRegion || (!endsBelowRegion && !node->isDescendantOf(lastEndNode))) { range->setEndAfter(node, IGNORE_EXCEPTION); endsBelowRegion = false; lastEndNode = node; } } } if (foundStartPosition || skipOverOutsideNodes) rangeObjects.append(range); } }
void HTMLPlugInImageElement::subframeLoaderWillCreatePlugIn(const KURL& url) { LOG(Plugins, "%p Plug-in URL: %s", this, m_url.utf8().data()); LOG(Plugins, " Loaded URL: %s", url.string().utf8().data()); m_loadedUrl = url; m_plugInWasCreated = false; m_deferredPromotionToPrimaryPlugIn = false; if (!document()->page() || !document()->page()->settings()->plugInSnapshottingEnabled()) { m_snapshotDecision = NeverSnapshot; return; } if (displayState() == Restarting) { LOG(Plugins, "%p Plug-in is explicitly restarting", this); m_snapshotDecision = NeverSnapshot; setDisplayState(Playing); return; } if (displayState() == RestartingWithPendingMouseClick) { LOG(Plugins, "%p Plug-in is explicitly restarting but also waiting for a click", this); m_snapshotDecision = NeverSnapshot; return; } if (m_snapshotDecision == NeverSnapshot) { LOG(Plugins, "%p Plug-in is blessed, allow it to start", this); return; } bool inMainFrame = document()->frame() == document()->page()->mainFrame(); if (document()->isPluginDocument() && inMainFrame) { LOG(Plugins, "%p Plug-in document in main frame", this); m_snapshotDecision = NeverSnapshot; return; } if (ScriptController::processingUserGesture()) { LOG(Plugins, "%p Script is currently processing user gesture, set to play", this); m_snapshotDecision = NeverSnapshot; return; } if (m_createdDuringUserGesture) { LOG(Plugins, "%p Plug-in was created when processing user gesture, set to play", this); m_snapshotDecision = NeverSnapshot; return; } if (documentHadRecentUserGesture(document())) { LOG(Plugins, "%p Plug-in was created shortly after a user gesture, set to play", this); m_snapshotDecision = NeverSnapshot; return; } if (document()->page()->settings()->snapshotAllPlugIns()) { LOG(Plugins, "%p Plug-in forced to snapshot by user preference", this); m_snapshotDecision = Snapshotted; setDisplayState(WaitingForSnapshot); return; } if (document()->page()->settings()->autostartOriginPlugInSnapshottingEnabled() && document()->page()->plugInClient() && document()->page()->plugInClient()->shouldAutoStartFromOrigin(document()->page()->mainFrame()->document()->baseURL().host(), url.host(), loadedMimeType())) { LOG(Plugins, "%p Plug-in from (%s, %s) is marked to auto-start, set to play", this, document()->page()->mainFrame()->document()->baseURL().host().utf8().data(), url.host().utf8().data()); m_snapshotDecision = NeverSnapshot; return; } RenderBox* renderEmbeddedObject = toRenderBox(renderer()); Length styleWidth = renderEmbeddedObject->style()->width(); Length styleHeight = renderEmbeddedObject->style()->height(); LayoutRect contentBoxRect = renderEmbeddedObject->contentBoxRect(); int contentWidth = contentBoxRect.width(); int contentHeight = contentBoxRect.height(); int contentArea = contentWidth * contentHeight; IntSize visibleViewSize = document()->frame()->view()->visibleSize(); int visibleArea = visibleViewSize.width() * visibleViewSize.height(); if (inMainFrame && styleWidth.isPercent() && (styleWidth.percent() == 100) && styleHeight.isPercent() && (styleHeight.percent() == 100) && (static_cast<float>(contentArea) / visibleArea > sizingFullPageAreaRatioThreshold)) { LOG(Plugins, "%p Plug-in is top level full page, set to play", this); m_snapshotDecision = NeverSnapshot; return; } if (contentWidth <= sizingTinyDimensionThreshold || contentHeight <= sizingTinyDimensionThreshold) { LOG(Plugins, "%p Plug-in is very small %dx%d, set to play", this, contentWidth, contentHeight); m_sizeWhenSnapshotted = IntSize(contentBoxRect.width().toInt(), contentBoxRect.height().toInt()); m_snapshotDecision = MaySnapshotWhenResized; return; } if (!document()->page()->plugInClient()) { LOG(Plugins, "%p There is no plug-in client. Set to wait for snapshot", this); m_snapshotDecision = NeverSnapshot; setDisplayState(WaitingForSnapshot); return; } LOG(Plugins, "%p Plug-in from (%s, %s) is not auto-start, sized at %dx%d, set to wait for snapshot", this, document()->page()->mainFrame()->document()->baseURL().host().utf8().data(), url.host().utf8().data(), contentWidth, contentHeight); m_snapshotDecision = Snapshotted; setDisplayState(WaitingForSnapshot); }
RenderObject* RenderObjectChildList::removeChildNode(RenderObject* owner, RenderObject* oldChild, bool notifyRenderer) { ASSERT(oldChild->parent() == owner); if (oldChild->isFloatingOrOutOfFlowPositioned()) toRenderBox(oldChild)->removeFloatingOrPositionedChildFromBlockLists(); // So that we'll get the appropriate dirty bit set (either that a normal flow child got yanked or // that a positioned child got yanked). We also repaint, so that the area exposed when the child // disappears gets repainted properly. if (!owner->documentBeingDestroyed() && notifyRenderer && oldChild->everHadLayout()) { oldChild->setNeedsLayoutAndPrefWidthsRecalc(); // We only repaint |oldChild| if we have a RenderLayer as its visual overflow may not be tracked by its parent. if (oldChild->isBody()) owner->view()->repaint(); else oldChild->repaint(); } // If we have a line box wrapper, delete it. if (oldChild->isBox()) toRenderBox(oldChild)->deleteLineBoxWrapper(); // If oldChild is the start or end of the selection, then clear the selection to // avoid problems of invalid pointers. // FIXME: The FrameSelection should be responsible for this when it // is notified of DOM mutations. if (!owner->documentBeingDestroyed() && oldChild->isSelectionBorder()) owner->view()->clearSelection(); if (!owner->documentBeingDestroyed() && notifyRenderer) oldChild->willBeRemovedFromTree(); // WARNING: There should be no code running between willBeRemovedFromTree and the actual removal below. // This is needed to avoid race conditions where willBeRemovedFromTree would dirty the tree's structure // and the code running here would force an untimely rebuilding, leaving |oldChild| dangling. if (oldChild->previousSibling()) oldChild->previousSibling()->setNextSibling(oldChild->nextSibling()); if (oldChild->nextSibling()) oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling()); if (firstChild() == oldChild) setFirstChild(oldChild->nextSibling()); if (lastChild() == oldChild) setLastChild(oldChild->previousSibling()); oldChild->setPreviousSibling(0); oldChild->setNextSibling(0); oldChild->setParent(0); // rendererRemovedFromTree walks the whole subtree. We can improve performance // by skipping this step when destroying the entire tree. if (!owner->documentBeingDestroyed()) RenderCounter::rendererRemovedFromTree(oldChild); if (AXObjectCache* cache = owner->document()->existingAXObjectCache()) cache->childrenChanged(owner); return oldChild; }
bool ContainerNode::getUpperLeftCorner(FloatPoint& point) const { if (!renderer()) return false; // What is this code really trying to do? RenderObject* o = renderer(); RenderObject* p = o; if (!o->isInline() || o->isReplaced()) { point = o->localToAbsolute(FloatPoint(), UseTransforms); return true; } // find the next text/image child, to get a position while (o) { p = o; if (o->firstChild()) o = o->firstChild(); else if (o->nextSibling()) o = o->nextSibling(); else { RenderObject* next = 0; while (!next && o->parent()) { o = o->parent(); next = o->nextSibling(); } o = next; if (!o) break; } ASSERT(o); if (!o->isInline() || o->isReplaced()) { point = o->localToAbsolute(FloatPoint(), UseTransforms); return true; } if (p->node() && p->node() == this && o->isText() && !o->isBR() && !toRenderText(o)->firstTextBox()) { // do nothing - skip unrendered whitespace that is a child or next sibling of the anchor } else if ((o->isText() && !o->isBR()) || o->isReplaced()) { point = FloatPoint(); if (o->isText() && toRenderText(o)->firstTextBox()) { point.move(toRenderText(o)->linesBoundingBox().x(), toRenderText(o)->firstTextBox()->root()->lineTop()); } else if (o->isBox()) { RenderBox* box = toRenderBox(o); point.moveBy(box->location()); } point = o->container()->localToAbsolute(point, UseTransforms); return true; } } // If the target doesn't have any children or siblings that could be used to calculate the scroll position, we must be // at the end of the document. Scroll to the bottom. FIXME: who said anything about scrolling? if (!o && document().view()) { point = FloatPoint(0, document().view()->contentsHeight()); return true; } return false; }
void InlineBox::deleteLine(RenderArena* arena) { if (!m_extracted && m_renderer->isBox()) toRenderBox(m_renderer)->setInlineBoxWrapper(0); destroy(arena); }
void RenderTreeAsText::writeRenderObject(TextStream& ts, const RenderObject& o, RenderAsTextBehavior behavior) { ts << o.renderName(); if (behavior & RenderAsTextShowAddresses) ts << " " << static_cast<const void*>(&o); if (o.style() && o.style()->zIndex()) ts << " zI: " << o.style()->zIndex(); if (o.node()) { String tagName = o.node()->nodeName(); if (!tagName.isEmpty()) { ts << " {" << tagName << "}"; // flag empty or unstyled AppleStyleSpan because we never // want to leave them in the DOM if (isEmptyOrUnstyledAppleStyleSpan(o.node())) ts << " *empty or unstyled AppleStyleSpan*"; } } LayoutRect r; if (o.isText()) { // FIXME: Would be better to dump the bounding box x and y rather than the first run's x and y, but that would involve updating // many test results. const RenderText& text = toRenderText(o); IntRect linesBox = text.linesBoundingBox(); r = IntRect(text.firstRunX(), text.firstRunY(), linesBox.width(), linesBox.height()); } else if (o.isRenderInline()) { // FIXME: Would be better not to just dump 0, 0 as the x and y here. const RenderInline& inlineFlow = toRenderInline(o); r = IntRect(0, 0, inlineFlow.linesBoundingBox().width(), inlineFlow.linesBoundingBox().height()); } else if (o.isBox()) r = toRenderBox(&o)->frameRect(); ts << " " << r; if (!o.isText()) { if (o.parent()) { Color color = o.resolveColor(CSSPropertyColor); if (o.parent()->resolveColor(CSSPropertyColor) != color) ts << " [color=" << color.nameForRenderTreeAsText() << "]"; // Do not dump invalid or transparent backgrounds, since that is the default. Color backgroundColor = o.resolveColor(CSSPropertyBackgroundColor); if (o.parent()->resolveColor(CSSPropertyBackgroundColor) != backgroundColor && backgroundColor.rgb()) ts << " [bgcolor=" << backgroundColor.nameForRenderTreeAsText() << "]"; Color textFillColor = o.resolveColor(CSSPropertyWebkitTextFillColor); if (o.parent()->resolveColor(CSSPropertyWebkitTextFillColor) != textFillColor && textFillColor != color && textFillColor.rgb()) ts << " [textFillColor=" << textFillColor.nameForRenderTreeAsText() << "]"; Color textStrokeColor = o.resolveColor(CSSPropertyWebkitTextStrokeColor); if (o.parent()->resolveColor(CSSPropertyWebkitTextStrokeColor) != textStrokeColor && textStrokeColor != color && textStrokeColor.rgb()) ts << " [textStrokeColor=" << textStrokeColor.nameForRenderTreeAsText() << "]"; if (o.parent()->style()->textStrokeWidth() != o.style()->textStrokeWidth() && o.style()->textStrokeWidth() > 0) ts << " [textStrokeWidth=" << o.style()->textStrokeWidth() << "]"; } if (!o.isBoxModelObject()) return; const RenderBoxModelObject& box = toRenderBoxModelObject(o); if (box.borderTop() || box.borderRight() || box.borderBottom() || box.borderLeft()) { ts << " [border:"; BorderValue prevBorder = o.style()->borderTop(); if (!box.borderTop()) ts << " none"; else { ts << " (" << box.borderTop() << "px "; printBorderStyle(ts, o.style()->borderTopStyle()); Color col = o.resolveColor(CSSPropertyBorderTopColor); ts << col.nameForRenderTreeAsText() << ")"; } if (o.style()->borderRight() != prevBorder) { prevBorder = o.style()->borderRight(); if (!box.borderRight()) ts << " none"; else { ts << " (" << box.borderRight() << "px "; printBorderStyle(ts, o.style()->borderRightStyle()); Color col = o.resolveColor(CSSPropertyBorderRightColor); ts << col.nameForRenderTreeAsText() << ")"; } } if (o.style()->borderBottom() != prevBorder) { prevBorder = box.style()->borderBottom(); if (!box.borderBottom()) ts << " none"; else { ts << " (" << box.borderBottom() << "px "; printBorderStyle(ts, o.style()->borderBottomStyle()); Color col = o.resolveColor(CSSPropertyBorderBottomColor); ts << col.nameForRenderTreeAsText() << ")"; } } if (o.style()->borderLeft() != prevBorder) { prevBorder = o.style()->borderLeft(); if (!box.borderLeft()) ts << " none"; else { ts << " (" << box.borderLeft() << "px "; printBorderStyle(ts, o.style()->borderLeftStyle()); Color col = o.resolveColor(CSSPropertyBorderLeftColor); ts << col.nameForRenderTreeAsText() << ")"; } } ts << "]"; } } if (behavior & RenderAsTextShowIDAndClass) { Node* node = o.node(); if (node && node->isElementNode()) { Element& element = toElement(*node); if (element.hasID()) ts << " id=\"" + element.getIdAttribute() + "\""; if (element.hasClass()) { ts << " class=\""; for (size_t i = 0; i < element.classNames().size(); ++i) { if (i > 0) ts << " "; ts << element.classNames()[i]; } ts << "\""; } } } if (behavior & RenderAsTextShowLayoutState) { bool needsLayout = o.selfNeedsLayout() || o.needsPositionedMovementLayout() || o.posChildNeedsLayout() || o.normalChildNeedsLayout(); if (needsLayout) ts << " (needs layout:"; bool havePrevious = false; if (o.selfNeedsLayout()) { ts << " self"; havePrevious = true; } if (o.needsPositionedMovementLayout()) { if (havePrevious) ts << ","; havePrevious = true; ts << " positioned movement"; } if (o.normalChildNeedsLayout()) { if (havePrevious) ts << ","; havePrevious = true; ts << " child"; } if (o.posChildNeedsLayout()) { if (havePrevious) ts << ","; ts << " positioned child"; } if (needsLayout) ts << ")"; } }