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 = flooredIntSize(intrinsicSize); // FIXME: This introduces precision errors. We should convert m_intrinsicSize to be a float.

        if (!isHorizontalWritingMode()) {
            if (intrinsicRatio)
                intrinsicRatio = 1 / intrinsicRatio;
            intrinsicSize = intrinsicSize.transposedSize();
        }
    } else {
        computeIntrinsicRatioInformation(intrinsicSize, intrinsicRatio, isPercentageIntrinsicSize);
        if (intrinsicRatio) {
            ASSERT(!isPercentageIntrinsicSize);
            if (!intrinsicSize.isEmpty())
                m_intrinsicSize = isHorizontalWritingMode() ? flooredIntSize(intrinsicSize) : flooredIntSize(intrinsicSize).transposedSize(); // FIXME: This introduces precision errors. We should convert m_intrinsicSize to be a float.
        }
    }

    // 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());
    }
}
Example #2
0
std::unique_ptr<Shape> ShapeOutsideInfo::createShapeForImage(
    StyleImage* styleImage,
    float shapeImageThreshold,
    WritingMode writingMode,
    float margin) const {
  const LayoutSize& imageSize =
      styleImage->imageSize(m_layoutBox, m_layoutBox.style()->effectiveZoom(),
                            m_referenceBoxLogicalSize);

  const LayoutRect& marginRect =
      getShapeImageMarginRect(m_layoutBox, m_referenceBoxLogicalSize);
  const LayoutRect& imageRect =
      (m_layoutBox.isLayoutImage())
          ? toLayoutImage(m_layoutBox).replacedContentRect()
          : LayoutRect(LayoutPoint(), imageSize);

  if (!isValidRasterShapeRect(marginRect) ||
      !isValidRasterShapeRect(imageRect)) {
    m_layoutBox.document().addConsoleMessage(
        ConsoleMessage::create(RenderingMessageSource, ErrorMessageLevel,
                               "The shape-outside image is too large."));
    return Shape::createEmptyRasterShape(writingMode, margin);
  }

  ASSERT(!styleImage->isPendingImage());
  RefPtr<Image> image =
      styleImage->image(m_layoutBox, flooredIntSize(imageSize),
                        m_layoutBox.style()->effectiveZoom());

  return Shape::createRasterShape(image.get(), shapeImageThreshold, imageRect,
                                  marginRect, writingMode, margin);
}
IntRect LayoutListMarker::getRelativeMarkerRect() const
{
    if (isImage()) {
        IntSize imageSize = flooredIntSize(imageBulletSize());
        return IntRect(0, 0, imageSize.width(), imageSize.height());
    }

    IntRect relativeRect;
    switch (listStyleCategory()) {
    case ListStyleCategory::None:
        return IntRect();
    case ListStyleCategory::Symbol: {
        // TODO(wkorman): Review and clean up/document the calculations below.
        // http://crbug.com/543193
        const FontMetrics& fontMetrics = style()->fontMetrics();
        int ascent = fontMetrics.ascent();
        int bulletWidth = (ascent * 2 / 3 + 1) / 2;
        relativeRect = IntRect(1, 3 * (ascent - ascent * 2 / 3) / 2, bulletWidth, bulletWidth);
        }
        break;
    case ListStyleCategory::Language:
        relativeRect = IntRect(0, 0, getWidthOfTextWithSuffix(), style()->font().fontMetrics().height());
        break;
    }

    if (!style()->isHorizontalWritingMode()) {
        relativeRect = relativeRect.transposedRect();
        relativeRect.setX(size().width() - relativeRect.x() - relativeRect.width());
    }

    return relativeRect;
}
Example #4
0
LayoutScrollbar::LayoutScrollbar(ScrollableArea* scrollableArea,
                                 ScrollbarOrientation orientation,
                                 Node* ownerNode,
                                 LocalFrame* owningFrame)
    : Scrollbar(scrollableArea,
                orientation,
                RegularScrollbar,
                nullptr,
                LayoutScrollbarTheme::layoutScrollbarTheme()),
      m_owner(ownerNode),
      m_owningFrame(owningFrame) {
  ASSERT(ownerNode || owningFrame);

  // FIXME: We need to do this because LayoutScrollbar::styleChanged is called
  // as soon as the scrollbar is created.

  // Update the scrollbar size.
  IntRect rect(0, 0, 0, 0);
  updateScrollbarPart(ScrollbarBGPart);
  if (LayoutScrollbarPart* part = m_parts.get(ScrollbarBGPart)) {
    part->layout();
    rect.setSize(flooredIntSize(part->size()));
  } else if (this->orientation() == HorizontalScrollbar) {
    rect.setWidth(this->width());
  } else {
    rect.setHeight(this->height());
  }

  setFrameRect(rect);
}
Example #5
0
void StyleGeneratedImage::computeIntrinsicDimensions(const RenderObject* renderer, Length& intrinsicWidth, Length& intrinsicHeight, FloatSize& intrinsicRatio)
{
    // At a zoom level of 1 the image is guaranteed to have an integer size.
    IntSize size = flooredIntSize(imageSize(renderer, 1));
    intrinsicWidth = Length(size.width(), Fixed);
    intrinsicHeight = Length(size.height(), Fixed);
    intrinsicRatio = size;
}
Example #6
0
bool RasterShape::firstIncludedIntervalLogicalTop(LayoutUnit minLogicalIntervalTop, const LayoutSize& minLogicalIntervalSize, LayoutUnit& result) const
{
    const RasterShapeIntervals& intervals = paddingIntervals();
    if (intervals.isEmpty())
        return false;

    return intervals.firstIncludedIntervalY(minLogicalIntervalTop.floor(), flooredIntSize(minLogicalIntervalSize), result);
}
Example #7
0
void GraphicsLayer::setSize(const FloatSize& size)
{
    // We are receiving negative sizes here that cause assertions to fail in the compositor. Clamp them to 0 to
    // avoid those assertions.
    // FIXME: This should be an ASSERT instead, as negative sizes should not exist in WebCore.
    FloatSize clampedSize = size;
    if (clampedSize.width() < 0 || clampedSize.height() < 0)
        clampedSize = FloatSize();

    if (clampedSize == m_size)
        return;

    m_size = clampedSize;

    m_layer->layer()->setBounds(flooredIntSize(m_size));
    // Note that we don't resize m_contentsLayer. It's up the caller to do that.
}
Example #8
0
bool RasterShape::firstIncludedIntervalLogicalTop(LayoutUnit minLogicalIntervalTop, const LayoutSize& minLogicalIntervalSize, LayoutUnit& result) const
{
    float minIntervalTop = minLogicalIntervalTop;
    float minIntervalHeight = minLogicalIntervalSize.height();
    float minIntervalWidth = minLogicalIntervalSize.width();

    const RasterShapeIntervals& intervals = paddingIntervals();
    if (intervals.isEmpty() || minIntervalWidth > intervals.bounds().width())
        return false;

    float minY = std::max<float>(intervals.bounds().y(), minIntervalTop);
    float maxY = minY + minIntervalHeight;
    if (maxY > intervals.bounds().maxY())
        return false;

    return intervals.firstIncludedIntervalY(minY, flooredIntSize(minLogicalIntervalSize), result);
}
Example #9
0
IntPoint VisualViewport::clampDocumentOffsetAtScale(const IntPoint& offset,
                                                    float scale) {
  if (!mainFrame() || !mainFrame()->view())
    return IntPoint();

  FrameView* view = mainFrame()->view();

  FloatSize scaledSize(m_size);
  scaledSize.scale(1 / scale);

  IntSize visualViewportMax =
      flooredIntSize(FloatSize(contentsSize()) - scaledSize);
  IntSize max = view->maximumScrollOffsetInt() + visualViewportMax;
  IntSize min =
      view->minimumScrollOffsetInt();  // VisualViewportMin should be (0, 0)

  IntSize clamped = toIntSize(offset);
  clamped = clamped.shrunkTo(max);
  clamped = clamped.expandedTo(min);
  return IntPoint(clamped);
}
DoublePoint VisualViewport::maximumScrollPositionDouble() const
{
    if (!mainFrame())
        return IntPoint();

    // FIXME: We probably shouldn't be storing the bounds in a float. crbug.com/422331.
    FloatSize frameViewSize(contentsSize());

    if (m_topControlsAdjustment) {
        float minScale = frameHost().pageScaleConstraintsSet().finalConstraints().minimumScale;
        frameViewSize.expand(0, m_topControlsAdjustment / minScale);
    }

    frameViewSize.scale(m_scale);
    frameViewSize = flooredIntSize(frameViewSize);

    FloatSize viewportSize(m_size);
    viewportSize.expand(0, m_topControlsAdjustment);

    FloatSize maxPosition = frameViewSize - viewportSize;
    maxPosition.scale(1 / m_scale);
    return DoublePoint(maxPosition);
}
Example #11
0
ScrollOffset VisualViewport::maximumScrollOffset() const {
  if (!mainFrame())
    return ScrollOffset();

  // TODO(bokan): We probably shouldn't be storing the bounds in a float.
  // crbug.com/470718.
  FloatSize frameViewSize(contentsSize());

  if (m_browserControlsAdjustment) {
    float minScale =
        frameHost().pageScaleConstraintsSet().finalConstraints().minimumScale;
    frameViewSize.expand(0, m_browserControlsAdjustment / minScale);
  }

  frameViewSize.scale(m_scale);
  frameViewSize = FloatSize(flooredIntSize(frameViewSize));

  FloatSize viewportSize(m_size);
  viewportSize.expand(0, ceilf(m_browserControlsAdjustment));

  FloatSize maxPosition = frameViewSize - viewportSize;
  maxPosition.scale(1 / m_scale);
  return ScrollOffset(maxPosition);
}
Example #12
0
 IntRect visibleContentRect(IncludeScrollbarsInRect) const override {
   FloatSize size(m_viewportSize);
   size.scale(1 / m_scale);
   return IntRect(IntPoint(flooredIntSize(getScrollOffset())),
                  expandedIntSize(size));
 }
