void RenderSVGRoot::computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio, bool& isPercentageIntrinsicSize) const { // Spec: http://www.w3.org/TR/SVG/coords.html#IntrinsicSizing // SVG needs to specify how to calculate some intrinsic sizing properties to enable inclusion within other languages. // The intrinsic width and height of the viewport of SVG content must be determined from the ‘width’ and ‘height’ attributes. // If either of these are not specified, a value of '100%' must be assumed. Note: the ‘width’ and ‘height’ attributes are not // the same as the CSS width and height properties. Specifically, percentage values do not provide an intrinsic width or height, // and do not indicate a percentage of the containing block. Rather, once the viewport is established, they indicate the portion // of the viewport that is actually covered by image data. SVGSVGElement* svg = static_cast<SVGSVGElement*>(node()); Length intrinsicWidthAttribute = svg->intrinsicWidth(SVGSVGElement::IgnoreCSSProperties); Length intrinsicHeightAttribute = svg->intrinsicHeight(SVGSVGElement::IgnoreCSSProperties); // The intrinsic aspect ratio of the viewport of SVG content is necessary for example, when including SVG from an ‘object’ // element in HTML styled with CSS. It is possible (indeed, common) for an SVG graphic to have an intrinsic aspect ratio but // not to have an intrinsic width or height. The intrinsic aspect ratio must be calculated based upon the following rules: // - The aspect ratio is calculated by dividing a width by a height. // - If the ‘width’ and ‘height’ of the rootmost ‘svg’ element are both specified with unit identifiers (in, mm, cm, pt, pc, // px, em, ex) or in user units, then the aspect ratio is calculated from the ‘width’ and ‘height’ attributes after // resolving both values to user units. if (intrinsicWidthAttribute.isFixed() || intrinsicHeightAttribute.isFixed()) { if (intrinsicWidthAttribute.isFixed()) intrinsicSize.setWidth(floatValueForLength(intrinsicWidthAttribute, 0)); if (intrinsicHeightAttribute.isFixed()) intrinsicSize.setHeight(floatValueForLength(intrinsicHeightAttribute, 0)); if (!intrinsicSize.isEmpty()) intrinsicRatio = intrinsicSize.width() / static_cast<double>(intrinsicSize.height()); return; } // - If either/both of the ‘width’ and ‘height’ of the rootmost ‘svg’ element are in percentage units (or omitted), the // aspect ratio is calculated from the width and height values of the ‘viewBox’ specified for the current SVG document // fragment. If the ‘viewBox’ is not correctly specified, or set to 'none', the intrinsic aspect ratio cannot be // calculated and is considered unspecified. intrinsicSize = svg->viewBox().size(); if (!intrinsicSize.isEmpty()) { // The viewBox can only yield an intrinsic ratio, not an intrinsic size. intrinsicRatio = intrinsicSize.width() / static_cast<double>(intrinsicSize.height()); intrinsicSize = FloatSize(); return; } // If our intrinsic size is in percentage units, return those to the caller through the intrinsicSize. Notify the caller // about the special situation, by setting isPercentageIntrinsicSize=true, so it knows how to interpret the return values. if (intrinsicWidthAttribute.isPercent() && intrinsicHeightAttribute.isPercent()) { isPercentageIntrinsicSize = true; intrinsicSize = FloatSize(intrinsicWidthAttribute.percent(), intrinsicHeightAttribute.percent()); } }
void RenderReplaced::computeAspectRatioInformationForRenderBox(RenderBox* contentRenderer, FloatSize& constrainedSize, double& intrinsicRatio, bool& isPercentageIntrinsicSize) const { FloatSize intrinsicSize; if (contentRenderer) { contentRenderer->computeIntrinsicRatioInformation(intrinsicSize, intrinsicRatio, isPercentageIntrinsicSize); if (intrinsicRatio) ASSERT(!isPercentageIntrinsicSize); // Handle zoom & vertical writing modes here, as the embedded document doesn't know about them. if (!isPercentageIntrinsicSize) intrinsicSize.scale(style()->effectiveZoom()); if (rendererHasAspectRatio(this) && isPercentageIntrinsicSize) intrinsicRatio = 1; // Update our intrinsic size to match what the content renderer has computed, so that when we // constrain the size below, the correct intrinsic size will be obtained for comparison against // min and max widths. if (intrinsicRatio && !isPercentageIntrinsicSize && !intrinsicSize.isEmpty()) m_intrinsicSize = LayoutSize(intrinsicSize); if (!isHorizontalWritingMode()) { if (intrinsicRatio) intrinsicRatio = 1 / intrinsicRatio; intrinsicSize = intrinsicSize.transposedSize(); } } else { computeIntrinsicRatioInformation(intrinsicSize, intrinsicRatio, isPercentageIntrinsicSize); if (intrinsicRatio) { ASSERT(!isPercentageIntrinsicSize); if (!intrinsicSize.isEmpty()) m_intrinsicSize = LayoutSize(isHorizontalWritingMode() ? intrinsicSize : intrinsicSize.transposedSize()); } } // 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 && !isPercentageIntrinsicSize && !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 - which include zoom! constrainedSize.setWidth(RenderBox::computeReplacedLogicalHeight() * intrinsicSize.width() / intrinsicSize.height()); constrainedSize.setHeight(RenderBox::computeReplacedLogicalWidth() * intrinsicSize.height() / intrinsicSize.width()); } }
bool SVGLengthContext::determineViewport(FloatSize& viewportSize) const { if (!m_context) return false; // If an overriden viewport is given, it has precedence. if (!m_overridenViewport.isEmpty()) { viewportSize = m_overridenViewport.size(); return true; } // Root <svg> element lengths are resolved against the top level viewport. if (m_context->isOutermostSVGSVGElement()) { viewportSize = downcast<SVGSVGElement>(*m_context).currentViewportSize(); return true; } // Take size from nearest viewport element. SVGElement* viewportElement = m_context->viewportElement(); if (!is<SVGSVGElement>(viewportElement)) return false; const SVGSVGElement& svg = downcast<SVGSVGElement>(*viewportElement); viewportSize = svg.currentViewBoxRect().size(); if (viewportSize.isEmpty()) viewportSize = svg.currentViewportSize(); return true; }
bool ImageBuffer::sizeNeedsClamping(const FloatSize& size) { if (size.isEmpty()) return false; return floorf(size.height()) * floorf(size.width()) > MaxClampedArea; }
void RenderSVGRoot::computeIntrinsicRatioInformation(FloatSize& intrinsicRatio, bool& isPercentageIntrinsicSize) const { // Spec: http://dev.w3.org/SVG/profiles/1.1F2/publish/coords.html#IntrinsicSizing // The intrinsic aspect ratio of the viewport of SVG content is necessary for example, when including // SVG from an ‘object’ element in HTML styled with CSS. It is possible (indeed, common) for an SVG // graphic to have an intrinsic aspect ratio but not to have an intrinsic width or height. // The intrinsic aspect ratio must be calculated based upon the following rules: // The aspect ratio is calculated by dividing a width by a height. // If the ‘width’ and ‘height’ of the rootmost ‘svg’ element are both specified with unit identifiers // (in, mm, cm, pt, pc, px, em, ex) or in user units, then the aspect ratio is calculated from the // ‘width’ and ‘height’ attributes after resolving both values to user units. isPercentageIntrinsicSize = false; if (style()->width().isFixed() && style()->height().isFixed()) { intrinsicRatio = FloatSize(width(), height()); return; } // If either/both of the ‘width’ and ‘height’ of the rootmost ‘svg’ element are in percentage units (or omitted), // the aspect ratio is calculated from the width and height values of the ‘viewBox’ specified for the current SVG // document fragment. If the ‘viewBox’ is not correctly specified, or set to 'none', the intrinsic aspect ratio // cannot be calculated and is considered unspecified. intrinsicRatio = static_cast<SVGSVGElement*>(node())->currentViewBoxRect().size(); // Compatibility with authors expectations and Firefox/Opera: when percentage units are used, take them into // account for certain cases of the intrinsic width/height calculation in RenderPart::computeReplacedLogicalWidth/Height. if (intrinsicRatio.isEmpty() && style()->width().isPercent() && style()->height().isPercent()) { isPercentageIntrinsicSize = true; intrinsicRatio = FloatSize(style()->width().percent(), style()->height().percent()); } }
RefPtr<Image> CSSCrossfadeValue::image(RenderElement* renderer, const FloatSize& size) { if (size.isEmpty()) return nullptr; // FIXME: Skip Content Security Policy check when cross fade is applied to an element in a user agent shadow tree. // See <https://bugs.webkit.org/show_bug.cgi?id=146663>. ResourceLoaderOptions options = CachedResourceLoader::defaultCachedResourceOptions(); CachedResourceLoader& cachedResourceLoader = renderer->document().cachedResourceLoader(); CachedImage* cachedFromImage = cachedImageForCSSValue(m_fromValue, cachedResourceLoader, options); CachedImage* cachedToImage = cachedImageForCSSValue(m_toValue, cachedResourceLoader, options); if (!cachedFromImage || !cachedToImage) return Image::nullImage(); Image* fromImage = cachedFromImage->imageForRenderer(renderer); Image* toImage = cachedToImage->imageForRenderer(renderer); if (!fromImage || !toImage) return Image::nullImage(); m_generatedImage = CrossfadeGeneratedImage::create(*fromImage, *toImage, m_percentageValue->getFloatValue(), fixedSize(renderer), size); return m_generatedImage; }
bool SVGLengthContext::determineViewport(float& width, float& height) const { if (!m_context) return false; // If an overriden viewport is given, it has precedence. if (!m_overridenViewport.isEmpty()) { width = m_overridenViewport.width(); height = m_overridenViewport.height(); return true; } // SVGLengthContext should NEVER be used to resolve width/height values for <svg> elements, // as they require special treatment, due the relationship with the CSS width/height properties. ASSERT(m_context->document().documentElement() != m_context); // Take size from nearest viewport element. SVGElement* viewportElement = m_context->viewportElement(); if (!viewportElement || !viewportElement->isSVGSVGElement()) return false; const SVGSVGElement* svg = static_cast<const SVGSVGElement*>(viewportElement); FloatSize viewportSize = svg->currentViewBoxRect().size(); if (viewportSize.isEmpty()) viewportSize = svg->currentViewportSize(); width = viewportSize.width(); height = viewportSize.height(); return true; }
IntSize SVGImage::containerSize() const { SVGSVGElement* rootElement = this->rootElement(); if (!rootElement) return IntSize(); auto* renderer = downcast<RenderSVGRoot>(rootElement->renderer()); if (!renderer) return IntSize(); // If a container size is available it has precedence. IntSize containerSize = renderer->containerSize(); if (!containerSize.isEmpty()) return containerSize; // Assure that a container size is always given for a non-identity zoom level. ASSERT(renderer->style().effectiveZoom() == 1); FloatSize currentSize; if (rootElement->hasIntrinsicWidth() && rootElement->hasIntrinsicHeight()) currentSize = rootElement->currentViewportSize(); else currentSize = rootElement->currentViewBoxRect().size(); if (!currentSize.isEmpty()) return IntSize(static_cast<int>(ceilf(currentSize.width())), static_cast<int>(ceilf(currentSize.height()))); // As last resort, use CSS default intrinsic size. return IntSize(300, 150); }
IntSize SVGImage::containerSize() const { if (!m_page) return IntSize(); Frame* frame = m_page->mainFrame(); SVGSVGElement* rootElement = toSVGDocument(frame->document())->rootElement(); if (!rootElement) return IntSize(); RenderSVGRoot* renderer = toRenderSVGRoot(rootElement->renderer()); if (!renderer) return IntSize(); // If a container size is available it has precedence. IntSize containerSize = renderer->containerSize(); if (!containerSize.isEmpty()) return containerSize; // Assure that a container size is always given for a non-identity zoom level. ASSERT(renderer->style()->effectiveZoom() == 1); FloatSize currentSize; if (rootElement->intrinsicWidth().isFixed() && rootElement->intrinsicHeight().isFixed()) currentSize = rootElement->currentViewportSize(); else currentSize = rootElement->currentViewBoxRect().size(); if (!currentSize.isEmpty()) return IntSize(static_cast<int>(ceilf(currentSize.width())), static_cast<int>(ceilf(currentSize.height()))); // As last resort, use CSS default intrinsic size. return IntSize(300, 150); }
void RenderReplaced::computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio) const { intrinsicSize = FloatSize(intrinsicLogicalWidth().toFloat(), intrinsicLogicalHeight().toFloat()); // Figure out if we need to compute an intrinsic ratio. if (intrinsicSize.isEmpty() || !rendererHasAspectRatio(this)) return; intrinsicRatio = intrinsicSize.width() / intrinsicSize.height(); }
IntSize SVGImage::containerSize() const { SVGSVGElement* rootElement = svgRootElement(m_page.get()); if (!rootElement) return IntSize(); LayoutSVGRoot* layoutObject = toLayoutSVGRoot(rootElement->layoutObject()); if (!layoutObject) return IntSize(); // If a container size is available it has precedence. IntSize containerSize = layoutObject->containerSize(); if (!containerSize.isEmpty()) return containerSize; // Assure that a container size is always given for a non-identity zoom level. ASSERT(layoutObject->style()->effectiveZoom() == 1); FloatSize intrinsicSize; double intrinsicRatio = 0; layoutObject->computeIntrinsicRatioInformation(intrinsicSize, intrinsicRatio); if (intrinsicSize.isEmpty() && intrinsicRatio) { if (!intrinsicSize.width() && intrinsicSize.height()) intrinsicSize.setWidth(intrinsicSize.height() * intrinsicRatio); else if (intrinsicSize.width() && !intrinsicSize.height()) intrinsicSize.setHeight(intrinsicSize.width() / intrinsicRatio); } // TODO(davve): In order to maintain aspect ratio the intrinsic // size is faked from the viewBox as a last resort. This may cause // unwanted side effects. Preferably we should be able to signal // the intrinsic ratio in another way. if (intrinsicSize.isEmpty()) intrinsicSize = rootElement->currentViewBoxRect().size(); if (!intrinsicSize.isEmpty()) return expandedIntSize(intrinsicSize); // As last resort, use CSS replaced element fallback size. return IntSize(300, 150); }
void PageViewportController::didChangeViewportSize(const FloatSize& newSize) { if (newSize.isEmpty()) return; m_viewportSize = newSize; // Let the WebProcess know about the new viewport size, so that // it can resize the content accordingly. m_webPageProxy->setViewportSize(roundedIntSize(newSize)); }
FloatSize ImageBuffer::clampedSize(const FloatSize& size, FloatSize& scale) { if (size.isEmpty()) return size; FloatSize clampedSize = ImageBuffer::clampedSize(size); scale = FloatSize(clampedSize.width() / size.width(), clampedSize.height() / size.height()); ASSERT(!sizeNeedsClamping(clampedSize)); ASSERT(!sizeNeedsClamping(size, scale)); return clampedSize; }
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 RenderReplaced::computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio) const { // If there's an embeddedContentBox() of a remote, referenced document available, this code-path should never be used. ASSERT(!embeddedContentBox()); intrinsicSize = FloatSize(intrinsicLogicalWidth(), intrinsicLogicalHeight()); // Figure out if we need to compute an intrinsic ratio. if (intrinsicSize.isEmpty() || !hasAspectRatio()) return; intrinsicRatio = intrinsicSize.width() / intrinsicSize.height(); }
static inline IntSize resolveAgainstIntrinsicWidthOrHeightAndRatio(const IntSize& size, const FloatSize& intrinsicRatio, int useWidth, int useHeight) { if (intrinsicRatio.isEmpty()) { if (useWidth) return IntSize(useWidth, size.height()); return IntSize(size.width(), useHeight); } if (useWidth) return IntSize(useWidth, resolveHeightForRatio(useWidth, intrinsicRatio)); return IntSize(resolveWidthForRatio(useHeight, intrinsicRatio), useHeight); }
void LayoutSVGRoot::computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio) const { // https://www.w3.org/TR/SVG/coords.html#IntrinsicSizing intrinsicSize = calculateIntrinsicSize(); if (!isHorizontalWritingMode()) intrinsicSize = intrinsicSize.transposedSize(); if (!intrinsicSize.isEmpty()) { intrinsicRatio = intrinsicSize.width() / static_cast<double>(intrinsicSize.height()); } else { SVGSVGElement* svg = toSVGSVGElement(node()); ASSERT(svg); FloatSize viewBoxSize = svg->viewBox()->currentValue()->value().size(); if (!viewBoxSize.isEmpty()) { // The viewBox can only yield an intrinsic ratio, not an intrinsic size. intrinsicRatio = viewBoxSize.width() / static_cast<double>(viewBoxSize.height()); if (!isHorizontalWritingMode()) intrinsicRatio = 1 / intrinsicRatio; } } }
void SVGImage::computeIntrinsicDimensions(Length& intrinsicWidth, Length& intrinsicHeight, FloatSize& intrinsicRatio) { SVGSVGElement* rootElement = this->rootElement(); if (!rootElement) return; intrinsicWidth = rootElement->intrinsicWidth(); intrinsicHeight = rootElement->intrinsicHeight(); if (rootElement->preserveAspectRatio().align() == SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE) return; intrinsicRatio = rootElement->viewBox().size(); if (intrinsicRatio.isEmpty() && intrinsicWidth.isFixed() && intrinsicHeight.isFixed()) intrinsicRatio = FloatSize(floatValueForLength(intrinsicWidth, 0), floatValueForLength(intrinsicHeight, 0)); }
FloatPoint Widget::convertFromContainingWindow(const FloatPoint& windowPoint) const { // Widgets / windows are required to be IntPoint aligned, but we may need to convert // FloatPoint values within them (eg. for event co-ordinates). IntPoint flooredPoint = flooredIntPoint(windowPoint); FloatPoint parentPoint = this->convertFromContainingWindow(flooredPoint); FloatSize windowFraction = windowPoint - flooredPoint; // Use linear interpolation handle any fractional value (eg. for iframes subject to a transform // beyond just a simple translation). // FIXME: Add FloatPoint variants of all co-ordinate space conversion APIs. if (!windowFraction.isEmpty()) { const int kFactor = 1000; IntPoint parentLineEnd = this->convertFromContainingWindow(flooredPoint + roundedIntSize(windowFraction.scaledBy(kFactor))); FloatSize parentFraction = (parentLineEnd - parentPoint).scaledBy(1.0f / kFactor); parentPoint.move(parentFraction); } return parentPoint; }
void SVGImage::computeIntrinsicDimensions(Length& intrinsicWidth, Length& intrinsicHeight, FloatSize& intrinsicRatio) { if (!m_page) return; Frame* frame = m_page->mainFrame(); SVGSVGElement* rootElement = static_cast<SVGDocument*>(frame->document())->rootElement(); if (!rootElement) return; intrinsicWidth = rootElement->intrinsicWidth(); intrinsicHeight = rootElement->intrinsicHeight(); if (rootElement->preserveAspectRatio().align() == SVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE) return; intrinsicRatio = rootElement->viewBox().size(); if (intrinsicRatio.isEmpty() && intrinsicWidth.isFixed() && intrinsicHeight.isFixed()) intrinsicRatio = FloatSize(intrinsicWidth.calcFloatValue(0), intrinsicHeight.calcFloatValue(0)); }
void RenderImage::computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio, bool& isPercentageIntrinsicSize) const { RenderReplaced::computeIntrinsicRatioInformation(intrinsicSize, intrinsicRatio, isPercentageIntrinsicSize); // Our intrinsicSize is empty if we're rendering generated images with relative width/height. Figure out the right intrinsic size to use. if (intrinsicSize.isEmpty() && (m_imageResource->imageHasRelativeWidth() || m_imageResource->imageHasRelativeHeight())) { RenderObject* containingBlock = isOutOfFlowPositioned() ? container() : this->containingBlock(); if (containingBlock->isBox()) { RenderBox* box = toRenderBox(containingBlock); intrinsicSize.setWidth(box->availableLogicalWidth()); intrinsicSize.setHeight(box->availableLogicalHeight(IncludeMarginBorderPadding)); } } // Don't compute an intrinsic ratio to preserve historical WebKit behavior if we're painting alt text and/or a broken image. if (m_imageResource && m_imageResource->errorOccurred()) { intrinsicRatio = 1; return; } }
void RenderReplaced::computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio, bool& isPercentageIntrinsicSize) const { // If there's an embeddedContentBox() of a remote, referenced document available, this code-path should never be used. ASSERT(!embeddedContentBox()); isPercentageIntrinsicSize = false; intrinsicSize = FloatSize(intrinsicLogicalWidth(), intrinsicLogicalHeight()); // Figure out if we need to compute an intrinsic ratio. if (intrinsicSize.isEmpty() || !rendererHasAspectRatio(this)) return; intrinsicRatio = intrinsicSize.width() / intrinsicSize.height(); if (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 - which include zoom! intrinsicSize.setWidth(RenderBox::computeReplacedLogicalHeight() * intrinsicLogicalWidth() / intrinsicLogicalHeight()); intrinsicSize.setHeight(RenderBox::computeReplacedLogicalWidth() * intrinsicLogicalHeight() / intrinsicLogicalWidth()); } }
void LayoutImage::computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio) const { LayoutReplaced::computeIntrinsicRatioInformation(intrinsicSize, intrinsicRatio); // Our intrinsicSize is empty if we're laying out generated images with relative width/height. Figure out the right intrinsic size to use. if (intrinsicSize.isEmpty() && (m_imageResource->imageHasRelativeWidth() || m_imageResource->imageHasRelativeHeight())) { LayoutObject* containingBlock = isOutOfFlowPositioned() ? container() : this->containingBlock(); if (containingBlock->isBox()) { LayoutBox* box = toLayoutBox(containingBlock); intrinsicSize.setWidth(box->availableLogicalWidth().toFloat()); intrinsicSize.setHeight(box->availableLogicalHeight(IncludeMarginBorderPadding).toFloat()); } } // Don't compute an intrinsic ratio to preserve historical WebKit behavior if we're painting alt text and/or a broken image. // Video is excluded from this behavior because video elements have a default aspect ratio that a failed poster image load should not override. if (m_imageResource && m_imageResource->errorOccurred() && !isVideo()) { intrinsicRatio = 1; return; } }
FloatSize SVGSVGElement::currentViewportSize() const { FloatSize viewportSize; if (renderer()) { if (is<RenderSVGRoot>(*renderer())) { auto& root = downcast<RenderSVGRoot>(*renderer()); viewportSize = root.contentBoxRect().size() / root.style().effectiveZoom(); } else viewportSize = downcast<RenderSVGViewportContainer>(*renderer()).viewport().size(); } if (!viewportSize.isEmpty()) return viewportSize; if (!(hasIntrinsicWidth() && hasIntrinsicHeight())) return { }; return FloatSize(floatValueForLength(intrinsicWidth(), 0), floatValueForLength(intrinsicHeight(), 0)); }
IntSize RenderBoxModelObject::calculateImageIntrinsicDimensions(StyleImage* image, const IntSize& positioningAreaSize, ScaleByEffectiveZoomOrNot shouldScaleOrNot) const { // A generated image without a fixed size, will always return the container size as intrinsic size. if (image->isGeneratedImage() && image->usesImageContainerSize()) return IntSize(positioningAreaSize.width(), positioningAreaSize.height()); Length intrinsicWidth; Length intrinsicHeight; FloatSize intrinsicRatio; image->computeIntrinsicDimensions(this, intrinsicWidth, intrinsicHeight, intrinsicRatio); ASSERT(!intrinsicWidth.isPercent()); ASSERT(!intrinsicHeight.isPercent()); IntSize resolvedSize(intrinsicWidth.value(), intrinsicHeight.value()); IntSize minimumSize(resolvedSize.width() > 0 ? 1 : 0, resolvedSize.height() > 0 ? 1 : 0); if (shouldScaleOrNot == ScaleByEffectiveZoom) resolvedSize.scale(style()->effectiveZoom()); resolvedSize.clampToMinimumSize(minimumSize); if (!resolvedSize.isEmpty()) return resolvedSize; // If the image has one of either an intrinsic width or an intrinsic height: // * and an intrinsic aspect ratio, then the missing dimension is calculated from the given dimension and the ratio. // * and no intrinsic aspect ratio, then the missing dimension is assumed to be the size of the rectangle that // establishes the coordinate system for the 'background-position' property. if (resolvedSize.width() > 0 || resolvedSize.height() > 0) return resolveAgainstIntrinsicWidthOrHeightAndRatio(positioningAreaSize, intrinsicRatio, resolvedSize.width(), resolvedSize.height()); // If the image has no intrinsic dimensions and has an intrinsic ratio the dimensions must be assumed to be the // largest dimensions at that ratio such that neither dimension exceeds the dimensions of the rectangle that // establishes the coordinate system for the 'background-position' property. if (!intrinsicRatio.isEmpty()) return resolveAgainstIntrinsicRatio(positioningAreaSize, intrinsicRatio); // If the image has no intrinsic ratio either, then the dimensions must be assumed to be the rectangle that // establishes the coordinate system for the 'background-position' property. return positioningAreaSize; }
bool SVGLengthContext::determineViewport(FloatSize& viewportSize) const { if (!m_context) return false; // Root <svg> element lengths are resolved against the top level viewport. if (m_context->isOutermostSVGSVGElement()) { viewportSize = toSVGSVGElement(m_context)->currentViewportSize(); return true; } // Take size from nearest viewport element. SVGElement* viewportElement = m_context->viewportElement(); if (!isSVGSVGElement(viewportElement)) return false; const SVGSVGElement& svg = toSVGSVGElement(*viewportElement); viewportSize = svg.currentViewBoxRect().size(); if (viewportSize.isEmpty()) viewportSize = svg.currentViewportSize(); return true; }
RefPtr<Image> CSSFilterImageValue::image(RenderElement* renderer, const FloatSize& size) { if (size.isEmpty()) return nullptr; // FIXME: Skip Content Security Policy check when filter is applied to an element in a user agent shadow tree. // See <https://bugs.webkit.org/show_bug.cgi?id=146663>. ResourceLoaderOptions options = CachedResourceLoader::defaultCachedResourceOptions(); CachedResourceLoader& cachedResourceLoader = renderer->document().cachedResourceLoader(); CachedImage* cachedImage = cachedImageForCSSValue(m_imageValue.get(), cachedResourceLoader, options); if (!cachedImage) return Image::nullImage(); Image* image = cachedImage->imageForRenderer(renderer); if (!image) return Image::nullImage(); // Transform Image into ImageBuffer. std::unique_ptr<ImageBuffer> texture = ImageBuffer::create(size); if (!texture) return Image::nullImage(); FloatRect imageRect = FloatRect(FloatPoint(), size); texture->context().drawImage(image, ColorSpaceDeviceRGB, imageRect); RefPtr<FilterEffectRenderer> filterRenderer = FilterEffectRenderer::create(); filterRenderer->setSourceImage(WTF::move(texture)); filterRenderer->setSourceImageRect(imageRect); filterRenderer->setFilterRegion(imageRect); if (!filterRenderer->build(renderer, m_filterOperations, FilterFunction)) return Image::nullImage(); filterRenderer->apply(); m_generatedImage = filterRenderer->output()->copyImage(); return m_generatedImage.release(); }
PassRefPtr<Image> CSSCrossfadeValue::image(RenderElement* renderer, const FloatSize& size) { if (size.isEmpty()) return nullptr; CachedResourceLoader& cachedResourceLoader = renderer->document().cachedResourceLoader(); CachedImage* cachedFromImage = cachedImageForCSSValue(m_fromValue.get(), cachedResourceLoader); CachedImage* cachedToImage = cachedImageForCSSValue(m_toValue.get(), cachedResourceLoader); if (!cachedFromImage || !cachedToImage) return Image::nullImage(); Image* fromImage = cachedFromImage->imageForRenderer(renderer); Image* toImage = cachedToImage->imageForRenderer(renderer); if (!fromImage || !toImage) return Image::nullImage(); m_generatedImage = CrossfadeGeneratedImage::create(fromImage, toImage, m_percentageValue->getFloatValue(), fixedSize(renderer), size); return m_generatedImage.release(); }
static void drawGDIGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) { Color fillColor = graphicsContext->fillColor(); bool drawIntoBitmap = false; int drawingMode = graphicsContext->textDrawingMode(); if (drawingMode == cTextFill) { if (!fillColor.alpha()) return; drawIntoBitmap = fillColor.alpha() != 255 || graphicsContext->inTransparencyLayer(); if (!drawIntoBitmap) { FloatSize size; float blur; Color color; graphicsContext->getShadow(size, blur, color); drawIntoBitmap = !size.isEmpty() || blur; } } // We have to convert CG's two-dimensional floating point advances to just horizontal integer advances. Vector<int, 2048> gdiAdvances; int totalWidth = 0; for (int i = 0; i < numGlyphs; i++) { gdiAdvances.append(lroundf(glyphBuffer.advanceAt(from + i))); totalWidth += gdiAdvances[i]; } HDC hdc = 0; OwnPtr<GraphicsContext::WindowsBitmap> bitmap; IntRect textRect; if (!drawIntoBitmap) hdc = graphicsContext->getWindowsContext(textRect, true, false); if (!hdc) { drawIntoBitmap = true; // We put slop into this rect, since glyphs can overflow the ascent/descent bounds and the left/right edges. // FIXME: Can get glyphs' optical bounds (even from CG) to get this right. int lineGap = font->lineGap(); textRect = IntRect(point.x() - (font->ascent() + font->descent()) / 2, point.y() - font->ascent() - lineGap, totalWidth + font->ascent() + font->descent(), font->lineSpacing()); bitmap.set(graphicsContext->createWindowsBitmap(textRect.size())); memset(bitmap->buffer(), 255, bitmap->bufferLength()); hdc = bitmap->hdc(); XFORM xform; xform.eM11 = 1.0f; xform.eM12 = 0.0f; xform.eM21 = 0.0f; xform.eM22 = 1.0f; xform.eDx = -textRect.x(); xform.eDy = -textRect.y(); SetWorldTransform(hdc, &xform); } SelectObject(hdc, font->platformData().hfont()); // Set the correct color. if (drawIntoBitmap) SetTextColor(hdc, RGB(0, 0, 0)); else SetTextColor(hdc, RGB(fillColor.red(), fillColor.green(), fillColor.blue())); SetBkMode(hdc, TRANSPARENT); SetTextAlign(hdc, TA_LEFT | TA_BASELINE); // Uniscribe gives us offsets to help refine the positioning of combining glyphs. FloatSize translation = glyphBuffer.offsetAt(from); if (translation.width() || translation.height()) { XFORM xform; xform.eM11 = 1.0; xform.eM12 = 0; xform.eM21 = 0; xform.eM22 = 1.0; xform.eDx = translation.width(); xform.eDy = translation.height(); ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY); } if (drawingMode == cTextFill) { XFORM xform; xform.eM11 = 1.0; xform.eM12 = 0; xform.eM21 = font->platformData().syntheticOblique() ? -tanf(syntheticObliqueAngle * piFloat / 180.0f) : 0; xform.eM22 = 1.0; xform.eDx = point.x(); xform.eDy = point.y(); ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY); ExtTextOut(hdc, 0, 0, ETO_GLYPH_INDEX, 0, reinterpret_cast<const WCHAR*>(glyphBuffer.glyphs(from)), numGlyphs, gdiAdvances.data()); if (font->syntheticBoldOffset()) { xform.eM21 = 0; xform.eDx = font->syntheticBoldOffset(); xform.eDy = 0; ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY); ExtTextOut(hdc, 0, 0, ETO_GLYPH_INDEX, 0, reinterpret_cast<const WCHAR*>(glyphBuffer.glyphs(from)), numGlyphs, gdiAdvances.data()); } } else { XFORM xform; GetWorldTransform(hdc, &xform); AffineTransform hdcTransform(xform.eM11, xform.eM21, xform.eM12, xform.eM22, xform.eDx, xform.eDy); CGAffineTransform initialGlyphTransform = hdcTransform.isInvertible() ? hdcTransform.inverse() : CGAffineTransformIdentity; if (font->platformData().syntheticOblique()) initialGlyphTransform = CGAffineTransformConcat(initialGlyphTransform, CGAffineTransformMake(1, 0, tanf(syntheticObliqueAngle * piFloat / 180.0f), 1, 0, 0)); initialGlyphTransform.tx = 0; initialGlyphTransform.ty = 0; CGContextRef cgContext = graphicsContext->platformContext(); CGContextSaveGState(cgContext); BOOL fontSmoothingEnabled = false; SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &fontSmoothingEnabled, 0); CGContextSetShouldAntialias(cgContext, fontSmoothingEnabled); CGContextScaleCTM(cgContext, 1.0, -1.0); CGContextTranslateCTM(cgContext, point.x() + glyphBuffer.offsetAt(from).width(), -(point.y() + glyphBuffer.offsetAt(from).height())); for (unsigned i = 0; i < numGlyphs; ++i) { RetainPtr<CGPathRef> glyphPath(AdoptCF, createPathForGlyph(hdc, glyphBuffer.glyphAt(from + i))); CGContextSaveGState(cgContext); CGContextConcatCTM(cgContext, initialGlyphTransform); if (drawingMode & cTextFill) { CGContextAddPath(cgContext, glyphPath.get()); CGContextFillPath(cgContext); if (font->syntheticBoldOffset()) { CGContextTranslateCTM(cgContext, font->syntheticBoldOffset(), 0); CGContextAddPath(cgContext, glyphPath.get()); CGContextFillPath(cgContext); CGContextTranslateCTM(cgContext, -font->syntheticBoldOffset(), 0); } } if (drawingMode & cTextStroke) { CGContextAddPath(cgContext, glyphPath.get()); CGContextStrokePath(cgContext); if (font->syntheticBoldOffset()) { CGContextTranslateCTM(cgContext, font->syntheticBoldOffset(), 0); CGContextAddPath(cgContext, glyphPath.get()); CGContextStrokePath(cgContext); CGContextTranslateCTM(cgContext, -font->syntheticBoldOffset(), 0); } } CGContextRestoreGState(cgContext); CGContextTranslateCTM(cgContext, gdiAdvances[i], 0); } CGContextRestoreGState(cgContext); } if (drawIntoBitmap) { UInt8* buffer = bitmap->buffer(); unsigned bufferLength = bitmap->bufferLength(); for (unsigned i = 0; i < bufferLength; i += 4) { // Use green, which is always in the middle. UInt8 alpha = (255 - buffer[i + 1]) * fillColor.alpha() / 255; buffer[i] = fillColor.blue(); buffer[i + 1] = fillColor.green(); buffer[i + 2] = fillColor.red(); buffer[i + 3] = alpha; } graphicsContext->drawWindowsBitmap(bitmap.get(), textRect.topLeft()); } else graphicsContext->releaseWindowsContext(hdc, textRect, true, false); }