diff --git a/DEPS b/DEPS index 4c815e0..6c26d1d 100644 --- a/DEPS +++ b/DEPS
@@ -39,11 +39,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': '6db0a7bdceb6be85721bfb0db8dea7fd27db5970', + 'skia_revision': 'cf9bafceafaf6c0bf8b0eac8de509aa1d8407fca', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': '8e18e51a50775594c8cbda14fca898c2923ac30d', + 'v8_revision': 'd71ff17b88337c131cecdbc00f093763e897f321', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling swarming_client # and whatever else without interference from each other.
diff --git a/cc/layers/video_frame_provider.h b/cc/layers/video_frame_provider.h index e7619a3..f747a88 100644 --- a/cc/layers/video_frame_provider.h +++ b/cc/layers/video_frame_provider.h
@@ -47,6 +47,9 @@ // BeginFrameObserver based approach. http://crbug.com/336733 virtual void DidReceiveFrame() = 0; + // Notifies the client of a new UV transform matrix to be used. + virtual void DidUpdateMatrix(const float* matrix) = 0; + protected: virtual ~Client() {} };
diff --git a/cc/layers/video_frame_provider_client_impl.cc b/cc/layers/video_frame_provider_client_impl.cc index d9734d09..f2c5eb2 100644 --- a/cc/layers/video_frame_provider_client_impl.cc +++ b/cc/layers/video_frame_provider_client_impl.cc
@@ -32,6 +32,14 @@ // frame provider client that does not require a lock. The same is true of // the call to Stop(). provider_->SetVideoFrameProviderClient(this); + + // This matrix is the default transformation for stream textures, and flips + // on the Y axis. + stream_texture_matrix_ = gfx::Transform( + 1.0, 0.0, 0.0, 0.0, + 0.0, -1.0, 0.0, 1.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0); } VideoFrameProviderClientImpl::~VideoFrameProviderClientImpl() { @@ -97,6 +105,12 @@ return provider_ && provider_->HasCurrentFrame(); } +const gfx::Transform& VideoFrameProviderClientImpl::StreamTextureMatrix() + const { + DCHECK(thread_checker_.CalledOnValidThread()); + return stream_texture_matrix_; +} + void VideoFrameProviderClientImpl::StopUsingProvider() { { // Block the provider from shutting down until this client is done @@ -137,6 +151,17 @@ active_video_layer_->SetNeedsRedraw(); } +void VideoFrameProviderClientImpl::DidUpdateMatrix(const float* matrix) { + DCHECK(thread_checker_.CalledOnValidThread()); + stream_texture_matrix_ = gfx::Transform( + matrix[0], matrix[4], matrix[8], matrix[12], + matrix[1], matrix[5], matrix[9], matrix[13], + matrix[2], matrix[6], matrix[10], matrix[14], + matrix[3], matrix[7], matrix[11], matrix[15]); + if (active_video_layer_) + active_video_layer_->SetNeedsRedraw(); +} + void VideoFrameProviderClientImpl::OnBeginFrame(const BeginFrameArgs& args) { DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(rendering_);
diff --git a/cc/layers/video_frame_provider_client_impl.h b/cc/layers/video_frame_provider_client_impl.h index f7892ee..17525ec 100644 --- a/cc/layers/video_frame_provider_client_impl.h +++ b/cc/layers/video_frame_provider_client_impl.h
@@ -45,6 +45,8 @@ void ReleaseLock(); bool HasCurrentFrame(); + const gfx::Transform& StreamTextureMatrix() const; + // VideoFrameController implementation. void OnBeginFrame(const BeginFrameArgs& args) override; void DidDrawFrame() override; @@ -56,6 +58,7 @@ void StartRendering() override; void StopRendering() override; void DidReceiveFrame() override; + void DidUpdateMatrix(const float* matrix) override; const VideoFrameProvider* get_provider_for_testing() const { return provider_; @@ -82,6 +85,8 @@ base::Lock provider_lock_; base::ThreadChecker thread_checker_; + gfx::Transform stream_texture_matrix_; + DISALLOW_COPY_AND_ASSIGN(VideoFrameProviderClientImpl); };
diff --git a/cc/layers/video_frame_provider_client_impl_unittest.cc b/cc/layers/video_frame_provider_client_impl_unittest.cc index eaa0e6f..e337baa9 100644 --- a/cc/layers/video_frame_provider_client_impl_unittest.cc +++ b/cc/layers/video_frame_provider_client_impl_unittest.cc
@@ -140,4 +140,29 @@ StopRendering(); } +TEST_F(VideoFrameProviderClientImplTest, StreamTextureMatrix) { + const float kIdentityMatrix[] = { + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + }; + + EXPECT_FALSE(client_impl_->StreamTextureMatrix().IsIdentity()); + client_impl_->DidUpdateMatrix(kIdentityMatrix); + EXPECT_TRUE(client_impl_->StreamTextureMatrix().IsIdentity()); +} + } // namespace cc
diff --git a/cc/layers/video_layer_impl.cc b/cc/layers/video_layer_impl.cc index 8fa674f5..f22860c 100644 --- a/cc/layers/video_layer_impl.cc +++ b/cc/layers/video_layer_impl.cc
@@ -319,9 +319,10 @@ scale.Scale(tex_width_scale, tex_height_scale); StreamVideoDrawQuad* stream_video_quad = render_pass->CreateAndAppendDrawQuad<StreamVideoDrawQuad>(); - stream_video_quad->SetNew(shared_quad_state, quad_rect, opaque_rect, - visible_quad_rect, frame_resources_[0].id, - frame_resources_[0].size_in_pixels, scale); + stream_video_quad->SetNew( + shared_quad_state, quad_rect, opaque_rect, visible_quad_rect, + frame_resources_[0].id, frame_resources_[0].size_in_pixels, + scale * provider_client_impl_->StreamTextureMatrix()); ValidateQuadResources(stream_video_quad); break; }
diff --git a/chrome/VERSION b/chrome/VERSION index a7cd6de..8001a3e 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=51 MINOR=0 -BUILD=2698 +BUILD=2699 PATCH=0
diff --git a/chrome/browser/ui/cocoa/url_drop_target.mm b/chrome/browser/ui/cocoa/url_drop_target.mm index 55d5e2bd..00b11c1 100644 --- a/chrome/browser/ui/cocoa/url_drop_target.mm +++ b/chrome/browser/ui/cocoa/url_drop_target.mm
@@ -6,17 +6,9 @@ #include "chrome/browser/ui/cocoa/drag_util.h" #import "third_party/mozilla/NSPasteboard+Utils.h" +#include "ui/base/clipboard/clipboard_util_mac.h" #include "url/gurl.h" -namespace { - -// Mac WebKit uses this type, declared in -// WebKit/mac/History/WebURLsWithTitles.h. -NSString* const kCrWebURLsWithTitlesPboardType = - @"WebURLsWithTitlesPboardType"; - -} // namespace - @interface URLDropTargetHandler(Private) // Gets the appropriate drag operation given the |NSDraggingInfo|. @@ -30,11 +22,10 @@ @implementation URLDropTargetHandler + (NSArray*)handledDragTypes { - return [NSArray arrayWithObjects:kCrWebURLsWithTitlesPboardType, - NSURLPboardType, - NSStringPboardType, - NSFilenamesPboardType, - nil]; + return @[ + ui::ClipboardUtil::UTIForWebURLsAndTitles(), NSURLPboardType, + NSStringPboardType, NSFilenamesPboardType + ]; } - (id)initWithView:(NSView<URLDropTarget>*)view {
diff --git a/components/bookmarks/browser/bookmark_pasteboard_helper_mac.mm b/components/bookmarks/browser/bookmark_pasteboard_helper_mac.mm index 1aac917..a2abbe8 100644 --- a/components/bookmarks/browser/bookmark_pasteboard_helper_mac.mm +++ b/components/bookmarks/browser/bookmark_pasteboard_helper_mac.mm
@@ -12,22 +12,19 @@ #include "base/strings/sys_string_conversions.h" #include "components/bookmarks/browser/bookmark_node.h" #include "ui/base/clipboard/clipboard.h" +#include "ui/base/clipboard/clipboard_util_mac.h" NSString* const kBookmarkDictionaryListPboardType = - @"BookmarkDictionaryListPboardType"; + @"com.google.chrome.BookmarkDictionaryListPboardType"; namespace bookmarks { namespace { -// An unofficial standard pasteboard title type to be provided alongside the -// |NSURLPboardType|. -NSString* const kNSURLTitlePboardType = @"public.url-name"; - // Pasteboard type used to store profile path to determine which profile // a set of bookmarks came from. NSString* const kChromiumProfilePathPboardType = - @"ChromiumProfilePathPboardType"; + @"com.google.chrome.ChromiumProfilePathPboardType"; // Internal bookmark ID for a bookmark node. Used only when moving inside // of one profile. @@ -36,10 +33,6 @@ // Internal bookmark meta info dictionary for a bookmark node. NSString* const kChromiumBookmarkMetaInfo = @"ChromiumBookmarkMetaInfo"; -// Mac WebKit uses this type, declared in -// WebKit/mac/History/WebURLsWithTitles.h. -NSString* const kCrWebURLsWithTitlesPboardType = @"WebURLsWithTitlesPboardType"; - // Keys for the type of node in BookmarkDictionaryListPboardType. NSString* const kWebBookmarkType = @"WebBookmarkType"; @@ -100,8 +93,9 @@ bool ReadBookmarkDictionaryListPboardType( NSPasteboard* pb, std::vector<BookmarkNodeData::Element>& elements) { - NSArray* bookmarks = - [pb propertyListForType:kBookmarkDictionaryListPboardType]; + NSString* uti = ui::ClipboardUtil::UTIForPasteboardType( + kBookmarkDictionaryListPboardType); + NSArray* bookmarks = [pb propertyListForType:uti]; if (!bookmarks) return false; ConvertPlistToElements(bookmarks, elements); @@ -111,16 +105,9 @@ bool ReadWebURLsWithTitlesPboardType( NSPasteboard* pb, std::vector<BookmarkNodeData::Element>& elements) { - NSArray* bookmarkPairs = - [pb propertyListForType:kCrWebURLsWithTitlesPboardType]; - if (![bookmarkPairs isKindOfClass:[NSArray class]]) - return false; - - NSArray* urlsArr = [bookmarkPairs objectAtIndex:0]; - NSArray* titlesArr = [bookmarkPairs objectAtIndex:1]; - if ([urlsArr count] < 1) - return false; - if ([urlsArr count] != [titlesArr count]) + NSArray* urlsArr = nil; + NSArray* titlesArr = nil; + if (!ui::ClipboardUtil::URLsAndTitlesFromPasteboard(pb, &urlsArr, &titlesArr)) return false; NSUInteger len = [titlesArr count]; @@ -139,25 +126,6 @@ return true; } -bool ReadNSURLPboardType(NSPasteboard* pb, - std::vector<BookmarkNodeData::Element>& elements) { - NSURL* url = [NSURL URLFromPasteboard:pb]; - if (url == nil) - return false; - - std::string urlString = base::SysNSStringToUTF8([url absoluteString]); - NSString* title = [pb stringForType:kNSURLTitlePboardType]; - if (!title) - title = [pb stringForType:NSStringPboardType]; - - BookmarkNodeData::Element element; - element.is_url = true; - element.url = GURL(urlString); - element.title = base::SysNSStringToUTF16(title); - elements.push_back(element); - return true; -} - NSDictionary* DictionaryFromBookmarkMetaInfo( const BookmarkNode::MetaInfoMap& meta_info_map) { NSMutableDictionary* dictionary = [NSMutableDictionary dictionary]; @@ -215,7 +183,10 @@ NSPasteboard* pb, const std::vector<BookmarkNodeData::Element>& elements) { NSArray* plist = GetPlistForBookmarkList(elements); - [pb setPropertyList:plist forType:kBookmarkDictionaryListPboardType]; + NSString* uti = ui::ClipboardUtil::UTIForPasteboardType( + kBookmarkDictionaryListPboardType); + [pb addTypes:@[ uti ] owner:nil]; + [pb setPropertyList:plist forType:uti]; } void FillFlattenedArraysForBookmarks( @@ -248,23 +219,22 @@ FillFlattenedArraysForBookmarks( elements, url_titles, urls, toplevel_string_data); + if ([urls count] > 0) { + base::scoped_nsobject<NSPasteboardItem> item; + if ([urls count] == 1) { + item = ui::ClipboardUtil::PasteboardItemFromUrl([urls firstObject], + [url_titles firstObject]); + } else { + item = ui::ClipboardUtil::PasteboardItemFromUrls(urls, url_titles); + } + + ui::ClipboardUtil::AddDataToPasteboard(pb, item); + } + // Write NSStringPboardType. + [pb addTypes:@[ NSStringPboardType ] owner:nil]; [pb setString:[toplevel_string_data componentsJoinedByString:@"\n"] forType:NSStringPboardType]; - - // The following pasteboard types only act on urls, not folders. - if ([urls count] < 1) - return; - - // Write WebURLsWithTitlesPboardType. - [pb setPropertyList:[NSArray arrayWithObjects:urls, url_titles, nil] - forType:kCrWebURLsWithTitlesPboardType]; - - // Write NSURLPboardType (with title). - NSURL* url = [NSURL URLWithString:[urls objectAtIndex:0]]; - [url writeToPasteboard:pb]; - NSString* titleString = [url_titles objectAtIndex:0]; - [pb setString:titleString forType:kNSURLTitlePboardType]; } NSPasteboard* PasteboardFromType(ui::ClipboardType type) { @@ -295,16 +265,10 @@ NSPasteboard* pb = PasteboardFromType(type); - NSArray* types = [NSArray arrayWithObjects:kBookmarkDictionaryListPboardType, - kCrWebURLsWithTitlesPboardType, - NSStringPboardType, - NSURLPboardType, - kNSURLTitlePboardType, - kChromiumProfilePathPboardType, - nil]; - [pb declareTypes:types owner:nil]; - [pb setString:base::SysUTF8ToNSString(profile_path.value()) - forType:kChromiumProfilePathPboardType]; + NSString* uti = + ui::ClipboardUtil::UTIForPasteboardType(kChromiumProfilePathPboardType); + [pb declareTypes:@[ uti ] owner:nil]; + [pb setString:base::SysUTF8ToNSString(profile_path.value()) forType:uti]; WriteBookmarkDictionaryListPboardType(pb, elements); WriteSimplifiedBookmarkTypes(pb, elements); } @@ -316,21 +280,21 @@ NSPasteboard* pb = PasteboardFromType(type); elements.clear(); - NSString* profile = [pb stringForType:kChromiumProfilePathPboardType]; + NSString* uti = + ui::ClipboardUtil::UTIForPasteboardType(kChromiumProfilePathPboardType); + NSString* profile = [pb stringForType:uti]; *profile_path = base::FilePath(base::SysNSStringToUTF8(profile)); return ReadBookmarkDictionaryListPboardType(pb, elements) || - ReadWebURLsWithTitlesPboardType(pb, elements) || - ReadNSURLPboardType(pb, elements); + ReadWebURLsWithTitlesPboardType(pb, elements); } bool PasteboardContainsBookmarks(ui::ClipboardType type) { NSPasteboard* pb = PasteboardFromType(type); - NSArray* availableTypes = - [NSArray arrayWithObjects:kBookmarkDictionaryListPboardType, - kCrWebURLsWithTitlesPboardType, - NSURLPboardType, - nil]; + NSArray* availableTypes = @[ + ui::ClipboardUtil::UTIForWebURLsAndTitles(), + ui::ClipboardUtil::UTIForPasteboardType(kBookmarkDictionaryListPboardType) + ]; return [pb availableTypeFromArray:availableTypes] != nil; }
diff --git a/content/common/gpu/stream_texture_android.cc b/content/common/gpu/stream_texture_android.cc index 15ebb53..ae135d3 100644 --- a/content/common/gpu/stream_texture_android.cc +++ b/content/common/gpu/stream_texture_android.cc
@@ -42,16 +42,16 @@ // TODO: Ideally a valid image id was returned to the client so that // it could then call glBindTexImage2D() for doing the following. - scoped_refptr<gpu::gles2::GLStreamTextureImage> gl_image( + scoped_refptr<gl::GLImage> gl_image( new StreamTexture(owner_stub, stream_id, texture->service_id())); gfx::Size size = gl_image->GetSize(); texture_manager->SetTarget(texture, GL_TEXTURE_EXTERNAL_OES); texture_manager->SetLevelInfo(texture, GL_TEXTURE_EXTERNAL_OES, 0, GL_RGBA, size.width(), size.height(), 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(size)); - texture_manager->SetLevelStreamTextureImage( - texture, GL_TEXTURE_EXTERNAL_OES, 0, gl_image.get(), - gpu::gles2::Texture::UNBOUND); + texture_manager->SetLevelImage(texture, GL_TEXTURE_EXTERNAL_OES, 0, + gl_image.get(), + gpu::gles2::Texture::UNBOUND); return true; } @@ -63,6 +63,7 @@ uint32_t texture_id) : surface_texture_(gfx::SurfaceTexture::Create(texture_id)), size_(0, 0), + has_valid_frame_(false), has_pending_frame_(false), owner_stub_(owner_stub), route_id_(route_id), @@ -89,12 +90,6 @@ } } -// gpu::gles2::GLStreamTextureMatrix implementation -void StreamTexture::GetTextureMatrix(float xform[16]) { - UpdateTexImage(); - surface_texture_->GetTransformMatrix(xform); -} - void StreamTexture::OnWillDestroyStub() { owner_stub_->RemoveDestructionObserver(this); owner_stub_->channel()->RemoveRoute(route_id_); @@ -147,8 +142,23 @@ surface_texture_->UpdateTexImage(); + has_valid_frame_ = true; has_pending_frame_ = false; + float mtx[16]; + surface_texture_->GetTransformMatrix(mtx); + + if (memcmp(current_matrix_, mtx, sizeof(mtx)) != 0) { + memcpy(current_matrix_, mtx, sizeof(mtx)); + + if (has_listener_) { + GpuStreamTextureMsg_MatrixChanged_Params params; + memcpy(¶ms.m00, mtx, sizeof(mtx)); + owner_stub_->channel()->Send( + new GpuStreamTextureMsg_MatrixChanged(route_id_, params)); + } + } + if (scoped_make_current.get()) { // UpdateTexImage() implies glBindTexture(). // The cmd decoder takes care of restoring the binding for this GLImage as @@ -166,6 +176,12 @@ } bool StreamTexture::CopyTexImage(unsigned target) { + if (target == GL_TEXTURE_2D) { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size_.width(), size_.height(), 0, + GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + return CopyTexSubImage(GL_TEXTURE_2D, gfx::Point(), gfx::Rect(size_)); + } + if (target != GL_TEXTURE_EXTERNAL_OES) return false; @@ -193,8 +209,8 @@ // By setting image state to UNBOUND instead of COPIED we ensure that // CopyTexImage() is called each time the surface texture is used for // drawing. - texture->SetLevelStreamTextureImage(GL_TEXTURE_EXTERNAL_OES, 0, this, - gpu::gles2::Texture::UNBOUND); + texture->SetLevelImage(GL_TEXTURE_EXTERNAL_OES, 0, this, + gpu::gles2::Texture::UNBOUND); } return true; @@ -256,7 +272,94 @@ bool StreamTexture::CopyTexSubImage(unsigned target, const gfx::Point& offset, const gfx::Rect& rect) { - return false; + if (target != GL_TEXTURE_2D) + return false; + + if (!owner_stub_ || !surface_texture_.get()) + return true; + + if (!offset.IsOrigin()) { + LOG(ERROR) << "Non-origin offset is not supported"; + return false; + } + + if (rect != gfx::Rect(size_)) { + LOG(ERROR) << "Sub-rectangle is not supported"; + return false; + } + + GLint target_texture = 0; + glGetIntegerv(GL_TEXTURE_BINDING_2D, &target_texture); + DCHECK(target_texture); + + UpdateTexImage(); + + if (!framebuffer_) { + glGenFramebuffersEXT(1, &framebuffer_); + + // This vertex shader introduces a y flip before applying the stream + // texture matrix. This is required because the stream texture matrix + // Android provides is intended to be used in a y-up coordinate system, + // whereas Chromium expects y-down. + + // clang-format off + const char kVertexShader[] = STRINGIZE( + attribute vec2 a_position; + varying vec2 v_texCoord; + uniform mat4 u_xform; + void main() { + gl_Position = vec4(a_position.x, a_position.y, 0.0, 1.0); + vec2 uv_untransformed = a_position * vec2(0.5, -0.5) + vec2(0.5, 0.5); + v_texCoord = (u_xform * vec4(uv_untransformed, 0.0, 1.0)).xy; + } + ); + const char kFragmentShader[] = + "#extension GL_OES_EGL_image_external : require\n" STRINGIZE( + precision mediump float; + uniform samplerExternalOES a_texture; + varying vec2 v_texCoord; + void main() { + gl_FragColor = texture2D(a_texture, v_texCoord); + } + ); + // clang-format on + + vertex_buffer_ = gfx::GLHelper::SetupQuadVertexBuffer(); + vertex_shader_ = gfx::GLHelper::LoadShader(GL_VERTEX_SHADER, kVertexShader); + fragment_shader_ = + gfx::GLHelper::LoadShader(GL_FRAGMENT_SHADER, kFragmentShader); + program_ = gfx::GLHelper::SetupProgram(vertex_shader_, fragment_shader_); + gfx::ScopedUseProgram use_program(program_); + int sampler_location = glGetUniformLocation(program_, "a_texture"); + DCHECK_NE(-1, sampler_location); + glUniform1i(sampler_location, 0); + u_xform_location_ = glGetUniformLocation(program_, "u_xform"); + DCHECK_NE(-1, u_xform_location_); + } + + gfx::ScopedActiveTexture active_texture(GL_TEXTURE0); + // UpdateTexImage() call below will bind the surface texture to + // TEXTURE_EXTERNAL_OES. This scoped texture binder will restore the current + // binding before this function returns. + gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_EXTERNAL_OES, texture_id_); + + { + gfx::ScopedFrameBufferBinder framebuffer_binder(framebuffer_); + gfx::ScopedViewport viewport(0, 0, size_.width(), size_.height()); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, target_texture, 0); + DCHECK_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE), + glCheckFramebufferStatusEXT(GL_FRAMEBUFFER)); + gfx::ScopedUseProgram use_program(program_); + + glUniformMatrix4fv(u_xform_location_, 1, false, current_matrix_); + gfx::GLHelper::DrawQuad(vertex_buffer_); + + // Detach the output texture from the fbo. + glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, 0, 0); + } + return true; } bool StreamTexture::ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
diff --git a/content/common/gpu/stream_texture_android.h b/content/common/gpu/stream_texture_android.h index 8852965..e19fc1b 100644 --- a/content/common/gpu/stream_texture_android.h +++ b/content/common/gpu/stream_texture_android.h
@@ -10,7 +10,6 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "content/common/gpu/gpu_command_buffer_stub.h" -#include "gpu/command_buffer/service/gl_stream_texture_image.h" #include "ipc/ipc_listener.h" #include "ui/gl/android/surface_texture.h" #include "ui/gl/gl_image.h" @@ -25,7 +24,7 @@ namespace content { -class StreamTexture : public gpu::gles2::GLStreamTextureImage, +class StreamTexture : public gl::GLImage, public IPC::Listener, public GpuCommandBufferStub::DestructionObserver { public: @@ -58,9 +57,6 @@ uint64_t process_tracing_id, const std::string& dump_name) override; - // gpu::gles2::GLStreamTextureMatrix implementation - void GetTextureMatrix(float xform[16]) override; - // GpuCommandBufferStub::DestructionObserver implementation. void OnWillDestroyStub() override; @@ -87,6 +83,9 @@ // Current size of the surface texture. gfx::Size size_; + // Whether we ever bound a valid frame. + bool has_valid_frame_; + // Whether a new frame is available that we should update to. bool has_pending_frame_;
diff --git a/content/renderer/gpu/stream_texture_host_android.cc b/content/renderer/gpu/stream_texture_host_android.cc index 3e62f98..08c4c2b 100644 --- a/content/renderer/gpu/stream_texture_host_android.cc +++ b/content/renderer/gpu/stream_texture_host_android.cc
@@ -42,6 +42,8 @@ IPC_BEGIN_MESSAGE_MAP(StreamTextureHost, message) IPC_MESSAGE_HANDLER(GpuStreamTextureMsg_FrameAvailable, OnFrameAvailable); + IPC_MESSAGE_HANDLER(GpuStreamTextureMsg_MatrixChanged, + OnMatrixChanged); IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() DCHECK(handled); @@ -56,4 +58,12 @@ listener_->OnFrameAvailable(); } +void StreamTextureHost::OnMatrixChanged( + const GpuStreamTextureMsg_MatrixChanged_Params& params) { + static_assert(sizeof(params) == sizeof(float) * 16, + "bad GpuStreamTextureMsg MatrixChanged_Params format"); + if (listener_) + listener_->OnMatrixChanged((const float*)¶ms); +} + } // namespace content
diff --git a/content/renderer/gpu/stream_texture_host_android.h b/content/renderer/gpu/stream_texture_host_android.h index d03151b..4c88ded 100644 --- a/content/renderer/gpu/stream_texture_host_android.h +++ b/content/renderer/gpu/stream_texture_host_android.h
@@ -37,6 +37,7 @@ class Listener { public: virtual void OnFrameAvailable() = 0; + virtual void OnMatrixChanged(const float mtx[16]) = 0; virtual ~Listener() {} }; @@ -49,6 +50,7 @@ private: // Message handlers: void OnFrameAvailable(); + void OnMatrixChanged(const GpuStreamTextureMsg_MatrixChanged_Params& param); int stream_id_; Listener* listener_;
diff --git a/content/renderer/media/android/stream_texture_factory_impl.cc b/content/renderer/media/android/stream_texture_factory_impl.cc index 81de90a..e38b6de 100644 --- a/content/renderer/media/android/stream_texture_factory_impl.cc +++ b/content/renderer/media/android/stream_texture_factory_impl.cc
@@ -31,6 +31,7 @@ // StreamTextureHost::Listener implementation: void OnFrameAvailable() override; + void OnMatrixChanged(const float matrix[16]) override; private: void BindOnThread(int32_t stream_id); @@ -101,6 +102,12 @@ client_->DidReceiveFrame(); } +void StreamTextureProxyImpl::OnMatrixChanged(const float matrix[16]) { + base::AutoLock lock(lock_); + if (client_) + client_->DidUpdateMatrix(matrix); +} + } // namespace // static
diff --git a/content/renderer/media/android/stream_texture_factory_synchronous_impl.cc b/content/renderer/media/android/stream_texture_factory_synchronous_impl.cc index 513432a..86a0e37 100644 --- a/content/renderer/media/android/stream_texture_factory_synchronous_impl.cc +++ b/content/renderer/media/android/stream_texture_factory_synchronous_impl.cc
@@ -54,13 +54,16 @@ scoped_refptr<StreamTextureFactorySynchronousImpl::ContextProvider> context_provider_; scoped_refptr<gfx::SurfaceTexture> surface_texture_; + float current_matrix_[16]; + bool has_updated_; DISALLOW_IMPLICIT_CONSTRUCTORS(StreamTextureProxyImpl); }; StreamTextureProxyImpl::StreamTextureProxyImpl( StreamTextureFactorySynchronousImpl::ContextProvider* provider) - : client_(NULL), context_provider_(provider) { + : client_(NULL), context_provider_(provider), has_updated_(false) { + std::fill(current_matrix_, current_matrix_ + 16, 0); } StreamTextureProxyImpl::~StreamTextureProxyImpl() {} @@ -119,6 +122,25 @@ } void StreamTextureProxyImpl::OnFrameAvailable() { + // GetTransformMatrix only returns something valid after both is true: + // - OnFrameAvailable was called + // - we called UpdateTexImage + if (has_updated_) { + float matrix[16]; + surface_texture_->GetTransformMatrix(matrix); + + if (memcmp(current_matrix_, matrix, sizeof(matrix)) != 0) { + memcpy(current_matrix_, matrix, sizeof(matrix)); + + base::AutoLock lock(lock_); + if (client_) + client_->DidUpdateMatrix(current_matrix_); + } + } + // OnFrameAvailable being called a second time implies that we called + // updateTexImage since after we received the first frame. + has_updated_ = true; + base::AutoLock lock(lock_); if (client_) client_->DidReceiveFrame();
diff --git a/content/renderer/media/webmediaplayer_ms_unittest.cc b/content/renderer/media/webmediaplayer_ms_unittest.cc index 5c890cec..beaad89 100644 --- a/content/renderer/media/webmediaplayer_ms_unittest.cc +++ b/content/renderer/media/webmediaplayer_ms_unittest.cc
@@ -395,6 +395,7 @@ void StartRendering() override; void StopRendering() override; void DidReceiveFrame() override {} + void DidUpdateMatrix(const float* matrix) override {} // For test use void SetBackgroundRendering(bool background_rendering) {
diff --git a/gpu/command_buffer/service/gl_stream_texture_image.h b/gpu/command_buffer/service/gl_stream_texture_image.h index b5bc370c..a6a517d 100644 --- a/gpu/command_buffer/service/gl_stream_texture_image.h +++ b/gpu/command_buffer/service/gl_stream_texture_image.h
@@ -19,18 +19,8 @@ // Get the matrix. // Copy the texture matrix for this image into |matrix|. - // Subclasses must return a matrix appropriate for a coordinate system where - // UV=(0,0) corresponds to the bottom left corner of the image. virtual void GetTextureMatrix(float matrix[16]) = 0; - // Copy the texture matrix for this image into |matrix|, returning a matrix - // for which UV=(0,0) corresponds to the top left of corner of the image, - // which is what Chromium generally expects. - void GetFlippedTextureMatrix(float matrix[16]) { - GetTextureMatrix(matrix); - matrix[13] += matrix[5]; - matrix[5] = -matrix[5]; - } protected: ~GLStreamTextureImage() override {}
diff --git a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc index dad3d03..407f1baa 100644 --- a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc +++ b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc
@@ -487,39 +487,10 @@ return; } - DoCopySubTextureWithTransform( - decoder, source_target, source_id, source_internal_format, dest_target, - dest_id, dest_internal_format, xoffset, yoffset, x, y, width, height, - dest_width, dest_height, source_width, source_height, flip_y, - premultiply_alpha, unpremultiply_alpha, kIdentityMatrix); -} - -void CopyTextureCHROMIUMResourceManager::DoCopySubTextureWithTransform( - const gles2::GLES2Decoder* decoder, - GLenum source_target, - GLuint source_id, - GLenum source_internal_format, - GLenum dest_target, - GLuint dest_id, - GLenum dest_internal_format, - GLint xoffset, - GLint yoffset, - GLint x, - GLint y, - GLsizei width, - GLsizei height, - GLsizei dest_width, - GLsizei dest_height, - GLsizei source_width, - GLsizei source_height, - bool flip_y, - bool premultiply_alpha, - bool unpremultiply_alpha, - const GLfloat transform_matrix[16]) { DoCopyTextureInternal(decoder, source_target, source_id, dest_target, dest_id, xoffset, yoffset, x, y, width, height, dest_width, dest_height, source_width, source_height, flip_y, premultiply_alpha, - unpremultiply_alpha, transform_matrix); + unpremultiply_alpha, kIdentityMatrix); } void CopyTextureCHROMIUMResourceManager::DoCopyTextureWithTransform(
diff --git a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h index 95b25a0..aae3741 100644 --- a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h +++ b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h
@@ -67,28 +67,6 @@ bool premultiply_alpha, bool unpremultiply_alpha); - void DoCopySubTextureWithTransform(const gles2::GLES2Decoder* decoder, - GLenum source_target, - GLuint source_id, - GLenum source_internal_format, - GLenum dest_target, - GLuint dest_id, - GLenum dest_internal_format, - GLint xoffset, - GLint yoffset, - GLint x, - GLint y, - GLsizei width, - GLsizei height, - GLsizei dest_width, - GLsizei dest_height, - GLsizei source_width, - GLsizei source_height, - bool flip_y, - bool premultiply_alpha, - bool unpremultiply_alpha, - const GLfloat transform_matrix[16]); - // This will apply a transform on the texture coordinates before sampling // the source texture and copying to the destination texture. The transform // matrix should be given in column-major form, so it can be passed
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index f28cc43..d9381f2 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -13911,29 +13911,34 @@ DoCopyTexImageIfNeeded(source_texture, source_target); - // GL_TEXTURE_EXTERNAL_OES texture requires that we apply a transform matrix + // GL_TEXTURE_EXTERNAL_OES texture requires apply a transform matrix // before presenting. if (source_target == GL_TEXTURE_EXTERNAL_OES) { + // TODO(hkuang): get the StreamTexture transform matrix in GPU process + // instead of using kIdentityMatrix crbug.com/226218. AVDACodecImage does + // this correctly, but others (e.g., stream_texture_android.cc) don't. + // (crbug.com/371500, crbug.com/588837) + GLfloat transform_matrix[16]; + memcpy(transform_matrix, kIdentityMatrix, sizeof(transform_matrix)); if (GLStreamTextureImage* image = source_texture->GetLevelStreamTextureImage(GL_TEXTURE_EXTERNAL_OES, 0)) { - // The coordinate system of this matrix is y-up, not y-down, so a flip is - // needed. - GLfloat transform_matrix[16]; - image->GetFlippedTextureMatrix(transform_matrix); - copy_texture_CHROMIUM_->DoCopyTextureWithTransform( - this, source_target, source_texture->service_id(), dest_target, - dest_texture->service_id(), source_width, source_height, - unpack_flip_y == GL_TRUE, unpack_premultiply_alpha == GL_TRUE, - unpack_unmultiply_alpha == GL_TRUE, transform_matrix); - return; + image->GetTextureMatrix(transform_matrix); } + copy_texture_CHROMIUM_->DoCopyTextureWithTransform( + this, source_target, source_texture->service_id(), dest_target, + dest_texture->service_id(), source_width, source_height, + unpack_flip_y == GL_TRUE, unpack_premultiply_alpha == GL_TRUE, + unpack_unmultiply_alpha == GL_TRUE, transform_matrix); + } else { + copy_texture_CHROMIUM_->DoCopyTexture( + this, source_target, source_texture->service_id(), + source_internal_format, dest_target, dest_texture->service_id(), + internal_format, source_width, source_height, + unpack_flip_y == GL_TRUE, + unpack_premultiply_alpha == GL_TRUE, + unpack_unmultiply_alpha == GL_TRUE); } - copy_texture_CHROMIUM_->DoCopyTexture( - this, source_target, source_texture->service_id(), source_internal_format, - dest_target, dest_texture->service_id(), internal_format, source_width, - source_height, unpack_flip_y == GL_TRUE, - unpack_premultiply_alpha == GL_TRUE, unpack_unmultiply_alpha == GL_TRUE); } void GLES2DecoderImpl::DoCopySubTextureCHROMIUM( @@ -14104,33 +14109,16 @@ DoCopyTexImageIfNeeded(source_texture, source_target); - - // GL_TEXTURE_EXTERNAL_OES texture requires apply a transform matrix - // before presenting. - if (source_target == GL_TEXTURE_EXTERNAL_OES) { - if (GLStreamTextureImage* image = - source_texture->GetLevelStreamTextureImage(GL_TEXTURE_EXTERNAL_OES, - 0)) { - // The coordinate system of this matrix is y-up, not y-down, so a flip is - // needed. - GLfloat transform_matrix[16]; - image->GetFlippedTextureMatrix(transform_matrix); - copy_texture_CHROMIUM_->DoCopySubTextureWithTransform( - this, source_target, source_texture->service_id(), - source_internal_format, dest_target, dest_texture->service_id(), - dest_internal_format, xoffset, yoffset, x, y, width, height, - dest_width, dest_height, source_width, source_height, - unpack_flip_y == GL_TRUE, unpack_premultiply_alpha == GL_TRUE, - unpack_unmultiply_alpha == GL_TRUE, transform_matrix); - return; - } - } + // TODO(hkuang): get the StreamTexture transform matrix in GPU process. + // crbug.com/226218. copy_texture_CHROMIUM_->DoCopySubTexture( this, source_target, source_texture->service_id(), source_internal_format, - dest_target, dest_texture->service_id(), dest_internal_format, xoffset, - yoffset, x, y, width, height, dest_width, dest_height, source_width, - source_height, unpack_flip_y == GL_TRUE, - unpack_premultiply_alpha == GL_TRUE, unpack_unmultiply_alpha == GL_TRUE); + dest_target, dest_texture->service_id(), dest_internal_format, + xoffset, yoffset, x, y, width, height, dest_width, dest_height, + source_width, source_height, + unpack_flip_y == GL_TRUE, + unpack_premultiply_alpha == GL_TRUE, + unpack_unmultiply_alpha == GL_TRUE); } void GLES2DecoderImpl::DoCompressedCopyTextureCHROMIUM(GLuint source_id, @@ -14291,11 +14279,22 @@ source_height, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(source_width, source_height)); - copy_texture_CHROMIUM_->DoCopyTexture( - this, source_texture->target(), source_texture->service_id(), - source_internal_format, dest_texture->target(), - dest_texture->service_id(), GL_RGBA, source_width, source_height, false, - false, false); + // GL_TEXTURE_EXTERNAL_OES texture requires apply a transform matrix + // before presenting. + if (source_texture->target() == GL_TEXTURE_EXTERNAL_OES) { + // TODO(hkuang): get the StreamTexture transform matrix in GPU process + // instead of using kIdentityMatrix crbug.com/226218. + copy_texture_CHROMIUM_->DoCopyTextureWithTransform( + this, source_texture->target(), source_texture->service_id(), + dest_texture->target(), dest_texture->service_id(), source_width, + source_height, false, false, false, kIdentityMatrix); + } else { + copy_texture_CHROMIUM_->DoCopyTexture( + this, source_texture->target(), source_texture->service_id(), + source_internal_format, dest_texture->target(), + dest_texture->service_id(), GL_RGBA, source_width, source_height, false, + false, false); + } } void GLES2DecoderImpl::DoTexStorage2DEXT(
diff --git a/gpu/ipc/common/gpu_messages.h b/gpu/ipc/common/gpu_messages.h index 61cb08e..00cd334 100644 --- a/gpu/ipc/common/gpu_messages.h +++ b/gpu/ipc/common/gpu_messages.h
@@ -70,6 +70,27 @@ IPC_STRUCT_MEMBER(uint64_t, image_release_count) IPC_STRUCT_END() +#if defined(OS_ANDROID) +IPC_STRUCT_BEGIN(GpuStreamTextureMsg_MatrixChanged_Params) + IPC_STRUCT_MEMBER(float, m00) + IPC_STRUCT_MEMBER(float, m01) + IPC_STRUCT_MEMBER(float, m02) + IPC_STRUCT_MEMBER(float, m03) + IPC_STRUCT_MEMBER(float, m10) + IPC_STRUCT_MEMBER(float, m11) + IPC_STRUCT_MEMBER(float, m12) + IPC_STRUCT_MEMBER(float, m13) + IPC_STRUCT_MEMBER(float, m20) + IPC_STRUCT_MEMBER(float, m21) + IPC_STRUCT_MEMBER(float, m22) + IPC_STRUCT_MEMBER(float, m23) + IPC_STRUCT_MEMBER(float, m30) + IPC_STRUCT_MEMBER(float, m31) + IPC_STRUCT_MEMBER(float, m32) + IPC_STRUCT_MEMBER(float, m33) +IPC_STRUCT_END() +#endif + //------------------------------------------------------------------------------ // GPU Channel Messages // These are messages from a renderer process to the GPU process. @@ -115,6 +136,10 @@ // Inform the renderer that a new frame is available. IPC_MESSAGE_ROUTED0(GpuStreamTextureMsg_FrameAvailable) + +// Inform the renderer process that the transform matrix has changed. +IPC_MESSAGE_ROUTED1(GpuStreamTextureMsg_MatrixChanged, + GpuStreamTextureMsg_MatrixChanged_Params /* params */) #endif //------------------------------------------------------------------------------
diff --git a/media/blink/video_frame_compositor_unittest.cc b/media/blink/video_frame_compositor_unittest.cc index 29274d38..b2e1695 100644 --- a/media/blink/video_frame_compositor_unittest.cc +++ b/media/blink/video_frame_compositor_unittest.cc
@@ -70,6 +70,7 @@ MOCK_METHOD0(StartRendering, void()); MOCK_METHOD0(StopRendering, void()); void DidReceiveFrame() override { ++did_receive_frame_count_; } + void DidUpdateMatrix(const float* matrix) override {} // VideoRendererSink::RenderCallback implementation. MOCK_METHOD3(Render,
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index 165abbcf..2f44a84 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1203,6 +1203,14 @@ crbug.com/521730 [ Win10 ] svg/as-image/svg-canvas-xhtml-tainted.html [ Failure ] crbug.com/521730 [ Win10 ] svg/css/text-shadow-multiple.xhtml [ Failure ] crbug.com/521730 [ Win10 ] svg/custom/textPath-change-id2-pattern.svg [ Failure ] +crbug.com/521730 [ Win10 ] printing/quirks-percentage-height-body.html [ Failure ] +crbug.com/521730 [ Win10 ] printing/quirks-percentage-height.html [ Failure ] +crbug.com/521730 [ Win10 ] printing/standards-percentage-heights.html [ Failure ] +crbug.com/521730 [ Win10 ] printing/subframes-percentage-height.html [ Failure ] +crbug.com/521730 [ Win10 ] virtual/threaded/printing/quirks-percentage-height-body.html [ Failure ] +crbug.com/521730 [ Win10 ] virtual/threaded/printing/quirks-percentage-height.html [ Failure ] +crbug.com/521730 [ Win10 ] virtual/threaded/printing/standards-percentage-heights.html [ Failure ] +crbug.com/521730 [ Win10 ] virtual/threaded/printing/subframes-percentage-height.html [ Failure ] crbug.com/591500 [ Win10 ] virtual/threaded/printing/ellipsis-printing-style.html [ Skip ] crbug.com/591500 [ Win10 ] printing/ellipsis-printing-style.html [ Skip ]
diff --git a/third_party/WebKit/Source/wtf/LinkedHashSet.h b/third_party/WebKit/Source/wtf/LinkedHashSet.h index f2b7902..c0319b1 100644 --- a/third_party/WebKit/Source/wtf/LinkedHashSet.h +++ b/third_party/WebKit/Source/wtf/LinkedHashSet.h
@@ -369,7 +369,7 @@ typedef LinkedHashSetConstIterator<LinkedHashSetType> const_iterator; - Node* getNode() { return const_cast<Node*>(m_iterator.node()); } + Node* getNode() { return const_cast<Node*>(m_iterator.getNode()); } protected: LinkedHashSetIterator(const Node* position, LinkedHashSetType* m_container) @@ -410,7 +410,7 @@ typedef const typename LinkedHashSetType::Value& ReferenceType; typedef const typename LinkedHashSetType::Value* PointerType; - const Node* node() const { return static_cast<const Node*>(m_position); } + const Node* getNode() const { return static_cast<const Node*>(m_position); } protected: LinkedHashSetConstIterator(const LinkedHashSetNodeBase* position, const LinkedHashSetType* container)
diff --git a/third_party/WebKit/Source/wtf/ListHashSet.h b/third_party/WebKit/Source/wtf/ListHashSet.h index bd15b8b..2f3ae61 100644 --- a/third_party/WebKit/Source/wtf/ListHashSet.h +++ b/third_party/WebKit/Source/wtf/ListHashSet.h
@@ -468,7 +468,7 @@ operator const_iterator() const { return m_iterator; } private: - Node* getNode() { return m_iterator.node(); } + Node* getNode() { return m_iterator.getNode(); } const_iterator m_iterator; @@ -536,7 +536,7 @@ } private: - Node* node() { return m_position; } + Node* getNode() { return m_position; } const Set* m_set; Node* m_position; @@ -578,7 +578,7 @@ operator const_reverse_iterator() const { return m_iterator; } private: - Node* node() { return m_iterator.node(); } + Node* getNode() { return m_iterator.node(); } const_reverse_iterator m_iterator; @@ -645,7 +645,7 @@ } private: - Node* node() { return m_position; } + Node* getNode() { return m_position; } const Set* m_set; Node* m_position;
diff --git a/third_party/WebKit/Source/wtf/WTFThreadData.h b/third_party/WebKit/Source/wtf/WTFThreadData.h index 6f7b0d7..9ddda8f5 100644 --- a/third_party/WebKit/Source/wtf/WTFThreadData.h +++ b/third_party/WebKit/Source/wtf/WTFThreadData.h
@@ -59,7 +59,7 @@ WTFThreadData(); ~WTFThreadData(); - AtomicStringTable* atomicStringTable() + AtomicStringTable* getAtomicStringTable() { return m_atomicStringTable; }
diff --git a/third_party/WebKit/Source/wtf/text/AtomicString.cpp b/third_party/WebKit/Source/wtf/text/AtomicString.cpp index 6d102b4..17e6c44 100644 --- a/third_party/WebKit/Source/wtf/text/AtomicString.cpp +++ b/third_party/WebKit/Source/wtf/text/AtomicString.cpp
@@ -95,11 +95,11 @@ HashSet<StringImpl*> m_table; }; -static inline AtomicStringTable& atomicStringTable() +static inline AtomicStringTable& getAtomicStringTable() { // Once possible we should make this non-lazy (constructed in WTFThreadData's constructor). WTFThreadData& data = wtfThreadData(); - AtomicStringTable* table = data.atomicStringTable(); + AtomicStringTable* table = data.getAtomicStringTable(); if (UNLIKELY(!table)) table = AtomicStringTable::create(data); return *table; @@ -107,12 +107,12 @@ static inline HashSet<StringImpl*>& atomicStrings() { - return atomicStringTable().table(); + return getAtomicStringTable().table(); } void AtomicString::reserveTableCapacity(size_t size) { - atomicStringTable().table().reserveCapacityForSize(size); + getAtomicStringTable().table().reserveCapacityForSize(size); } template<typename T, typename HashTranslator> @@ -371,7 +371,7 @@ PassRefPtr<StringImpl> AtomicString::addSlowCase(StringImpl* string) { - return atomicStringTable().addStringImpl(string); + return getAtomicStringTable().addStringImpl(string); } template<typename CharacterType>
diff --git a/ui/base/clipboard/clipboard_mac.mm b/ui/base/clipboard/clipboard_mac.mm index 08a6041..20cdb95 100644 --- a/ui/base/clipboard/clipboard_mac.mm +++ b/ui/base/clipboard/clipboard_mac.mm
@@ -426,18 +426,7 @@ base::scoped_nsobject<NSPasteboardItem> item( ClipboardUtil::PasteboardItemFromUrl(url, title)); NSPasteboard* pb = GetPasteboard(); - - NSSet* oldTypes = [NSSet setWithArray:[pb types]]; - NSMutableSet* newTypes = [NSMutableSet setWithArray:[item types]]; - [newTypes minusSet:oldTypes]; - - [pb addTypes:[newTypes allObjects] owner:nil]; - for (NSString* type in newTypes) { - // Technically, the object associated with |type| might be an NSString or a - // property list. It doesn't matter though, since the type gets pulled from - // and shoved into an NSDictionary. - [pb setData:[item dataForType:type] forType:type]; - } + ui::ClipboardUtil::AddDataToPasteboard(pb, item); } void ClipboardMac::WriteBitmap(const SkBitmap& bitmap) {
diff --git a/ui/base/clipboard/clipboard_util_mac.h b/ui/base/clipboard/clipboard_util_mac.h index 5d62cfa..1c4ff0a 100644 --- a/ui/base/clipboard/clipboard_util_mac.h +++ b/ui/base/clipboard/clipboard_util_mac.h
@@ -35,6 +35,11 @@ NSString* url, NSString* title); + // Returns an NSPasteboardItem that represents the given |urls| and |titles|. + static base::scoped_nsobject<NSPasteboardItem> PasteboardItemFromUrls( + NSArray* urls, + NSArray* titles); + // Returns an NSPasteboardItem that represents the given string. // |string| must not be nil. static base::scoped_nsobject<NSPasteboardItem> PasteboardItemFromString( @@ -44,6 +49,21 @@ // url NSPasteboardItem. static NSString* GetTitleFromPasteboardURL(NSPasteboard* pboard); static NSString* GetURLFromPasteboardURL(NSPasteboard* pboard); + + // Returns the UTI of a pasteboard type. + static NSString* UTIForPasteboardType(NSString* type); + static NSString* UTIForWebURLsAndTitles(); + + // For each pasteboard type in |item| that is not in |pboard|, add the type + // and its associated data. + static void AddDataToPasteboard(NSPasteboard* pboard, NSPasteboardItem* item); + + // Returns whether the operation was succesful. On success, the two arrays are + // guaranteed to be equal length, and are populated with strings of |urls| and + // |titles|. + static bool URLsAndTitlesFromPasteboard(NSPasteboard* pboard, + NSArray** urls, + NSArray** titles); }; }
diff --git a/ui/base/clipboard/clipboard_util_mac.mm b/ui/base/clipboard/clipboard_util_mac.mm index cff59788..590ebf8 100644 --- a/ui/base/clipboard/clipboard_util_mac.mm +++ b/ui/base/clipboard/clipboard_util_mac.mm
@@ -78,6 +78,20 @@ } // static +base::scoped_nsobject<NSPasteboardItem> ClipboardUtil::PasteboardItemFromUrls( + NSArray* urls, + NSArray* titles) { + base::scoped_nsobject<NSPasteboardItem> item([[NSPasteboardItem alloc] init]); + + // Set Safari's URL + title arrays Pboard type. + NSArray* urlsAndTitles = @[ urls, titles ]; + [item setPropertyList:urlsAndTitles + forType:UTIFromPboardType(kWebURLsWithTitlesPboardType)]; + + return item; +} + +// static base::scoped_nsobject<NSPasteboardItem> ClipboardUtil::PasteboardItemFromString( NSString* string) { base::scoped_nsobject<NSPasteboardItem> item([[NSPasteboardItem alloc] init]); @@ -97,4 +111,69 @@ [pboard stringForType:UTIFromPboardType(kCorePasteboardFlavorType_url)]; } +// static +NSString* ClipboardUtil::UTIForPasteboardType(NSString* type) { + return UTIFromPboardType(type); +} + +// static +NSString* ClipboardUtil::UTIForWebURLsAndTitles() { + return UTIFromPboardType(kWebURLsWithTitlesPboardType); +} + +// static +void ClipboardUtil::AddDataToPasteboard(NSPasteboard* pboard, + NSPasteboardItem* item) { + NSSet* oldTypes = [NSSet setWithArray:[pboard types]]; + NSMutableSet* newTypes = [NSMutableSet setWithArray:[item types]]; + [newTypes minusSet:oldTypes]; + + [pboard addTypes:[newTypes allObjects] owner:nil]; + for (NSString* type in newTypes) { + // Technically, the object associated with |type| might be an NSString or a + // property list. It doesn't matter though, since the type gets pulled from + // and shoved into an NSDictionary. + [pboard setData:[item dataForType:type] forType:type]; + } +} + +// static +bool ClipboardUtil::URLsAndTitlesFromPasteboard(NSPasteboard* pboard, + NSArray** urls, + NSArray** titles) { + NSArray* bookmarkPairs = base::mac::ObjCCast<NSArray>([pboard + propertyListForType:UTIFromPboardType(kWebURLsWithTitlesPboardType)]); + if (!bookmarkPairs) + return false; + + if ([bookmarkPairs count] != 2) + return false; + + NSArray* urlsArr = + base::mac::ObjCCast<NSArray>([bookmarkPairs objectAtIndex:0]); + NSArray* titlesArr = + base::mac::ObjCCast<NSArray>([bookmarkPairs objectAtIndex:1]); + + if (!urlsArr || !titlesArr) + return false; + if ([urlsArr count] < 1) + return false; + if ([urlsArr count] != [titlesArr count]) + return false; + + for (id obj in urlsArr) { + if (![obj isKindOfClass:[NSString class]]) + return false; + } + + for (id obj in titlesArr) { + if (![obj isKindOfClass:[NSString class]]) + return false; + } + + *urls = urlsArr; + *titles = titlesArr; + return true; +} + } // namespace ui