// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "ui/base/clipboard/clipboard.h" #include #include #include #include "base/debug/dump_without_crashing.h" #include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/stl_util.h" #include "third_party/skia/include/core/SkBitmap.h" #include "ui/gfx/geometry/size.h" namespace ui { base::LazyInstance::DestructorAtExit Clipboard::allowed_threads_ = LAZY_INSTANCE_INITIALIZER; base::LazyInstance::DestructorAtExit Clipboard::clipboard_map_ = LAZY_INSTANCE_INITIALIZER; base::LazyInstance::Leaky Clipboard::clipboard_map_lock_ = LAZY_INSTANCE_INITIALIZER; // static void Clipboard::SetAllowedThreads( const std::vector& allowed_threads) { base::AutoLock lock(clipboard_map_lock_.Get()); allowed_threads_.Get().clear(); std::copy(allowed_threads.begin(), allowed_threads.end(), std::back_inserter(allowed_threads_.Get())); } // static void Clipboard::SetClipboardForCurrentThread( std::unique_ptr platform_clipboard) { base::AutoLock lock(clipboard_map_lock_.Get()); base::PlatformThreadId id = Clipboard::GetAndValidateThreadID(); ClipboardMap* clipboard_map = clipboard_map_.Pointer(); ClipboardMap::const_iterator it = clipboard_map->find(id); if (it != clipboard_map->end()) { // This shouldn't happen. The clipboard should not already exist. NOTREACHED(); } clipboard_map->insert(std::make_pair(id, std::move(platform_clipboard))); } // static Clipboard* Clipboard::GetForCurrentThread() { base::AutoLock lock(clipboard_map_lock_.Get()); base::PlatformThreadId id = GetAndValidateThreadID(); ClipboardMap* clipboard_map = clipboard_map_.Pointer(); ClipboardMap::const_iterator it = clipboard_map->find(id); if (it != clipboard_map->end()) return it->second.get(); Clipboard* clipboard = Clipboard::Create(); clipboard_map->insert(std::make_pair(id, base::WrapUnique(clipboard))); return clipboard; } // static void Clipboard::OnPreShutdownForCurrentThread() { base::AutoLock lock(clipboard_map_lock_.Get()); base::PlatformThreadId id = GetAndValidateThreadID(); ClipboardMap* clipboard_map = clipboard_map_.Pointer(); ClipboardMap::const_iterator it = clipboard_map->find(id); if (it != clipboard_map->end()) it->second->OnPreShutdown(); } // static void Clipboard::DestroyClipboardForCurrentThread() { base::AutoLock lock(clipboard_map_lock_.Get()); ClipboardMap* clipboard_map = clipboard_map_.Pointer(); base::PlatformThreadId id = base::PlatformThread::CurrentId(); ClipboardMap::iterator it = clipboard_map->find(id); if (it != clipboard_map->end()) clipboard_map->erase(it); } base::Time Clipboard::GetLastModifiedTime() const { return base::Time(); } void Clipboard::ClearLastModifiedTime() {} void Clipboard::DispatchObject(ObjectType type, const ObjectMapParams& params) { // Ignore writes with empty parameters. for (const auto& param : params) { if (param.empty()) return; } switch (type) { case CBF_TEXT: WriteText(&(params[0].front()), params[0].size()); break; case CBF_HTML: if (params.size() == 2) { if (params[1].empty()) return; WriteHTML(&(params[0].front()), params[0].size(), &(params[1].front()), params[1].size()); } else if (params.size() == 1) { WriteHTML(&(params[0].front()), params[0].size(), NULL, 0); } break; case CBF_RTF: WriteRTF(&(params[0].front()), params[0].size()); break; case CBF_BOOKMARK: WriteBookmark(&(params[0].front()), params[0].size(), &(params[1].front()), params[1].size()); break; case CBF_WEBKIT: WriteWebSmartPaste(); break; case CBF_SMBITMAP: { // Usually, the params are just UTF-8 strings. However, for images, // ScopedClipboardWriter actually sizes the buffer to sizeof(SkBitmap*), // aliases the contents of the vector to a SkBitmap**, and writes the // pointer to the actual SkBitmap in the clipboard object param. const char* packed_pointer_buffer = ¶ms[0].front(); WriteBitmap(**reinterpret_cast(packed_pointer_buffer)); break; } case CBF_DATA: WriteData( FormatType::Deserialize( std::string(&(params[0].front()), params[0].size())), &(params[1].front()), params[1].size()); break; default: NOTREACHED(); } } base::PlatformThreadId Clipboard::GetAndValidateThreadID() { clipboard_map_lock_.Get().AssertAcquired(); const base::PlatformThreadId id = base::PlatformThread::CurrentId(); // TODO(fdoray): Surround this block with #if DCHECK_IS_ON() and remove the // DumpWithoutCrashing() call once https://crbug.com/662055 is resolved. AllowedThreadsVector* allowed_threads = allowed_threads_.Pointer(); if (!allowed_threads->empty() && !base::ContainsValue(*allowed_threads, id)) { NOTREACHED(); base::debug::DumpWithoutCrashing(); } return id; } } // namespace ui