Exemple #1
0
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());
    }
}
Exemple #3
0
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;
}
Exemple #4
0
bool ImageBuffer::sizeNeedsClamping(const FloatSize& size)
{
    if (size.isEmpty())
        return false;

    return floorf(size.height()) * floorf(size.width()) > MaxClampedArea;
}
Exemple #5
0
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;
}
Exemple #8
0
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);
}
Exemple #10
0
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();
}
Exemple #11
0
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));
}
Exemple #13
0
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;
}
Exemple #14
0
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());
    }
}
Exemple #15
0
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;
        }
    }
}
Exemple #18
0
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));
}
Exemple #19
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;
}
Exemple #20
0
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));
}
Exemple #21
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;
    }
}
Exemple #22
0
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());
    }
}
Exemple #23
0
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;
    }
}
Exemple #24
0
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();
}
Exemple #29
0
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);
}