bool DragController::startDrag(Frame* src, const DragState& state, DragOperation srcOp, const PlatformMouseEvent& dragEvent, const IntPoint& dragOrigin) { ASSERT(src); if (!src->view() || !src->contentRenderer()) return false; HitTestResult hitTestResult = src->eventHandler()->hitTestResultAtPoint(dragOrigin, true); if (!state.m_dragSrc->contains(hitTestResult.innerNode())) // The original node being dragged isn't under the drag origin anymore... maybe it was // hidden or moved out from under the cursor. Regardless, we don't want to start a drag on // something that's not actually under the drag origin. return false; KURL linkURL = hitTestResult.absoluteLinkURL(); KURL imageURL = hitTestResult.absoluteImageURL(); IntPoint mouseDraggedPoint = src->view()->windowToContents(dragEvent.position()); m_draggingImageURL = KURL(); m_sourceDragOperation = srcOp; DragImageRef dragImage = 0; IntPoint dragLoc(0, 0); IntPoint dragImageOffset(0, 0); Clipboard* clipboard = state.m_dragClipboard.get(); if (state.m_dragType == DragSourceActionDHTML) dragImage = clipboard->createDragImage(dragImageOffset); if (state.m_dragType == DragSourceActionSelection || !imageURL.isEmpty() || !linkURL.isEmpty()) // Selection, image, and link drags receive a default set of allowed drag operations that // follows from: // http://trac.webkit.org/browser/trunk/WebKit/mac/WebView/WebHTMLView.mm?rev=48526#L3430 m_sourceDragOperation = static_cast<DragOperation>(m_sourceDragOperation | DragOperationGeneric | DragOperationCopy); // We allow DHTML/JS to set the drag image, even if its a link, image or text we're dragging. // This is in the spirit of the IE API, which allows overriding of pasteboard data and DragOp. if (dragImage) { dragLoc = dragLocForDHTMLDrag(mouseDraggedPoint, dragOrigin, dragImageOffset, !linkURL.isEmpty()); m_dragOffset = dragImageOffset; } bool startedDrag = true; // optimism - we almost always manage to start the drag Node* node = state.m_dragSrc.get(); Image* image = getImage(static_cast<Element*>(node)); if (state.m_dragType == DragSourceActionSelection) { if (!clipboard->hasData()) { if (enclosingTextFormControl(src->selection()->start())) clipboard->writePlainText(src->editor()->selectedText()); else { RefPtr<Range> selectionRange = src->selection()->toNormalizedRange(); ASSERT(selectionRange); clipboard->writeRange(selectionRange.get(), src); } } m_client->willPerformDragSourceAction(DragSourceActionSelection, dragOrigin, clipboard); if (!dragImage) { dragImage = createDragImageForSelection(src); dragLoc = dragLocForSelectionDrag(src); m_dragOffset = IntPoint(dragOrigin.x() - dragLoc.x(), dragOrigin.y() - dragLoc.y()); } doSystemDrag(dragImage, dragLoc, dragOrigin, clipboard, src, false); } else if (!imageURL.isEmpty() && node && node->isElementNode() && image && !image->isNull() && (m_dragSourceAction & DragSourceActionImage)) { // We shouldn't be starting a drag for an image that can't provide an extension. // This is an early detection for problems encountered later upon drop. ASSERT(!image->filenameExtension().isEmpty()); Element* element = static_cast<Element*>(node); if (!clipboard->hasData()) { m_draggingImageURL = imageURL; prepareClipboardForImageDrag(src, clipboard, element, linkURL, imageURL, hitTestResult.altDisplayString()); } m_client->willPerformDragSourceAction(DragSourceActionImage, dragOrigin, clipboard); if (!dragImage) { IntRect imageRect = hitTestResult.imageRect(); imageRect.setLocation(m_page->mainFrame()->view()->rootViewToContents(src->view()->contentsToRootView(imageRect.location()))); doImageDrag(element, dragOrigin, hitTestResult.imageRect(), clipboard, src, m_dragOffset); } else // DHTML defined drag image doSystemDrag(dragImage, dragLoc, dragOrigin, clipboard, src, false); } else if (!linkURL.isEmpty() && (m_dragSourceAction & DragSourceActionLink)) { if (!clipboard->hasData()) // Simplify whitespace so the title put on the clipboard resembles what the user sees // on the web page. This includes replacing newlines with spaces. clipboard->writeURL(linkURL, hitTestResult.textContent().simplifyWhiteSpace(), src); if (src->selection()->isCaret() && src->selection()->isContentEditable()) { // a user can initiate a drag on a link without having any text // selected. In this case, we should expand the selection to // the enclosing anchor element Position pos = src->selection()->base(); Node* node = enclosingAnchorElement(pos); if (node) src->selection()->setSelection(VisibleSelection::selectionFromContentsOfNode(node)); } m_client->willPerformDragSourceAction(DragSourceActionLink, dragOrigin, clipboard); if (!dragImage) { dragImage = createDragImageForLink(linkURL, hitTestResult.textContent(), src); IntSize size = dragImageSize(dragImage); m_dragOffset = IntPoint(-size.width() / 2, -LinkDragBorderInset); dragLoc = IntPoint(mouseDraggedPoint.x() + m_dragOffset.x(), mouseDraggedPoint.y() + m_dragOffset.y()); } doSystemDrag(dragImage, dragLoc, mouseDraggedPoint, clipboard, src, true); } else if (state.m_dragType == DragSourceActionDHTML) { ASSERT(m_dragSourceAction & DragSourceActionDHTML); m_client->willPerformDragSourceAction(DragSourceActionDHTML, dragOrigin, clipboard); doSystemDrag(dragImage, dragLoc, dragOrigin, clipboard, src, false); } else { // draggableNode() determined an image or link node was draggable, but it turns out the // image or link had no URL, so there is nothing to drag. startedDrag = false; } if (dragImage) deleteDragImage(dragImage); return startedDrag; }
// This is only used to draw borders. void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2) { if (paintingDisabled()) return; StrokeStyle style = strokeStyle(); if (style == NoStroke) return; SkPaint paint; SkCanvas* canvas = GC2Canvas(this); const int idx = SkAbs32(point2.x() - point1.x()); const int idy = SkAbs32(point2.y() - point1.y()); // special-case horizontal and vertical lines that are really just dots if (m_data->setup_paint_stroke(&paint, NULL) && (0 == idx || 0 == idy)) { const SkScalar diameter = paint.getStrokeWidth(); const SkScalar radius = SkScalarHalf(diameter); SkScalar x = SkIntToScalar(SkMin32(point1.x(), point2.x())); SkScalar y = SkIntToScalar(SkMin32(point1.y(), point2.y())); SkScalar dx, dy; int count; SkRect bounds; if (0 == idy) { // horizontal bounds.set(x, y - radius, x + SkIntToScalar(idx), y + radius); x += radius; dx = diameter * 2; dy = 0; count = idx; } else { // vertical bounds.set(x - radius, y, x + radius, y + SkIntToScalar(idy)); y += radius; dx = 0; dy = diameter * 2; count = idy; } // the actual count is the number of ONs we hit alternating // ON(diameter), OFF(diameter), ... { SkScalar width = SkScalarDiv(SkIntToScalar(count), diameter); // now computer the number of cells (ON and OFF) count = SkScalarRound(width); // now compute the number of ONs count = (count + 1) >> 1; } SkAutoMalloc storage(count * sizeof(SkPoint)); SkPoint* verts = (SkPoint*)storage.get(); // now build the array of vertices to past to drawPoints for (int i = 0; i < count; i++) { verts[i].set(x, y); x += dx; y += dy; } paint.setStyle(SkPaint::kFill_Style); paint.setPathEffect(NULL); // clipping to bounds is not required for correctness, but it does // allow us to reject the entire array of points if we are completely // offscreen. This is common in a webpage for android, where most of // the content is clipped out. If drawPoints took an (optional) bounds // parameter, that might even be better, as we would *just* use it for // culling, and not both wacking the canvas' save/restore stack. canvas->save(SkCanvas::kClip_SaveFlag); canvas->clipRect(bounds); canvas->drawPoints(SkCanvas::kPoints_PointMode, count, verts, paint); canvas->restore(); } else {
IntPoint Widget::convertSelfToChild(const Widget* child, const IntPoint& point) const { return IntPoint(point.x() - child->x(), point.y() - child->y()); }
void SVGRootPainter::paint(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) { // An empty viewport disables rendering. if (m_layoutSVGRoot.pixelSnappedBorderBoxRect().isEmpty()) return; // SVG outlines are painted during PaintPhaseForeground. if (shouldPaintSelfOutline(paintInfo.phase)) return; // An empty viewBox also disables rendering. // (http://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute) SVGSVGElement* svg = toSVGSVGElement(m_layoutSVGRoot.node()); ASSERT(svg); if (svg->hasEmptyViewBox()) return; // Don't paint if we don't have kids, except if we have filters we should paint those. if (!m_layoutSVGRoot.firstChild()) { SVGResources* resources = SVGResourcesCache::cachedResourcesForLayoutObject(&m_layoutSVGRoot); if (!resources || !resources->filter()) return; } PaintInfo paintInfoBeforeFiltering(paintInfo); // At the HTML->SVG boundary, SVGRoot will have a paint offset transform // paint property but may not have a PaintLayer, so we need to update the // paint properties here since they will not be updated by PaintLayer // (See: PaintPropertyTreeBuilder::createPaintOffsetTranslationIfNeeded). Optional<ScopedPaintChunkProperties> paintOffsetTranslationPropertyScope; if (RuntimeEnabledFeatures::slimmingPaintV2Enabled() && !m_layoutSVGRoot.hasLayer()) { const auto* objectProperties = m_layoutSVGRoot.objectPaintProperties(); if (objectProperties && objectProperties->paintOffsetTranslation()) { auto& paintController = paintInfoBeforeFiltering.context.paintController(); PaintChunkProperties properties(paintController.currentPaintChunkProperties()); properties.transform = objectProperties->paintOffsetTranslation(); paintOffsetTranslationPropertyScope.emplace(paintController, properties); } } // Apply initial viewport clip. Optional<ClipRecorder> clipRecorder; if (m_layoutSVGRoot.shouldApplyViewportClip()) { // TODO(pdr): Clip the paint info cull rect here. clipRecorder.emplace(paintInfoBeforeFiltering.context, m_layoutSVGRoot, paintInfoBeforeFiltering.displayItemTypeForClipping(), LayoutRect(pixelSnappedIntRect(m_layoutSVGRoot.overflowClipRect(paintOffset)))); } // Convert from container offsets (html layoutObjects) to a relative transform (svg layoutObjects). // Transform from our paint container's coordinate system to our local coords. IntPoint adjustedPaintOffset = roundedIntPoint(paintOffset); AffineTransform paintOffsetToBorderBox = AffineTransform::translation(adjustedPaintOffset.x(), adjustedPaintOffset.y()) * m_layoutSVGRoot.localToBorderBoxTransform(); paintInfoBeforeFiltering.updateCullRect(paintOffsetToBorderBox); TransformRecorder transformRecorder(paintInfoBeforeFiltering.context, m_layoutSVGRoot, paintOffsetToBorderBox); SVGPaintContext paintContext(m_layoutSVGRoot, paintInfoBeforeFiltering); if (paintContext.paintInfo().phase == PaintPhaseForeground && !paintContext.applyClipMaskAndFilterIfNecessary()) return; BoxPainter(m_layoutSVGRoot).paint(paintContext.paintInfo(), LayoutPoint()); PaintTiming& timing = PaintTiming::from(m_layoutSVGRoot.node()->document().topDocument()); timing.markFirstContentfulPaint(); }
IntSize IntRect::differenceToPoint(const IntPoint& point) const { int xdistance = distanceToInterval(point.x(), x(), maxX()); int ydistance = distanceToInterval(point.y(), y(), maxY()); return IntSize(xdistance, ydistance); }
void RenderSVGRoot::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { // An empty viewport disables rendering. if (pixelSnappedBorderBoxRect().isEmpty()) return; // Don't paint, if the context explicitely disabled it. if (paintInfo.context->paintingDisabled()) return; Page* page = 0; if (Frame* frame = this->frame()) page = frame->page(); // Don't paint if we don't have kids, except if we have filters we should paint those. if (!firstChild()) { SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(this); if (!resources || !resources->filter()) { if (page && paintInfo.phase == PaintPhaseForeground) page->addRelevantUnpaintedObject(this, visualOverflowRect()); return; } } if (page && paintInfo.phase == PaintPhaseForeground) page->addRelevantRepaintedObject(this, visualOverflowRect()); // Make a copy of the PaintInfo because applyTransform will modify the damage rect. PaintInfo childPaintInfo(paintInfo); childPaintInfo.context->save(); // Apply initial viewport clip - not affected by overflow handling childPaintInfo.context->clip(pixelSnappedIntRect(overflowClipRect(paintOffset, paintInfo.renderRegion))); // Convert from container offsets (html renderers) to a relative transform (svg renderers). // Transform from our paint container's coordinate system to our local coords. IntPoint adjustedPaintOffset = roundedIntPoint(paintOffset); childPaintInfo.applyTransform(AffineTransform::translation(adjustedPaintOffset.x() - x(), adjustedPaintOffset.y() - y()) * localToParentTransform()); SVGRenderingContext renderingContext; bool continueRendering = true; if (childPaintInfo.phase == PaintPhaseForeground) { renderingContext.prepareToRenderSVGContent(this, childPaintInfo); continueRendering = renderingContext.isRenderingPrepared(); } if (continueRendering) RenderBox::paint(childPaintInfo, LayoutPoint()); childPaintInfo.context->restore(); }
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); } gulong unmapHandler = g_signal_connect(m_popup, "unmap", G_CALLBACK(menuUnmapped), this); 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 = TRUE; }, &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; } // WebPageProxy expects the menu to run in a nested run loop, since it invalidates the // menu right after calling WebPopupMenuProxy::showPopupMenu(). m_runLoop = adoptGRef(g_main_loop_new(nullptr, FALSE)); // This is to suppress warnings about gdk_threads_leave and gdk_threads_enter. #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" gdk_threads_leave(); g_main_loop_run(m_runLoop.get()); gdk_threads_enter(); #pragma GCC diagnostic pop m_runLoop.clear(); g_signal_handler_disconnect(m_popup, unmapHandler); if (!m_client) return; m_client->valueChangedForPopupMenu(this, m_activeItem); }
unsigned TileController::blankPixelCountForTiles(const PlatformLayerList& tiles, const FloatRect& visibleRect, const IntPoint& tileTranslation) { Region paintedVisibleTiles; for (PlatformLayerList::const_iterator it = tiles.begin(), end = tiles.end(); it != end; ++it) { const PlatformLayer* tileLayer = it->get(); FloatRect visiblePart(CGRectOffset(PlatformCALayer::frameForLayer(tileLayer), tileTranslation.x(), tileTranslation.y())); visiblePart.intersect(visibleRect); if (!visiblePart.isEmpty()) paintedVisibleTiles.unite(enclosingIntRect(visiblePart)); } Region uncoveredRegion(enclosingIntRect(visibleRect)); uncoveredRegion.subtract(paintedVisibleTiles); return uncoveredRegion.totalArea(); }
IntRect enclosingIntRect(const LayoutRect& rect) { // Empty rects with fractional x, y values turn into non-empty rects when converting to enclosing. // We need to ensure that empty rects stay empty after the conversion, because the selection code expects them to be empty. IntPoint location = flooredIntPoint(rect.minXMinYCorner()); IntPoint maxPoint = IntPoint(rect.width() ? rect.maxX().ceil() : location.x(), rect.height() ? rect.maxY().ceil() : location.y()); return IntRect(location, maxPoint - location); }
void ImageBuffer::putUnmultipliedImageData(ByteArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint) { ASSERT(context() && context()->platformContext()); // Request for canvas bitmap; conversion required. if (context()->platformContext()->isRecording()) context()->platformContext()->convertToNonRecording(); GraphicsContext* gc = this->context(); if (!gc) { return; } const SkBitmap& dst = imageBufferCanvas(this)->getDevice()->accessBitmap(true); SkAutoLockPixels alp(dst); if (!dst.getPixels()) { return; } ASSERT(sourceRect.width() > 0); ASSERT(sourceRect.height() > 0); int originx = sourceRect.x(); int destx = destPoint.x() + sourceRect.x(); ASSERT(destx >= 0); ASSERT(destx < m_size.width()); ASSERT(originx >= 0); ASSERT(originx <= sourceRect.maxX()); int endx = destPoint.x() + sourceRect.maxX(); ASSERT(endx <= m_size.width()); int numColumns = endx - destx; int originy = sourceRect.y(); int desty = destPoint.y() + sourceRect.y(); ASSERT(desty >= 0); ASSERT(desty < m_size.height()); ASSERT(originy >= 0); ASSERT(originy <= sourceRect.maxY()); int endy = destPoint.y() + sourceRect.maxY(); ASSERT(endy <= m_size.height()); int numRows = endy - desty; unsigned srcBytesPerRow = 4 * sourceSize.width(); unsigned dstPixelsPerRow = dst.rowBytesAsPixels(); unsigned char* srcRows = source->data() + originy * srcBytesPerRow + originx * 4; SkPMColor* dstRows = dst.getAddr32(destx, desty); for (int y = 0; y < numRows; ++y) { for (int x = 0; x < numColumns; x++) { int basex = x * 4; dstRows[x] = SkPackARGB32(srcRows[basex + 3], srcRows[basex + 0], srcRows[basex + 1], srcRows[basex + 2]); } dstRows += dstPixelsPerRow; srcRows += srcBytesPerRow; } }
void ScrollableAreaPainter::paintOverflowControls(GraphicsContext* context, const IntPoint& paintOffset, const IntRect& damageRect, bool paintingOverlayControls) { // Don't do anything if we have no overflow. if (!m_scrollableArea.box().hasOverflowClip()) return; IntPoint adjustedPaintOffset = paintOffset; if (paintingOverlayControls) adjustedPaintOffset = m_scrollableArea.cachedOverlayScrollbarOffset(); IntRect localDamageRect = damageRect; localDamageRect.moveBy(-adjustedPaintOffset); // Overlay scrollbars paint in a second pass through the layer tree so that they will paint // on top of everything else. If this is the normal painting pass, paintingOverlayControls // will be false, and we should just tell the root layer that there are overlay scrollbars // that need to be painted. That will cause the second pass through the layer tree to run, // and we'll paint the scrollbars then. In the meantime, cache tx and ty so that the // second pass doesn't need to re-enter the LayoutTree to get it right. if (m_scrollableArea.hasOverlayScrollbars() && !paintingOverlayControls) { m_scrollableArea.setCachedOverlayScrollbarOffset(paintOffset); // It's not necessary to do the second pass if the scrollbars paint into layers. if ((m_scrollableArea.horizontalScrollbar() && m_scrollableArea.layerForHorizontalScrollbar()) || (m_scrollableArea.verticalScrollbar() && m_scrollableArea.layerForVerticalScrollbar())) return; if (!overflowControlsIntersectRect(localDamageRect)) return; LayoutView* layoutView = m_scrollableArea.box().view(); DeprecatedPaintLayer* paintingRoot = m_scrollableArea.layer()->enclosingLayerWithCompositedDeprecatedPaintLayerMapping(IncludeSelf); if (!paintingRoot) paintingRoot = layoutView->layer(); paintingRoot->setContainsDirtyOverlayScrollbars(true); return; } // This check is required to avoid painting custom CSS scrollbars twice. if (paintingOverlayControls && !m_scrollableArea.hasOverlayScrollbars()) return; { if (m_scrollableArea.horizontalScrollbar() && !m_scrollableArea.layerForHorizontalScrollbar()) { TransformRecorder translateRecorder(*context, *m_scrollableArea.horizontalScrollbar(), AffineTransform::translation(adjustedPaintOffset.x(), adjustedPaintOffset.y())); m_scrollableArea.horizontalScrollbar()->paint(context, localDamageRect); } if (m_scrollableArea.verticalScrollbar() && !m_scrollableArea.layerForVerticalScrollbar()) { TransformRecorder translateRecorder(*context, *m_scrollableArea.verticalScrollbar(), AffineTransform::translation(adjustedPaintOffset.x(), adjustedPaintOffset.y())); m_scrollableArea.verticalScrollbar()->paint(context, localDamageRect); } } if (m_scrollableArea.layerForScrollCorner()) return; // We fill our scroll corner with white if we have a scrollbar that doesn't run all the way up to the // edge of the box. paintScrollCorner(context, adjustedPaintOffset, damageRect); // Paint our resizer last, since it sits on top of the scroll corner. paintResizer(context, adjustedPaintOffset, damageRect); }
void EventTargetNode::dispatchWheelEvent(PlatformWheelEvent& e) { assert(!eventDispatchForbidden()); if (e.delta() == 0) return; FrameView* view = document()->view(); if (!view) return; IntPoint pos = view->viewportToContents(e.pos()); RefPtr<WheelEvent> we = new WheelEvent(e.isHorizontal(), e.delta(), document()->defaultView(), e.globalX(), e.globalY(), pos.x(), pos.y(), e.ctrlKey(), e.altKey(), e.shiftKey(), e.metaKey()); ExceptionCode ec = 0; if (!dispatchEvent(we, ec, true)) e.accept(); }
FloatPoint::FloatPoint(const IntPoint& p) : m_x(p.x()), m_y(p.y()) { }
void RenderMathMLFraction::paint(PaintInfo& info, const LayoutPoint& paintOffset) { RenderMathMLBlock::paint(info, paintOffset); if (info.context().paintingDisabled() || info.phase != PaintPhaseForeground || style().visibility() != VISIBLE || !isValid() || isStack()) return; IntPoint adjustedPaintOffset = roundedIntPoint(paintOffset + location() + LayoutPoint(0, m_ascent - mathAxisHeight())); GraphicsContextStateSaver stateSaver(info.context()); info.context().setStrokeThickness(m_lineThickness); info.context().setStrokeStyle(SolidStroke); info.context().setStrokeColor(style().visitedDependentColor(CSSPropertyColor)); info.context().drawLine(adjustedPaintOffset, roundedIntPoint(LayoutPoint(adjustedPaintOffset.x() + logicalWidth(), adjustedPaintOffset.y()))); }
void GraphicsContext::drawWindowsBitmap(WindowsBitmap* bitmap, const IntPoint& point) { drawBitmapToContext(m_data, platformContext()->cr(), bitmap->windowsDIB(), IntSize(point.x(), bitmap->size().height() + point.y())); }
int Frame::checkOverflowScroll(OverflowScrollAction action) { Position extent = selection().selection().extent(); if (extent.isNull()) return OverflowScrollNone; RenderObject* renderer = extent.deprecatedNode()->renderer(); if (!renderer) return OverflowScrollNone; FrameView* view = this->view(); if (!view) return OverflowScrollNone; RenderBlock* containingBlock = renderer->containingBlock(); if (!containingBlock || !containingBlock->hasOverflowClip()) return OverflowScrollNone; RenderLayer* layer = containingBlock->layer(); ASSERT(layer); IntRect visibleRect = IntRect(view->scrollX(), view->scrollY(), view->visibleWidth(), view->visibleHeight()); IntPoint position = m_overflowAutoScrollPos; if (visibleRect.contains(position.x(), position.y())) return OverflowScrollNone; int scrollType = 0; int deltaX = 0; int deltaY = 0; IntPoint selectionPosition; // This constant will make the selection draw a little bit beyond the edge of the visible area. // This prevents a visual glitch, in that you can fail to select a portion of a character that // is being rendered right at the edge of the visible rectangle. // FIXME: This probably needs improvement, and may need to take the font size into account. static const int scrollBoundsAdjustment = 3; // FIXME: Make a small buffer at the end of a visible rectangle so that autoscrolling works // even if the visible extends to the limits of the screen. if (position.x() < visibleRect.x()) { scrollType |= OverflowScrollLeft; if (action == PerformOverflowScroll) { deltaX -= static_cast<int>(m_overflowAutoScrollDelta); selectionPosition.setX(view->scrollX() - scrollBoundsAdjustment); } } else if (position.x() > visibleRect.maxX()) { scrollType |= OverflowScrollRight; if (action == PerformOverflowScroll) { deltaX += static_cast<int>(m_overflowAutoScrollDelta); selectionPosition.setX(view->scrollX() + view->visibleWidth() + scrollBoundsAdjustment); } } if (position.y() < visibleRect.y()) { scrollType |= OverflowScrollUp; if (action == PerformOverflowScroll) { deltaY -= static_cast<int>(m_overflowAutoScrollDelta); selectionPosition.setY(view->scrollY() - scrollBoundsAdjustment); } } else if (position.y() > visibleRect.maxY()) { scrollType |= OverflowScrollDown; if (action == PerformOverflowScroll) { deltaY += static_cast<int>(m_overflowAutoScrollDelta); selectionPosition.setY(view->scrollY() + view->visibleHeight() + scrollBoundsAdjustment); } } Ref<Frame> protectedThis(*this); if (action == PerformOverflowScroll && (deltaX || deltaY)) { layer->scrollToOffset(layer->scrollOffset() + IntSize(deltaX, deltaY)); // Handle making selection. VisiblePosition visiblePosition(renderer->positionForPoint(selectionPosition, nullptr)); if (visiblePosition.isNotNull()) { VisibleSelection visibleSelection = selection().selection(); visibleSelection.setExtent(visiblePosition); if (selection().granularity() != CharacterGranularity) visibleSelection.expandUsingGranularity(selection().granularity()); if (selection().shouldChangeSelection(visibleSelection)) selection().setSelection(visibleSelection); } m_overflowAutoScrollDelta *= 1.02f; // Accelerate the scroll } return scrollType; }
void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& pt, int width, bool grammar) { if (paintingDisabled()) return; // Create the pattern we'll use to draw the underline. static SkBitmap* misspellBitmap = 0; if (!misspellBitmap) { // We use a 2-pixel-high misspelling indicator because that seems to be // what WebKit is designed for, and how much room there is in a typical // page for it. const int rowPixels = 32; // Must be multiple of 4 for pattern below. const int colPixels = 2; misspellBitmap = new SkBitmap; misspellBitmap->setConfig(SkBitmap::kARGB_8888_Config, rowPixels, colPixels); misspellBitmap->allocPixels(); misspellBitmap->eraseARGB(0, 0, 0, 0); const uint32_t lineColor = 0xFFFF0000; // Opaque red. const uint32_t antiColor = 0x60600000; // Semitransparent red. // Pattern: X o o X o o X // o X o o X o uint32_t* row1 = misspellBitmap->getAddr32(0, 0); uint32_t* row2 = misspellBitmap->getAddr32(0, 1); for (int x = 0; x < rowPixels; x++) { switch (x % 4) { case 0: row1[x] = lineColor; break; case 1: row1[x] = antiColor; row2[x] = antiColor; break; case 2: row2[x] = lineColor; break; case 3: row1[x] = antiColor; row2[x] = antiColor; break; } } } // Offset it vertically by 1 so that there's some space under the text. SkScalar originX = SkIntToScalar(pt.x()); SkScalar originY = SkIntToScalar(pt.y()) + 1; // Make a shader for the bitmap with an origin of the box we'll draw. This // shader is refcounted and will have an initial refcount of 1. SkShader* shader = SkShader::CreateBitmapShader( *misspellBitmap, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode); SkMatrix matrix; matrix.reset(); matrix.postTranslate(originX, originY); shader->setLocalMatrix(matrix); // Assign the shader to the paint & release our reference. The paint will // now own the shader and the shader will be destroyed when the paint goes // out of scope. SkPaint paint; paint.setShader(shader); shader->unref(); SkRect rect; rect.set(originX, originY, originX + SkIntToScalar(width), originY + SkIntToScalar(misspellBitmap->height())); platformContext()->canvas()->drawRect(rect, paint); }
void RenderSVGRoot::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { // An empty viewport disables rendering. if (pixelSnappedBorderBoxRect().isEmpty()) return; // Don't paint, if the context explicitly disabled it. if (paintInfo.context->paintingDisabled()) return; // SVG outlines are painted during PaintPhaseForeground. if (paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) return; // An empty viewBox also disables rendering. // (http://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute) if (svgSVGElement().hasEmptyViewBox()) return; Page* page = frame().page(); // Don't paint if we don't have kids, except if we have filters we should paint those. if (!firstChild()) { auto* resources = SVGResourcesCache::cachedResourcesForRenderer(*this); if (!resources || !resources->filter()) { if (page && paintInfo.phase == PaintPhaseForeground) page->addRelevantUnpaintedObject(this, visualOverflowRect()); return; } } if (page && paintInfo.phase == PaintPhaseForeground) page->addRelevantRepaintedObject(this, visualOverflowRect()); // Make a copy of the PaintInfo because applyTransform will modify the damage rect. PaintInfo childPaintInfo(paintInfo); childPaintInfo.context->save(); // Apply initial viewport clip if (shouldApplyViewportClip()) childPaintInfo.context->clip(snappedIntRect(overflowClipRect(paintOffset, currentRenderNamedFlowFragment()))); // Convert from container offsets (html renderers) to a relative transform (svg renderers). // Transform from our paint container's coordinate system to our local coords. IntPoint adjustedPaintOffset = roundedIntPoint(paintOffset); childPaintInfo.applyTransform(AffineTransform::translation(adjustedPaintOffset.x(), adjustedPaintOffset.y()) * localToBorderBoxTransform()); // SVGRenderingContext must be destroyed before we restore the childPaintInfo.context, because a filter may have // changed the context and it is only reverted when the SVGRenderingContext destructor finishes applying the filter. { SVGRenderingContext renderingContext; bool continueRendering = true; if (childPaintInfo.phase == PaintPhaseForeground) { renderingContext.prepareToRenderSVGContent(*this, childPaintInfo); continueRendering = renderingContext.isRenderingPrepared(); } if (continueRendering) { childPaintInfo.updateSubtreePaintRootForChildren(this); for (auto& child : childrenOfType<RenderElement>(*this)) child.paint(childPaintInfo, location()); } } childPaintInfo.context->restore(); }
Tile::Coordinate TiledBackingStore::tileCoordinateForPoint(const IntPoint& point) const { int x = point.x() / m_tileSize.width(); int y = point.y() / m_tileSize.height(); return Tile::Coordinate(std::max(x, 0), std::max(y, 0)); }
IntSize scrollOffsetForFixedPosition(const IntRect& visibleContentRect, const IntSize& contentsSize, const IntPoint& scrollPosition, const IntPoint& scrollOrigin, float frameScaleFactor, bool fixedElementsLayoutRelativeToFrame) { int x = fixedPositionScrollOffset(visibleContentRect.width(), contentsSize.width(), scrollPosition.x(), scrollOrigin.x(), frameScaleFactor, fixedElementsLayoutRelativeToFrame); int y = fixedPositionScrollOffset(visibleContentRect.height(), contentsSize.height(), scrollPosition.y(), scrollOrigin.y(), frameScaleFactor, fixedElementsLayoutRelativeToFrame); return IntSize(x, y); }
void ChromeClientQt::delegatedScrollRequested(const IntPoint& point) { QPoint currentPosition(m_webPage->mainFrame()->scrollPosition()); emit m_webPage->scrollRequested(point.x() - currentPosition.x(), point.y() - currentPosition.y(), QRect(QPoint(0, 0), m_webPage->viewportSize())); }
bool RenderFrameSet::canResizeRow(const IntPoint& p) const { int r = hitTestSplit(m_rows, p.y()); return r != noSplit && m_rows.m_allowBorder[r] && !m_rows.m_preventResize[r]; }
void ScrollView::updateScrollbars(const IntSize& desiredOffset) { if (m_inUpdateScrollbars || prohibitsScrolling() || delegatesScrolling() || platformWidget()) return; // If we came in here with the view already needing a layout, then go ahead and do that // first. (This will be the common case, e.g., when the page changes due to window resizing for example). // This layout will not re-enter updateScrollbars and does not count towards our max layout pass total. if (!m_scrollbarsSuppressed) { m_inUpdateScrollbars = true; visibleContentsResized(); m_inUpdateScrollbars = false; } bool hasHorizontalScrollbar = m_horizontalScrollbar; bool hasVerticalScrollbar = m_verticalScrollbar; bool newHasHorizontalScrollbar = hasHorizontalScrollbar; bool newHasVerticalScrollbar = hasVerticalScrollbar; ScrollbarMode hScroll = m_horizontalScrollbarMode; ScrollbarMode vScroll = m_verticalScrollbarMode; if (hScroll != ScrollbarAuto) newHasHorizontalScrollbar = (hScroll == ScrollbarAlwaysOn); if (vScroll != ScrollbarAuto) newHasVerticalScrollbar = (vScroll == ScrollbarAlwaysOn); if (m_scrollbarsSuppressed || (hScroll != ScrollbarAuto && vScroll != ScrollbarAuto)) { if (hasHorizontalScrollbar != newHasHorizontalScrollbar) setHasHorizontalScrollbar(newHasHorizontalScrollbar); if (hasVerticalScrollbar != newHasVerticalScrollbar) setHasVerticalScrollbar(newHasVerticalScrollbar); } else { bool sendContentResizedNotification = false; IntSize docSize = contentsSize(); IntSize frameSize = m_boundsSize; if (hScroll == ScrollbarAuto) { newHasHorizontalScrollbar = docSize.width() > visibleWidth(); if (newHasHorizontalScrollbar && !m_updateScrollbarsPass && docSize.width() <= frameSize.width() && docSize.height() <= frameSize.height()) newHasHorizontalScrollbar = false; } if (vScroll == ScrollbarAuto) { newHasVerticalScrollbar = docSize.height() > visibleHeight(); if (newHasVerticalScrollbar && !m_updateScrollbarsPass && docSize.width() <= frameSize.width() && docSize.height() <= frameSize.height()) newHasVerticalScrollbar = false; } // If we ever turn one scrollbar off, always turn the other one off too. Never ever // try to both gain/lose a scrollbar in the same pass. if (!newHasHorizontalScrollbar && hasHorizontalScrollbar && vScroll != ScrollbarAlwaysOn) newHasVerticalScrollbar = false; if (!newHasVerticalScrollbar && hasVerticalScrollbar && hScroll != ScrollbarAlwaysOn) newHasHorizontalScrollbar = false; if (hasHorizontalScrollbar != newHasHorizontalScrollbar) { if (m_scrollOrigin.y() && !newHasHorizontalScrollbar) m_scrollOrigin.setY(m_scrollOrigin.y() - m_horizontalScrollbar->height()); setHasHorizontalScrollbar(newHasHorizontalScrollbar); sendContentResizedNotification = true; } if (hasVerticalScrollbar != newHasVerticalScrollbar) { if (m_scrollOrigin.x() && !newHasVerticalScrollbar) m_scrollOrigin.setX(m_scrollOrigin.x() - m_verticalScrollbar->width()); setHasVerticalScrollbar(newHasVerticalScrollbar); sendContentResizedNotification = true; } if (sendContentResizedNotification && m_updateScrollbarsPass < cMaxUpdateScrollbarsPass) { m_updateScrollbarsPass++; contentsResized(); visibleContentsResized(); IntSize newDocSize = contentsSize(); if (newDocSize == docSize) { // The layout with the new scroll state had no impact on // the document's overall size, so updateScrollbars didn't get called. // Recur manually. updateScrollbars(desiredOffset); } m_updateScrollbarsPass--; } } // Set up the range (and page step/line step), but only do this if we're not in a nested call (to avoid // doing it multiple times). if (m_updateScrollbarsPass) return; m_inUpdateScrollbars = true; IntPoint scrollPoint = adjustScrollPositionWithinRange(IntPoint(desiredOffset)); IntSize scroll(scrollPoint.x(), scrollPoint.y()); if (m_horizontalScrollbar) { int clientWidth = visibleWidth(); m_horizontalScrollbar->setEnabled(contentsWidth() > clientWidth); int pageStep = max(max<int>(clientWidth * Scrollbar::minFractionToStepWhenPaging(), clientWidth - Scrollbar::maxOverlapBetweenPages()), 1); IntRect oldRect(m_horizontalScrollbar->frameRect()); IntRect hBarRect = IntRect(0, m_boundsSize.height() - m_horizontalScrollbar->height(), m_boundsSize.width() - (m_verticalScrollbar ? m_verticalScrollbar->width() : 0), m_horizontalScrollbar->height()); m_horizontalScrollbar->setFrameRect(hBarRect); if (!m_scrollbarsSuppressed && oldRect != m_horizontalScrollbar->frameRect()) m_horizontalScrollbar->invalidate(); if (m_scrollbarsSuppressed) m_horizontalScrollbar->setSuppressInvalidation(true); m_horizontalScrollbar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep); m_horizontalScrollbar->setProportion(clientWidth, contentsWidth()); if (m_scrollbarsSuppressed) m_horizontalScrollbar->setSuppressInvalidation(false); } if (m_verticalScrollbar) { int clientHeight = visibleHeight(); m_verticalScrollbar->setEnabled(contentsHeight() > clientHeight); int pageStep = max(max<int>(clientHeight * Scrollbar::minFractionToStepWhenPaging(), clientHeight - Scrollbar::maxOverlapBetweenPages()), 1); IntRect oldRect(m_verticalScrollbar->frameRect()); IntRect vBarRect = IntRect(m_boundsSize.width() - m_verticalScrollbar->width(), 0, m_verticalScrollbar->width(), m_boundsSize.height() - (m_horizontalScrollbar ? m_horizontalScrollbar->height() : 0)); m_verticalScrollbar->setFrameRect(vBarRect); if (!m_scrollbarsSuppressed && oldRect != m_verticalScrollbar->frameRect()) m_verticalScrollbar->invalidate(); if (m_scrollbarsSuppressed) m_verticalScrollbar->setSuppressInvalidation(true); m_verticalScrollbar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep); m_verticalScrollbar->setProportion(clientHeight, contentsHeight()); if (m_scrollbarsSuppressed) m_verticalScrollbar->setSuppressInvalidation(false); } if (hasHorizontalScrollbar != (m_horizontalScrollbar != 0) || hasVerticalScrollbar != (m_verticalScrollbar != 0)) { frameRectsChanged(); updateScrollCorner(); } ScrollableArea::scrollToOffsetWithoutAnimation(FloatPoint(scroll.width() + m_scrollOrigin.x(), scroll.height() + m_scrollOrigin.y())); // Make sure the scrollbar offsets are up to date. if (m_horizontalScrollbar) m_horizontalScrollbar->offsetDidChange(); if (m_verticalScrollbar) m_verticalScrollbar->offsetDidChange(); m_inUpdateScrollbars = false; }
void RenderMathMLRoot::paint(PaintInfo& info, const LayoutPoint& paintOffset) { RenderMathMLBlock::paint(info, paintOffset); if (info.context->paintingDisabled()) return; if (!firstChild() || !lastChild()) return; IntPoint adjustedPaintOffset = roundedIntPoint(paintOffset + location()); RenderBoxModelObject* baseWrapper = toRenderBoxModelObject(lastChild()); int baseHeight = baseWrapper->pixelSnappedOffsetHeight(); // default to the font size in pixels if we're empty if (!baseHeight) baseHeight = style()->fontSize(); int overbarWidth = baseWrapper->pixelSnappedOffsetWidth(); int indexWidth = 0; RenderObject* current = firstChild(); while (current != lastChild()) { if (current->isBoxModelObject()) { RenderBoxModelObject* box = toRenderBoxModelObject(current); indexWidth += box->pixelSnappedOffsetWidth(); } current = current->nextSibling(); } int frontWidth = static_cast<int>(style()->fontSize() * gFrontWidthEms); int overbarLeftPointShift = 0; // Base height above which the shape of the root changes int thresholdHeight = static_cast<int>(gThresholdBaseHeightEms * style()->fontSize()); if (baseHeight > thresholdHeight && thresholdHeight) { float shift = (baseHeight - thresholdHeight) / static_cast<float>(thresholdHeight); if (shift > 1.) shift = 1.0f; overbarLeftPointShift = static_cast<int>(gRadicalBottomPointXFront * frontWidth * shift); } overbarWidth += overbarLeftPointShift; int rootPad = static_cast<int>(gRootPaddingEms * style()->fontSize()); int startX = adjustedPaintOffset.x() + indexWidth + gRadicalLeftExtra + style()->paddingLeft().value() - rootPad; adjustedPaintOffset.setY(adjustedPaintOffset.y() + style()->paddingTop().value() - rootPad); FloatPoint overbarLeftPoint(startX - overbarLeftPointShift, adjustedPaintOffset.y()); FloatPoint bottomPoint(startX - gRadicalBottomPointXFront * frontWidth, adjustedPaintOffset.y() + baseHeight + gRadicalBottomPointLower); FloatPoint dipLeftPoint(startX - gRadicalDipLeftPointXFront * frontWidth, adjustedPaintOffset.y() + gRadicalDipLeftPointYPos * baseHeight); FloatPoint leftEnd(startX - frontWidth, dipLeftPoint.y() + gRadicalLeftEndYShiftEms * style()->fontSize()); GraphicsContextStateSaver stateSaver(*info.context); info.context->setStrokeThickness(gRadicalLineThicknessEms * style()->fontSize()); info.context->setStrokeStyle(SolidStroke); info.context->setStrokeColor(style()->visitedDependentColor(CSSPropertyColor), ColorSpaceDeviceRGB); info.context->setLineJoin(MiterJoin); info.context->setMiterLimit(style()->fontSize()); Path root; root.moveTo(FloatPoint(overbarLeftPoint.x() + overbarWidth, adjustedPaintOffset.y())); // draw top root.addLineTo(overbarLeftPoint); // draw from top left corner to bottom point of radical root.addLineTo(bottomPoint); // draw from bottom point to top of left part of radical base "dip" root.addLineTo(dipLeftPoint); // draw to end root.addLineTo(leftEnd); info.context->strokePath(root); GraphicsContextStateSaver maskStateSaver(*info.context); // Build a mask to draw the thick part of the root. Path mask; mask.moveTo(overbarLeftPoint); mask.addLineTo(bottomPoint); mask.addLineTo(dipLeftPoint); mask.addLineTo(FloatPoint(2 * dipLeftPoint.x() - leftEnd.x(), 2 * dipLeftPoint.y() - leftEnd.y())); info.context->clip(mask); // Draw the thick part of the root. info.context->setStrokeThickness(gRadicalThickLineThicknessEms * style()->fontSize()); info.context->setLineCap(SquareCap); Path line; line.moveTo(bottomPoint); line.addLineTo(dipLeftPoint); info.context->strokePath(line); }
IntRect pixelSnappedIntRect(const FractionalLayoutRect& rect) { IntPoint roundedLocation = roundedIntPoint(rect.location()); return IntRect(roundedLocation, IntSize((rect.x() + rect.width()).round() - roundedLocation.x(), (rect.y() + rect.height()).round() - roundedLocation.y())); }
static PlatformRefPtr<GdkCursor> createCustomCursor(Image* image, const IntPoint& hotSpot) { IntPoint effectiveHotSpot = determineHotSpot(image, hotSpot); PlatformRefPtr<GdkPixbuf> pixbuf = adoptPlatformRef(image->getGdkPixbuf()); return adoptPlatformRef(gdk_cursor_new_from_pixbuf(gdk_display_get_default(), pixbuf.get(), effectiveHotSpot.x(), effectiveHotSpot.y())); }
IntPoint Widget::convertChildToSelf(const Widget* child, const IntPoint& point) const { return IntPoint(point.x() + child->x(), point.y() + child->y()); }
void SpinButtonElement::defaultEventHandler(Event* event) { if (!event->isMouseEvent()) { if (!event->defaultHandled()) HTMLDivElement::defaultEventHandler(event); return; } RenderBox* box = renderBox(); if (!box) { if (!event->defaultHandled()) HTMLDivElement::defaultEventHandler(event); return; } if (!shouldRespondToMouseEvents()) { if (!event->defaultHandled()) HTMLDivElement::defaultEventHandler(event); return; } MouseEvent* mouseEvent = static_cast<MouseEvent*>(event); IntPoint local = roundedIntPoint(box->absoluteToLocal(mouseEvent->absoluteLocation(), UseTransforms | SnapOffsetForTransforms)); if (mouseEvent->type() == eventNames().mousedownEvent && mouseEvent->button() == LeftButton) { if (box->pixelSnappedBorderBoxRect().contains(local)) { // The following functions of HTMLInputElement may run JavaScript // code which detaches this shadow node. We need to take a reference // and check renderer() after such function calls. RefPtr<Node> protector(this); if (m_spinButtonOwner) m_spinButtonOwner->focusAndSelectSpinButtonOwner(); if (renderer()) { if (m_upDownState != Indeterminate) { // A JavaScript event handler called in doStepAction() below // might change the element state and we might need to // cancel the repeating timer by the state change. If we // started the timer after doStepAction(), we would have no // chance to cancel the timer. startRepeatingTimer(); doStepAction(m_upDownState == Up ? 1 : -1); } } event->setDefaultHandled(); } } else if (mouseEvent->type() == eventNames().mouseupEvent && mouseEvent->button() == LeftButton) stopRepeatingTimer(); else if (event->type() == eventNames().mousemoveEvent) { if (box->pixelSnappedBorderBoxRect().contains(local)) { if (!m_capturing) { if (Frame* frame = document()->frame()) { frame->eventHandler()->setCapturingMouseEventsNode(this); m_capturing = true; if (Page* page = document()->page()) { if (page->chrome()) page->chrome()->registerPopupOpeningObserver(this); } } } UpDownState oldUpDownState = m_upDownState; m_upDownState = local.y() < box->height() / 2 ? Up : Down; if (m_upDownState != oldUpDownState) renderer()->repaint(); } else { releaseCapture(); m_upDownState = Indeterminate; } } if (!event->defaultHandled()) HTMLDivElement::defaultEventHandler(event); }
void ImageBuffer::putByteArray(Multiply multiplied, Uint8ClampedArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint, CoordinateSystem) { ASSERT(sourceRect.width() > 0); ASSERT(sourceRect.height() > 0); int originx = sourceRect.x(); int destx = destPoint.x() + sourceRect.x(); ASSERT(destx >= 0); ASSERT(destx < m_size.width()); ASSERT(originx >= 0); ASSERT(originx <= sourceRect.maxX()); int endx = destPoint.x() + sourceRect.maxX(); ASSERT(endx <= m_size.width()); int numColumns = endx - destx; int originy = sourceRect.y(); int desty = destPoint.y() + sourceRect.y(); ASSERT(desty >= 0); ASSERT(desty < m_size.height()); ASSERT(originy >= 0); ASSERT(originy <= sourceRect.maxY()); int endy = destPoint.y() + sourceRect.maxY(); ASSERT(endy <= m_size.height()); int numRows = endy - desty; IntRect imageRect(destx, desty, numColumns, numRows); RefPtr<cairo_surface_t> imageSurface = copySurfaceToImageAndAdjustRect(m_data.m_surface.get(), imageRect); destx = imageRect.x(); desty = imageRect.y(); unsigned char* pixelData = cairo_image_surface_get_data(imageSurface.get()); unsigned srcBytesPerRow = 4 * sourceSize.width(); int stride = cairo_image_surface_get_stride(imageSurface.get()); unsigned char* srcRows = source->data() + originy * srcBytesPerRow + originx * 4; for (int y = 0; y < numRows; ++y) { unsigned* row = reinterpret_cast_ptr<unsigned*>(pixelData + stride * (y + desty)); for (int x = 0; x < numColumns; x++) { int basex = x * 4; unsigned* pixel = row + x + destx; // Avoid calling Color::premultipliedARGBFromColor() because one // function call per pixel is too expensive. unsigned red = srcRows[basex]; unsigned green = srcRows[basex + 1]; unsigned blue = srcRows[basex + 2]; unsigned alpha = srcRows[basex + 3]; if (multiplied == Unmultiplied) { if (alpha != 255) { red = (red * alpha + 254) / 255; green = (green * alpha + 254) / 255; blue = (blue * alpha + 254) / 255; } } *pixel = (alpha << 24) | red << 16 | green << 8 | blue; } srcRows += srcBytesPerRow; } cairo_surface_mark_dirty_rectangle(imageSurface.get(), destx, desty, numColumns, numRows); if (imageSurface != m_data.m_surface.get()) copyRectFromOneSurfaceToAnother(imageSurface.get(), m_data.m_surface.get(), IntSize(), IntRect(0, 0, numColumns, numRows), IntSize(destPoint.x() + sourceRect.x(), destPoint.y() + sourceRect.y()), CAIRO_OPERATOR_SOURCE); }
void EwkView::setCursor(const Cursor& cursor) { if (cursor.image()) { // Custom cursor. if (cursor.image() == m_cursorIdentifier) return; m_cursorIdentifier = cursor.image(); Ewk_View_Smart_Data* sd = smartData(); RefPtr<Evas_Object> cursorObject = adoptRef(cursor.image()->getEvasObject(sd->base.evas)); if (!cursorObject) return; // Resize cursor. evas_object_resize(cursorObject.get(), cursor.image()->size().width(), cursor.image()->size().height()); // Get cursor hot spot. IntPoint hotSpot; cursor.image()->getHotSpot(hotSpot); Ecore_Evas* ecoreEvas = ecore_evas_ecore_evas_get(sd->base.evas); // ecore_evas takes care of freeing the cursor object. ecore_evas_object_cursor_set(ecoreEvas, cursorObject.release().leakRef(), EVAS_LAYER_MAX, hotSpot.x(), hotSpot.y()); return; } // Standard cursor. const char* group = cursor.platformCursor(); if (!group || group == m_cursorIdentifier) return; m_cursorIdentifier = group; Ewk_View_Smart_Data* sd = smartData(); RefPtr<Evas_Object> cursorObject = adoptRef(edje_object_add(sd->base.evas)); Ecore_Evas* ecoreEvas = ecore_evas_ecore_evas_get(sd->base.evas); if (!m_theme || !edje_object_file_set(cursorObject.get(), m_theme, group)) { ecore_evas_object_cursor_set(ecoreEvas, 0, 0, 0, 0); #ifdef HAVE_ECORE_X if (WebCore::isUsingEcoreX(sd->base.evas)) WebCore::applyFallbackCursor(ecoreEvas, group); #endif return; } // Set cursor size. Evas_Coord width, height; edje_object_size_min_get(cursorObject.get(), &width, &height); if (width <= 0 || height <= 0) edje_object_size_min_calc(cursorObject.get(), &width, &height); if (width <= 0 || height <= 0) { width = defaultCursorSize; height = defaultCursorSize; } evas_object_resize(cursorObject.get(), width, height); // Get cursor hot spot. const char* data; int hotspotX = 0; data = edje_object_data_get(cursorObject.get(), "hot.x"); if (data) hotspotX = atoi(data); int hotspotY = 0; data = edje_object_data_get(cursorObject.get(), "hot.y"); if (data) hotspotY = atoi(data); // ecore_evas takes care of freeing the cursor object. ecore_evas_object_cursor_set(ecoreEvas, cursorObject.release().leakRef(), EVAS_LAYER_MAX, hotspotX, hotspotY); }