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()); } }
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; }
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); }
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; }
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); }
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. }
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); }
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); }
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); }
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); }
IntSize scrollOffsetInt() const override { return flooredIntSize(m_scrollOffset); }
IntSize maximumScrollOffsetInt() const override { return flooredIntSize(maximumScrollOffset()); }
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); }
IntSize VisualViewport::maximumScrollOffsetInt() const { return flooredIntSize(maximumScrollOffset()); }