inline LayoutUnit borderAndPaddingBeforeInWritingMode(const RenderBox& renderer, WritingMode writingMode) { switch (writingMode) { case TopToBottomWritingMode: return renderer.borderTop() + renderer.paddingTop(); case BottomToTopWritingMode: return renderer.borderBottom() + renderer.paddingBottom(); case LeftToRightWritingMode: return renderer.borderLeft() + renderer.paddingLeft(); case RightToLeftWritingMode: return renderer.borderRight() + renderer.paddingRight(); } ASSERT_NOT_REACHED(); return renderer.borderAndPaddingBefore(); }
inline LayoutUnit borderAndPaddingStartWithStyleForWritingMode(const RenderBox& renderer, const RenderStyle* style) { if (style->isHorizontalWritingMode()) { if (style->isLeftToRightDirection()) return renderer.borderLeft() + renderer.paddingLeft(); return renderer.borderRight() + renderer.paddingRight(); } if (style->isLeftToRightDirection()) return renderer.borderTop() + renderer.paddingTop(); return renderer.borderBottom() + renderer.paddingBottom(); }
static inline LayoutUnit borderStartWithStyleForWritingMode(const RenderBox& renderer, const RenderStyle& style) { if (style.isHorizontalWritingMode()) { if (style.isLeftToRightDirection()) return renderer.borderLeft(); return renderer.borderRight(); } if (style.isLeftToRightDirection()) return renderer.borderTop(); return renderer.borderBottom(); }
int RenderMarquee::computePosition(EMarqueeDirection dir, bool stopAtContentEdge) { RenderBox* box = m_layer->renderBox(); ASSERT(box); RenderStyle* s = box->style(); if (isHorizontal()) { bool ltr = s->direction() == LTR; int clientWidth = box->clientWidth(); int contentWidth = ltr ? box->rightmostPosition(true, false) : box->leftmostPosition(true, false); if (ltr) contentWidth += (box->paddingRight() - box->borderLeft()); else { contentWidth = box->width() - contentWidth; contentWidth += (box->paddingLeft() - box->borderRight()); } if (dir == MRIGHT) { if (stopAtContentEdge) return max(0, ltr ? (contentWidth - clientWidth) : (clientWidth - contentWidth)); else return ltr ? contentWidth : clientWidth; } else { if (stopAtContentEdge) return min(0, ltr ? (contentWidth - clientWidth) : (clientWidth - contentWidth)); else return ltr ? -clientWidth : -contentWidth; } } else { int contentHeight = box->lowestPosition(true, false) - box->borderTop() + box->paddingBottom(); int clientHeight = box->clientHeight(); if (dir == MUP) { if (stopAtContentEdge) return min(contentHeight - clientHeight, 0); else return -clientHeight; } else { if (stopAtContentEdge) return max(contentHeight - clientHeight, 0); else return contentHeight; } } }
int RenderMarquee::computePosition(EMarqueeDirection dir, bool stopAtContentEdge) { RenderBox* box = m_layer->renderBox(); ASSERT(box); RenderStyle* s = box->style(); if (isHorizontal()) { bool ltr = s->isLeftToRightDirection(); LayoutUnit clientWidth = box->clientWidth(); LayoutUnit contentWidth = ltr ? box->maxPreferredLogicalWidth() : box->minPreferredLogicalWidth(); if (ltr) contentWidth += (box->paddingRight() - box->borderLeft()); else { contentWidth = box->width() - contentWidth; contentWidth += (box->paddingLeft() - box->borderRight()); } if (dir == MRIGHT) { if (stopAtContentEdge) return max<LayoutUnit>(0, ltr ? (contentWidth - clientWidth) : (clientWidth - contentWidth)); else return ltr ? contentWidth : clientWidth; } else { if (stopAtContentEdge) return min<LayoutUnit>(0, ltr ? (contentWidth - clientWidth) : (clientWidth - contentWidth)); else return ltr ? -clientWidth : -contentWidth; } } else { int contentHeight = box->layoutOverflowRect().maxY() - box->borderTop() + box->paddingBottom(); int clientHeight = box->clientHeight(); if (dir == MUP) { if (stopAtContentEdge) return min(contentHeight - clientHeight, 0); else return -clientHeight; } else { if (stopAtContentEdge) return max(contentHeight - clientHeight, 0); else return contentHeight; } } }
bool RenderView::initializeLayoutState(LayoutState& state) { bool isSeamlessAncestorInFlowThread = false; // FIXME: May be better to push a clip and avoid issuing offscreen repaints. state.m_clipped = false; // Check the writing mode of the seamless ancestor. It has to match our document's writing mode, or we won't inherit any // pagination information. RenderBox* seamlessAncestor = enclosingSeamlessRenderer(document()); LayoutState* seamlessLayoutState = seamlessAncestor ? seamlessAncestor->view().layoutState() : 0; bool shouldInheritPagination = seamlessLayoutState && !m_pageLogicalHeight && seamlessAncestor->style()->writingMode() == style()->writingMode(); state.m_pageLogicalHeight = shouldInheritPagination ? seamlessLayoutState->m_pageLogicalHeight : m_pageLogicalHeight; state.m_pageLogicalHeightChanged = shouldInheritPagination ? seamlessLayoutState->m_pageLogicalHeightChanged : m_pageLogicalHeightChanged; state.m_isPaginated = state.m_pageLogicalHeight; if (state.m_isPaginated && shouldInheritPagination) { // Set up the correct pagination offset. We can use a negative offset in order to push the top of the RenderView into its correct place // on a page. We can take the iframe's offset from the logical top of the first page and make the negative into the pagination offset within the child // view. bool isFlipped = seamlessAncestor->style()->isFlippedBlocksWritingMode(); LayoutSize layoutOffset = seamlessLayoutState->layoutOffset(); LayoutSize iFrameOffset(layoutOffset.width() + seamlessAncestor->x() + (!isFlipped ? seamlessAncestor->borderLeft() + seamlessAncestor->paddingLeft() : seamlessAncestor->borderRight() + seamlessAncestor->paddingRight()), layoutOffset.height() + seamlessAncestor->y() + (!isFlipped ? seamlessAncestor->borderTop() + seamlessAncestor->paddingTop() : seamlessAncestor->borderBottom() + seamlessAncestor->paddingBottom())); LayoutSize offsetDelta = seamlessLayoutState->m_pageOffset - iFrameOffset; state.m_pageOffset = offsetDelta; // Set the current render flow thread to point to our ancestor. This will allow the seamless document to locate the correct // regions when doing a layout. if (seamlessAncestor->flowThreadContainingBlock()) { flowThreadController().setCurrentRenderFlowThread(seamlessAncestor->view().flowThreadController().currentRenderFlowThread()); isSeamlessAncestorInFlowThread = true; } } // FIXME: We need to make line grids and exclusions work with seamless iframes as well here. Basically all layout state information needs // to propagate here and not just pagination information. return isSeamlessAncestorInFlowThread; }
static void buildRendererHighlight(RenderObject* renderer, RenderRegion* region, const HighlightConfig& highlightConfig, Highlight* highlight, InspectorOverlay::CoordinateSystem coordinateSystem) { Frame* containingFrame = renderer->document().frame(); if (!containingFrame) return; highlight->setDataFromConfig(highlightConfig); FrameView* containingView = containingFrame->view(); FrameView* mainView = containingFrame->page()->mainFrame().view(); // RenderSVGRoot should be highlighted through the isBox() code path, all other SVG elements should just dump their absoluteQuads(). bool isSVGRenderer = renderer->node() && renderer->node()->isSVGElement() && !renderer->isSVGRoot(); if (isSVGRenderer) { highlight->type = HighlightTypeRects; renderer->absoluteQuads(highlight->quads); for (size_t i = 0; i < highlight->quads.size(); ++i) contentsQuadToCoordinateSystem(mainView, containingView, highlight->quads[i], coordinateSystem); } else if (renderer->isBox() || renderer->isRenderInline()) { LayoutRect contentBox; LayoutRect paddingBox; LayoutRect borderBox; LayoutRect marginBox; if (renderer->isBox()) { RenderBox* renderBox = toRenderBox(renderer); LayoutBoxExtent margins(renderBox->marginTop(), renderBox->marginRight(), renderBox->marginBottom(), renderBox->marginLeft()); if (!renderBox->isOutOfFlowPositioned() && region) { RenderBox::LogicalExtentComputedValues computedValues; renderBox->computeLogicalWidthInRegion(computedValues, region); margins.mutableLogicalLeft(renderBox->style().writingMode()) = computedValues.m_margins.m_start; margins.mutableLogicalRight(renderBox->style().writingMode()) = computedValues.m_margins.m_end; } paddingBox = renderBox->clientBoxRectInRegion(region); contentBox = LayoutRect(paddingBox.x() + renderBox->paddingLeft(), paddingBox.y() + renderBox->paddingTop(), paddingBox.width() - renderBox->paddingLeft() - renderBox->paddingRight(), paddingBox.height() - renderBox->paddingTop() - renderBox->paddingBottom()); borderBox = LayoutRect(paddingBox.x() - renderBox->borderLeft(), paddingBox.y() - renderBox->borderTop(), paddingBox.width() + renderBox->borderLeft() + renderBox->borderRight(), paddingBox.height() + renderBox->borderTop() + renderBox->borderBottom()); marginBox = LayoutRect(borderBox.x() - margins.left(), borderBox.y() - margins.top(), borderBox.width() + margins.left() + margins.right(), borderBox.height() + margins.top() + margins.bottom()); } else { RenderInline* renderInline = toRenderInline(renderer); // RenderInline's bounding box includes paddings and borders, excludes margins. borderBox = renderInline->linesBoundingBox(); paddingBox = LayoutRect(borderBox.x() + renderInline->borderLeft(), borderBox.y() + renderInline->borderTop(), borderBox.width() - renderInline->borderLeft() - renderInline->borderRight(), borderBox.height() - renderInline->borderTop() - renderInline->borderBottom()); contentBox = LayoutRect(paddingBox.x() + renderInline->paddingLeft(), paddingBox.y() + renderInline->paddingTop(), paddingBox.width() - renderInline->paddingLeft() - renderInline->paddingRight(), paddingBox.height() - renderInline->paddingTop() - renderInline->paddingBottom()); // Ignore marginTop and marginBottom for inlines. marginBox = LayoutRect(borderBox.x() - renderInline->marginLeft(), borderBox.y(), borderBox.width() + renderInline->horizontalMarginExtent(), borderBox.height()); } FloatQuad absContentQuad; FloatQuad absPaddingQuad; FloatQuad absBorderQuad; FloatQuad absMarginQuad; if (region) { RenderFlowThread* flowThread = region->flowThread(); // Figure out the quads in the space of the RenderFlowThread. absContentQuad = renderer->localToContainerQuad(FloatRect(contentBox), flowThread); absPaddingQuad = renderer->localToContainerQuad(FloatRect(paddingBox), flowThread); absBorderQuad = renderer->localToContainerQuad(FloatRect(borderBox), flowThread); absMarginQuad = renderer->localToContainerQuad(FloatRect(marginBox), flowThread); // Move the quad relative to the space of the current region. LayoutRect flippedRegionRect(region->flowThreadPortionRect()); flowThread->flipForWritingMode(flippedRegionRect); FloatSize delta = region->contentBoxRect().location() - flippedRegionRect.location(); absContentQuad.move(delta); absPaddingQuad.move(delta); absBorderQuad.move(delta); absMarginQuad.move(delta); // Resolve the absolute quads starting from the current region. absContentQuad = region->localToAbsoluteQuad(absContentQuad); absPaddingQuad = region->localToAbsoluteQuad(absPaddingQuad); absBorderQuad = region->localToAbsoluteQuad(absBorderQuad); absMarginQuad = region->localToAbsoluteQuad(absMarginQuad); } else { absContentQuad = renderer->localToAbsoluteQuad(FloatRect(contentBox)); absPaddingQuad = renderer->localToAbsoluteQuad(FloatRect(paddingBox)); absBorderQuad = renderer->localToAbsoluteQuad(FloatRect(borderBox)); absMarginQuad = renderer->localToAbsoluteQuad(FloatRect(marginBox)); } contentsQuadToCoordinateSystem(mainView, containingView, absContentQuad, coordinateSystem); contentsQuadToCoordinateSystem(mainView, containingView, absPaddingQuad, coordinateSystem); contentsQuadToCoordinateSystem(mainView, containingView, absBorderQuad, coordinateSystem); contentsQuadToCoordinateSystem(mainView, containingView, absMarginQuad, coordinateSystem); highlight->type = HighlightTypeNode; highlight->quads.append(absMarginQuad); highlight->quads.append(absBorderQuad); highlight->quads.append(absPaddingQuad); highlight->quads.append(absContentQuad); } }
bool GraphicsLayerAndroid::repaint() { LOG("(%x) repaint(), gPaused(%d) m_needsRepaint(%d) m_haveContents(%d) ", this, gPaused, m_needsRepaint, m_haveContents); if (!gPaused && m_haveContents && m_needsRepaint && !m_image) { // with SkPicture, we request the entire layer's content. IntRect layerBounds(0, 0, m_size.width(), m_size.height()); RenderLayer* layer = renderLayerFromClient(m_client); if (!layer) return false; if (m_foregroundLayer) { PaintingPhase phase(this); // Paint the background into a separate context. phase.set(GraphicsLayerPaintBackground); if (!paintContext(m_contentLayer->recordContext(), layerBounds)) return false; m_contentLayer->checkTextPresence(); // Construct the foreground layer and draw. RenderBox* box = layer->renderBox(); int outline = box->view()->maximalOutlineSize(); IntRect contentsRect(0, 0, box->borderLeft() + box->borderRight() + layer->scrollWidth(), box->borderTop() + box->borderBottom() + layer->scrollHeight()); contentsRect.inflate(outline); // Update the foreground layer size. m_foregroundLayer->setSize(contentsRect.width(), contentsRect.height()); // Paint everything else into the main recording canvas. phase.clear(GraphicsLayerPaintBackground); // Paint at 0,0. IntSize scroll = layer->scrolledContentOffset(); layer->scrollToOffset(0, 0); // At this point, it doesn't matter if painting failed. (void) paintContext(m_foregroundLayer->recordContext(), contentsRect); m_foregroundLayer->checkTextPresence(); layer->scrollToOffset(scroll.width(), scroll.height()); // Construct the clip layer for masking the contents. IntRect clip = layer->renderer()->absoluteBoundingBoxRect(); // absoluteBoundingBoxRect does not include the outline so we need // to offset the position. int x = box->borderLeft() + outline; int y = box->borderTop() + outline; int width = clip.width() - box->borderLeft() - box->borderRight(); int height = clip.height() - box->borderTop() - box->borderBottom(); m_foregroundClipLayer->setPosition(x, y); m_foregroundClipLayer->setSize(width, height); // Need to offset the foreground layer by the clip layer in order // for the contents to be in the correct position. m_foregroundLayer->setPosition(-x, -y); // Set the scrollable bounds of the layer. m_foregroundLayer->setScrollLimits(-x, -y, m_size.width(), m_size.height()); // Invalidate the entire layer for now, as webkit will only send the // setNeedsDisplayInRect() for the visible (clipped) scrollable area, // offsetting the invals by the scroll position would not be enough. // TODO: have webkit send us invals even for non visible area SkRegion region; region.setRect(0, 0, contentsRect.width(), contentsRect.height()); m_foregroundLayer->markAsDirty(region); m_foregroundLayer->needsRepaint(); } else { // If there is no contents clip, we can draw everything into one // picture. if (!paintContext(m_contentLayer->recordContext(), layerBounds)) return false; m_contentLayer->checkTextPresence(); // Check for a scrollable iframe and report the scrolling // limits based on the view size. if (m_contentLayer->contentIsScrollable()) { FrameView* view = layer->renderer()->frame()->view(); static_cast<ScrollableLayerAndroid*>(m_contentLayer)->setScrollLimits( m_position.x(), m_position.y(), view->layoutWidth(), view->layoutHeight()); } } LOG("(%x) repaint() on (%.2f,%.2f) contentlayer(%.2f,%.2f,%.2f,%.2f)paintGraphicsLayer called!", this, m_size.width(), m_size.height(), m_contentLayer->getPosition().fX, m_contentLayer->getPosition().fY, m_contentLayer->getSize().width(), m_contentLayer->getSize().height()); m_contentLayer->markAsDirty(m_dirtyRegion); m_dirtyRegion.setEmpty(); m_contentLayer->needsRepaint(); m_needsRepaint = false; return true; } if (m_needsRepaint && m_image && m_newImage) { // We need to tell the GL thread that we will need to repaint the // texture. Only do so if we effectively have a new image! m_contentLayer->markAsDirty(m_dirtyRegion); m_dirtyRegion.setEmpty(); m_contentLayer->needsRepaint(); m_newImage = false; m_needsRepaint = false; return true; } return false; }
LayoutState::LayoutState(RenderBox& renderer, const LayoutSize& offset, LayoutUnit pageLogicalHeight, bool pageLogicalHeightChanged, ColumnInfo* columnInfo, bool containingBlockLogicalWidthChanged) : m_containingBlockLogicalWidthChanged(containingBlockLogicalWidthChanged) , m_columnInfo(columnInfo) , m_next(renderer.view()->layoutState()) , m_renderer(renderer) { m_flowThread = renderer.isRenderFlowThread() ? toRenderFlowThread(&renderer) : m_next->flowThread(); renderer.view()->pushLayoutState(*this); bool fixed = renderer.isOutOfFlowPositioned() && renderer.style()->position() == FixedPosition; if (fixed) { // FIXME: This doesn't work correctly with transforms. FloatPoint fixedOffset = renderer.view()->localToAbsolute(FloatPoint(), IsFixed); m_layoutOffset = LayoutSize(fixedOffset.x(), fixedOffset.y()) + offset; } else { m_layoutOffset = m_next->m_layoutOffset + offset; } if (renderer.isOutOfFlowPositioned() && !fixed) { if (RenderObject* container = renderer.container()) { if (container->style()->hasInFlowPosition() && container->isRenderInline()) m_layoutOffset += toRenderInline(container)->offsetForInFlowPositionedInline(renderer); } } // If we establish a new page height, then cache the offset to the top of the first page. // We can compare this later on to figure out what part of the page we're actually on, if (pageLogicalHeight || m_columnInfo || renderer.isRenderFlowThread()) { m_pageLogicalHeight = pageLogicalHeight; bool isFlipped = renderer.style()->isFlippedBlocksWritingMode(); m_pageOffset = LayoutSize(m_layoutOffset.width() + (!isFlipped ? renderer.borderLeft() + renderer.paddingLeft() : renderer.borderRight() + renderer.paddingRight()), m_layoutOffset.height() + (!isFlipped ? renderer.borderTop() + renderer.paddingTop() : renderer.borderBottom() + renderer.paddingBottom())); m_pageLogicalHeightChanged = pageLogicalHeightChanged; m_isPaginated = true; } else { // If we don't establish a new page height, then propagate the old page height and offset down. m_pageLogicalHeight = m_next->m_pageLogicalHeight; m_pageLogicalHeightChanged = m_next->m_pageLogicalHeightChanged; m_pageOffset = m_next->m_pageOffset; // Disable pagination for objects we don't support. For now this includes overflow:scroll/auto, inline blocks and // writing mode roots. if (renderer.isUnsplittableForPagination()) { m_pageLogicalHeight = 0; m_isPaginated = false; } else { m_isPaginated = m_pageLogicalHeight || m_next->m_columnInfo || renderer.flowThreadContainingBlock(); } } if (!m_columnInfo) m_columnInfo = m_next->m_columnInfo; // FIXME: <http://bugs.webkit.org/show_bug.cgi?id=13443> Apply control clip if present. }