void RenderView::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState& transformState, ApplyContainerFlipOrNot, bool* wasFixed) const { // If a container was specified, and was not 0 or the RenderView, // then we should have found it by now. ASSERT_ARG(repaintContainer, !repaintContainer || repaintContainer == this); ASSERT_UNUSED(wasFixed, !wasFixed || *wasFixed == fixed); if (!repaintContainer && useTransforms && shouldUseTransformFromContainer(0)) { TransformationMatrix t; getTransformFromContainer(0, LayoutSize(), t); transformState.applyTransform(t); } if (fixed && m_frameView) transformState.move(m_frameView->scrollOffsetForFixedPosition()); }
void PaintInvalidationState::applyClipIfNeeded(const LayoutObject& layoutObject) { if (!layoutObject.hasOverflowClip()) return; const LayoutBox& box = toLayoutBox(layoutObject); // Do not clip scroll layer contents because the compositor expects the whole layer // to be always invalidated in-time. if (box.usesCompositedScrolling()) ASSERT(!m_clipped); // The box should establish paint invalidation container, so no m_clipped inherited. else addClipRectRelativeToPaintOffset(LayoutSize(box.layer()->size())); m_paintOffset -= box.scrolledContentOffset(); }
bool ExclusionShapeInsideInfo::adjustLogicalLineTop(float minSegmentWidth) { const ExclusionShape* shape = computedShape(); if (!shape || m_lineHeight <= 0 || logicalLineTop() > shapeLogicalBottom()) return false; LayoutUnit newLineTop; if (shape->firstIncludedIntervalLogicalTop(m_shapeLineTop, LayoutSize(minSegmentWidth, m_lineHeight), newLineTop)) { if (newLineTop > m_shapeLineTop) { m_shapeLineTop = newLineTop; return true; } } return false; }
void RenderView::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed) const { // If a container was specified, and was not 0 or the RenderView, // then we should have found it by now. ASSERT_ARG(repaintContainer, !repaintContainer || repaintContainer == this); ASSERT_UNUSED(wasFixed, !wasFixed || *wasFixed == (mode & IsFixed)); if (!repaintContainer && mode & UseTransforms && shouldUseTransformFromContainer(0)) { TransformationMatrix t; getTransformFromContainer(0, LayoutSize(), t); transformState.applyTransform(t); } if (mode & IsFixed && m_frameView) transformState.move(m_frameView->scrollOffsetForFixedPosition()); }
void ImagePainter::paintIntoRect(GraphicsContext& context, const LayoutRect& destRect, const LayoutRect& contentRect) { if (!m_layoutImage.imageResource()->hasImage() || m_layoutImage.imageResource()->errorOccurred()) return; // FIXME: should we just ASSERT these conditions? (audit all // callers). IntRect pixelSnappedDestRect = pixelSnappedIntRect(destRect); if (pixelSnappedDestRect.isEmpty()) return; RefPtr<Image> image = m_layoutImage.imageResource()->image( pixelSnappedDestRect.size(), m_layoutImage.style()->effectiveZoom()); if (!image || image->isNull()) return; // FIXME: why is interpolation quality selection not included in the // Instrumentation reported cost of drawing an image? InterpolationQuality interpolationQuality = BoxPainter::chooseInterpolationQuality( m_layoutImage, image.get(), image.get(), LayoutSize(pixelSnappedDestRect.size())); FloatRect srcRect = image->rect(); // If the content rect requires clipping, adjust |srcRect| and // |pixelSnappedDestRect| over using a clip. if (!contentRect.contains(destRect)) { IntRect pixelSnappedContentRect = pixelSnappedIntRect(contentRect); pixelSnappedContentRect.intersect(pixelSnappedDestRect); if (pixelSnappedContentRect.isEmpty()) return; srcRect = mapRect(pixelSnappedContentRect, pixelSnappedDestRect, srcRect); pixelSnappedDestRect = pixelSnappedContentRect; } TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "PaintImage", "data", InspectorPaintImageEvent::data(m_layoutImage)); InterpolationQuality previousInterpolationQuality = context.imageInterpolationQuality(); context.setImageInterpolationQuality(interpolationQuality); context.drawImage( image.get(), pixelSnappedDestRect, &srcRect, SkXfermode::kSrcOver_Mode, LayoutObject::shouldRespectImageOrientation(&m_layoutImage)); context.setImageInterpolationQuality(previousInterpolationQuality); }
void IntersectionObservation::clipToRoot(LayoutRect& rect) { // Map and clip rect into root element coordinates. // TODO(szager): the writing mode flipping needs a test. ASSERT(m_target); LayoutObject* rootLayoutObject = m_observer->rootLayoutObject(); LayoutObject* targetLayoutObject = target()->layoutObject(); targetLayoutObject->mapToVisibleRectInAncestorSpace(toLayoutBoxModelObject(rootLayoutObject), rect, nullptr); if (rootLayoutObject->hasOverflowClip()) { LayoutBox* rootLayoutBox = toLayoutBox(rootLayoutObject); LayoutRect clipRect(LayoutPoint(), LayoutSize(rootLayoutBox->layer()->size())); m_observer->applyRootMargin(clipRect); rootLayoutBox->flipForWritingMode(rect); rect.intersect(clipRect); rootLayoutBox->flipForWritingMode(rect); } }
void LayoutGeometryMap::popMappingsToAncestor(const LayoutBoxModelObject* ancestorLayoutObject) { ASSERT(m_mapping.size()); bool mightBeSaturated = false; while (m_mapping.size() && m_mapping.last().m_layoutObject != ancestorLayoutObject) { mightBeSaturated = mightBeSaturated || m_accumulatedOffset.width().mightBeSaturated(); mightBeSaturated = mightBeSaturated || m_accumulatedOffset.height().mightBeSaturated(); stepRemoved(m_mapping.last()); m_mapping.removeLast(); } if (UNLIKELY(mightBeSaturated)) { m_accumulatedOffset = LayoutSize(); for (const auto& step : m_mapping) m_accumulatedOffset += step.m_offset; } }
const RenderObject* RenderView::pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const { // If a container was specified, and was not 0 or the RenderView, // then we should have found it by now. ASSERT_ARG(ancestorToStopAt, !ancestorToStopAt || ancestorToStopAt == this); LayoutSize scrollOffset = frameView().scrollOffsetForFixedPosition(); if (!ancestorToStopAt && shouldUseTransformFromContainer(0)) { TransformationMatrix t; getTransformFromContainer(0, LayoutSize(), t); geometryMap.pushView(this, scrollOffset, &t); } else geometryMap.pushView(this, scrollOffset); return 0; }
static void applyClipRects(const ClipRectsContext& context, const LayoutBoxModelObject& layoutObject, LayoutPoint offset, ClipRects& clipRects) { DCHECK(layoutObject.hasClipRelatedProperty() || (layoutObject.isSVGRoot() && toLayoutSVGRoot(&layoutObject)->shouldApplyViewportClip())); LayoutView* view = layoutObject.view(); DCHECK(view); if (clipRects.fixed() && context.rootLayer->layoutObject() == view) offset -= LayoutSize(view->frameView()->scrollOffset()); if (layoutObject.hasOverflowClip() || (layoutObject.isSVGRoot() && toLayoutSVGRoot(&layoutObject)->shouldApplyViewportClip()) || (layoutObject.styleRef().containsPaint() && layoutObject.isBox())) { ClipRect newOverflowClip = toLayoutBox(layoutObject) .overflowClipRect(offset, context.overlayScrollbarClipBehavior); newOverflowClip.setHasRadius(layoutObject.styleRef().hasBorderRadius()); clipRects.setOverflowClipRect( intersection(newOverflowClip, clipRects.overflowClipRect())); if (layoutObject.isPositioned()) clipRects.setPosClipRect( intersection(newOverflowClip, clipRects.posClipRect())); if (layoutObject.isLayoutView()) clipRects.setFixedClipRect( intersection(newOverflowClip, clipRects.fixedClipRect())); if (layoutObject.styleRef().containsPaint()) { clipRects.setPosClipRect( intersection(newOverflowClip, clipRects.posClipRect())); clipRects.setFixedClipRect( intersection(newOverflowClip, clipRects.fixedClipRect())); } } if (layoutObject.hasClip()) { LayoutRect newClip = toLayoutBox(layoutObject).clipRect(offset); clipRects.setPosClipRect( intersection(newClip, clipRects.posClipRect()).setIsClippedByClipCss()); clipRects.setOverflowClipRect( intersection(newClip, clipRects.overflowClipRect()) .setIsClippedByClipCss()); clipRects.setFixedClipRect(intersection(newClip, clipRects.fixedClipRect()) .setIsClippedByClipCss()); } }
void RenderGeometryMap::push(const RenderObject* renderer, const TransformationMatrix& t, bool accumulatingTransform, bool isNonUniform, bool isFixedPosition, bool hasTransform, LayoutSize offsetForFixedPosition) { ASSERT(m_insertionPosition != kNotFound); ASSERT(!renderer->isRenderView() || !m_insertionPosition || m_mapCoordinatesFlags & TraverseDocumentBoundaries); ASSERT(offsetForFixedPosition.isZero() || renderer->isRenderView()); m_mapping.insert(m_insertionPosition, RenderGeometryMapStep(renderer, accumulatingTransform, isNonUniform, isFixedPosition, hasTransform)); RenderGeometryMapStep& step = m_mapping[m_insertionPosition]; step.m_offsetForFixedPosition = offsetForFixedPosition; if (!t.isIntegerTranslation()) step.m_transform = adoptPtr(new TransformationMatrix(t)); else step.m_offset = LayoutSize(t.e(), t.f()); stepInserted(step); }
void LayoutGeometryMap::push(const LayoutObject* layoutObject, const TransformationMatrix& t, GeometryInfoFlags flags, LayoutSize offsetForFixedPosition) { ASSERT(m_insertionPosition != kNotFound); ASSERT(!layoutObject->isLayoutView() || !m_insertionPosition || m_mapCoordinatesFlags & TraverseDocumentBoundaries); ASSERT(offsetForFixedPosition.isZero() || layoutObject->isLayoutView()); m_mapping.insert(m_insertionPosition, LayoutGeometryMapStep(layoutObject, flags)); LayoutGeometryMapStep& step = m_mapping[m_insertionPosition]; step.m_offsetForFixedPosition = offsetForFixedPosition; if (!t.isIntegerTranslation()) step.m_transform = TransformationMatrix::create(t); else step.m_offset = LayoutSize(LayoutUnit(t.e()), LayoutUnit(t.f())); stepInserted(step); }
void EllipsisBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit lineTop, LayoutUnit lineBottom) { GraphicsContext* context = paintInfo.context; RenderStyle* style = renderer().style(isFirstLineStyle()); const Font& font = style->font(); FloatPoint boxOrigin = locationIncludingFlipping(); boxOrigin.moveBy(FloatPoint(paintOffset)); FloatRect boxRect(boxOrigin, LayoutSize(logicalWidth(), virtualLogicalHeight())); GraphicsContextStateSaver stateSaver(*context); FloatPoint textOrigin = FloatPoint(boxOrigin.x(), boxOrigin.y() + font.fontMetrics().ascent()); Color styleTextColor = renderer().resolveColor(style, CSSPropertyWebkitTextFillColor); if (styleTextColor != context->fillColor()) context->setFillColor(styleTextColor); if (selectionState() != RenderObject::SelectionNone) { paintSelection(context, boxOrigin, style, font); // Select the correct color for painting the text. Color foreground = paintInfo.forceBlackText() ? Color::black : renderer().selectionForegroundColor(); if (foreground != styleTextColor) context->setFillColor(foreground); } const ShadowList* shadowList = style->textShadow(); bool hasShadow = shadowList; if (hasShadow) context->setDrawLooper(shadowList->createDrawLooper(DrawLooperBuilder::ShadowIgnoresAlpha)); TextRun textRun = constructTextRun(&renderer(), font, m_str, style, TextRun::AllowTrailingExpansion); TextRunPaintInfo textRunPaintInfo(textRun); textRunPaintInfo.bounds = boxRect; context->drawText(font, textRunPaintInfo, textOrigin); // Restore the regular fill color. if (styleTextColor != context->fillColor()) context->setFillColor(styleTextColor); if (hasShadow) context->clearDrawLooper(); paintMarkupBox(paintInfo, paintOffset, lineTop, lineBottom, style); }
AffineTransform SVGGraphicsElement::calculateAnimatedLocalTransform() const { AffineTransform matrix; const ComputedStyle* style = layoutObject() ? layoutObject()->style() : nullptr; // If CSS property was set, use that, otherwise fallback to attribute (if set). if (style && style->hasTransform()) { TransformationMatrix transform; float zoom = style->effectiveZoom(); // SVGTextElements need special handling for the text positioning code. if (isSVGTextElement(this)) { // Do not take into account SVG's zoom rules, transform-origin, or percentage values. style->applyTransform(transform, LayoutSize(0, 0), ComputedStyle::ExcludeTransformOrigin, ComputedStyle::IncludeMotionPath, ComputedStyle::IncludeIndependentTransformProperties); } else { // CSS transforms operate with pre-scaled lengths. To make this work with SVG // (which applies the zoom factor globally, at the root level) we // // * pre-scale the bounding box (to bring it into the same space as the other CSS values) // * invert the zoom factor (to effectively compute the CSS transform under a 1.0 zoom) // // Note: objectBoundingBox is an emptyRect for elements like pattern or clipPath. // See the "Object bounding box units" section of http://dev.w3.org/csswg/css3-transforms/ if (zoom != 1) { FloatRect scaledBBox = layoutObject()->objectBoundingBox(); scaledBBox.scale(zoom); transform.scale(1 / zoom); style->applyTransform(transform, scaledBBox, ComputedStyle::IncludeTransformOrigin, ComputedStyle::IncludeMotionPath, ComputedStyle::IncludeIndependentTransformProperties); transform.scale(zoom); } else { style->applyTransform(transform, layoutObject()->objectBoundingBox(), ComputedStyle::IncludeTransformOrigin, ComputedStyle::IncludeMotionPath, ComputedStyle::IncludeIndependentTransformProperties); } } // Flatten any 3D transform. matrix = transform.toAffineTransform(); } else { m_transform->currentValue()->concatenate(matrix); } if (hasSVGRareData()) return *svgRareData()->animateMotionTransform() * matrix; return matrix; }
LayoutRect RootFrameViewport::rootContentsToLayoutViewportContents( FrameView& rootFrameView, const LayoutRect& rect) const { LayoutRect ret(rect); // If the root FrameView is the layout viewport then coordinates in the // root FrameView's content space are already in the layout viewport's // content space. if (rootFrameView.layoutViewportScrollableArea() == &layoutViewport()) return ret; // Make the given rect relative to the top of the layout viewport's content // by adding the scroll position. // TODO(bokan): This will have to be revisited if we ever remove the // restriction that a root scroller must be exactly screen filling. ret.move(LayoutSize(layoutViewport().getScrollOffset())); return ret; }
LayoutState::LayoutState(LayoutObject& root) : m_isPaginated(false) , m_pageLogicalHeightChanged(false) , m_containingBlockLogicalWidthChanged(false) , m_flowThread(nullptr) , m_next(root.view()->layoutState()) , m_layoutObject(root) { ASSERT(!m_next); // We'll end up pushing in LayoutView itself, so don't bother adding it. if (root.isLayoutView()) return; root.view()->pushLayoutState(*this); LayoutObject* container = root.container(); FloatPoint absContentPoint = container->localToAbsolute(FloatPoint(), UseTransforms); m_layoutOffset = LayoutSize(absContentPoint.x(), absContentPoint.y()); }
LayoutRect RootFrameViewport::scrollIntoView(const LayoutRect& rectInContent, const ScrollAlignment& alignX, const ScrollAlignment& alignY) { // We want to move the rect into the viewport that excludes the scrollbars so we intersect // the visual viewport with the scrollbar-excluded frameView content rect. However, we don't // use visibleContentRect directly since it floors the scroll position. Instead, we use // FrameView::scrollPositionDouble and construct a LayoutRect from that (the FrameView size // is always integer sized. LayoutRect frameRectInContent = LayoutRect( layoutViewport().scrollPositionDouble(), layoutViewport().visibleContentRect().size()); LayoutRect visualRectInContent = LayoutRect( layoutViewport().scrollPositionDouble() + toDoubleSize(visualViewport().scrollPositionDouble()), visualViewport().visibleContentRect().size()); LayoutRect viewRectInContent = intersection(visualRectInContent, frameRectInContent); LayoutRect targetViewport = ScrollAlignment::getRectToExpose(viewRectInContent, rectInContent, alignX, alignY); // visualViewport.scrollIntoView will attempt to center the given rect within the viewport // so to prevent it from adjusting r's coordinates the rect must match the viewport's size // i.e. add the subtracted scrollbars from above back in. // FIXME: This is hacky and required because getRectToExpose doesn't naturally account // for the two viewports. crbug.com/449340. targetViewport.setSize(LayoutSize(visualViewport().visibleContentRect().size())); // Snap the visible rect to layout units to match the calculated target viewport rect. FloatRect visible = LayoutRect(visualViewport().scrollPositionDouble(), visualViewport().visibleContentRect().size()); float centeringOffsetX = (visible.width() - targetViewport.width()) / 2; float centeringOffsetY = (visible.height() - targetViewport.height()) / 2; DoublePoint targetOffset( targetViewport.x() - centeringOffsetX, targetViewport.y() - centeringOffsetY); setScrollPosition(targetOffset, ProgrammaticScroll); // RootFrameViewport only changes the viewport relative to the document so we can't change the input // rect's location relative to the document origin. return rectInContent; }
void RenderView::layout() { if (!document()->paginated()) setPageLogicalHeight(0); if (shouldUsePrintingLayout()) m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = logicalWidth(); // Use calcWidth/Height to get the new width/height, since this will take the full page zoom factor into account. bool relayoutChildren = !shouldUsePrintingLayout() && (!m_frameView || width() != viewWidth() || height() != viewHeight()); if (relayoutChildren) { setChildNeedsLayout(true, MarkOnlyThis); for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { if ((child->isBox() && toRenderBox(child)->hasRelativeLogicalHeight()) || child->style()->logicalHeight().isPercent() || child->style()->logicalMinHeight().isPercent() || child->style()->logicalMaxHeight().isPercent()) child->setChildNeedsLayout(true, MarkOnlyThis); } } ASSERT(!m_layoutState); LayoutState state; // FIXME: May be better to push a clip and avoid issuing offscreen repaints. state.m_clipped = false; state.m_pageLogicalHeight = m_pageLogicalHeight; state.m_pageLogicalHeightChanged = m_pageLogicalHeightChanged; state.m_isPaginated = state.m_pageLogicalHeight; m_pageLogicalHeightChanged = false; m_layoutState = &state; if (needsLayout()) { RenderBlock::layout(); if (hasRenderNamedFlowThreads()) flowThreadController()->layoutRenderNamedFlowThreads(); } ASSERT(layoutDelta() == LayoutSize()); ASSERT(m_layoutStateDisableCount == 0); ASSERT(m_layoutState == &state); m_layoutState = 0; setNeedsLayout(false); }
void TransformState::applyTransform( const TransformationMatrix& transformFromContainer, TransformAccumulation accumulate, bool* wasClamped) { if (wasClamped) *wasClamped = false; if (transformFromContainer.isIntegerTranslation()) { move(LayoutSize(LayoutUnit(transformFromContainer.e()), LayoutUnit(transformFromContainer.f())), accumulate); return; } applyAccumulatedOffset(); // If we have an accumulated transform from last time, multiply in this // transform if (m_accumulatedTransform) { if (m_direction == ApplyTransformDirection) m_accumulatedTransform = TransformationMatrix::create( transformFromContainer * *m_accumulatedTransform); else m_accumulatedTransform->multiply(transformFromContainer); } else if (accumulate == AccumulateTransform) { // Make one if we started to accumulate m_accumulatedTransform = TransformationMatrix::create(transformFromContainer); } if (accumulate == FlattenTransform) { if (m_forceAccumulatingTransform) { m_accumulatedTransform->flattenTo2d(); } else { const TransformationMatrix* finalTransform = m_accumulatedTransform ? m_accumulatedTransform.get() : &transformFromContainer; flattenWithTransform(*finalTransform, wasClamped); } } m_accumulatingTransform = accumulate == AccumulateTransform || m_forceAccumulatingTransform; }
const RenderObject* RenderView::pushMappingToContainer(const RenderBox* ancestorToStopAt, RenderGeometryMap& geometryMap) const { LayoutSize offset; RenderObject* container = 0; // If a container was specified, and was not 0 or the RenderView, then we // should have found it by now unless we're traversing to a parent document. ASSERT_ARG(ancestorToStopAt, !ancestorToStopAt || ancestorToStopAt == this || container); if ((!ancestorToStopAt || container) && shouldUseTransformFromContainer(container)) { TransformationMatrix t; getTransformFromContainer(container, LayoutSize(), t); geometryMap.push(this, t, false, false, true); } else { geometryMap.push(this, offset, false, false, false); } return container; }
PassOwnPtr<Shape> ShapeOutsideInfo::createShapeForImage(StyleImage* styleImage, float shapeImageThreshold, WritingMode writingMode, float margin) const { const IntSize& imageSize = m_layoutBox.calculateImageIntrinsicDimensions(styleImage, roundedIntSize(m_referenceBoxLogicalSize), LayoutImage::ScaleByEffectiveZoom); styleImage->setContainerSizeForLayoutObject(&m_layoutBox, imageSize, m_layoutBox.style()->effectiveZoom()); const LayoutRect& marginRect = getShapeImageMarginRect(m_layoutBox, m_referenceBoxLogicalSize); const LayoutRect& imageRect = (m_layoutBox.isLayoutImage()) ? toLayoutImage(m_layoutBox).replacedContentRect() : LayoutRect(LayoutPoint(), LayoutSize(imageSize)); if (!isValidRasterShapeRect(marginRect) || !isValidRasterShapeRect(imageRect)) { m_layoutBox.document().addConsoleMessage(ConsoleMessage::create(RenderingMessageSource, ErrorMessageLevel, "The shape-outside image is too large.")); return Shape::createEmptyRasterShape(writingMode, margin); } ASSERT(!styleImage->isPendingImage()); RefPtr<Image> image = styleImage->image(const_cast<LayoutBox*>(&m_layoutBox), imageSize); return Shape::createRasterShape(image.get(), shapeImageThreshold, imageRect, marginRect, writingMode, margin); }
void EllipsisBoxPainter::paintEllipsis(const PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit lineTop, LayoutUnit lineBottom, const ComputedStyle& style) { bool haveSelection = !paintInfo.isPrinting() && paintInfo.phase != PaintPhaseTextClip && m_ellipsisBox.getSelectionState() != SelectionNone; LayoutRect paintRect(m_ellipsisBox.logicalFrameRect()); if (haveSelection) paintRect.unite(LayoutRect(m_ellipsisBox.selectionRect())); m_ellipsisBox.logicalRectToPhysicalRect(paintRect); paintRect.moveBy(paintOffset); GraphicsContext& context = paintInfo.context; DisplayItem::Type displayItemType = DisplayItem::paintPhaseToDrawingType(paintInfo.phase); if (DrawingRecorder::useCachedDrawingIfPossible(context, m_ellipsisBox, displayItemType)) return; DrawingRecorder recorder(context, m_ellipsisBox, displayItemType, FloatRect(paintRect)); LayoutPoint boxOrigin = m_ellipsisBox.locationIncludingFlipping(); boxOrigin.moveBy(paintOffset); LayoutRect boxRect(boxOrigin, LayoutSize(m_ellipsisBox.logicalWidth(), m_ellipsisBox.virtualLogicalHeight())); GraphicsContextStateSaver stateSaver(context); if (!m_ellipsisBox.isHorizontal()) context.concatCTM(TextPainter::rotation(boxRect, TextPainter::Clockwise)); const Font& font = style.font(); if (haveSelection) paintSelection(context, boxOrigin, style, font); else if (paintInfo.phase == PaintPhaseSelection) return; TextPainter::Style textStyle = TextPainter::textPaintingStyle(m_ellipsisBox.getLineLayoutItem(), style, paintInfo); if (haveSelection) textStyle = TextPainter::selectionPaintingStyle(m_ellipsisBox.getLineLayoutItem(), true, paintInfo, textStyle); TextRun textRun = constructTextRun(font, m_ellipsisBox.ellipsisStr(), style, TextRun::AllowTrailingExpansion); LayoutPoint textOrigin(boxOrigin.x(), boxOrigin.y() + font.getFontMetrics().ascent()); TextPainter textPainter(context, font, textRun, textOrigin, boxRect, m_ellipsisBox.isHorizontal()); textPainter.paint(0, m_ellipsisBox.ellipsisStr().length(), m_ellipsisBox.ellipsisStr().length(), textStyle); }
VisiblePosition LocalFrame::visiblePositionForPoint(const IntPoint& framePoint) { if (!contentRenderer() || !view() || !view()->didFirstLayout()) return VisiblePosition(); LayoutSize padding = LayoutSize(); HitTestResult result(framePoint, padding.height(), padding.width(), padding.height(), padding.width()); HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active); contentRenderer()->hitTest(request, result); Node* node = result.innerNonSharedNode(); if (!node) return VisiblePosition(); RenderObject* renderer = node->renderer(); if (!renderer) return VisiblePosition(); VisiblePosition visiblePos = VisiblePosition(renderer->positionForPoint(result.localPoint())); if (visiblePos.isNull()) visiblePos = VisiblePosition(firstPositionInOrBeforeNode(node)); return visiblePos; }
void RenderReplaced::computeAspectRatioInformationForRenderBox(FloatSize& constrainedSize, double& intrinsicRatio) const { FloatSize intrinsicSize; computeIntrinsicRatioInformation(intrinsicSize, intrinsicRatio); if (intrinsicRatio && !intrinsicSize.isEmpty()) m_intrinsicSize = LayoutSize(intrinsicSize); // Now constrain the intrinsic size along each axis according to minimum and maximum width/heights along the // opposite axis. So for example a maximum width that shrinks our width will result in the height we compute here // having to shrink in order to preserve the aspect ratio. Because we compute these values independently along // each axis, the final returned size may in fact not preserve the aspect ratio. // FIXME: In the long term, it might be better to just return this code more to the way it used to be before this // function was added, since all it has done is make the code more unclear. constrainedSize = intrinsicSize; if (intrinsicRatio && !intrinsicSize.isEmpty() && style()->logicalWidth().isAuto() && style()->logicalHeight().isAuto()) { // We can't multiply or divide by 'intrinsicRatio' here, it breaks tests, like fast/images/zoomed-img-size.html, which // can only be fixed once subpixel precision is available for things like intrinsicWidth/Height. constrainedSize.setWidth(RenderBox::computeReplacedLogicalHeight() * intrinsicSize.width() / intrinsicSize.height()); constrainedSize.setHeight(RenderBox::computeReplacedLogicalWidth() * intrinsicSize.height() / intrinsicSize.width()); } }
void EllipsisBoxPainter::paintSelection(GraphicsContext& context, const LayoutPoint& boxOrigin, const ComputedStyle& style, const Font& font) { Color textColor = m_ellipsisBox.getLineLayoutItem().resolveColor(style, CSSPropertyColor); Color c = m_ellipsisBox.getLineLayoutItem().selectionBackgroundColor(); if (!c.alpha()) return; // If the text color ends up being the same as the selection background, invert the selection // background. if (textColor == c) c = Color(0xff - c.red(), 0xff - c.green(), 0xff - c.blue()); GraphicsContextStateSaver stateSaver(context); LayoutUnit selectionBottom = m_ellipsisBox.root().selectionBottom(); LayoutUnit top = m_ellipsisBox.root().selectionTop(); LayoutUnit h = m_ellipsisBox.root().selectionHeight(); const int deltaY = roundToInt(m_ellipsisBox.getLineLayoutItem().styleRef().isFlippedLinesWritingMode() ? selectionBottom - m_ellipsisBox.logicalBottom() : m_ellipsisBox.logicalTop() - top); const FloatPoint localOrigin(LayoutPoint(boxOrigin.x(), boxOrigin.y() - deltaY)); FloatRect clipRect(localOrigin, FloatSize(LayoutSize(m_ellipsisBox.logicalWidth(), h))); context.clip(clipRect); context.drawHighlightForText(font, constructTextRun(font, m_ellipsisBox.ellipsisStr(), style, TextRun::AllowTrailingExpansion), localOrigin, h, c); }
LayoutSize StyleGeneratedImage::imageSize(const RenderObject* renderer, float multiplier) const { if (m_fixedSize) { IntSize fixedSize = m_imageGeneratorValue->fixedSize(renderer); if (multiplier == 1.0f) return fixedSize; LayoutUnit width = fixedSize.width() * multiplier; LayoutUnit height = fixedSize.height() * multiplier; // Don't let images that have a width/height >= 1 shrink below 1 when zoomed. if (fixedSize.width() > 0) width = max<LayoutUnit>(1, width); if (fixedSize.height() > 0) height = max<LayoutUnit>(1, height); return LayoutSize(width, height); } return m_containerSize; }
void RenderMedia::layout() { StackStats::LayoutCheckPoint layoutCheckPoint; LayoutSize oldSize = contentBoxRect().size(); RenderImage::layout(); RenderBox* controlsRenderer = toRenderBox(m_children.firstChild()); if (!controlsRenderer) return; bool controlsNeedLayout = controlsRenderer->needsLayout(); // If the region chain has changed we also need to relayout the controls to update the region box info. // FIXME: We can do better once we compute region box info for RenderReplaced, not only for RenderBlock. const RenderFlowThread* flowThread = flowThreadContainingBlock(); if (flowThread && !controlsNeedLayout) { if (flowThread->pageLogicalSizeChanged()) controlsNeedLayout = true; } LayoutSize newSize = contentBoxRect().size(); if (newSize == oldSize && !controlsNeedLayout) return; // When calling layout() on a child node, a parent must either push a LayoutStateMaintainter, or // instantiate LayoutStateDisabler. Since using a LayoutStateMaintainer is slightly more efficient, // and this method will be called many times per second during playback, use a LayoutStateMaintainer: LayoutStateMaintainer statePusher(view(), this, locationOffset(), hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode()); controlsRenderer->setLocation(LayoutPoint(borderLeft(), borderTop()) + LayoutSize(paddingLeft(), paddingTop())); controlsRenderer->style()->setHeight(Length(newSize.height(), Fixed)); controlsRenderer->style()->setWidth(Length(newSize.width(), Fixed)); controlsRenderer->setNeedsLayout(true, MarkOnlyThis); controlsRenderer->layout(); setChildNeedsLayout(false); statePusher.pop(); }
PaintInvalidationState::PaintInvalidationState(const LayoutView& layoutView, Vector<LayoutObject*>& pendingDelayedPaintInvalidations, PaintInvalidationState* ownerPaintInvalidationState) : m_clipped(false) , m_cachedOffsetsEnabled(true) , m_ancestorHadPaintInvalidationForLocationChange(false) , m_paintInvalidationContainer(*layoutView.containerForPaintInvalidation()) , m_pendingDelayedPaintInvalidations(pendingDelayedPaintInvalidations) { bool establishesPaintInvalidationContainer = layoutView == m_paintInvalidationContainer; if (!establishesPaintInvalidationContainer) { if ((ownerPaintInvalidationState && !ownerPaintInvalidationState->m_cachedOffsetsEnabled) || !layoutView.supportsPaintInvalidationStateCachedOffsets()) { m_cachedOffsetsEnabled = false; return; } if (ownerPaintInvalidationState && ownerPaintInvalidationState->m_ancestorHadPaintInvalidationForLocationChange) m_ancestorHadPaintInvalidationForLocationChange = true; FloatPoint point = layoutView.localToContainerPoint(FloatPoint(), &m_paintInvalidationContainer, TraverseDocumentBoundaries); m_paintOffset = LayoutSize(point.x(), point.y()); } m_clipRect = layoutView.viewRect(); m_clipRect.move(m_paintOffset); m_clipped = true; }
void EllipsisBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit lineTop, LayoutUnit lineBottom) { GraphicsContext& context = paintInfo.context(); const RenderStyle& lineStyle = this->lineStyle(); Color textColor = lineStyle.visitedDependentColor(CSSPropertyWebkitTextFillColor); if (textColor != context.fillColor()) context.setFillColor(textColor); bool setShadow = false; if (lineStyle.textShadow()) { context.setShadow(LayoutSize(lineStyle.textShadow()->x(), lineStyle.textShadow()->y()), lineStyle.textShadow()->radius(), lineStyle.textShadow()->color()); setShadow = true; } const FontCascade& font = lineStyle.fontCascade(); if (selectionState() != RenderObject::SelectionNone) { paintSelection(context, paintOffset, lineStyle, font); // Select the correct color for painting the text. Color foreground = paintInfo.forceTextColor() ? paintInfo.forcedTextColor() : blockFlow().selectionForegroundColor(); if (foreground.isValid() && foreground != textColor) context.setFillColor(foreground); } // FIXME: Why is this always LTR? Fix by passing correct text run flags below. context.drawText(font, RenderBlock::constructTextRun(&blockFlow(), font, m_str, lineStyle, AllowTrailingExpansion), LayoutPoint(x() + paintOffset.x(), y() + paintOffset.y() + lineStyle.fontMetrics().ascent())); // Restore the regular fill color. if (textColor != context.fillColor()) context.setFillColor(textColor); if (setShadow) context.clearShadow(); paintMarkupBox(paintInfo, paintOffset, lineTop, lineBottom, lineStyle); }
LayoutState::LayoutState(RenderObject& root) : m_clipped(false) , m_isPaginated(false) , m_pageLogicalHeightChanged(false) #if !ASSERT_DISABLED , m_layoutDeltaXSaturated(false) , m_layoutDeltaYSaturated(false) #endif #ifndef NDEBUG , m_renderer(&root) #endif { if (RenderElement* container = root.container()) { FloatPoint absContentPoint = container->localToAbsolute(FloatPoint(), UseTransforms); m_paintOffset = LayoutSize(absContentPoint.x(), absContentPoint.y()); if (container->hasOverflowClip()) { m_clipped = true; auto& containerBox = downcast<RenderBox>(*container); m_clipRect = LayoutRect(toLayoutPoint(m_paintOffset), containerBox.cachedSizeForOverflowClip()); m_paintOffset -= containerBox.scrolledContentOffset(); } } }
void EllipsisBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit lineTop, LayoutUnit lineBottom) { GraphicsContext* context = paintInfo.context; RenderStyle* style = renderer().style(isFirstLineStyle()); Color textColor = style->visitedDependentColor(CSSPropertyWebkitTextFillColor); if (textColor != context->fillColor()) context->setFillColor(textColor, style->colorSpace()); bool setShadow = false; if (style->textShadow()) { context->setShadow(LayoutSize(style->textShadow()->x(), style->textShadow()->y()), style->textShadow()->radius(), style->textShadow()->color(), style->colorSpace()); setShadow = true; } const Font& font = style->font(); if (selectionState() != RenderObject::SelectionNone) { paintSelection(context, paintOffset, style, font); // Select the correct color for painting the text. Color foreground = paintInfo.forceBlackText() ? Color::black : renderer().selectionForegroundColor(); if (foreground.isValid() && foreground != textColor) context->setFillColor(foreground, style->colorSpace()); } // FIXME: Why is this always LTR? Fix by passing correct text run flags below. context->drawText(font, RenderBlock::constructTextRun(&renderer(), font, m_str, style, TextRun::AllowTrailingExpansion), LayoutPoint(x() + paintOffset.x(), y() + paintOffset.y() + style->fontMetrics().ascent())); // Restore the regular fill color. if (textColor != context->fillColor()) context->setFillColor(textColor, style->colorSpace()); if (setShadow) context->clearShadow(); paintMarkupBox(paintInfo, paintOffset, lineTop, lineBottom, style); }