void PopupContainer::showInRect(const IntRect& r, FrameView* v, int index) { // The rect is the size of the select box. It's usually larger than we need. // subtract border size so that usually the container will be displayed // exactly the same width as the select box. listBox()->setBaseWidth(max(r.width() - kBorderSize * 2, 0)); listBox()->updateFromElement(); // We set the selected item in updateFromElement(), and disregard the // index passed into this function (same as Webkit's PopupMenuWin.cpp) // FIXME: make sure this is correct, and add an assertion. // ASSERT(popupWindow(popup)->listBox()->selectedIndex() == index); // Convert point to main window coords. IntPoint location = v->contentsToWindow(r.location()); // Move it below the select widget. location.move(0, r.height()); m_originalFrameRect = IntRect(location, r.size()); // Position at (0, 0) since the frameRect().location() is relative to the parent WebWidget. setFrameRect(IntRect(IntPoint(), r.size())); showPopup(v); }
IntRect FilterEffect::requestedRegionOfInputImageData(const IntRect& effectRect) const { ASSERT(m_effectBuffer); IntPoint location = m_absolutePaintRect.location(); location.move(-effectRect.x(), -effectRect.y()); return IntRect(location, m_effectBuffer->size()); }
IntPoint ScrollView::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const { IntPoint newPoint = parentPoint; // Scrollbars won't be transformed within us newPoint.move(-scrollbar->location()); return newPoint; }
ScrollbarPart PlatformScrollbar::hitTest(const PlatformMouseEvent& evt) { if (!isEnabled()) return NoPart; IntPoint mousePosition = convertFromContainingWindow(evt.pos()); mousePosition.move(x(), y()); if (hasButtons()) { if (backButtonRect().contains(mousePosition)) return BackButtonPart; if (forwardButtonRect().contains(mousePosition)) return ForwardButtonPart; } if (!hasThumb()) return NoPart; IntRect track = trackRect(); if (track.contains(mousePosition)) { IntRect beforeThumbRect, thumbRect, afterThumbRect; splitTrack(track, beforeThumbRect, thumbRect, afterThumbRect); if (beforeThumbRect.contains(mousePosition)) return BackTrackPart; if (thumbRect.contains(mousePosition)) return ThumbPart; return ForwardTrackPart; } return NoPart; }
void PopupMenuGtk::show(const IntRect& rect, FrameView* view, int index) { ASSERT(client()); if (!m_popup) { m_popup = GtkPopupMenu::create(); g_signal_connect(m_popup->platformMenu(), "unmap", G_CALLBACK(PopupMenuGtk::menuUnmapped), this); } else m_popup->clear(); const int size = client()->listSize(); for (int i = 0; i < size; ++i) { if (client()->itemIsSeparator(i)) m_popup->appendSeparator(); else { GRefPtr<GtkAction> action = adoptGRef(createGtkActionForMenuItem(i)); m_popup->appendItem(action.get()); } } IntPoint menuPosition = convertWidgetPointToScreenPoint(GTK_WIDGET(view->hostWindow()->platformPageClient()), view->contentsToWindow(rect.location())); menuPosition.move(0, rect.height()); m_popup->popUp(rect.size(), menuPosition, size, index, gtk_get_current_event()); // GTK can refuse to actually open the menu when mouse grabs fails. // Ensure WebCore does not go into some pesky state. if (!gtk_widget_get_visible(m_popup->platformMenu())) client()->popupDidHide(); }
// FIXME: test these on windows IntPoint ScrollView::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntPoint& localPoint) const { // Scrollbars won't be transformed within us IntPoint newPoint = localPoint; newPoint.move(scrollbar->location()); return newPoint; }
void PopupMenuGtk::show(const IntRect& rect, FrameView* view, int index) { ASSERT(client()); if (!m_popup) { m_popup = GtkPopupMenu::create(); g_signal_connect(m_popup->platformMenu(), "unmap", G_CALLBACK(PopupMenuGtk::menuUnmapped), this); } else m_popup->clear(); const int size = client()->listSize(); for (int i = 0; i < size; ++i) { if (client()->itemIsSeparator(i)) m_popup->appendSeparator(); else { GRefPtr<GtkAction> action = adoptGRef(createGtkActionForMenuItem(i)); m_popup->appendItem(action.get()); } } IntPoint menuPosition = convertWidgetPointToScreenPoint(GTK_WIDGET(view->hostWindow()->platformPageClient()), view->contentsToWindow(rect.location())); menuPosition.move(0, rect.height()); m_popup->popUp(rect.size(), menuPosition, size, index, gtk_get_current_event()); }
// Tests moving extent over to the other side of the vase and immediately // passing the word boundary and going into word granularity. TEST_F(GranularityStrategyTest, DirectionSwitchSideWordGranularityThenShrink) { dummyPageHolder().frame().settings()->setDefaultFontSize(12); String str = "ab cd efghijkl mnopqr iiin, abc"; RawPtr<Text> text = document().createTextNode(str); document().body()->appendChild(text); dummyPageHolder().frame().settings()->setSelectionStrategy(SelectionStrategy::Direction); parseText(text.get()); // "abcd efgh ijkl mno^pqr|> iiin, abc" (^ means base, | means extent, < means start, and > means end). selection().setSelection(VisibleSelection(Position(text, 18), Position(text, 21))); EXPECT_EQ_SELECTED_TEXT("pqr"); // Move to the middle of word #4 selecting it - this will set the offset to // be half the width of "iiin". selection().moveRangeSelectionExtent(m_wordMiddles[4]); EXPECT_EQ_SELECTED_TEXT("pqr iiin"); // Move to the middle of word #2 - extent will switch over to the other // side of the base, and we should enter word granularity since we pass // the word boundary. The offset should become negative since the width // of "efghjkkl" is greater than that of "iiin". int offset = m_letterPos[26].x() - m_wordMiddles[4].x(); IntPoint p = IntPoint(m_wordMiddles[2].x() - offset - 1, m_wordMiddles[2].y()); selection().moveRangeSelectionExtent(p); EXPECT_EQ_SELECTED_TEXT("efghijkl mno"); p.move(m_letterPos[7].x() - m_letterPos[6].x(), 0); selection().moveRangeSelectionExtent(p); EXPECT_EQ_SELECTED_TEXT("fghijkl mno"); }
ScrollbarPart PlatformScrollbar::hitTest(const PlatformMouseEvent& evt) { ScrollbarPart result = NoPart; if (!isEnabled() || !parent()) return result; IntPoint mousePosition = convertFromContainingWindow(evt.pos()); mousePosition.move(x(), y()); if (backButtonRect().contains(mousePosition)) result = BackButtonPart; else if (forwardButtonRect().contains(mousePosition)) result = ForwardButtonPart; else { IntRect track = trackRect(); if (track.contains(mousePosition)) { IntRect beforeThumbRect, thumbRect, afterThumbRect; splitTrack(track, beforeThumbRect, thumbRect, afterThumbRect); if (beforeThumbRect.contains(mousePosition)) result = BackTrackPart; else if (thumbRect.contains(mousePosition)) result = ThumbPart; else result = ForwardTrackPart; } } return result; }
bool RenderThemeGtk::paintMediaSliderTrack(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) { GraphicsContext* context = paintInfo.context; context->fillRect(FloatRect(r), m_panelColor, ColorSpaceDeviceRGB); context->fillRect(FloatRect(IntRect(r.x(), r.y() + (r.height() - m_mediaSliderHeight) / 2, r.width(), m_mediaSliderHeight)), m_sliderColor, ColorSpaceDeviceRGB); RenderStyle* style = o->style(); HTMLMediaElement* mediaElement = toParentMediaElement(o); if (!mediaElement) return false; // Draw the buffered ranges. This code is highly inspired from // Chrome for the gradient code. float mediaDuration = mediaElement->duration(); RefPtr<TimeRanges> timeRanges = mediaElement->buffered(); IntRect trackRect = r; int totalWidth = trackRect.width(); trackRect.inflate(-style->borderLeftWidth()); context->save(); context->setStrokeStyle(NoStroke); for (unsigned index = 0; index < timeRanges->length(); ++index) { ExceptionCode ignoredException; float start = timeRanges->start(index, ignoredException); float end = timeRanges->end(index, ignoredException); int width = ((end - start) * totalWidth) / mediaDuration; IntRect rangeRect; if (!index) { rangeRect = trackRect; rangeRect.setWidth(width); } else { rangeRect.setLocation(IntPoint(trackRect.x() + start / mediaDuration* totalWidth, trackRect.y())); rangeRect.setSize(IntSize(width, trackRect.height())); } // Don't bother drawing empty range. if (rangeRect.isEmpty()) continue; IntPoint sliderTopLeft = rangeRect.location(); IntPoint sliderTopRight = sliderTopLeft; sliderTopRight.move(0, rangeRect.height()); RefPtr<Gradient> gradient = Gradient::create(sliderTopLeft, sliderTopRight); Color startColor = m_panelColor; gradient->addColorStop(0.0, startColor); gradient->addColorStop(1.0, Color(startColor.red() / 2, startColor.green() / 2, startColor.blue() / 2, startColor.alpha())); context->setFillGradient(gradient); context->fillRect(rangeRect); } context->restore(); return false; }
void AXObject::scrollToGlobalPoint(const IntPoint& globalPoint) const { // Search up the parent chain and create a vector of all scrollable parent objects // and ending with this object itself. Vector<const AXObject*> objects; AXObject* parentObject; for (parentObject = this->parentObject(); parentObject; parentObject = parentObject->parentObject()) { if (parentObject->getScrollableAreaIfScrollable()) objects.prepend(parentObject); } objects.append(this); // Start with the outermost scrollable (the main window) and try to scroll the // next innermost object to the given point. int offsetX = 0, offsetY = 0; IntPoint point = globalPoint; size_t levels = objects.size() - 1; for (size_t i = 0; i < levels; i++) { const AXObject* outer = objects[i]; const AXObject* inner = objects[i + 1]; ScrollableArea* scrollableArea = outer->getScrollableAreaIfScrollable(); LayoutRect innerRect = inner->isAXScrollView() ? inner->parentObject()->elementRect() : inner->elementRect(); LayoutRect objectRect = innerRect; IntPoint scrollPosition = scrollableArea->scrollPosition(); // Convert the object rect into local coordinates. objectRect.move(offsetX, offsetY); if (!outer->isAXScrollView()) objectRect.move(scrollPosition.x(), scrollPosition.y()); int desiredX = computeBestScrollOffset( 0, objectRect.x(), objectRect.maxX(), objectRect.x(), objectRect.maxX(), point.x(), point.x()); int desiredY = computeBestScrollOffset( 0, objectRect.y(), objectRect.maxY(), objectRect.y(), objectRect.maxY(), point.y(), point.y()); outer->scrollTo(IntPoint(desiredX, desiredY)); if (outer->isAXScrollView() && !inner->isAXScrollView()) { // If outer object we just scrolled is a scroll view (main window or iframe) but the // inner object is not, keep track of the coordinate transformation to apply to // future nested calculations. scrollPosition = scrollableArea->scrollPosition(); offsetX -= (scrollPosition.x() + point.x()); offsetY -= (scrollPosition.y() + point.y()); point.move(scrollPosition.x() - innerRect.x(), scrollPosition.y() - innerRect.y()); } else if (inner->isAXScrollView()) { // Otherwise, if the inner object is a scroll view, reset the coordinate transformation. offsetX = 0; offsetY = 0; } } }
IntPoint visiblePositionToContentsPoint(const VisiblePosition& pos) { IntPoint result = absoluteCaretBoundsOf(pos).minXMaxYCorner(); // Need to move the point at least by 1 - caret's minXMaxYCorner is not // evaluated to the same line as the text by hit testing. result.move(0, -1); return result; }
bool RenderTextControlSingleLine::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int xPos, int yPos, int tx, int ty, HitTestAction hitTestAction) { // If we're within the text control, we want to act as if we've hit the inner text block element, in case the point // was on the control but not on the inner element (see Radar 4617841). // In a search field, we want to act as if we've hit the results block if we're to the left of the inner text block, // and act as if we've hit the close block if we're to the right of the inner text block. if (!RenderTextControl::nodeAtPoint(request, result, xPos, yPos, tx, ty, hitTestAction)) return false; // If we hit a node inside the inner text element, say that we hit that element, // and if we hit our node (e.g. we're over the border or padding), also say that we hit the // inner text element so that it gains focus. if (result.innerNode()->isDescendantOf(innerTextElement()) || result.innerNode() == node()) hitInnerTextElement(result, xPos, yPos, tx, ty); // If we're not a search field, or we already found the results or cancel buttons, we're done. if (!m_innerBlock || result.innerNode() == m_resultsButton || result.innerNode() == m_cancelButton) return true; Node* innerNode = 0; RenderBox* innerBlockRenderer = m_innerBlock->renderBox(); RenderBox* innerTextRenderer = innerTextElement()->renderBox(); IntPoint localPoint = result.localPoint(); localPoint.move(-innerBlockRenderer->x(), -innerBlockRenderer->y()); int textLeft = tx + x() + innerBlockRenderer->x() + innerTextRenderer->x(); if (m_resultsButton && m_resultsButton->renderer() && xPos < textLeft) innerNode = m_resultsButton.get(); if (!innerNode) { int textRight = textLeft + innerTextRenderer->width(); if (m_cancelButton && m_cancelButton->renderer() && xPos > textRight) innerNode = m_cancelButton.get(); } if (innerNode) { result.setInnerNode(innerNode); localPoint.move(-innerNode->renderBox()->x(), -innerNode->renderBox()->y()); } result.setLocalPoint(localPoint); return true; }
static bool paintMediaSlider(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect) { HTMLMediaElement* mediaElement = toParentMediaElement(object); if (!mediaElement) return false; RenderStyle* style = object->style(); GraphicsContext* context = paintInfo.context; // Draw the border of the time bar. // FIXME: this should be a rounded rect but need to fix GraphicsContextSkia first. // https://bugs.webkit.org/show_bug.cgi?id=30143 context->save(); context->setShouldAntialias(true); context->setStrokeStyle(SolidStroke); context->setStrokeColor(style->visitedDependentColor(CSSPropertyBorderLeftColor), ColorSpaceDeviceRGB); context->setStrokeThickness(style->borderLeftWidth()); context->setFillColor(style->visitedDependentColor(CSSPropertyBackgroundColor), ColorSpaceDeviceRGB); context->drawRect(rect); context->restore(); // Draw the buffered ranges. // FIXME: Draw multiple ranges if there are multiple buffered ranges. IntRect bufferedRect = rect; bufferedRect.inflate(-style->borderLeftWidth()); double bufferedWidth = 0.0; if (mediaElement->percentLoaded() > 0.0) { // Account for the width of the slider thumb. Image* mediaSliderThumb = getMediaSliderThumb(); double thumbWidth = mediaSliderThumb->width() / 2.0 + 1.0; double rectWidth = bufferedRect.width() - thumbWidth; if (rectWidth < 0.0) rectWidth = 0.0; bufferedWidth = rectWidth * mediaElement->percentLoaded() + thumbWidth; } bufferedRect.setWidth(bufferedWidth); // Don't bother drawing an empty area. if (!bufferedRect.isEmpty()) { IntPoint sliderTopLeft = bufferedRect.location(); IntPoint sliderTopRight = sliderTopLeft; sliderTopRight.move(0, bufferedRect.height()); RefPtr<Gradient> gradient = Gradient::create(sliderTopLeft, sliderTopRight); Color startColor = object->style()->visitedDependentColor(CSSPropertyColor); gradient->addColorStop(0.0, startColor); gradient->addColorStop(1.0, Color(startColor.red() / 2, startColor.green() / 2, startColor.blue() / 2, startColor.alpha())); context->save(); context->setStrokeStyle(NoStroke); context->setFillGradient(gradient); context->fillRect(bufferedRect); context->restore(); } return true; }
bool ScrollbarTheme::shouldSnapBackToDragOrigin( const ScrollbarThemeClient& scrollbar, const PlatformMouseEvent& evt) { IntPoint mousePosition = scrollbar.convertFromRootFrame(evt.position()); mousePosition.move(scrollbar.x(), scrollbar.y()); return Platform::current()->scrollbarBehavior()->shouldSnapBackToDragOrigin( mousePosition, trackRect(scrollbar), scrollbar.orientation() == HorizontalScrollbar); }
IntPoint ChromeClientBlackBerry::screenToRootView(const IntPoint& screenPos) const { IntPoint windowPoint; if (Window* window = m_webPagePrivate->m_client->window()) windowPoint = window->windowLocation(); windowPoint.move(-screenPos.x(), -screenPos.y()); return windowPoint; }
bool RenderTextControlSingleLine::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int xPos, int yPos, int tx, int ty, HitTestAction hitTestAction) { // If we're within the text control, we want to act as if we've hit the inner text block element, in case the point // was on the control but not on the inner element (see Radar 4617841). // In a search field, we want to act as if we've hit the results block if we're to the left of the inner text block, // and act as if we've hit the close block if we're to the right of the inner text block. if (!RenderTextControl::nodeAtPoint(request, result, xPos, yPos, tx, ty, hitTestAction)) return false; if (result.innerNode() != element() && result.innerNode() != m_innerBlock.get()) return false; hitInnerTextBlock(result, xPos, yPos, tx, ty); if (!m_innerBlock) return true; Node* innerNode = 0; RenderBox* innerBlockRenderer = m_innerBlock->renderBox(); RenderBox* innerTextRenderer = innerTextElement()->renderBox(); IntPoint localPoint = result.localPoint(); localPoint.move(-innerBlockRenderer->x(), -innerBlockRenderer->y()); int textLeft = tx + x() + innerBlockRenderer->x() + innerTextRenderer->x(); if (m_resultsButton && m_resultsButton->renderer() && xPos < textLeft) innerNode = m_resultsButton.get(); if (!innerNode) { int textRight = textLeft + innerTextRenderer->width(); if (m_cancelButton && m_cancelButton->renderer() && xPos > textRight) innerNode = m_cancelButton.get(); } if (innerNode) { result.setInnerNode(innerNode); localPoint.move(-innerNode->renderBox()->x(), -innerNode->renderBox()->y()); } result.setLocalPoint(localPoint); return true; }
// Tests moving selection extent over to the other side of the base // on text "abcd efgh ijkl mno^pqr|> iiinmni, abc" // (^ means base, | means extent, < means start, and > means end). // Text needs to be laid out on a single line with no rotation. void GranularityStrategyTest::testDirectionSwitchSide() { // Move to the middle of word #4, selecting it - this will set the offset to // be half the width of "iiinmni. selection().moveRangeSelectionExtent(m_wordMiddles[4]); EXPECT_EQ_SELECTED_TEXT("pqr iiinmni"); // Move back leaving only one letter selected. IntPoint p = m_wordMiddles[4]; p.move(m_letterPos[19].x() - m_letterPos[29].x(), 0); selection().moveRangeSelectionExtent(p); EXPECT_EQ_SELECTED_TEXT("p"); // Confirm selection doesn't change if extent is positioned at base. p.move(m_letterPos[18].x() - m_letterPos[19].x(), 0); selection().moveRangeSelectionExtent(p); EXPECT_EQ_SELECTED_TEXT("p"); // Move over to the other side of the base. Confirm the offset is preserved. // (i.e. the selection start stays on the right of the extent) // Confirm we stay in character granularity until the beginning of the word // is passed. p.move(m_letterPos[17].x() - m_letterPos[18].x(), 0); selection().moveRangeSelectionExtent(p); EXPECT_EQ_SELECTED_TEXT("o"); p.move(m_letterPos[16].x() - m_letterPos[17].x(), 0); selection().moveRangeSelectionExtent(p); EXPECT_EQ_SELECTED_TEXT("no"); p.move(m_letterPos[14].x() - m_letterPos[16].x(), 0); selection().moveRangeSelectionExtent(p); EXPECT_EQ_SELECTED_TEXT(" mno"); // Move to just one pixel on the right before the middle of the word #2. // We should switch to word granularity, so the selection shouldn't change. p.move(m_wordMiddles[2].x() - m_letterPos[14].x() + 1, 0); selection().moveRangeSelectionExtent(p); EXPECT_EQ_SELECTED_TEXT(" mno"); // Move over the middle of the word. The word should get selected. // This should reduce the offset, but it should still stay greated than 0, // since the width of "iiinmni" is greater than the width of "ijkl". p.move(-2, 0); selection().moveRangeSelectionExtent(p); EXPECT_EQ_SELECTED_TEXT("ijkl mno"); // Move to just one pixel on the right of the middle of word #1. // The selection should now include the space between the words. p.move(m_wordMiddles[1].x() - m_letterPos[10].x() + 1, 0); selection().moveRangeSelectionExtent(p); EXPECT_EQ_SELECTED_TEXT(" ijkl mno"); // Move over the middle of the word. The word should get selected. p.move(-2, 0); selection().moveRangeSelectionExtent(p); EXPECT_EQ_SELECTED_TEXT("efgh ijkl mno"); }
void WebPopupMenuProxyGtk::showPopupMenu(const IntRect& rect, TextDirection, double /* pageScaleFactor */, const Vector<WebPopupItem>& items, const PlatformPopupMenuData&, int32_t selectedIndex) { populatePopupMenu(items); gtk_menu_set_active(GTK_MENU(m_popup), selectedIndex); resetTypeAheadFindState(); IntPoint menuPosition = convertWidgetPointToScreenPoint(m_webView, rect.location()); menuPosition.move(0, rect.height()); // This approach follows the one in gtkcombobox.c. GtkRequisition requisition; gtk_widget_set_size_request(m_popup, -1, -1); gtk_widget_get_preferred_size(m_popup, &requisition, nullptr); gtk_widget_set_size_request(m_popup, std::max(rect.width(), requisition.width), -1); if (int itemCount = items.size()) { GUniquePtr<GList> children(gtk_container_get_children(GTK_CONTAINER(m_popup))); int i; GList* child; for (i = 0, child = children.get(); i < itemCount; i++, child = g_list_next(child)) { if (i > selectedIndex) break; GtkWidget* item = GTK_WIDGET(child->data); GtkRequisition itemRequisition; gtk_widget_get_preferred_size(item, &itemRequisition, nullptr); menuPosition.setY(menuPosition.y() - itemRequisition.height); } } else { // Center vertically the empty popup in the combo box area. menuPosition.setY(menuPosition.y() - rect.height() / 2); } const GdkEvent* event = m_client->currentlyProcessedMouseDownEvent() ? m_client->currentlyProcessedMouseDownEvent()->nativeEvent() : nullptr; gtk_menu_popup_for_device(GTK_MENU(m_popup), event ? gdk_event_get_device(event) : nullptr, nullptr, nullptr, [](GtkMenu*, gint* x, gint* y, gboolean* pushIn, gpointer userData) { // We can pass a pointer to the menuPosition local variable because the nested main loop ensures this is called in the function context. IntPoint* menuPosition = static_cast<IntPoint*>(userData); *x = menuPosition->x(); *y = menuPosition->y(); *pushIn = menuPosition->y() < 0; }, &menuPosition, nullptr, event && event->type == GDK_BUTTON_PRESS ? event->button.button : 1, event ? gdk_event_get_time(event) : GDK_CURRENT_TIME); // Now that the menu has a position, schedule a resize to make sure it's resized to fit vertically in the work area. gtk_widget_queue_resize(m_popup); // PopupMenu can fail to open when there is no mouse grab. // Ensure WebCore does not go into some pesky state. if (!gtk_widget_get_visible(m_popup)) { m_client->failedToShowPopupMenu(); return; } }
IntPoint RenderLayerScrollableArea::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntPoint& scrollbarPoint) const { RenderView* view = box().view(); if (!view) return scrollbarPoint; IntPoint point = scrollbarPoint; point.move(scrollbarOffset(scrollbar)); return view->frameView()->convertFromRenderer(box(), point); }
// DirectionGranularityStrategy strategy on rotated text should revert to the // same behavior as CharacterGranularityStrategy TEST_F(GranularityStrategyTest, DirectionRotate) { RefPtrWillBeRawPtr<Text> text = setupRotate("Foo Bar Baz,"); // "Foo B^a|>r Baz," (^ means base, | means extent, , < means start, and > means end). selection().setSelection(VisibleSelection(Position(text, 5), Position(text, 6))); EXPECT_EQ_SELECTED_TEXT("a"); IntPoint p = m_letterPos[9]; // Need to move by one pixel, otherwise this point is not evaluated // to the same line as the text by hit testing. p.move(1, 0); // "Foo B^ar B|>az," selection().moveRangeSelectionExtent(p); EXPECT_EQ_SELECTED_TEXT("ar B"); p = m_letterPos[1]; p.move(1, 0); // "F<|oo B^ar Baz," selection().moveRangeSelectionExtent(p); EXPECT_EQ_SELECTED_TEXT("oo B"); }
Region ScrollingCoordinator::computeNonFastScrollableRegion(const Frame* frame, const IntPoint& frameLocation) const { #if ENABLE(IOS_TOUCH_EVENTS) // On iOS, we use nonFastScrollableRegion to represent the region covered by elements with touch event handlers. ASSERT(frame->isMainFrame()); UNUSED_PARAM(frameLocation); Document* document = frame->document(); if (!document) return Region(); Vector<IntRect> touchRects; document->getTouchRects(touchRects); Region touchRegion; for (const auto& rect : touchRects) touchRegion.unite(rect); return touchRegion; #else Region nonFastScrollableRegion; FrameView* frameView = frame->view(); if (!frameView) return nonFastScrollableRegion; IntPoint offset = frameLocation; offset.moveBy(frameView->frameRect().location()); offset.move(0, frameView->topContentInset()); if (const FrameView::ScrollableAreaSet* scrollableAreas = frameView->scrollableAreas()) { for (FrameView::ScrollableAreaSet::const_iterator it = scrollableAreas->begin(), end = scrollableAreas->end(); it != end; ++it) { ScrollableArea* scrollableArea = *it; // Composited scrollable areas can be scrolled off the main thread. if (scrollableArea->usesCompositedScrolling()) continue; IntRect box = scrollableArea->scrollableAreaBoundingBox(); box.moveBy(offset); nonFastScrollableRegion.unite(box); } } for (const auto& child : frameView->children()) { if (!child->isPluginViewBase()) continue; PluginViewBase* pluginViewBase = toPluginViewBase(child.get()); if (pluginViewBase->wantsWheelEvents()) nonFastScrollableRegion.unite(pluginViewBase->frameRect()); } for (Frame* subframe = frame->tree().firstChild(); subframe; subframe = subframe->tree().nextSibling()) nonFastScrollableRegion.unite(computeNonFastScrollableRegion(subframe, offset)); return nonFastScrollableRegion; #endif }
IntPoint RenderLayerScrollableArea::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const { RenderView* view = box().view(); if (!view) return parentPoint; IntPoint point = view->frameView()->convertToRenderer(box(), parentPoint); point.move(-scrollbarOffset(scrollbar)); return point; }
static void paintSliderRangeHighlight(const IntRect& rect, const RenderStyle* style, GraphicsContext* context, int startPosition, int endPosition, Color startColor, Color endColor) { // Calculate border radius; need to avoid being smaller than half the slider height // because of https://bugs.webkit.org/show_bug.cgi?id=30143. int borderRadius = rect.height() / 2; IntSize radii(borderRadius, borderRadius); // Calculate highlight rectangle and edge dimensions. int startOffset = startPosition; int endOffset = rect.width() - endPosition; int rangeWidth = endPosition - startPosition; if (rangeWidth <= 0) return; // Make sure the range width is bigger than border radius at the edges to retain rounded corners. if (startOffset < borderRadius && rangeWidth < borderRadius) rangeWidth = borderRadius; if (endOffset < borderRadius && rangeWidth < borderRadius) rangeWidth = borderRadius; // Set rectangle to highlight range. IntRect highlightRect = rect; highlightRect.move(startOffset, 0); highlightRect.setWidth(rangeWidth); // Don't bother drawing an empty area. if (highlightRect.isEmpty()) return; // Calculate white-grey gradient. IntPoint sliderTopLeft = highlightRect.location(); IntPoint sliderBottomLeft = sliderTopLeft; sliderBottomLeft.move(0, highlightRect.height()); RefPtr<Gradient> gradient = Gradient::create(sliderTopLeft, sliderBottomLeft); gradient->addColorStop(0.0, startColor); gradient->addColorStop(1.0, endColor); // Fill highlight rectangle with gradient, potentially rounded if on left or right edge. context->save(); context->setFillGradient(gradient); if (startOffset < borderRadius && endOffset < borderRadius) context->fillRoundedRect(highlightRect, radii, radii, radii, radii, startColor); else if (startOffset < borderRadius) context->fillRoundedRect(highlightRect, radii, IntSize(0, 0), radii, IntSize(0, 0), startColor); else if (endOffset < borderRadius) context->fillRoundedRect(highlightRect, IntSize(0, 0), radii, IntSize(0, 0), radii, startColor); else context->fillRect(highlightRect); context->restore(); }
void WebPopupMenuProxyWin::paint(const IntRect& damageRect, HDC hdc) { if (!m_popup) return; if (!m_DC) { m_DC = ::CreateCompatibleDC(::GetDC(m_popup)); if (!m_DC) return; } if (m_bmp) { bool keepBitmap = false; BITMAP bitmap; if (::GetObject(m_bmp, sizeof(bitmap), &bitmap)) keepBitmap = bitmap.bmWidth == clientRect().width() && bitmap.bmHeight == clientRect().height(); if (!keepBitmap) { ::DeleteObject(m_bmp); m_bmp = 0; } } if (!m_bmp) { BitmapInfo bitmapInfo = BitmapInfo::createBottomUp(clientRect().size()); void* pixels = 0; m_bmp = ::CreateDIBSection(m_DC, &bitmapInfo, DIB_RGB_COLORS, &pixels, 0, 0); if (!m_bmp) return; ::SelectObject(m_DC, m_bmp); } GraphicsContext context(m_DC); IntRect translatedDamageRect = damageRect; translatedDamageRect.move(IntSize(0, m_scrollOffset * m_itemHeight)); m_data.m_notSelectedBackingStore->paint(context, damageRect.location(), translatedDamageRect); IntRect selectedIndexRectInBackingStore(0, focusedIndex() * m_itemHeight, m_data.m_selectedBackingStore->size().width(), m_itemHeight); IntPoint selectedIndexDstPoint = selectedIndexRectInBackingStore.location(); selectedIndexDstPoint.move(0, -m_scrollOffset * m_itemHeight); m_data.m_selectedBackingStore->paint(context, selectedIndexDstPoint, selectedIndexRectInBackingStore); if (m_scrollbar) m_scrollbar->paint(&context, damageRect); HDC localDC = hdc ? hdc : ::GetDC(m_popup); ::BitBlt(localDC, damageRect.x(), damageRect.y(), damageRect.width(), damageRect.height(), m_DC, damageRect.x(), damageRect.y(), SRCCOPY); if (!hdc) ::ReleaseDC(m_popup, localDC); }
void WebCoreDrawDoubledTextAtPoint(GraphicsContext& context, const String& text, const IntPoint& point, const Font& font, const Color& topColor, const Color& bottomColor, int underlinedIndex) { context.save(); IntPoint textPos = point; doDrawTextAtPoint(context, text, textPos, font, bottomColor, underlinedIndex); textPos.move(0, -1); doDrawTextAtPoint(context, text, textPos, font, topColor, underlinedIndex); context.restore(); }
IntPoint RenderListBox::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const { RenderView* view = this->view(); if (!view) return parentPoint; IntPoint point = view->frameView()->convertToRenderer(this, parentPoint); int scrollbarLeft = width() - borderRight() - scrollbar->width(); int scrollbarTop = borderTop(); point.move(-scrollbarLeft, -scrollbarTop); return point; }
// Tests shrinking selection on text "abcdef ghij kl mno^pqr|> iiinmni, abc" // (^ means base, | means extent, < means start, and > means end). // Text needs to be laid out on a single line with no rotation. void GranularityStrategyTest::testDirectionShrink() { // Move to the middle of word #4 to it and then move back, confirming // that the selection end is moving with the extent. The offset between the // extent and the selection end will be equal to half the width of "iiinmni". selection().moveRangeSelectionExtent(m_wordMiddles[4]); EXPECT_EQ_SELECTED_TEXT("pqr iiinmni"); IntPoint p = m_wordMiddles[4]; p.move(m_letterPos[28].x() - m_letterPos[29].x(), 0); selection().moveRangeSelectionExtent(p); EXPECT_EQ_SELECTED_TEXT("pqr iiinmn"); p.move(m_letterPos[27].x() - m_letterPos[28].x(), 0); selection().moveRangeSelectionExtent(p); EXPECT_EQ_SELECTED_TEXT("pqr iiinm"); p.move(m_letterPos[26].x() - m_letterPos[27].x(), 0); selection().moveRangeSelectionExtent(p); EXPECT_EQ_SELECTED_TEXT("pqr iiin"); // Move right by the width of char 30 ('m'). Selection shouldn't change, // but offset should be reduced. p.move(m_letterPos[27].x() - m_letterPos[26].x(), 0); selection().moveRangeSelectionExtent(p); EXPECT_EQ_SELECTED_TEXT("pqr iiin"); // Move back a couple of character widths and confirm the selection still // updates accordingly. p.move(m_letterPos[25].x() - m_letterPos[26].x(), 0); selection().moveRangeSelectionExtent(p); EXPECT_EQ_SELECTED_TEXT("pqr iii"); p.move(m_letterPos[24].x() - m_letterPos[25].x(), 0); selection().moveRangeSelectionExtent(p); EXPECT_EQ_SELECTED_TEXT("pqr ii"); // "Catch up" with the handle - move the extent to where the handle is. // "abcdef ghij kl mno^pqr ii|>inmni, abc" selection().moveRangeSelectionExtent(m_letterPos[24]); EXPECT_EQ_SELECTED_TEXT("pqr ii"); // Move ahead and confirm the selection expands accordingly // "abcdef ghij kl mno^pqr iii|>nmni, abc" selection().moveRangeSelectionExtent(m_letterPos[25]); EXPECT_EQ_SELECTED_TEXT("pqr iii"); // Confirm we stay in character granularity if the user moves within a word. // "abcdef ghij kl mno^pqr |>iiinmni, abc" selection().moveRangeSelectionExtent(m_letterPos[22]); EXPECT_EQ_SELECTED_TEXT("pqr "); // It's possible to get a move when position doesn't change. // It shouldn't affect anything. p = m_letterPos[22]; p.move(1, 0); selection().moveRangeSelectionExtent(p); EXPECT_EQ_SELECTED_TEXT("pqr "); // "abcdef ghij kl mno^pqr i|>iinmni, abc" selection().moveRangeSelectionExtent(m_letterPos[23]); EXPECT_EQ_SELECTED_TEXT("pqr i"); }
IntPoint RenderListBox::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntPoint& scrollbarPoint) const { RenderView* view = this->view(); if (!view) return scrollbarPoint; IntPoint point = scrollbarPoint; int scrollbarLeft = width() - borderRight() - scrollbar->width(); int scrollbarTop = borderTop(); point.move(scrollbarLeft, scrollbarTop); return view->frameView()->convertFromRenderer(this, point); }
bool ScrollbarThemeWin::shouldSnapBackToDragOrigin(Scrollbar* scrollbar, const PlatformMouseEvent& evt) { // Find the rect within which we shouldn't snap, by expanding the track rect // in both dimensions. IntRect rect = trackRect(scrollbar); const bool horz = scrollbar->orientation() == HorizontalScrollbar; const int thickness = scrollbarThickness(scrollbar->controlSize()); rect.inflateX((horz ? kOffEndMultiplier : kOffSideMultiplier) * thickness); rect.inflateY((horz ? kOffSideMultiplier : kOffEndMultiplier) * thickness); // Convert the event to local coordinates. IntPoint mousePosition = scrollbar->convertFromContainingWindow(evt.pos()); mousePosition.move(scrollbar->x(), scrollbar->y()); // We should snap iff the event is outside our calculated rect. return !rect.contains(mousePosition); }