+2011-11-02 Dan Bernstein <mitz@apple.com>
+
+ <rdar://problem/10336700> Add API to get rendered text image without having to select it
+ https://bugs.webkit.org/show_bug.cgi?id=71407
+
+ Reviewed by Simon Fraser.
+
+ Test: TestWebKitAPI/Tests/mac/RenderedImageFromDOMRange.mm
+
+ * bindings/objc/DOM.mm:
+ (-[DOMRange renderedImageForcingBlackText:]): Added.
+ * bindings/objc/DOMPrivate.h:
+ * page/Frame.h:
+ * page/mac/FrameMac.mm:
+ (WebCore::Frame::rangeImage): Added. Sets the selection in the RenderView (only) based on the
+ given range and gets a selection-only rendering of the view, then restores the selection.
+ * rendering/RenderView.cpp:
+ (WebCore::RenderView::setSelection): Skip all invalidation if the repaint behavior is RepaintNothing.
+ (WebCore::RenderView::getSelection): Added this getter.
+ * rendering/RenderView.h:
+
2011-11-02 Tom Sepez <tsepez@chromium.org>
XSSAuditor is silent
return core(self)->boundingBox();
}
+- (NSImage *)renderedImageForcingBlackText:(BOOL)forceBlackText
+{
+ WebCore::Range* range = core(self);
+ WebCore::Frame* frame = range->ownerDocument()->frame();
+ if (!frame)
+ return nil;
+
+ return frame->rangeImage(range, forceBlackText);
+}
+
- (NSArray *)textRects
{
// FIXME: The call to updateLayoutIgnorePendingStylesheets should be moved into WebCore::Range.
@interface DOMRange (DOMRangeExtensions)
- (NSRect)boundingBox;
+- (NSImage *)renderedImageForcingBlackText:(BOOL)forceBlackText;
- (NSArray *)lineBoxRects; // Deprecated. Use textRects instead.
- (NSArray *)textRects;
@end
#if PLATFORM(MAC)
NSImage* selectionImage(bool forceBlackText = false) const;
+ NSImage* rangeImage(Range*, bool forceBlackText = false) const;
NSImage* snapshotDragImage(Node*, NSRect* imageRect, NSRect* elementRect) const;
NSImage* imageFromRect(NSRect) const;
#endif
#import "PlatformWheelEvent.h"
#import "RegularExpression.h"
#import "RenderTableCell.h"
+#import "RenderView.h"
#import "Scrollbar.h"
#import "SimpleFontData.h"
#import "visible_units.h"
return result;
}
+NSImage *Frame::rangeImage(Range* range, bool forceBlackText) const
+{
+ m_view->setPaintBehavior(PaintBehaviorSelectionOnly | (forceBlackText ? PaintBehaviorForceBlackText : 0));
+ m_doc->updateLayout();
+ RenderView* view = contentRenderer();
+ if (!view)
+ return nil;
+
+ VisibleSelection visibleSelection(range);
+
+ if (!visibleSelection.isRange())
+ return nil;
+
+ Position start = visibleSelection.start();
+ Position candidate = start.downstream();
+ if (candidate.isCandidate())
+ start = candidate;
+ Position end = visibleSelection.end();
+ candidate = end.upstream();
+ if (candidate.isCandidate())
+ end = candidate;
+
+ if (start.isNull() || end.isNull() || visibleSelection.visibleStart() == visibleSelection.visibleEnd())
+ return nil;
+
+ RenderObject* savedStartRenderer;
+ int savedStartOffset;
+ RenderObject* savedEndRenderer;
+ int savedEndOffset;
+ view->getSelection(savedStartRenderer, savedStartOffset, savedEndRenderer, savedEndOffset);
+
+ RenderObject* startRenderer = start.deprecatedNode()->renderer();
+ RenderObject* endRenderer = end.deprecatedNode()->renderer();
+
+ view->setSelection(startRenderer, start.deprecatedEditingOffset(), endRenderer, end.deprecatedEditingOffset(), RenderView::RepaintNothing);
+ NSImage* result = imageFromRect(view->selectionBounds());
+ view->setSelection(savedStartRenderer, savedStartOffset, savedEndRenderer, savedEndOffset, RenderView::RepaintNothing);
+
+ m_view->setPaintBehavior(PaintBehaviorNormal);
+ return result;
+}
+
NSImage* Frame::snapshotDragImage(Node* node, NSRect* imageRect, NSRect* elementRect) const
{
RenderObject* renderer = node->renderer();
o = o->nextInPreOrder();
}
- m_layer->clearBlockSelectionGapsBounds();
+ if (blockRepaintMode != RepaintNothing)
+ m_layer->clearBlockSelectionGapsBounds();
// Now that the selection state has been updated for the new objects, walk them again and
// put them in the new objects list.
o = o->nextInPreOrder();
}
- if (!m_frameView) {
+ if (!m_frameView || blockRepaintMode == RepaintNothing) {
// We built the maps, but we aren't going to use them.
// We need to delete the values, otherwise they'll all leak!
deleteAllValues(oldSelectedObjects);
m_frameView->endDeferredRepaints();
}
+void RenderView::getSelection(RenderObject*& startRenderer, int& startOffset, RenderObject*& endRenderer, int& endOffset) const
+{
+ startRenderer = m_selectionStart;
+ startOffset = m_selectionStartPos;
+ endRenderer = m_selectionEnd;
+ endOffset = m_selectionEndPos;
+}
+
void RenderView::clearSelection()
{
m_layer->repaintBlockSelectionGaps();
virtual void paint(PaintInfo&, const LayoutPoint&);
virtual void paintBoxDecorations(PaintInfo&, const IntPoint&);
- enum SelectionRepaintMode { RepaintNewXOROld, RepaintNewMinusOld };
+ enum SelectionRepaintMode { RepaintNewXOROld, RepaintNewMinusOld, RepaintNothing };
void setSelection(RenderObject* start, int startPos, RenderObject* end, int endPos, SelectionRepaintMode = RepaintNewXOROld);
+ void getSelection(RenderObject*& startRenderer, int& startOffset, RenderObject*& endRenderer, int& endOffset) const;
void clearSelection();
RenderObject* selectionStart() const { return m_selectionStart; }
RenderObject* selectionEnd() const { return m_selectionEnd; }
+2011-11-02 Dan Bernstein <mitz@apple.com>
+
+ <rdar://problem/10336700> Add API to get rendered text image without having to select it
+ https://bugs.webkit.org/show_bug.cgi?id=71407
+
+ Reviewed by Simon Fraser.
+
+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+ * TestWebKitAPI/Tests/mac/RenderedImageFromDOMRange.mm: Added.
+ (-[RenderedImageFromDOMRangeFrameLoadDelegate webView:didFinishLoadForFrame:]):
+ (TestWebKitAPI::TEST):
+
2011-11-02 Benjamin Poulain <benjamin@webkit.org>
Make the main frame's base path more explicit in _drt_descriptionSuitableForTestResult
33DC89141419579F00747EF7 /* LoadCanceledNoServerRedirectCallback_Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 33DC89131419579F00747EF7 /* LoadCanceledNoServerRedirectCallback_Bundle.cpp */; };
33E79E06137B5FD900E32D99 /* mouse-move-listener.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 33E79E05137B5FCE00E32D99 /* mouse-move-listener.html */; };
37200B9213A16230007A4FAD /* VectorReverse.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 37200B9113A16230007A4FAD /* VectorReverse.cpp */; };
+ 3722C8691461E03E00C45D00 /* RenderedImageFromDOMRange.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3722C8681461E03E00C45D00 /* RenderedImageFromDOMRange.mm */; };
3799AD3A14120A43005EB0C6 /* StringByEvaluatingJavaScriptFromString.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3799AD3914120A43005EB0C6 /* StringByEvaluatingJavaScriptFromString.mm */; };
37DC678D140D7C5000ABCCDB /* DOMRangeOfString.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37DC678B140D7C5000ABCCDB /* DOMRangeOfString.mm */; };
37DC6791140D7D7600ABCCDB /* DOMRangeOfString.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 37DC678F140D7D3A00ABCCDB /* DOMRangeOfString.html */; };
33DC89131419579F00747EF7 /* LoadCanceledNoServerRedirectCallback_Bundle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LoadCanceledNoServerRedirectCallback_Bundle.cpp; sourceTree = "<group>"; };
33E79E05137B5FCE00E32D99 /* mouse-move-listener.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "mouse-move-listener.html"; sourceTree = "<group>"; };
37200B9113A16230007A4FAD /* VectorReverse.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = VectorReverse.cpp; path = WTF/VectorReverse.cpp; sourceTree = "<group>"; };
+ 3722C8681461E03E00C45D00 /* RenderedImageFromDOMRange.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = RenderedImageFromDOMRange.mm; sourceTree = "<group>"; };
3799AD3914120A43005EB0C6 /* StringByEvaluatingJavaScriptFromString.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = StringByEvaluatingJavaScriptFromString.mm; sourceTree = "<group>"; };
37DC678B140D7C5000ABCCDB /* DOMRangeOfString.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DOMRangeOfString.mm; sourceTree = "<group>"; };
37DC678F140D7D3A00ABCCDB /* DOMRangeOfString.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = DOMRangeOfString.html; sourceTree = "<group>"; };
37DC678B140D7C5000ABCCDB /* DOMRangeOfString.mm */,
C07E6CAE13FD67650038B22B /* DynamicDeviceScaleFactor.mm */,
939BA91614103412001A01BD /* DeviceScaleFactorOnBack.mm */,
+ 3722C8681461E03E00C45D00 /* RenderedImageFromDOMRange.mm */,
3799AD3914120A43005EB0C6 /* StringByEvaluatingJavaScriptFromString.mm */,
);
path = mac;
BC3C4C7214575B6A0025FB62 /* WKBrowsingContextLoadDelegateTest.mm in Sources */,
BC3C4C7F14587AA60025FB62 /* WKBrowsingContextGroupTest.mm in Sources */,
C0C5D3BE14598B6F00A802A6 /* GetBackingScaleFactor.mm in Sources */,
+ 3722C8691461E03E00C45D00 /* RenderedImageFromDOMRange.mm in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
--- /dev/null
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+#import "PlatformUtilities.h"
+#import <WebKit/WebDocumentPrivate.h>
+#import <WebKit/DOMPrivate.h>
+#import <wtf/RetainPtr.h>
+
+@interface RenderedImageFromDOMRangeFrameLoadDelegate : NSObject {
+}
+@end
+
+static bool didFinishLoad;
+
+@implementation RenderedImageFromDOMRangeFrameLoadDelegate
+
+- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame
+{
+ didFinishLoad = true;
+}
+
+@end
+
+namespace TestWebKitAPI {
+
+TEST(WebKit1, RenderedImageFromDOMRange)
+{
+ RetainPtr<WebView> webView(AdoptNS, [[WebView alloc] initWithFrame:NSMakeRect(0, 0, 120, 200) frameName:nil groupName:nil]);
+ RetainPtr<RenderedImageFromDOMRangeFrameLoadDelegate> frameLoadDelegate(AdoptNS, [RenderedImageFromDOMRangeFrameLoadDelegate new]);
+
+ webView.get().frameLoadDelegate = frameLoadDelegate.get();
+ [webView.get().mainFrame loadHTMLString:@"<div style=\"width: 100px;\">Lorem <span id=\"target\">ipsum dolor</span> sit amet</div>" baseURL:[NSURL URLWithString:@"about:blank"]];
+
+ Util::run(&didFinishLoad);
+
+ DOMDocument *document = webView.get().mainFrameDocument;
+ DOMRange *range = [document createRange];
+ [range selectNode:[document getElementById:@"target"]];
+ NSImage *actualImage = [range renderedImageForcingBlackText:YES];
+
+ [webView.get() setSelectedDOMRange:range affinity:NSSelectionAffinityDownstream];
+ id <WebDocumentView> documentView = webView.get().mainFrame.frameView.documentView;
+ NSImage *expectedImage = [(id <WebDocumentSelection>)documentView selectionImageForcingBlackText:YES];
+ EXPECT_TRUE([actualImage.TIFFRepresentation isEqual:expectedImage.TIFFRepresentation]);
+}
+
+} // namespace TestWebKitAPI