Chromium Code Reviews| Index: third_party/WebKit/Source/core/frame/LocalFrame.cpp |
| diff --git a/third_party/WebKit/Source/core/frame/LocalFrame.cpp b/third_party/WebKit/Source/core/frame/LocalFrame.cpp |
| index 900be2856592ddbd2a098beb70384a235e416917..de802ca84f418bc4a1570a82a30254f8140e9999 100644 |
| --- a/third_party/WebKit/Source/core/frame/LocalFrame.cpp |
| +++ b/third_party/WebKit/Source/core/frame/LocalFrame.cpp |
| @@ -60,6 +60,8 @@ |
| #include "core/page/FocusController.h" |
| #include "core/page/Page.h" |
| #include "core/page/scrolling/ScrollingCoordinator.h" |
| +#include "core/paint/ObjectPainter.h" |
| +#include "core/paint/PaintInfo.h" |
| #include "core/paint/PaintLayer.h" |
| #include "core/paint/TransformRecorder.h" |
| #include "core/svg/SVGDocumentExtensions.h" |
| @@ -71,6 +73,7 @@ |
| #include "platform/graphics/StaticBitmapImage.h" |
| #include "platform/graphics/paint/ClipRecorder.h" |
| #include "platform/graphics/paint/SkPictureBuilder.h" |
| +#include "platform/graphics/paint/TransformDisplayItem.h" |
| #include "platform/text/TextStream.h" |
| #include "public/platform/WebFrameScheduler.h" |
| #include "public/platform/WebSecurityOrigin.h" |
| @@ -85,27 +88,57 @@ using namespace HTMLNames; |
| namespace { |
| -struct ScopedFramePaintingState { |
| +// Convenience class for initializing a GraphicsContext to build a DragImage from a specific |
| +// region specified by |bounds|. After painting the using context(), the DragImage returned from |
| +// createImage() will only contain the content in |bounds| with the appropriate device scale |
| +// factor included. |
| +class DragImageBuilder { |
| STACK_ALLOCATED(); |
| public: |
| - ScopedFramePaintingState(LocalFrame* frame, Node* node) |
| - : frame(frame) |
| - , node(node) |
| + DragImageBuilder(const LocalFrame& localFrame, const IntRect& bounds, Node* draggedNode, float opacity = 1) |
| + : m_localFrame(localFrame) |
| + , m_draggedNode(draggedNode) |
| + , m_bounds(bounds) |
| + , m_opacity(opacity) |
| { |
| - ASSERT(!node || node->layoutObject()); |
| - if (node) |
| - node->layoutObject()->updateDragState(true); |
| + if (m_draggedNode && m_draggedNode->layoutObject()) |
| + m_draggedNode->layoutObject()->updateDragState(true); |
| + |
| + float deviceScaleFactor = m_localFrame.host()->deviceScaleFactor(); |
| + m_bounds.setWidth(m_bounds.width() * deviceScaleFactor); |
| + m_bounds.setHeight(m_bounds.height() * deviceScaleFactor); |
| + m_pictureBuilder = adoptPtr(new SkPictureBuilder(SkRect::MakeIWH(m_bounds.width(), m_bounds.height()))); |
| + |
| + AffineTransform transform; |
| + transform.scale(deviceScaleFactor, deviceScaleFactor); |
| + transform.translate(-m_bounds.x(), -m_bounds.y()); |
| + context().paintController().createAndAppend<BeginTransformDisplayItem>(m_localFrame, transform); |
| } |
| - ~ScopedFramePaintingState() |
| + GraphicsContext& context() { return m_pictureBuilder->context(); } |
| + |
| + PassOwnPtr<DragImage> createImage() |
| { |
| - if (node && node->layoutObject()) |
| - node->layoutObject()->updateDragState(false); |
| - frame->view()->setNodeToDraw(0); |
| + if (m_draggedNode && m_draggedNode->layoutObject()) |
| + m_draggedNode->layoutObject()->updateDragState(false); |
| + context().paintController().endItem<EndTransformDisplayItem>(m_localFrame); |
| + RefPtr<const SkPicture> recording = m_pictureBuilder->endRecording(); |
| + RefPtr<SkImage> skImage = adoptRef(SkImage::NewFromPicture(recording.get(), |
| + SkISize::Make(m_bounds.width(), m_bounds.height()), nullptr, nullptr)); |
| + RefPtr<Image> image = StaticBitmapImage::create(skImage.release()); |
| + RespectImageOrientationEnum imageOrientation = DoNotRespectImageOrientation; |
| + if (m_draggedNode && m_draggedNode->layoutObject()) |
| + imageOrientation = LayoutObject::shouldRespectImageOrientation(m_draggedNode->layoutObject()); |
| + return DragImage::create(image.get(), imageOrientation, |
| + m_localFrame.host()->deviceScaleFactor(), InterpolationHigh, m_opacity); |
| } |
| - RawPtrWillBeMember<LocalFrame> frame; |
| - RawPtrWillBeMember<Node> node; |
| +private: |
| + const LocalFrame& m_localFrame; |
| + Node* m_draggedNode; |
| + IntRect m_bounds; |
| + float m_opacity; |
| + OwnPtr<SkPictureBuilder> m_pictureBuilder; |
| }; |
| inline float parentPageZoomFactor(LocalFrame* frame) |
| @@ -608,63 +641,42 @@ double LocalFrame::devicePixelRatio() const |
| return ratio; |
| } |
| -PassOwnPtr<DragImage> LocalFrame::paintIntoDragImage( |
| - const DisplayItemClient& displayItemClient, |
| - RespectImageOrientationEnum shouldRespectImageOrientation, |
| - const GlobalPaintFlags globalPaintFlags, IntRect paintingRect, float opacity) |
| +PassOwnPtr<DragImage> LocalFrame::paintIntoDragImage(const GlobalPaintFlags globalPaintFlags, |
| + IntRect paintingRect, Node* draggedNode, float opacity) |
| { |
| ASSERT(document()->isActive()); |
| // Not flattening compositing layers will result in a broken image being painted. |
| ASSERT(globalPaintFlags & GlobalPaintFlattenCompositingLayers); |
| - float deviceScaleFactor = m_host->deviceScaleFactor(); |
| - paintingRect.setWidth(paintingRect.width() * deviceScaleFactor); |
| - paintingRect.setHeight(paintingRect.height() * deviceScaleFactor); |
| - |
| - // The content is shifted to origin, to fit within the image bounds - which are the same |
| - // as the picture bounds. |
| - SkRect pictureBounds = SkRect::MakeIWH(paintingRect.width(), paintingRect.height()); |
| - SkPictureBuilder pictureBuilder(pictureBounds); |
| - { |
| - GraphicsContext& paintContext = pictureBuilder.context(); |
| - |
| - AffineTransform transform; |
| - transform.scale(deviceScaleFactor, deviceScaleFactor); |
| - transform.translate(-paintingRect.x(), -paintingRect.y()); |
| - TransformRecorder transformRecorder(paintContext, displayItemClient, transform); |
| - |
| - m_view->paintContents(paintContext, globalPaintFlags, paintingRect); |
| - |
| - } |
| - RefPtr<const SkPicture> recording = pictureBuilder.endRecording(); |
| - RefPtr<SkImage> skImage = adoptRef(SkImage::NewFromPicture(recording.get(), |
| - SkISize::Make(paintingRect.width(), paintingRect.height()), nullptr, nullptr)); |
| - RefPtr<Image> image = StaticBitmapImage::create(skImage.release()); |
| - |
| - return DragImage::create(image.get(), shouldRespectImageOrientation, deviceScaleFactor, |
| - InterpolationHigh, opacity); |
| + DragImageBuilder dragImageBuilder(*this, paintingRect, draggedNode, opacity); |
| + m_view->paintContents(dragImageBuilder.context(), globalPaintFlags, paintingRect); |
| + return dragImageBuilder.createImage(); |
| } |
| PassOwnPtr<DragImage> LocalFrame::nodeImage(Node& node) |
| { |
| - if (!node.layoutObject()) |
| - return nullptr; |
| - |
| - const ScopedFramePaintingState state(this, &node); |
| - |
| m_view->updateAllLifecyclePhases(); |
| - |
| - m_view->setNodeToDraw(&node); // Enable special sub-tree drawing mode. |
| - |
| - // Document::updateLayout may have blown away the original LayoutObject. |
| LayoutObject* layoutObject = node.layoutObject(); |
| if (!layoutObject) |
| return nullptr; |
| - IntRect rect; |
| + // Directly paint boxes as if they are a stacking context. |
| + if (layoutObject->isBox() && layoutObject->container()) { |
| + IntRect boundingBox = layoutObject->absoluteBoundingBoxRectIncludingDescendants(); |
| + LayoutPoint paintOffset = boundingBox.location() - layoutObject->offsetFromContainer(layoutObject->container(), LayoutPoint()); |
| + |
| + DragImageBuilder dragImageBuilder(*this, boundingBox, &node); |
| + { |
| + PaintInfo paintInfo(dragImageBuilder.context(), boundingBox, PaintPhase::PaintPhaseForeground, GlobalPaintFlattenCompositingLayers, 0); |
| + ObjectPainter(*layoutObject).paintAsPseudoStackingContext(paintInfo, LayoutPoint(paintOffset)); |
| + } |
| + return dragImageBuilder.createImage(); |
| + } |
| - return paintIntoDragImage(*layoutObject, LayoutObject::shouldRespectImageOrientation(layoutObject), |
| - GlobalPaintFlattenCompositingLayers, layoutObject->paintingRootRect(rect)); |
| + // FIXME(pdr): This will also paint the background if the object contains transparency. We can |
|
Xianzhu
2016/01/20 00:25:18
Nit: s/FIXME/TODO/ ?
|
| + // directly call layoutObject->paint(...) (see: ObjectPainter::paintAsPseudoStackingContext) but |
| + // painters are inconsistent about which transform space they expect (see: svg, inlines, etc.) |
| + return paintIntoDragImage(GlobalPaintFlattenCompositingLayers, layoutObject->absoluteBoundingBoxRectIncludingDescendants(), &node); |
| } |
| PassOwnPtr<DragImage> LocalFrame::dragImageForSelection(float opacity) |
| @@ -672,12 +684,10 @@ PassOwnPtr<DragImage> LocalFrame::dragImageForSelection(float opacity) |
| if (!selection().isRange()) |
| return nullptr; |
| - const ScopedFramePaintingState state(this, 0); |
| m_view->updateAllLifecyclePhases(); |
| - return paintIntoDragImage(*this, DoNotRespectImageOrientation, |
| - GlobalPaintSelectionOnly | GlobalPaintFlattenCompositingLayers, |
| - enclosingIntRect(selection().bounds()), opacity); |
| + return paintIntoDragImage(GlobalPaintSelectionOnly | GlobalPaintFlattenCompositingLayers, |
| + enclosingIntRect(selection().bounds()), nullptr, opacity); |
| } |
| String LocalFrame::selectedText() const |