IntSize PageScaleConstraintsSet::layoutSize() const
{
    return flooredIntSize(computeConstraintsStack().layoutSize);
}
Example #14
0
 IntSize scrollOffsetInt() const override {
   return flooredIntSize(m_scrollOffset);
 }
Example #15
0
 IntSize maximumScrollOffsetInt() const override {
   return flooredIntSize(maximumScrollOffset());
 }
Example #16
0
IntSize RootFrameViewport::scrollOffsetInt() const {
  return flooredIntSize(getScrollOffset());
}
void ContextMenuClientImpl::showContextMenu(const WebCore::ContextMenu* defaultMenu)
{
    // Displaying the context menu in this function is a big hack as we don't
    // have context, i.e. whether this is being invoked via a script or in
    // response to user input (Mouse event WM_RBUTTONDOWN,
    // Keyboard events KeyVK_APPS, Shift+F10). Check if this is being invoked
    // in response to the above input events before popping up the context menu.
    if (!m_webView->contextMenuAllowed())
        return;

    HitTestResult r = m_webView->page()->contextMenuController().hitTestResult();
    LocalFrame* selectedFrame = r.innerNodeFrame();

    WebContextMenuData data;
    IntPoint mousePoint = selectedFrame->view()->contentsToWindow(r.roundedPointInInnerNodeFrame());

    // FIXME(bokan): crbug.com/371902 - We shouldn't be making these scale
    // related coordinate transformatios in an ad hoc way.
    PinchViewport& pinchViewport = selectedFrame->host()->pinchViewport();
    mousePoint -= flooredIntSize(pinchViewport.visibleRect().location());
    mousePoint.scale(m_webView->pageScaleFactor(), m_webView->pageScaleFactor());
    data.mousePosition = mousePoint;

    // Compute edit flags.
    data.editFlags = WebContextMenuData::CanDoNone;
    if (toLocalFrame(m_webView->focusedWebCoreFrame())->editor().canUndo())
        data.editFlags |= WebContextMenuData::CanUndo;
    if (toLocalFrame(m_webView->focusedWebCoreFrame())->editor().canRedo())
        data.editFlags |= WebContextMenuData::CanRedo;
    if (toLocalFrame(m_webView->focusedWebCoreFrame())->editor().canCut())
        data.editFlags |= WebContextMenuData::CanCut;
    if (toLocalFrame(m_webView->focusedWebCoreFrame())->editor().canCopy())
        data.editFlags |= WebContextMenuData::CanCopy;
    if (toLocalFrame(m_webView->focusedWebCoreFrame())->editor().canPaste())
        data.editFlags |= WebContextMenuData::CanPaste;
    if (toLocalFrame(m_webView->focusedWebCoreFrame())->editor().canDelete())
        data.editFlags |= WebContextMenuData::CanDelete;
    // We can always select all...
    data.editFlags |= WebContextMenuData::CanSelectAll;
    data.editFlags |= WebContextMenuData::CanTranslate;

    // Links, Images, Media tags, and Image/Media-Links take preference over
    // all else.
    data.linkURL = r.absoluteLinkURL();

    if (isHTMLCanvasElement(r.innerNonSharedNode())) {
        data.mediaType = WebContextMenuData::MediaTypeCanvas;
    } else if (!r.absoluteImageURL().isEmpty()) {
        data.srcURL = r.absoluteImageURL();
        data.mediaType = WebContextMenuData::MediaTypeImage;
        data.mediaFlags |= WebContextMenuData::MediaCanPrint;
    } else if (!r.absoluteMediaURL().isEmpty()) {
        data.srcURL = r.absoluteMediaURL();

        // We know that if absoluteMediaURL() is not empty, then this
        // is a media element.
        HTMLMediaElement* mediaElement = toHTMLMediaElement(r.innerNonSharedNode());
        if (isHTMLVideoElement(*mediaElement))
            data.mediaType = WebContextMenuData::MediaTypeVideo;
        else if (isHTMLAudioElement(*mediaElement))
            data.mediaType = WebContextMenuData::MediaTypeAudio;

        if (mediaElement->error())
            data.mediaFlags |= WebContextMenuData::MediaInError;
        if (mediaElement->paused())
            data.mediaFlags |= WebContextMenuData::MediaPaused;
        if (mediaElement->muted())
            data.mediaFlags |= WebContextMenuData::MediaMuted;
        if (mediaElement->loop())
            data.mediaFlags |= WebContextMenuData::MediaLoop;
        if (mediaElement->supportsSave())
            data.mediaFlags |= WebContextMenuData::MediaCanSave;
        if (mediaElement->hasAudio())
            data.mediaFlags |= WebContextMenuData::MediaHasAudio;
        // Media controls can be toggled only for video player. If we toggle
        // controls for audio then the player disappears, and there is no way to
        // return it back. Don't set this bit for fullscreen video, since
        // toggling is ignored in that case.
        if (mediaElement->hasVideo() && !mediaElement->isFullscreen())
            data.mediaFlags |= WebContextMenuData::MediaCanToggleControls;
        if (mediaElement->controls())
            data.mediaFlags |= WebContextMenuData::MediaControls;
    } else if (isHTMLObjectElement(*r.innerNonSharedNode()) || isHTMLEmbedElement(*r.innerNonSharedNode())) {
        RenderObject* object = r.innerNonSharedNode()->renderer();
        if (object && object->isWidget()) {
            Widget* widget = toRenderWidget(object)->widget();
            if (widget && widget->isPluginContainer()) {
                data.mediaType = WebContextMenuData::MediaTypePlugin;
                WebPluginContainerImpl* plugin = toWebPluginContainerImpl(widget);
                WebString text = plugin->plugin()->selectionAsText();
                if (!text.isEmpty()) {
                    data.selectedText = text;
                    data.editFlags |= WebContextMenuData::CanCopy;
                }
                data.editFlags &= ~WebContextMenuData::CanTranslate;
                data.linkURL = plugin->plugin()->linkAtPosition(data.mousePosition);
                if (plugin->plugin()->supportsPaginatedPrint())
                    data.mediaFlags |= WebContextMenuData::MediaCanPrint;

                HTMLPlugInElement* pluginElement = toHTMLPlugInElement(r.innerNonSharedNode());
                data.srcURL = pluginElement->document().completeURL(pluginElement->url());
                data.mediaFlags |= WebContextMenuData::MediaCanSave;

                // Add context menu commands that are supported by the plugin.
                if (plugin->plugin()->canRotateView())
                    data.mediaFlags |= WebContextMenuData::MediaCanRotate;
            }
        }
    }

    // An image can to be null for many reasons, like being blocked, no image
    // data received from server yet.
    data.hasImageContents =
        (data.mediaType == WebContextMenuData::MediaTypeImage)
        && r.image() && !(r.image()->isNull());

    // If it's not a link, an image, a media element, or an image/media link,
    // show a selection menu or a more generic page menu.
    if (selectedFrame->document()->loader())
        data.frameEncoding = selectedFrame->document()->encodingName();

    // Send the frame and page URLs in any case.
    data.pageURL = urlFromFrame(m_webView->mainFrameImpl()->frame());
    if (selectedFrame != m_webView->mainFrameImpl()->frame()) {
        data.frameURL = urlFromFrame(selectedFrame);
        RefPtr<HistoryItem> historyItem = selectedFrame->loader().currentItem();
        if (historyItem)
            data.frameHistoryItem = WebHistoryItem(historyItem);
    }

    if (r.isSelected()) {
        if (!isHTMLInputElement(*r.innerNonSharedNode()) || !toHTMLInputElement(r.innerNonSharedNode())->isPasswordField())
            data.selectedText = selectedFrame->selectedText().stripWhiteSpace();
    }

    if (r.isContentEditable()) {
        data.isEditable = true;

        // When Chrome enables asynchronous spellchecking, its spellchecker adds spelling markers to misspelled
        // words and attaches suggestions to these markers in the background. Therefore, when a user right-clicks
        // a mouse on a word, Chrome just needs to find a spelling marker on the word instead of spellchecking it.
        if (selectedFrame->settings() && selectedFrame->settings()->asynchronousSpellCheckingEnabled()) {
            DocumentMarker marker;
            data.misspelledWord = selectMisspellingAsync(selectedFrame, marker);
            data.misspellingHash = marker.hash();
            if (marker.description().length()) {
                Vector<String> suggestions;
                marker.description().split('\n', suggestions);
                data.dictionarySuggestions = suggestions;
            } else if (m_webView->spellCheckClient()) {
                int misspelledOffset, misspelledLength;
                m_webView->spellCheckClient()->spellCheck(data.misspelledWord, misspelledOffset, misspelledLength, &data.dictionarySuggestions);
            }
        } else {
            data.isSpellCheckingEnabled =
                toLocalFrame(m_webView->focusedWebCoreFrame())->spellChecker().isContinuousSpellCheckingEnabled();
            // Spellchecking might be enabled for the field, but could be disabled on the node.
            if (toLocalFrame(m_webView->focusedWebCoreFrame())->spellChecker().isSpellCheckingEnabledInFocusedNode()) {
                data.misspelledWord = selectMisspelledWord(selectedFrame);
                if (m_webView->spellCheckClient()) {
                    int misspelledOffset, misspelledLength;
                    m_webView->spellCheckClient()->spellCheck(
                        data.misspelledWord, misspelledOffset, misspelledLength,
                        &data.dictionarySuggestions);
                    if (!misspelledLength)
                        data.misspelledWord.reset();
                }
            }
        }
        HTMLFormElement* form = selectedFrame->selection().currentForm();
        if (form && isHTMLInputElement(*r.innerNonSharedNode())) {
            HTMLInputElement& selectedElement = toHTMLInputElement(*r.innerNonSharedNode());
            WebSearchableFormData ws = WebSearchableFormData(WebFormElement(form), WebInputElement(&selectedElement));
            if (ws.url().isValid())
                data.keywordURL = ws.url();
        }
    }

    if (selectedFrame->editor().selectionHasStyle(CSSPropertyDirection, "ltr") != FalseTriState)
        data.writingDirectionLeftToRight |= WebContextMenuData::CheckableMenuItemChecked;
    if (selectedFrame->editor().selectionHasStyle(CSSPropertyDirection, "rtl") != FalseTriState)
        data.writingDirectionRightToLeft |= WebContextMenuData::CheckableMenuItemChecked;

    // Now retrieve the security info.
    DocumentLoader* dl = selectedFrame->loader().documentLoader();
    WebDataSource* ds = WebDataSourceImpl::fromDocumentLoader(dl);
    if (ds)
        data.securityInfo = ds->response().securityInfo();

    data.referrerPolicy = static_cast<WebReferrerPolicy>(selectedFrame->document()->referrerPolicy());

    // Filter out custom menu elements and add them into the data.
    populateCustomMenuItems(defaultMenu, &data);

    // Extract suggested filename for saving file.
    if (isHTMLAnchorElement(r.URLElement())) {
        HTMLAnchorElement* anchor = toHTMLAnchorElement(r.URLElement());
        data.suggestedFilename = anchor->fastGetAttribute(HTMLNames::downloadAttr);
    }

    data.node = r.innerNonSharedNode();

    WebLocalFrameImpl* selectedWebFrame = WebLocalFrameImpl::fromFrame(selectedFrame);
    if (selectedWebFrame->client())
        selectedWebFrame->client()->showContextMenu(data);
}
Example #18
0
IntSize VisualViewport::maximumScrollOffsetInt() const {
  return flooredIntSize(maximumScrollOffset());
}