LayoutRect RenderReplaced::replacedContentRect(const LayoutSize* overriddenIntrinsicSize) const { LayoutRect contentRect = contentBoxRect(); ObjectFit objectFit = style()->objectFit(); if (objectFit == ObjectFitFill && style()->objectPosition() == RenderStyle::initialObjectPosition()) objectFit = ObjectFitContain; LayoutSize intrinsicSize = overriddenIntrinsicSize ? *overriddenIntrinsicSize : this->intrinsicSize(); if (!intrinsicSize.width() || !intrinsicSize.height()) return contentRect; LayoutRect finalRect = contentRect; switch (objectFit) { case ObjectFitContain: case ObjectFitScaleDown: case ObjectFitCover: finalRect.setSize(finalRect.size().fitToAspectRatio(intrinsicSize, objectFit == ObjectFitCover ? AspectRatioFitGrow : AspectRatioFitShrink)); if (objectFit != ObjectFitScaleDown || finalRect.width() <= intrinsicSize.width()) break; // fall through case ObjectFitNone: finalRect.setSize(intrinsicSize); break; case ObjectFitFill: break; default: ASSERT_NOT_REACHED(); } LayoutUnit xOffset = minimumValueForLength(style()->objectPosition().x(), contentRect.width() - finalRect.width()); LayoutUnit yOffset = minimumValueForLength(style()->objectPosition().y(), contentRect.height() - finalRect.height()); finalRect.move(xOffset, yOffset); return finalRect; }
LayoutSize RenderVideo::calculateIntrinsicSize() { // Spec text from 4.8.6 // // The intrinsic width of a video element's playback area is the intrinsic width // of the video resource, if that is available; otherwise it is the intrinsic // width of the poster frame, if that is available; otherwise it is 300 CSS pixels. // // The intrinsic height of a video element's playback area is the intrinsic height // of the video resource, if that is available; otherwise it is the intrinsic // height of the poster frame, if that is available; otherwise it is 150 CSS pixels. MediaPlayer* player = videoElement().player(); if (player && videoElement().readyState() >= HTMLVideoElement::HAVE_METADATA) { LayoutSize size = player->naturalSize(); if (!size.isEmpty()) return size; } if (videoElement().shouldDisplayPosterImage() && !m_cachedImageSize.isEmpty() && !imageResource()->errorOccurred()) return m_cachedImageSize; // When the natural size of the video is unavailable, we use the provided // width and height attributes of the video element as the intrinsic size until // better values become available. if (videoElement().hasAttribute(widthAttr) && videoElement().hasAttribute(heightAttr)) return LayoutSize(videoElement().width(), videoElement().height()); // <video> in standalone media documents should not use the default 300x150 // size since they also have audio-only files. By setting the intrinsic // size to 300x1 the video will resize itself in these cases, and audio will // have the correct height (it needs to be > 0 for controls to render properly). if (videoElement().document().isMediaDocument()) return LayoutSize(defaultSize().width(), 1); return defaultSize(); }
void RenderImage::layoutShadowControls(const LayoutSize& oldSize) { auto* controlsRenderer = downcast<RenderBox>(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 might be called many times per second during video playback, use a LayoutStateMaintainer: LayoutStateMaintainer statePusher(view(), *this, locationOffset(), hasTransform() || hasReflection() || style().isFlippedBlocksWritingMode()); if (shadowControlsNeedCustomLayoutMetrics()) { controlsRenderer->setLocation(LayoutPoint(borderLeft(), borderTop()) + LayoutSize(paddingLeft(), paddingTop())); controlsRenderer->style().setHeight(Length(newSize.height(), Fixed)); controlsRenderer->style().setWidth(Length(newSize.width(), Fixed)); } controlsRenderer->setNeedsLayout(MarkOnlyThis); controlsRenderer->layout(); clearChildNeedsLayout(); statePusher.pop(); }
void ImageDocument::imageUpdated() { ASSERT(m_imageElement); if (m_imageSizeIsKnown) return; LayoutSize imageSize = this->imageSize(); if (imageSize.isEmpty()) return; m_imageSizeIsKnown = true; if (m_shouldShrinkImage) { #if PLATFORM(IOS) FloatSize screenSize = page()->chrome().screenSize(); if (imageSize.width() > screenSize.width()) processViewport(String::format("width=%u", static_cast<unsigned>(imageSize.width().toInt())), ViewportArguments::ImageDocument); #else // Call windowSizeChanged for its side effect of sizing the image. windowSizeChanged(); #endif } }
void RenderGeometryMap::push(const RenderObject* renderer, const LayoutSize& offsetFromContainer, bool accumulatingTransform, bool isNonUniform, bool isFixedPosition, bool hasTransform, LayoutSize offsetForFixedPosition) { // fprintf(stderr, "RenderGeometryMap::push %p %d,%d isNonUniform=%d\n", renderer, offsetFromContainer.width().toInt(), offsetFromContainer.height().toInt(), isNonUniform); 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_offset = offsetFromContainer; step.m_offsetForFixedPosition = offsetForFixedPosition; stepInserted(step); }
void LayoutGeometryMap::push(const LayoutObject* layoutObject, const LayoutSize& offsetFromContainer, GeometryInfoFlags flags, LayoutSize offsetForFixedPosition) { LAYOUT_GEOMETRY_MAP_LOG("LayoutGeometryMap::push %p %d,%d isNonUniform=%d\n", layoutObject, offsetFromContainer.width().toInt(), offsetFromContainer.height().toInt(), isNonUniform); 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_offset = offsetFromContainer; step.m_offsetForFixedPosition = offsetForFixedPosition; stepInserted(step); }
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 CachedImage::setContainerSizeForRenderer(const CachedImageClient* renderer, const LayoutSize& containerSize, float containerZoom) { if (containerSize.isEmpty()) return; ASSERT(renderer); ASSERT(containerZoom); if (!m_image) { m_pendingContainerSizeRequests.set(renderer, SizeAndZoom(containerSize, containerZoom)); return; } if (!m_image->isSVGImage()) { m_image->setContainerSize(containerSize); return; } m_svgImageCache->setContainerSizeForRenderer(renderer, containerSize, containerZoom); }
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); }
bool ImageDocument::imageFitsInWindow() { if (!m_imageElement) return true; FrameView* view = this->view(); if (!view) return true; LayoutSize imageSize = this->imageSize(); LayoutSize windowSize = LayoutSize(view->width(), view->height()); return imageSize.width() <= windowSize.width() && imageSize.height() <= windowSize.height(); }
LayoutRect RenderSnapshottedPlugIn::tryToFitStartLabel(LabelSize size, const LayoutRect& contentBox) const { Image* labelImage = startLabelImage(size); if (!labelImage) return LayoutRect(); // Assume that the labelImage has been provided to match our device scale. float scaleFactor = 1; if (document()->page()) scaleFactor = document()->page()->deviceScaleFactor(); IntSize labelImageSize = labelImage->size(); labelImageSize.scale(1 / (scaleFactor ? scaleFactor : 1)); LayoutSize labelSize = labelImageSize - LayoutSize(2 * startLabelInset, 2 * startLabelInset); LayoutRect candidateRect(contentBox.maxXMinYCorner() + LayoutSize(-startLabelPadding, startLabelPadding) + LayoutSize(-labelSize.width(), 0), labelSize); // The minimum allowed content box size is the label image placed in the center of the box, surrounded by startLabelPadding. if (candidateRect.x() < startLabelPadding || candidateRect.maxY() > contentBox.height() - startLabelPadding) return LayoutRect(); return candidateRect; }
void ShapeOutsideInfo::setReferenceBoxLogicalSize( LayoutSize newReferenceBoxLogicalSize) { bool isHorizontalWritingMode = m_layoutBox.containingBlock()->style()->isHorizontalWritingMode(); switch (referenceBox(*m_layoutBox.style()->shapeOutside())) { case MarginBox: if (isHorizontalWritingMode) newReferenceBoxLogicalSize.expand(m_layoutBox.marginWidth(), m_layoutBox.marginHeight()); else newReferenceBoxLogicalSize.expand(m_layoutBox.marginHeight(), m_layoutBox.marginWidth()); break; case BorderBox: break; case PaddingBox: if (isHorizontalWritingMode) newReferenceBoxLogicalSize.shrink(m_layoutBox.borderWidth(), m_layoutBox.borderHeight()); else newReferenceBoxLogicalSize.shrink(m_layoutBox.borderHeight(), m_layoutBox.borderWidth()); break; case ContentBox: if (isHorizontalWritingMode) newReferenceBoxLogicalSize.shrink(m_layoutBox.borderAndPaddingWidth(), m_layoutBox.borderAndPaddingHeight()); else newReferenceBoxLogicalSize.shrink(m_layoutBox.borderAndPaddingHeight(), m_layoutBox.borderAndPaddingWidth()); break; case BoxMissing: ASSERT_NOT_REACHED(); break; } newReferenceBoxLogicalSize.clampNegativeToZero(); if (m_referenceBoxLogicalSize == newReferenceBoxLogicalSize) return; markShapeAsDirty(); m_referenceBoxLogicalSize = newReferenceBoxLogicalSize; }
bool ImageDocument::imageFitsInWindow() const { ASSERT(m_shrinkToFitMode == Desktop); if (!m_imageElement || m_imageElement->document() != this) return true; FrameView* view = frame()->view(); if (!view) return true; ASSERT(m_imageElement->cachedImage()); LayoutSize imageSize = m_imageElement->cachedImage()->imageSizeForLayoutObject(m_imageElement->layoutObject(), pageZoomFactor(this)); LayoutSize windowSize = LayoutSize(view->width(), view->height()); return imageSize.width() <= windowSize.width() && imageSize.height() <= windowSize.height(); }
float ImageDocument::scale() const { if (!m_imageElement || m_imageElement->document() != this) return 1.0f; FrameView* view = frame()->view(); if (!view) return 1; ASSERT(m_imageElement->cachedImage()); LayoutSize imageSize = m_imageElement->cachedImage()->imageSizeForLayoutObject(m_imageElement->layoutObject(), pageZoomFactor(this)); LayoutSize windowSize = LayoutSize(view->width(), view->height()); float widthScale = windowSize.width().toFloat() / imageSize.width().toFloat(); float heightScale = windowSize.height().toFloat() / imageSize.height().toFloat(); return min(widthScale, heightScale); }
LayoutSize RenderBoxModelObject::relativePositionOffset() const { LayoutSize offset = accumulateInFlowPositionOffsets(this); RenderBlock* containingBlock = this->containingBlock(); // Objects that shrink to avoid floats normally use available line width when computing containing block width. However // in the case of relative positioning using percentages, we can't do this. The offset should always be resolved using the // available width of the containing block. Therefore we don't use containingBlockLogicalWidthForContent() here, but instead explicitly // call availableWidth on our containing block. if (!style()->left().isAuto()) { if (!style()->right().isAuto() && !containingBlock->style()->isLeftToRightDirection()) offset.setWidth(-valueForLength(style()->right(), containingBlock->availableWidth())); else offset.expand(valueForLength(style()->left(), containingBlock->availableWidth()), 0); } else if (!style()->right().isAuto()) { offset.expand(-valueForLength(style()->right(), containingBlock->availableWidth()), 0); } // If the containing block of a relatively positioned element does not // specify a height, a percentage top or bottom offset should be resolved as // auto. An exception to this is if the containing block has the WinIE quirk // where <html> and <body> assume the size of the viewport. In this case, // calculate the percent offset based on this height. // See <https://bugs.webkit.org/show_bug.cgi?id=26396>. if (!style()->top().isAuto() && (!containingBlock->hasAutoHeightOrContainingBlockWithAutoHeight() || !style()->top().isPercent() || containingBlock->stretchesToViewport())) offset.expand(0, valueForLength(style()->top(), containingBlock->availableHeight())); else if (!style()->bottom().isAuto() && (!containingBlock->hasAutoHeightOrContainingBlockWithAutoHeight() || !style()->bottom().isPercent() || containingBlock->stretchesToViewport())) offset.expand(0, -valueForLength(style()->bottom(), containingBlock->availableHeight())); return offset; }
void ShapeOutsideInfo::setReferenceBoxLogicalSize(LayoutSize newReferenceBoxLogicalSize) { bool isHorizontalWritingMode = m_renderer.containingBlock()->style().isHorizontalWritingMode(); switch (referenceBox(*m_renderer.style().shapeOutside())) { case MarginBox: if (isHorizontalWritingMode) newReferenceBoxLogicalSize.expand(m_renderer.horizontalMarginExtent(), m_renderer.verticalMarginExtent()); else newReferenceBoxLogicalSize.expand(m_renderer.verticalMarginExtent(), m_renderer.horizontalMarginExtent()); break; case BorderBox: break; case PaddingBox: if (isHorizontalWritingMode) newReferenceBoxLogicalSize.shrink(m_renderer.horizontalBorderExtent(), m_renderer.verticalBorderExtent()); else newReferenceBoxLogicalSize.shrink(m_renderer.verticalBorderExtent(), m_renderer.horizontalBorderExtent()); break; case ContentBox: if (isHorizontalWritingMode) newReferenceBoxLogicalSize.shrink(m_renderer.horizontalBorderAndPaddingExtent(), m_renderer.verticalBorderAndPaddingExtent()); else newReferenceBoxLogicalSize.shrink(m_renderer.verticalBorderAndPaddingExtent(), m_renderer.horizontalBorderAndPaddingExtent()); break; case Fill: case Stroke: case ViewBox: case BoxMissing: ASSERT_NOT_REACHED(); break; } if (m_referenceBoxLogicalSize == newReferenceBoxLogicalSize) return; markShapeAsDirty(); m_referenceBoxLogicalSize = newReferenceBoxLogicalSize; }
void RenderImage::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { LayoutUnit cWidth = contentWidth(); LayoutUnit cHeight = contentHeight(); LayoutUnit leftBorder = borderLeft(); LayoutUnit topBorder = borderTop(); LayoutUnit leftPad = paddingLeft(); LayoutUnit topPad = paddingTop(); GraphicsContext* context = paintInfo.context; if (!m_imageResource->hasImage() || m_imageResource->errorOccurred()) { if (paintInfo.phase == PaintPhaseSelection) return; if (cWidth > 2 && cHeight > 2) { // Draw an outline rect where the image should be. context->setStrokeStyle(SolidStroke); context->setStrokeColor(Color::lightGray, style()->colorSpace()); context->setFillColor(Color::transparent, style()->colorSpace()); context->drawRect(LayoutRect(paintOffset.x() + leftBorder + leftPad, paintOffset.y() + topBorder + topPad, cWidth, cHeight)); bool errorPictureDrawn = false; LayoutSize imageOffset; // When calculating the usable dimensions, exclude the pixels of // the ouline rect so the error image/alt text doesn't draw on it. LayoutUnit usableWidth = cWidth - 2; LayoutUnit usableHeight = cHeight - 2; RefPtr<Image> image = m_imageResource->image(); if (m_imageResource->errorOccurred() && !image->isNull() && usableWidth >= image->width() && usableHeight >= image->height()) { float deviceScaleFactor = Page::deviceScaleFactor(frame()); // Call brokenImage() explicitly to ensure we get the broken image icon at the appropriate resolution. pair<Image*, float> brokenImageAndImageScaleFactor = m_imageResource->cachedImage()->brokenImage(deviceScaleFactor); image = brokenImageAndImageScaleFactor.first; IntSize imageSize = image->size(); imageSize.scale(1 / brokenImageAndImageScaleFactor.second); // Center the error image, accounting for border and padding. LayoutUnit centerX = (usableWidth - imageSize.width()) / 2; if (centerX < 0) centerX = 0; LayoutUnit centerY = (usableHeight - imageSize.height()) / 2; if (centerY < 0) centerY = 0; imageOffset = LayoutSize(leftBorder + leftPad + centerX + 1, topBorder + topPad + centerY + 1); context->drawImage(image.get(), style()->colorSpace(), IntRect(paintOffset + imageOffset, imageSize)); errorPictureDrawn = true; } if (!m_altText.isEmpty()) { String text = document()->displayStringModifiedByEncoding(m_altText); context->setFillColor(style()->visitedDependentColor(CSSPropertyColor), style()->colorSpace()); const Font& font = style()->font(); const FontMetrics& fontMetrics = font.fontMetrics(); LayoutUnit ascent = fontMetrics.ascent(); LayoutPoint altTextOffset = paintOffset; altTextOffset.move(leftBorder + leftPad, topBorder + topPad + ascent); // Only draw the alt text if it'll fit within the content box, // and only if it fits above the error image. TextRun textRun = RenderBlock::constructTextRun(this, font, text, style()); LayoutUnit textWidth = font.width(textRun); if (errorPictureDrawn) { if (usableWidth >= textWidth && fontMetrics.height() <= imageOffset.height()) context->drawText(font, textRun, altTextOffset); } else if (usableWidth >= textWidth && cHeight >= fontMetrics.height()) context->drawText(font, textRun, altTextOffset); } } } else if (m_imageResource->hasImage() && cWidth > 0 && cHeight > 0) { RefPtr<Image> img = m_imageResource->image(cWidth, cHeight); if (!img || img->isNull()) return; #if PLATFORM(MAC) if (style()->highlight() != nullAtom && !paintInfo.context->paintingDisabled()) paintCustomHighlight(toPoint(paintOffset - location()), style()->highlight(), true); #endif LayoutSize contentSize(cWidth, cHeight); LayoutPoint contentLocation = paintOffset; contentLocation.move(leftBorder + leftPad, topBorder + topPad); paintIntoRect(context, LayoutRect(contentLocation, contentSize)); } }
void FloatPoint::move(const LayoutSize& size) { m_x += size.width(); m_y += size.height(); }
void LayoutTextControlSingleLine::layout() { LayoutAnalyzer::Scope analyzer(*this); LayoutBlockFlow::layoutBlock(true); LayoutBox* innerEditorLayoutObject = innerEditorElement()->layoutBox(); Element* container = containerElement(); LayoutBox* containerLayoutObject = container ? container->layoutBox() : nullptr; // Center the child block in the block progression direction (vertical // centering for horizontal text fields). if (!container && innerEditorLayoutObject && innerEditorLayoutObject->size().height() != contentLogicalHeight()) { LayoutUnit logicalHeightDiff = innerEditorLayoutObject->logicalHeight() - contentLogicalHeight(); innerEditorLayoutObject->setLogicalTop( innerEditorLayoutObject->logicalTop() - (logicalHeightDiff / 2 + layoutMod(logicalHeightDiff, 2))); } else if (container && containerLayoutObject && containerLayoutObject->size().height() != contentLogicalHeight()) { LayoutUnit logicalHeightDiff = containerLayoutObject->logicalHeight() - contentLogicalHeight(); containerLayoutObject->setLogicalTop( containerLayoutObject->logicalTop() - (logicalHeightDiff / 2 + layoutMod(logicalHeightDiff, 2))); } HTMLElement* placeholderElement = inputElement()->placeholderElement(); if (LayoutBox* placeholderBox = placeholderElement ? placeholderElement->layoutBox() : 0) { LayoutSize innerEditorSize; if (innerEditorLayoutObject) innerEditorSize = innerEditorLayoutObject->size(); placeholderBox->mutableStyleRef().setWidth(Length( innerEditorSize.width() - placeholderBox->borderAndPaddingWidth(), Fixed)); bool neededLayout = placeholderBox->needsLayout(); placeholderBox->layoutIfNeeded(); LayoutPoint textOffset; if (innerEditorLayoutObject) textOffset = innerEditorLayoutObject->location(); if (editingViewPortElement() && editingViewPortElement()->layoutBox()) textOffset += toLayoutSize(editingViewPortElement()->layoutBox()->location()); if (containerLayoutObject) textOffset += toLayoutSize(containerLayoutObject->location()); if (innerEditorLayoutObject) { // We use inlineBlockBaseline() for innerEditor because it has no // inline boxes when we show the placeholder. int innerEditorBaseline = innerEditorLayoutObject->inlineBlockBaseline(HorizontalLine); // We use firstLineBoxBaseline() for placeholder. // TODO(tkent): It's inconsistent with innerEditorBaseline. However // placeholderBox->inlineBlockBase() is unexpectedly larger. int placeholderBaseline = placeholderBox->firstLineBoxBaseline(); textOffset += LayoutSize(0, innerEditorBaseline - placeholderBaseline); } placeholderBox->setLocation(textOffset); // The placeholder gets layout last, after the parent text control and its // other children, so in order to get the correct overflow from the // placeholder we need to recompute it now. if (neededLayout) computeOverflow(clientLogicalBottom()); } }
FloatSize::FloatSize(const LayoutSize& size) : m_width(size.width()), m_height(size.height()) { }
std::unique_ptr<Shape> Shape::createShape(const BasicShape* basicShape, const LayoutSize& logicalBoxSize, WritingMode writingMode, float margin) { ASSERT(basicShape); bool horizontalWritingMode = isHorizontalWritingMode(writingMode); float boxWidth = horizontalWritingMode ? logicalBoxSize.width() : logicalBoxSize.height(); float boxHeight = horizontalWritingMode ? logicalBoxSize.height() : logicalBoxSize.width(); std::unique_ptr<Shape> shape; switch (basicShape->type()) { case BasicShape::BasicShapeCircleType: { const BasicShapeCircle* circle = static_cast<const BasicShapeCircle*>(basicShape); float centerX = floatValueForCenterCoordinate(circle->centerX(), boxWidth); float centerY = floatValueForCenterCoordinate(circle->centerY(), boxHeight); float radius = circle->floatValueForRadiusInBox(boxWidth, boxHeight); FloatPoint logicalCenter = physicalPointToLogical(FloatPoint(centerX, centerY), logicalBoxSize.height(), writingMode); shape = createCircleShape(logicalCenter, radius); break; } case BasicShape::BasicShapeEllipseType: { const BasicShapeEllipse* ellipse = static_cast<const BasicShapeEllipse*>(basicShape); float centerX = floatValueForCenterCoordinate(ellipse->centerX(), boxWidth); float centerY = floatValueForCenterCoordinate(ellipse->centerY(), boxHeight); float radiusX = ellipse->floatValueForRadiusInBox(ellipse->radiusX(), centerX, boxWidth); float radiusY = ellipse->floatValueForRadiusInBox(ellipse->radiusY(), centerY, boxHeight); FloatPoint logicalCenter = physicalPointToLogical(FloatPoint(centerX, centerY), logicalBoxSize.height(), writingMode); shape = createEllipseShape(logicalCenter, FloatSize(radiusX, radiusY)); break; } case BasicShape::BasicShapePolygonType: { const BasicShapePolygon& polygon = *static_cast<const BasicShapePolygon*>(basicShape); const Vector<Length>& values = polygon.values(); size_t valuesSize = values.size(); ASSERT(!(valuesSize % 2)); std::unique_ptr<Vector<FloatPoint>> vertices = std::make_unique<Vector<FloatPoint>>(valuesSize / 2); for (unsigned i = 0; i < valuesSize; i += 2) { FloatPoint vertex( floatValueForLength(values.at(i), boxWidth), floatValueForLength(values.at(i + 1), boxHeight)); (*vertices)[i / 2] = physicalPointToLogical(vertex, logicalBoxSize.height(), writingMode); } shape = createPolygonShape(WTF::move(vertices), polygon.windRule()); break; } case BasicShape::BasicShapeInsetType: { const BasicShapeInset& inset = *static_cast<const BasicShapeInset*>(basicShape); float left = floatValueForLength(inset.left(), boxWidth); float top = floatValueForLength(inset.top(), boxHeight); FloatRect rect(left, top, std::max<float>(boxWidth - left - floatValueForLength(inset.right(), boxWidth), 0), std::max<float>(boxHeight - top - floatValueForLength(inset.bottom(), boxHeight), 0)); FloatRect logicalRect = physicalRectToLogical(rect, logicalBoxSize.height(), writingMode); FloatSize boxSize(boxWidth, boxHeight); FloatSize topLeftRadius = physicalSizeToLogical(floatSizeForLengthSize(inset.topLeftRadius(), boxSize), writingMode); FloatSize topRightRadius = physicalSizeToLogical(floatSizeForLengthSize(inset.topRightRadius(), boxSize), writingMode); FloatSize bottomLeftRadius = physicalSizeToLogical(floatSizeForLengthSize(inset.bottomLeftRadius(), boxSize), writingMode); FloatSize bottomRightRadius = physicalSizeToLogical(floatSizeForLengthSize(inset.bottomRightRadius(), boxSize), writingMode); FloatRoundedRect::Radii cornerRadii(topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius); cornerRadii.scale(calcBorderRadiiConstraintScaleFor(logicalRect, cornerRadii)); shape = createInsetShape(FloatRoundedRect(logicalRect, cornerRadii)); break; } default: ASSERT_NOT_REACHED(); } shape->m_writingMode = writingMode; shape->m_margin = margin; return shape; }
void RenderTextControlSingleLine::layout() { StackStats::LayoutCheckPoint layoutCheckPoint; // FIXME: We should remove the height-related hacks in layout() and // styleDidChange(). We need them because // - Center the inner elements vertically if the input height is taller than // the intrinsic height of the inner elements. // - Shrink the inner elment heights if the input height is samller than the // intrinsic heights of the inner elements. // We don't honor paddings and borders for textfields without decorations // and type=search if the text height is taller than the contentHeight() // because of compability. RenderTextControlInnerBlock* innerTextRenderer = innerTextElement()->renderer(); RenderBox* innerBlockRenderer = innerBlockElement() ? innerBlockElement()->renderBox() : 0; // To ensure consistency between layouts, we need to reset any conditionally overriden height. if (innerTextRenderer && !innerTextRenderer->style().logicalHeight().isAuto()) { innerTextRenderer->style().setLogicalHeight(Length(Auto)); setNeedsLayoutOnAncestors(innerTextRenderer, this); } if (innerBlockRenderer && !innerBlockRenderer->style().logicalHeight().isAuto()) { innerBlockRenderer->style().setLogicalHeight(Length(Auto)); setNeedsLayoutOnAncestors(innerBlockRenderer, this); } RenderBlockFlow::layoutBlock(false); HTMLElement* container = containerElement(); RenderBox* containerRenderer = container ? container->renderBox() : 0; // Set the text block height LayoutUnit desiredLogicalHeight = textBlockLogicalHeight(); LayoutUnit logicalHeightLimit = computeLogicalHeightLimit(); if (innerTextRenderer && innerTextRenderer->logicalHeight() > logicalHeightLimit) { if (desiredLogicalHeight != innerTextRenderer->logicalHeight()) setNeedsLayout(MarkOnlyThis); m_desiredInnerTextLogicalHeight = desiredLogicalHeight; innerTextRenderer->style().setLogicalHeight(Length(desiredLogicalHeight, Fixed)); innerTextRenderer->setNeedsLayout(MarkOnlyThis); if (innerBlockRenderer) { innerBlockRenderer->style().setLogicalHeight(Length(desiredLogicalHeight, Fixed)); innerBlockRenderer->setNeedsLayout(MarkOnlyThis); } } // The container might be taller because of decoration elements. if (containerRenderer) { containerRenderer->layoutIfNeeded(); LayoutUnit containerLogicalHeight = containerRenderer->logicalHeight(); if (containerLogicalHeight > logicalHeightLimit) { containerRenderer->style().setLogicalHeight(Length(logicalHeightLimit, Fixed)); setNeedsLayout(MarkOnlyThis); } else if (containerRenderer->logicalHeight() < contentLogicalHeight()) { containerRenderer->style().setLogicalHeight(Length(contentLogicalHeight(), Fixed)); setNeedsLayout(MarkOnlyThis); } else containerRenderer->style().setLogicalHeight(Length(containerLogicalHeight, Fixed)); } // If we need another layout pass, we have changed one of children's height so we need to relayout them. if (needsLayout()) RenderBlockFlow::layoutBlock(true); // Center the child block in the block progression direction (vertical centering for horizontal text fields). if (!container && innerTextRenderer && innerTextRenderer->height() != contentLogicalHeight()) centerRenderer(*innerTextRenderer); else centerContainerIfNeeded(containerRenderer); // Ignores the paddings for the inner spin button. if (RenderBox* innerSpinBox = innerSpinButtonElement() ? innerSpinButtonElement()->renderBox() : 0) { RenderBox* parentBox = innerSpinBox->parentBox(); if (containerRenderer && !containerRenderer->style().isLeftToRightDirection()) innerSpinBox->setLogicalLocation(LayoutPoint(-paddingLogicalLeft(), -paddingBefore())); else innerSpinBox->setLogicalLocation(LayoutPoint(parentBox->logicalWidth() - innerSpinBox->logicalWidth() + paddingLogicalRight(), -paddingBefore())); innerSpinBox->setLogicalHeight(logicalHeight() - borderBefore() - borderAfter()); } HTMLElement* placeholderElement = inputElement().placeholderElement(); if (RenderBox* placeholderBox = placeholderElement ? placeholderElement->renderBox() : 0) { LayoutSize innerTextSize; if (innerTextRenderer) innerTextSize = innerTextRenderer->size(); placeholderBox->style().setWidth(Length(innerTextSize.width() - placeholderBox->horizontalBorderAndPaddingExtent(), Fixed)); placeholderBox->style().setHeight(Length(innerTextSize.height() - placeholderBox->verticalBorderAndPaddingExtent(), Fixed)); bool neededLayout = placeholderBox->needsLayout(); bool placeholderBoxHadLayout = placeholderBox->everHadLayout(); placeholderBox->layoutIfNeeded(); LayoutPoint textOffset; if (innerTextRenderer) textOffset = innerTextRenderer->location(); if (innerBlockElement() && innerBlockElement()->renderBox()) textOffset += toLayoutSize(innerBlockElement()->renderBox()->location()); if (containerRenderer) textOffset += toLayoutSize(containerRenderer->location()); placeholderBox->setLocation(textOffset); if (!placeholderBoxHadLayout && placeholderBox->checkForRepaintDuringLayout()) { // This assumes a shadow tree without floats. If floats are added, the // logic should be shared with RenderBlock::layoutBlockChild. placeholderBox->repaint(); } // The placeholder gets layout last, after the parent text control and its other children, // so in order to get the correct overflow from the placeholder we need to recompute it now. if (neededLayout) computeOverflow(clientLogicalBottom()); } #if PLATFORM(IOS) // FIXME: We should not be adjusting styles during layout. <rdar://problem/7675493> if (inputElement().isSearchField()) RenderThemeIOS::adjustRoundBorderRadius(style(), *this); #endif }
PassOwnPtr<Shape> Shape::createShape(const BasicShape* basicShape, const LayoutSize& logicalBoxSize, WritingMode writingMode, Length margin, Length padding) { ASSERT(basicShape); bool horizontalWritingMode = isHorizontalWritingMode(writingMode); float boxWidth = horizontalWritingMode ? logicalBoxSize.width() : logicalBoxSize.height(); float boxHeight = horizontalWritingMode ? logicalBoxSize.height() : logicalBoxSize.width(); OwnPtr<Shape> shape; switch (basicShape->type()) { case BasicShape::BasicShapeRectangleType: { const BasicShapeRectangle* rectangle = static_cast<const BasicShapeRectangle*>(basicShape); FloatRect bounds( floatValueForLength(rectangle->x(), boxWidth), floatValueForLength(rectangle->y(), boxHeight), floatValueForLength(rectangle->width(), boxWidth), floatValueForLength(rectangle->height(), boxHeight)); FloatSize cornerRadii( floatValueForLength(rectangle->cornerRadiusX(), boxWidth), floatValueForLength(rectangle->cornerRadiusY(), boxHeight)); ensureRadiiDoNotOverlap(bounds, cornerRadii); FloatRect logicalBounds = physicalRectToLogical(bounds, logicalBoxSize.height(), writingMode); shape = createRectangleShape(logicalBounds, physicalSizeToLogical(cornerRadii, writingMode)); break; } case BasicShape::BasicShapeCircleType: { const BasicShapeCircle* circle = static_cast<const BasicShapeCircle*>(basicShape); float centerX = floatValueForLength(circle->centerX(), boxWidth); float centerY = floatValueForLength(circle->centerY(), boxHeight); float radius = floatValueForLength(circle->radius(), sqrtf((boxWidth * boxWidth + boxHeight * boxHeight) / 2)); FloatPoint logicalCenter = physicalPointToLogical(FloatPoint(centerX, centerY), logicalBoxSize.height(), writingMode); shape = createShapeCircle(logicalCenter, radius); break; } case BasicShape::BasicShapeEllipseType: { const BasicShapeEllipse* ellipse = static_cast<const BasicShapeEllipse*>(basicShape); float centerX = floatValueForLength(ellipse->centerX(), boxWidth); float centerY = floatValueForLength(ellipse->centerY(), boxHeight); float radiusX = floatValueForLength(ellipse->radiusX(), boxWidth); float radiusY = floatValueForLength(ellipse->radiusY(), boxHeight); FloatPoint logicalCenter = physicalPointToLogical(FloatPoint(centerX, centerY), logicalBoxSize.height(), writingMode); FloatSize logicalRadii = physicalSizeToLogical(FloatSize(radiusX, radiusY), writingMode); shape = createShapeEllipse(logicalCenter, logicalRadii); break; } case BasicShape::BasicShapePolygonType: { const BasicShapePolygon* polygon = static_cast<const BasicShapePolygon*>(basicShape); const Vector<Length>& values = polygon->values(); size_t valuesSize = values.size(); ASSERT(!(valuesSize % 2)); OwnPtr<Vector<FloatPoint> > vertices = adoptPtr(new Vector<FloatPoint>(valuesSize / 2)); for (unsigned i = 0; i < valuesSize; i += 2) { FloatPoint vertex( floatValueForLength(values.at(i), boxWidth), floatValueForLength(values.at(i + 1), boxHeight)); (*vertices)[i / 2] = physicalPointToLogical(vertex, logicalBoxSize.height(), writingMode); } shape = createPolygonShape(vertices.release(), polygon->windRule()); break; } case BasicShape::BasicShapeInsetRectangleType: { const BasicShapeInsetRectangle* rectangle = static_cast<const BasicShapeInsetRectangle*>(basicShape); float left = floatValueForLength(rectangle->left(), boxWidth); float top = floatValueForLength(rectangle->top(), boxHeight); FloatRect bounds( left, top, boxWidth - left - floatValueForLength(rectangle->right(), boxWidth), boxHeight - top - floatValueForLength(rectangle->bottom(), boxHeight)); FloatSize cornerRadii( floatValueForLength(rectangle->cornerRadiusX(), boxWidth), floatValueForLength(rectangle->cornerRadiusY(), boxHeight)); ensureRadiiDoNotOverlap(bounds, cornerRadii); FloatRect logicalBounds = physicalRectToLogical(bounds, logicalBoxSize.height(), writingMode); shape = createRectangleShape(logicalBounds, physicalSizeToLogical(cornerRadii, writingMode)); break; } default: ASSERT_NOT_REACHED(); } shape->m_writingMode = writingMode; shape->m_margin = floatValueForLength(margin, 0); shape->m_padding = floatValueForLength(padding, 0); return shape.release(); }
void RenderEmbeddedObject::layout() { StackStats::LayoutCheckPoint layoutCheckPoint; ASSERT(needsLayout()); LayoutSize oldSize = contentBoxRect().size(); updateLogicalWidth(); updateLogicalHeight(); RenderPart::layout(); m_overflow.clear(); addVisualEffectOverflow(); updateLayerTransform(); bool wasMissingWidget = false; if (!widget() && frameView() && canHaveWidget()) { wasMissingWidget = true; frameView()->addWidgetToUpdate(this); } setNeedsLayout(false); LayoutSize newSize = contentBoxRect().size(); if (!wasMissingWidget && newSize.width() >= oldSize.width() && newSize.height() >= oldSize.height()) { Element* element = toElement(node()); if (element && element->isPluginElement() && toHTMLPlugInElement(element)->isPlugInImageElement()) { HTMLPlugInImageElement* plugInImageElement = toHTMLPlugInImageElement(element); if (plugInImageElement->displayState() > HTMLPlugInElement::DisplayingSnapshot && plugInImageElement->snapshotDecision() == HTMLPlugInImageElement::MaySnapshotWhenResized && document()->view()) { plugInImageElement->setNeedsCheckForSizeChange(); document()->view()->addWidgetToUpdate(this); } } } if (!canHaveChildren()) return; // This code copied from RenderMedia::layout(). RenderObject* child = m_children.firstChild(); if (!child) return; RenderBox* childBox = toRenderBox(child); if (!childBox) return; if (newSize == oldSize && !childBox->needsLayout()) 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()); childBox->setLocation(LayoutPoint(borderLeft(), borderTop()) + LayoutSize(paddingLeft(), paddingTop())); childBox->style()->setHeight(Length(newSize.height(), Fixed)); childBox->style()->setWidth(Length(newSize.width(), Fixed)); childBox->setNeedsLayout(true, MarkOnlyThis); childBox->layout(); setChildNeedsLayout(false); statePusher.pop(); }
void ImagePainter::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { LayoutUnit cWidth = m_renderImage.contentWidth(); LayoutUnit cHeight = m_renderImage.contentHeight(); GraphicsContext* context = paintInfo.context; if (!m_renderImage.imageResource()->hasImage() || m_renderImage.imageResource()->errorOccurred()) { if (paintInfo.phase == PaintPhaseSelection) return; if (cWidth > 2 && cHeight > 2) { const int borderWidth = 1; LayoutUnit leftBorder = m_renderImage.borderLeft(); LayoutUnit topBorder = m_renderImage.borderTop(); LayoutUnit leftPad = m_renderImage.paddingLeft(); LayoutUnit topPad = m_renderImage.paddingTop(); // Draw an outline rect where the image should be. IntRect paintRect = pixelSnappedIntRect(LayoutRect(paintOffset.x() + leftBorder + leftPad, paintOffset.y() + topBorder + topPad, cWidth, cHeight)); DrawingRecorder recorder(context, &m_renderImage, paintInfo.phase, paintRect); context->setStrokeStyle(SolidStroke); context->setStrokeColor(Color::lightGray); context->setFillColor(Color::transparent); context->drawRect(paintRect); bool errorPictureDrawn = false; LayoutSize imageOffset; // When calculating the usable dimensions, exclude the pixels of // the ouline rect so the error image/alt text doesn't draw on it. LayoutUnit usableWidth = cWidth - 2 * borderWidth; LayoutUnit usableHeight = cHeight - 2 * borderWidth; RefPtr<Image> image = m_renderImage.imageResource()->image(); if (m_renderImage.imageResource()->errorOccurred() && !image->isNull() && usableWidth >= image->width() && usableHeight >= image->height()) { float deviceScaleFactor = blink::deviceScaleFactor(m_renderImage.frame()); // Call brokenImage() explicitly to ensure we get the broken image icon at the appropriate resolution. pair<Image*, float> brokenImageAndImageScaleFactor = ImageResource::brokenImage(deviceScaleFactor); image = brokenImageAndImageScaleFactor.first; IntSize imageSize = image->size(); imageSize.scale(1 / brokenImageAndImageScaleFactor.second); // Center the error image, accounting for border and padding. LayoutUnit centerX = (usableWidth - imageSize.width()) / 2; if (centerX < 0) centerX = 0; LayoutUnit centerY = (usableHeight - imageSize.height()) / 2; if (centerY < 0) centerY = 0; imageOffset = LayoutSize(leftBorder + leftPad + centerX + borderWidth, topBorder + topPad + centerY + borderWidth); context->drawImage(image.get(), pixelSnappedIntRect(LayoutRect(paintOffset + imageOffset, imageSize)), CompositeSourceOver, m_renderImage.shouldRespectImageOrientation()); errorPictureDrawn = true; } if (!m_renderImage.altText().isEmpty()) { const Font& font = m_renderImage.style()->font(); const FontMetrics& fontMetrics = font.fontMetrics(); LayoutUnit ascent = fontMetrics.ascent(); LayoutPoint textRectOrigin = paintOffset; textRectOrigin.move(leftBorder + leftPad + (RenderImage::paddingWidth / 2) - borderWidth, topBorder + topPad + (RenderImage::paddingHeight / 2) - borderWidth); LayoutPoint textOrigin(textRectOrigin.x(), textRectOrigin.y() + ascent); // Only draw the alt text if it'll fit within the content box, // and only if it fits above the error image. TextRun textRun = constructTextRun(&m_renderImage, font, m_renderImage.altText(), m_renderImage.style(), TextRun::AllowTrailingExpansion | TextRun::ForbidLeadingExpansion, DefaultTextRunFlags | RespectDirection); float textWidth = font.width(textRun); TextRunPaintInfo textRunPaintInfo(textRun); textRunPaintInfo.bounds = FloatRect(textRectOrigin, FloatSize(textWidth, fontMetrics.height())); context->setFillColor(m_renderImage.resolveColor(CSSPropertyColor)); if (textRun.direction() == RTL) { int availableWidth = cWidth - static_cast<int>(RenderImage::paddingWidth); textOrigin.move(availableWidth - ceilf(textWidth), 0); } if (errorPictureDrawn) { if (usableWidth >= textWidth && fontMetrics.height() <= imageOffset.height()) context->drawBidiText(font, textRunPaintInfo, textOrigin); } else if (usableWidth >= textWidth && usableHeight >= fontMetrics.height()) { context->drawBidiText(font, textRunPaintInfo, textOrigin); } } } } else if (m_renderImage.imageResource()->hasImage() && cWidth > 0 && cHeight > 0) { LayoutRect contentRect = m_renderImage.contentBoxRect(); contentRect.moveBy(paintOffset); LayoutRect paintRect = m_renderImage.replacedContentRect(); paintRect.moveBy(paintOffset); DrawingRecorder recorder(context, &m_renderImage, paintInfo.phase, contentRect); bool clip = !contentRect.contains(paintRect); if (clip) { context->save(); context->clip(contentRect); } paintIntoRect(context, paintRect); if (clip) context->restore(); } }
void AsyncScrollingCoordinator::updateScrollPositionAfterAsyncScroll(ScrollingNodeID scrollingNodeID, const FloatPoint& scrollPosition, bool programmaticScroll, SetOrSyncScrollingLayerPosition scrollingLayerPositionAction) { ASSERT(isMainThread()); if (!m_page) return; FrameView* frameViewPtr = frameViewForScrollingNode(scrollingNodeID); if (!frameViewPtr) return; FrameView& frameView = *frameViewPtr; if (scrollingNodeID == frameView.scrollLayerID()) { bool oldProgrammaticScroll = frameView.inProgrammaticScroll(); frameView.setInProgrammaticScroll(programmaticScroll); frameView.setConstrainsScrollingToContentEdge(false); frameView.notifyScrollPositionChanged(roundedIntPoint(scrollPosition)); frameView.setConstrainsScrollingToContentEdge(true); frameView.setInProgrammaticScroll(oldProgrammaticScroll); if (GraphicsLayer* scrollLayer = scrollLayerForFrameView(frameView)) { GraphicsLayer* counterScrollingLayer = counterScrollingLayerForFrameView(frameView); GraphicsLayer* insetClipLayer = insetClipLayerForFrameView(frameView); GraphicsLayer* contentShadowLayer = contentShadowLayerForFrameView(frameView); GraphicsLayer* scrolledContentsLayer = rootContentLayerForFrameView(frameView); GraphicsLayer* headerLayer = headerLayerForFrameView(frameView); GraphicsLayer* footerLayer = footerLayerForFrameView(frameView); LayoutSize scrollOffsetForFixed = frameView.scrollOffsetForFixedPosition(); float topContentInset = frameView.topContentInset(); FloatPoint positionForInsetClipLayer = FloatPoint(0, FrameView::yPositionForInsetClipLayer(scrollPosition, topContentInset)); FloatPoint positionForContentsLayer = FloatPoint(scrolledContentsLayer->position().x(), FrameView::yPositionForRootContentLayer(scrollPosition, topContentInset, frameView.headerHeight())); FloatPoint positionForHeaderLayer = FloatPoint(scrollOffsetForFixed.width(), FrameView::yPositionForHeaderLayer(scrollPosition, topContentInset)); FloatPoint positionForFooterLayer = FloatPoint(scrollOffsetForFixed.width(), FrameView::yPositionForFooterLayer(scrollPosition, topContentInset, frameView.totalContentsSize().height(), frameView.footerHeight())); if (programmaticScroll || scrollingLayerPositionAction == SetScrollingLayerPosition) { scrollLayer->setPosition(-frameView.scrollPosition()); if (counterScrollingLayer) counterScrollingLayer->setPosition(toLayoutPoint(scrollOffsetForFixed)); if (insetClipLayer) insetClipLayer->setPosition(positionForInsetClipLayer); if (contentShadowLayer) contentShadowLayer->setPosition(positionForContentsLayer); if (scrolledContentsLayer) scrolledContentsLayer->setPosition(positionForContentsLayer); if (headerLayer) headerLayer->setPosition(positionForHeaderLayer); if (footerLayer) footerLayer->setPosition(positionForFooterLayer); } else { scrollLayer->syncPosition(-frameView.scrollPosition()); if (counterScrollingLayer) counterScrollingLayer->syncPosition(toLayoutPoint(scrollOffsetForFixed)); if (insetClipLayer) insetClipLayer->syncPosition(positionForInsetClipLayer); if (contentShadowLayer) contentShadowLayer->syncPosition(positionForContentsLayer); if (scrolledContentsLayer) scrolledContentsLayer->syncPosition(positionForContentsLayer); if (headerLayer) headerLayer->syncPosition(positionForHeaderLayer); if (footerLayer) footerLayer->syncPosition(positionForFooterLayer); LayoutRect viewportRect = frameView.viewportConstrainedVisibleContentRect(); syncChildPositions(viewportRect); } } #if PLATFORM(COCOA) if (m_page->expectsWheelEventTriggers()) { frameView.scrollAnimator().setWheelEventTestTrigger(m_page->testTrigger()); if (const auto& trigger = m_page->testTrigger()) trigger->removeTestDeferralForReason(reinterpret_cast<WheelEventTestTrigger::ScrollableAreaIdentifier>(scrollingNodeID), WheelEventTestTrigger::ScrollingThreadSyncNeeded); } #endif return; } // Overflow-scroll area. if (ScrollableArea* scrollableArea = frameView.scrollableAreaForScrollLayerID(scrollingNodeID)) { scrollableArea->setIsUserScroll(scrollingLayerPositionAction == SyncScrollingLayerPosition); scrollableArea->scrollToOffsetWithoutAnimation(scrollPosition); scrollableArea->setIsUserScroll(false); if (scrollingLayerPositionAction == SetScrollingLayerPosition) m_page->editorClient().overflowScrollPositionChanged(); #if PLATFORM(COCOA) if (m_page->expectsWheelEventTriggers()) { frameView.scrollAnimator().setWheelEventTestTrigger(m_page->testTrigger()); if (const auto& trigger = m_page->testTrigger()) trigger->removeTestDeferralForReason(reinterpret_cast<WheelEventTestTrigger::ScrollableAreaIdentifier>(scrollingNodeID), WheelEventTestTrigger::ScrollingThreadSyncNeeded); } #endif } }
PassOwnPtr<Shape> Shape::createShape(const BasicShape* basicShape, const LayoutSize& logicalBoxSize, WritingMode writingMode, float margin) { ASSERT(basicShape); bool horizontalWritingMode = isHorizontalWritingMode(writingMode); float boxWidth = horizontalWritingMode ? logicalBoxSize.width().toFloat() : logicalBoxSize.height().toFloat(); float boxHeight = horizontalWritingMode ? logicalBoxSize.height().toFloat() : logicalBoxSize.width().toFloat(); OwnPtr<Shape> shape; switch (basicShape->type()) { case BasicShape::BasicShapeCircleType: { const BasicShapeCircle* circle = toBasicShapeCircle(basicShape); FloatPoint center = floatPointForCenterCoordinate(circle->centerX(), circle->centerY(), FloatSize(boxWidth, boxHeight)); float radius = circle->floatValueForRadiusInBox(FloatSize(boxWidth, boxHeight)); FloatPoint logicalCenter = physicalPointToLogical(center, logicalBoxSize.height().toFloat(), writingMode); shape = createCircleShape(logicalCenter, radius); break; } case BasicShape::BasicShapeEllipseType: { const BasicShapeEllipse* ellipse = toBasicShapeEllipse(basicShape); FloatPoint center = floatPointForCenterCoordinate(ellipse->centerX(), ellipse->centerY(), FloatSize(boxWidth, boxHeight)); float radiusX = ellipse->floatValueForRadiusInBox(ellipse->radiusX(), center.x(), boxWidth); float radiusY = ellipse->floatValueForRadiusInBox(ellipse->radiusY(), center.y(), boxHeight); FloatPoint logicalCenter = physicalPointToLogical(center, logicalBoxSize.height().toFloat(), writingMode); shape = createEllipseShape(logicalCenter, FloatSize(radiusX, radiusY)); break; } case BasicShape::BasicShapePolygonType: { const BasicShapePolygon* polygon = toBasicShapePolygon(basicShape); const Vector<Length>& values = polygon->values(); size_t valuesSize = values.size(); ASSERT(!(valuesSize % 2)); OwnPtr<Vector<FloatPoint>> vertices = adoptPtr(new Vector<FloatPoint>(valuesSize / 2)); for (unsigned i = 0; i < valuesSize; i += 2) { FloatPoint vertex( floatValueForLength(values.at(i), boxWidth), floatValueForLength(values.at(i + 1), boxHeight)); (*vertices)[i / 2] = physicalPointToLogical(vertex, logicalBoxSize.height().toFloat(), writingMode); } shape = createPolygonShape(vertices.release(), polygon->windRule()); break; } case BasicShape::BasicShapeInsetType: { const BasicShapeInset& inset = *toBasicShapeInset(basicShape); float left = floatValueForLength(inset.left(), boxWidth); float top = floatValueForLength(inset.top(), boxHeight); float right = floatValueForLength(inset.right(), boxWidth); float bottom = floatValueForLength(inset.bottom(), boxHeight); FloatRect rect(left, top, std::max<float>(boxWidth - left - right, 0), std::max<float>(boxHeight - top - bottom, 0)); FloatRect logicalRect = physicalRectToLogical(rect, logicalBoxSize.height().toFloat(), writingMode); FloatSize boxSize(boxWidth, boxHeight); FloatSize topLeftRadius = physicalSizeToLogical(floatSizeForLengthSize(inset.topLeftRadius(), boxSize), writingMode); FloatSize topRightRadius = physicalSizeToLogical(floatSizeForLengthSize(inset.topRightRadius(), boxSize), writingMode); FloatSize bottomLeftRadius = physicalSizeToLogical(floatSizeForLengthSize(inset.bottomLeftRadius(), boxSize), writingMode); FloatSize bottomRightRadius = physicalSizeToLogical(floatSizeForLengthSize(inset.bottomRightRadius(), boxSize), writingMode); FloatRoundedRect::Radii cornerRadii(topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius); FloatRoundedRect finalRect(logicalRect, cornerRadii); finalRect.constrainRadii(); shape = createInsetShape(finalRect); break; } default: ASSERT_NOT_REACHED(); } shape->m_writingMode = writingMode; shape->m_margin = margin; return shape.release(); }
void RenderTextControlSingleLine::layout() { SubtreeLayoutScope layoutScope(this); // FIXME: We should remove the height-related hacks in layout() and // styleDidChange(). We need them because // - Center the inner elements vertically if the input height is taller than // the intrinsic height of the inner elements. // - Shrink the inner elment heights if the input height is samller than the // intrinsic heights of the inner elements. // We don't honor paddings and borders for textfields without decorations // and type=search if the text height is taller than the contentHeight() // because of compability. RenderBox* innerTextRenderer = innerTextElement()->renderBox(); RenderBox* viewPortRenderer = editingViewPortElement() ? editingViewPortElement()->renderBox() : 0; // To ensure consistency between layouts, we need to reset any conditionally overriden height. if (innerTextRenderer && !innerTextRenderer->style()->logicalHeight().isAuto()) { innerTextRenderer->style()->setLogicalHeight(Length(Auto)); layoutScope.setNeedsLayout(innerTextRenderer); } if (viewPortRenderer && !viewPortRenderer->style()->logicalHeight().isAuto()) { viewPortRenderer->style()->setLogicalHeight(Length(Auto)); layoutScope.setNeedsLayout(viewPortRenderer); } RenderBlockFlow::layoutBlock(false); Element* container = containerElement(); RenderBox* containerRenderer = container ? container->renderBox() : 0; // Set the text block height LayoutUnit desiredLogicalHeight = textBlockLogicalHeight(); LayoutUnit logicalHeightLimit = computeLogicalHeightLimit(); if (innerTextRenderer && innerTextRenderer->logicalHeight() > logicalHeightLimit) { if (desiredLogicalHeight != innerTextRenderer->logicalHeight()) layoutScope.setNeedsLayout(this); m_desiredInnerTextLogicalHeight = desiredLogicalHeight; innerTextRenderer->style()->setLogicalHeight(Length(desiredLogicalHeight, Fixed)); layoutScope.setNeedsLayout(innerTextRenderer); if (viewPortRenderer) { viewPortRenderer->style()->setLogicalHeight(Length(desiredLogicalHeight, Fixed)); layoutScope.setNeedsLayout(viewPortRenderer); } } // The container might be taller because of decoration elements. if (containerRenderer) { containerRenderer->layoutIfNeeded(); LayoutUnit containerLogicalHeight = containerRenderer->logicalHeight(); if (containerLogicalHeight > logicalHeightLimit) { containerRenderer->style()->setLogicalHeight(Length(logicalHeightLimit, Fixed)); layoutScope.setNeedsLayout(this); } else if (containerRenderer->logicalHeight() < contentLogicalHeight()) { containerRenderer->style()->setLogicalHeight(Length(contentLogicalHeight(), Fixed)); layoutScope.setNeedsLayout(this); } else containerRenderer->style()->setLogicalHeight(Length(containerLogicalHeight, Fixed)); } // If we need another layout pass, we have changed one of children's height so we need to relayout them. if (needsLayout()) RenderBlockFlow::layoutBlock(true); // Center the child block in the block progression direction (vertical centering for horizontal text fields). if (!container && innerTextRenderer && innerTextRenderer->height() != contentLogicalHeight()) { LayoutUnit logicalHeightDiff = innerTextRenderer->logicalHeight() - contentLogicalHeight(); innerTextRenderer->setLogicalTop(innerTextRenderer->logicalTop() - (logicalHeightDiff / 2 + layoutMod(logicalHeightDiff, 2))); } else centerContainerIfNeeded(containerRenderer); HTMLElement* placeholderElement = inputElement()->placeholderElement(); if (RenderBox* placeholderBox = placeholderElement ? placeholderElement->renderBox() : 0) { LayoutSize innerTextSize; if (innerTextRenderer) innerTextSize = innerTextRenderer->size(); placeholderBox->style()->setWidth(Length(innerTextSize.width() - placeholderBox->borderAndPaddingWidth(), Fixed)); placeholderBox->style()->setHeight(Length(innerTextSize.height() - placeholderBox->borderAndPaddingHeight(), Fixed)); bool neededLayout = placeholderBox->needsLayout(); bool placeholderBoxHadLayout = placeholderBox->everHadLayout(); placeholderBox->layoutIfNeeded(); LayoutPoint textOffset; if (innerTextRenderer) textOffset = innerTextRenderer->location(); if (editingViewPortElement() && editingViewPortElement()->renderBox()) textOffset += toLayoutSize(editingViewPortElement()->renderBox()->location()); if (containerRenderer) textOffset += toLayoutSize(containerRenderer->location()); placeholderBox->setLocation(textOffset); if (!placeholderBoxHadLayout && placeholderBox->checkForRepaintDuringLayout()) { // This assumes a shadow tree without floats. If floats are added, the // logic should be shared with RenderBlockFlow::layoutBlockChild. placeholderBox->repaint(); } // The placeholder gets layout last, after the parent text control and its other children, // so in order to get the correct overflow from the placeholder we need to recompute it now. if (neededLayout) computeOverflow(clientLogicalBottom()); } }
void LayoutMedia::layout() { LayoutSize oldSize = contentBoxRect().size(); LayoutImage::layout(); LayoutRect newRect = contentBoxRect(); LayoutState state(*this); Optional<LayoutUnit> newPanelWidth; // Iterate the children in reverse order so that the media controls are laid // out before the text track container. This is to ensure that the text // track rendering has an up-to-date position of the media controls for // overlap checking, see LayoutVTTCue. #if ENABLE(ASSERT) bool seenTextTrackContainer = false; #endif for (LayoutObject* child = m_children.lastChild(); child; child = child->previousSibling()) { #if ENABLE(ASSERT) if (child->node()->isMediaControls()) ASSERT(!seenTextTrackContainer); else if (child->node()->isTextTrackContainer()) seenTextTrackContainer = true; else ASSERT_NOT_REACHED(); #endif // TODO(mlamouri): we miss some layouts because needsLayout returns false in // some cases where we want to change the width of the controls because the // visible viewport has changed for example. if (newRect.size() == oldSize && !child->needsLayout()) continue; LayoutUnit width = newRect.width(); if (child->node()->isMediaControls()) { width = computePanelWidth(newRect); if (width != oldSize.width()) newPanelWidth = width; } LayoutBox* layoutBox = toLayoutBox(child); layoutBox->setLocation(newRect.location()); // TODO(foolip): Remove the mutableStyleRef() and depend on CSS // width/height: inherit to match the media element size. layoutBox->mutableStyleRef().setHeight(Length(newRect.height(), Fixed)); layoutBox->mutableStyleRef().setWidth(Length(width, Fixed)); layoutBox->forceLayout(); } clearNeedsLayout(); // Notify our MediaControls that a layout has happened. if (mediaElement() && mediaElement()->mediaControls() && newPanelWidth.has_value()) { mediaElement()->mediaControls()->notifyPanelWidthChanged( newPanelWidth.value()); } }
void AsyncScrollingCoordinator::updateScrollPositionAfterAsyncScroll(ScrollingNodeID scrollingNodeID, const FloatPoint& scrollPosition, bool programmaticScroll, SetOrSyncScrollingLayerPosition scrollingLayerPositionAction) { ASSERT(isMainThread()); if (!m_page) return; FrameView* frameView = m_page->mainFrame().view(); if (!frameView) return; // Main frame. if (scrollingNodeID == frameView->scrollLayerID()) { bool oldProgrammaticScroll = frameView->inProgrammaticScroll(); frameView->setInProgrammaticScroll(programmaticScroll); frameView->setConstrainsScrollingToContentEdge(false); frameView->notifyScrollPositionChanged(roundedIntPoint(scrollPosition)); frameView->setConstrainsScrollingToContentEdge(true); frameView->setInProgrammaticScroll(oldProgrammaticScroll); if (GraphicsLayer* scrollLayer = scrollLayerForFrameView(frameView)) { GraphicsLayer* counterScrollingLayer = counterScrollingLayerForFrameView(frameView); GraphicsLayer* insetClipLayer = insetClipLayerForFrameView(frameView); GraphicsLayer* contentShadowLayer = contentShadowLayerForFrameView(frameView); GraphicsLayer* scrolledContentsLayer = rootContentLayerForFrameView(frameView); GraphicsLayer* headerLayer = headerLayerForFrameView(frameView); GraphicsLayer* footerLayer = footerLayerForFrameView(frameView); LayoutSize scrollOffsetForFixed = frameView->scrollOffsetForFixedPosition(); float topContentInset = frameView->topContentInset(); FloatPoint positionForInsetClipLayer = FloatPoint(0, FrameView::yPositionForInsetClipLayer(scrollPosition, topContentInset)); FloatPoint positionForContentsLayer = FloatPoint(scrolledContentsLayer->position().x(), FrameView::yPositionForRootContentLayer(scrollPosition, topContentInset, frameView->headerHeight())); FloatPoint positionForHeaderLayer = FloatPoint(scrollOffsetForFixed.width(), FrameView::yPositionForHeaderLayer(scrollPosition, topContentInset)); FloatPoint positionForFooterLayer = FloatPoint(scrollOffsetForFixed.width(), FrameView::yPositionForFooterLayer(scrollPosition, topContentInset, frameView->totalContentsSize().height(), frameView->footerHeight())); if (programmaticScroll || scrollingLayerPositionAction == SetScrollingLayerPosition) { scrollLayer->setPosition(-frameView->scrollPosition()); if (counterScrollingLayer) counterScrollingLayer->setPosition(toLayoutPoint(scrollOffsetForFixed)); if (insetClipLayer) insetClipLayer->setPosition(positionForInsetClipLayer); if (contentShadowLayer) contentShadowLayer->setPosition(positionForContentsLayer); if (scrolledContentsLayer) scrolledContentsLayer->setPosition(positionForContentsLayer); if (headerLayer) headerLayer->setPosition(positionForHeaderLayer); if (footerLayer) footerLayer->setPosition(positionForFooterLayer); } else { scrollLayer->syncPosition(-frameView->scrollPosition()); if (counterScrollingLayer) counterScrollingLayer->syncPosition(toLayoutPoint(scrollOffsetForFixed)); if (insetClipLayer) insetClipLayer->syncPosition(positionForInsetClipLayer); if (contentShadowLayer) contentShadowLayer->syncPosition(positionForContentsLayer); if (scrolledContentsLayer) scrolledContentsLayer->syncPosition(positionForContentsLayer); if (headerLayer) headerLayer->syncPosition(positionForHeaderLayer); if (footerLayer) footerLayer->syncPosition(positionForFooterLayer); LayoutRect viewportRect = frameView->viewportConstrainedVisibleContentRect(); syncChildPositions(viewportRect); } } return; } // Overflow-scroll area. if (ScrollableArea* scrollableArea = frameView->scrollableAreaForScrollLayerID(scrollingNodeID)) { scrollableArea->setIsUserScroll(scrollingLayerPositionAction == SyncScrollingLayerPosition); scrollableArea->scrollToOffsetWithoutAnimation(scrollPosition); scrollableArea->setIsUserScroll(false); } }