diff options
author | erg@chromium.org <erg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-25 01:18:08 +0000 |
---|---|---|
committer | erg@chromium.org <erg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-25 01:18:08 +0000 |
commit | 62ecc80cabdb2d0d852d640ca9ae35a969f2ca59 (patch) | |
tree | 7c28bb3dc28652f90095ebf825f6c37925a9a9d7 /ui/base | |
parent | ee7d94d9447a33d623ab3439241fee53a55c419f (diff) | |
download | chromium_src-62ecc80cabdb2d0d852d640ca9ae35a969f2ca59.zip chromium_src-62ecc80cabdb2d0d852d640ca9ae35a969f2ca59.tar.gz chromium_src-62ecc80cabdb2d0d852d640ca9ae35a969f2ca59.tar.bz2 |
linux_aura: Redo how memory is handled in clipboard/drag code.
This changes the ownership model from manually allocated arrays to
RefCountedMemory segments. Coincidentally, this also reduces the number
of memcpys by letting us pass around data sent to us by the X server.
BUG=130806
Review URL: https://chromiumcodereview.appspot.com/17029020
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@208342 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/base')
-rw-r--r-- | ui/base/clipboard/clipboard_aurax11.cc | 174 | ||||
-rw-r--r-- | ui/base/dragdrop/os_exchange_data_provider_aurax11.cc | 62 | ||||
-rw-r--r-- | ui/base/dragdrop/os_exchange_data_provider_aurax11.h | 7 | ||||
-rw-r--r-- | ui/base/x/selection_owner.cc | 73 | ||||
-rw-r--r-- | ui/base/x/selection_owner.h | 9 | ||||
-rw-r--r-- | ui/base/x/selection_requestor.cc | 12 | ||||
-rw-r--r-- | ui/base/x/selection_requestor.h | 15 | ||||
-rw-r--r-- | ui/base/x/selection_utils.cc | 155 | ||||
-rw-r--r-- | ui/base/x/selection_utils.h | 45 | ||||
-rw-r--r-- | ui/base/x/x11_util.cc | 58 | ||||
-rw-r--r-- | ui/base/x/x11_util.h | 37 |
11 files changed, 346 insertions, 301 deletions
diff --git a/ui/base/clipboard/clipboard_aurax11.cc b/ui/base/clipboard/clipboard_aurax11.cc index 8809d26..287941d 100644 --- a/ui/base/clipboard/clipboard_aurax11.cc +++ b/ui/base/clipboard/clipboard_aurax11.cc @@ -239,7 +239,7 @@ class Clipboard::AuraX11Details : public base::MessagePumpDispatcher { SelectionRequestor* GetSelectionRequestorForBuffer(Buffer buffer); // Finds the SelectionFormatMap for the incoming selection atom. - SelectionFormatMap* LookupStorageForAtom(::Atom atom); + const SelectionFormatMap& LookupStorageForAtom(::Atom atom); // As we need to collect all the data types before we tell X11 that we own a // particular selection, we create a temporary clipboard mapping that @@ -248,7 +248,8 @@ class Clipboard::AuraX11Details : public base::MessagePumpDispatcher { void CreateNewClipboardData(); // Inserts a mapping into clipboard_data_. - void InsertMapping(const std::string& key, char* data, size_t data_len); + void InsertMapping(const std::string& key, + const scoped_refptr<base::RefCountedMemory>& memory); // Moves the temporary |clipboard_data_| to the long term data storage for // |buffer|. @@ -262,9 +263,8 @@ class Clipboard::AuraX11Details : public base::MessagePumpDispatcher { // selection holder is some other window, we spin up a nested message loop // and do the asynchronous dance with whatever application is holding the // selection. - scoped_ptr<SelectionData> RequestAndWaitForTypes( - Buffer buffer, - const std::vector< ::Atom>& types); + ui::SelectionData RequestAndWaitForTypes(Buffer buffer, + const std::vector< ::Atom>& types); // Retrieves the list of possible data types the current clipboard owner has. // @@ -299,7 +299,7 @@ class Clipboard::AuraX11Details : public base::MessagePumpDispatcher { SelectionRequestor primary_requestor_; // Temporary target map that we write to during DispatchObects. - scoped_ptr<SelectionFormatMap> clipboard_data_; + SelectionFormatMap clipboard_data_; // Objects which offer selection data to other windows. SelectionOwner clipboard_owner_; @@ -345,18 +345,17 @@ Clipboard::AuraX11Details::~AuraX11Details() { Buffer buffer) const { if (buffer == BUFFER_STANDARD) return atom_cache_.GetAtom(kClipboard); - else - return XA_PRIMARY; + + return XA_PRIMARY; } -SelectionFormatMap* Clipboard::AuraX11Details::LookupStorageForAtom( +const SelectionFormatMap& Clipboard::AuraX11Details::LookupStorageForAtom( ::Atom atom) { if (atom == XA_PRIMARY) return primary_owner_.selection_format_map(); - else if (atom == atom_cache_.GetAtom(kClipboard)) - return clipboard_owner_.selection_format_map(); - else - return NULL; + + DCHECK_EQ(atom_cache_.GetAtom(kClipboard), atom); + return clipboard_owner_.selection_format_map(); } ui::SelectionRequestor* @@ -368,42 +367,37 @@ Clipboard::AuraX11Details::GetSelectionRequestorForBuffer(Buffer buffer) { } void Clipboard::AuraX11Details::CreateNewClipboardData() { - clipboard_data_.reset(new SelectionFormatMap); + clipboard_data_ = SelectionFormatMap(); } -void Clipboard::AuraX11Details::InsertMapping(const std::string& key, - char* data, - size_t data_len) { +void Clipboard::AuraX11Details::InsertMapping( + const std::string& key, + const scoped_refptr<base::RefCountedMemory>& memory) { ::Atom atom_key = atom_cache_.GetAtom(key.c_str()); - clipboard_data_->Insert(atom_key, data, data_len); + clipboard_data_.Insert(atom_key, memory); } void Clipboard::AuraX11Details::TakeOwnershipOfSelection(Buffer buffer) { if (buffer == BUFFER_STANDARD) - return clipboard_owner_.TakeOwnershipOfSelection(clipboard_data_.Pass()); + return clipboard_owner_.TakeOwnershipOfSelection(clipboard_data_); else - return primary_owner_.TakeOwnershipOfSelection(clipboard_data_.Pass()); + return primary_owner_.TakeOwnershipOfSelection(clipboard_data_); } -scoped_ptr<SelectionData> Clipboard::AuraX11Details::RequestAndWaitForTypes( +SelectionData Clipboard::AuraX11Details::RequestAndWaitForTypes( Buffer buffer, const std::vector< ::Atom>& types) { ::Atom selection_name = LookupSelectionForBuffer(buffer); if (XGetSelectionOwner(x_display_, selection_name) == x_window_) { // We can local fastpath instead of playing the nested message loop game // with the X server. - SelectionFormatMap* format_map = LookupStorageForAtom(selection_name); - DCHECK(format_map); + const SelectionFormatMap& format_map = LookupStorageForAtom(selection_name); for (std::vector< ::Atom>::const_iterator it = types.begin(); it != types.end(); ++it) { - SelectionFormatMap::const_iterator format_map_it = format_map->find(*it); - if (format_map_it != format_map->end()) { - scoped_ptr<SelectionData> data_out(new SelectionData); - data_out->Set(format_map_it->first, format_map_it->second.first, - format_map_it->second.second, false); - return data_out.Pass(); - } + SelectionFormatMap::const_iterator format_map_it = format_map.find(*it); + if (format_map_it != format_map.end()) + return SelectionData(format_map_it->first, format_map_it->second); } } else { TargetList targets = WaitAndGetTargetsList(buffer); @@ -414,7 +408,7 @@ scoped_ptr<SelectionData> Clipboard::AuraX11Details::RequestAndWaitForTypes( return receiver->RequestAndWaitForTypes(intersection); } - return scoped_ptr<SelectionData>(); + return SelectionData(); } TargetList Clipboard::AuraX11Details::WaitAndGetTargetsList( @@ -423,15 +417,14 @@ TargetList Clipboard::AuraX11Details::WaitAndGetTargetsList( std::vector< ::Atom> out; if (XGetSelectionOwner(x_display_, selection_name) == x_window_) { // We can local fastpath and return the list of local targets. - SelectionFormatMap* format_map = LookupStorageForAtom(selection_name); - DCHECK(format_map); + const SelectionFormatMap& format_map = LookupStorageForAtom(selection_name); - for (SelectionFormatMap::const_iterator it = format_map->begin(); - it != format_map->end(); ++it) { + for (SelectionFormatMap::const_iterator it = format_map.begin(); + it != format_map.end(); ++it) { out.push_back(it->first); } } else { - unsigned char* data = NULL; + scoped_refptr<base::RefCountedMemory> data; size_t out_data_items = 0; ::Atom out_type = None; @@ -441,11 +434,9 @@ TargetList Clipboard::AuraX11Details::WaitAndGetTargetsList( NULL, &out_data_items, &out_type)) { - ::Atom* atom_array = reinterpret_cast< ::Atom*>(data); + const ::Atom* atom_array = reinterpret_cast<const ::Atom*>(data->front()); for (size_t i = 0; i < out_data_items; ++i) out.push_back(atom_array[i]); - - XFree(data); } else { // There was no target list. Most Java apps doesn't offer a TARGETS list, // even though they AWT to. They will offer individual text types if you @@ -599,22 +590,20 @@ void Clipboard::ReadAvailableTypes(Buffer buffer, std::vector<string16>* types, types->push_back(UTF8ToUTF16(kMimeTypePNG)); *contains_filenames = false; - scoped_ptr<SelectionData> data(aurax11_details_->RequestAndWaitForTypes( + SelectionData data(aurax11_details_->RequestAndWaitForTypes( buffer, aurax11_details_->GetAtomsForFormat(GetWebCustomDataFormatType()))); - if (!data.get()) - return; - - ReadCustomDataTypes(data->data(), data->size(), types); + if (data.IsValid()) + ReadCustomDataTypes(data.GetData(), data.GetSize(), types); } void Clipboard::ReadText(Buffer buffer, string16* result) const { DCHECK(CalledOnValidThread()); - scoped_ptr<SelectionData> data(aurax11_details_->RequestAndWaitForTypes( + SelectionData data(aurax11_details_->RequestAndWaitForTypes( buffer, aurax11_details_->GetTextAtoms())); - if (data.get()) { - std::string text = data->GetText(); + if (data.IsValid()) { + std::string text = data.GetText(); *result = UTF8ToUTF16(text); } } @@ -622,10 +611,10 @@ void Clipboard::ReadText(Buffer buffer, string16* result) const { void Clipboard::ReadAsciiText(Buffer buffer, std::string* result) const { DCHECK(CalledOnValidThread()); - scoped_ptr<SelectionData> data(aurax11_details_->RequestAndWaitForTypes( + SelectionData data(aurax11_details_->RequestAndWaitForTypes( buffer, aurax11_details_->GetTextAtoms())); - if (data.get()) - result->assign(data->GetText()); + if (data.IsValid()) + result->assign(data.GetText()); } // TODO(estade): handle different charsets. @@ -642,25 +631,24 @@ void Clipboard::ReadHTML(Buffer buffer, *fragment_start = 0; *fragment_end = 0; - scoped_ptr<SelectionData> data(aurax11_details_->RequestAndWaitForTypes( + SelectionData data(aurax11_details_->RequestAndWaitForTypes( buffer, aurax11_details_->GetAtomsForFormat(GetHtmlFormatType()))); - if (!data.get()) - return; + if (data.IsValid()) { + *markup = data.GetHtml(); - *markup = data->GetHtml(); - - *fragment_start = 0; - DCHECK(markup->length() <= kuint32max); - *fragment_end = static_cast<uint32>(markup->length()); + *fragment_start = 0; + DCHECK(markup->length() <= kuint32max); + *fragment_end = static_cast<uint32>(markup->length()); + } } void Clipboard::ReadRTF(Buffer buffer, std::string* result) const { DCHECK(CalledOnValidThread()); - scoped_ptr<SelectionData> data(aurax11_details_->RequestAndWaitForTypes( + SelectionData data(aurax11_details_->RequestAndWaitForTypes( buffer, aurax11_details_->GetAtomsForFormat(GetRtfFormatType()))); - if (data.get()) - data->AssignTo(result); + if (data.IsValid()) + data.AssignTo(result); } SkBitmap Clipboard::ReadImage(Buffer buffer) const { @@ -674,13 +662,11 @@ void Clipboard::ReadCustomData(Buffer buffer, string16* result) const { DCHECK(CalledOnValidThread()); - scoped_ptr<SelectionData> data(aurax11_details_->RequestAndWaitForTypes( + SelectionData data(aurax11_details_->RequestAndWaitForTypes( buffer, aurax11_details_->GetAtomsForFormat(GetWebCustomDataFormatType()))); - if (!data.get()) - return; - - ReadCustomDataForType(data->data(), data->size(), type, result); + if (data.IsValid()) + ReadCustomDataForType(data.GetData(), data.GetSize(), type, result); } void Clipboard::ReadBookmark(string16* title, std::string* url) const { @@ -692,10 +678,10 @@ void Clipboard::ReadBookmark(string16* title, std::string* url) const { void Clipboard::ReadData(const FormatType& format, std::string* result) const { DCHECK(CalledOnValidThread()); - scoped_ptr<SelectionData> data(aurax11_details_->RequestAndWaitForTypes( + SelectionData data(aurax11_details_->RequestAndWaitForTypes( BUFFER_STANDARD, aurax11_details_->GetAtomsForFormat(format))); - if (data.get()) - data->AssignTo(result); + if (data.IsValid()) + data.AssignTo(result); } uint64 Clipboard::GetSequenceNumber(Buffer buffer) { @@ -707,13 +693,14 @@ uint64 Clipboard::GetSequenceNumber(Buffer buffer) { } void Clipboard::WriteText(const char* text_data, size_t text_len) { - char* data = new char[text_len]; - memcpy(data, text_data, text_len); + std::string str(text_data, text_len); + scoped_refptr<base::RefCountedMemory> mem( + base::RefCountedString::TakeString(&str)); - aurax11_details_->InsertMapping(kMimeTypeText, data, text_len); - aurax11_details_->InsertMapping(kText, data, text_len); - aurax11_details_->InsertMapping(kString, data, text_len); - aurax11_details_->InsertMapping(kUtf8String, data, text_len); + aurax11_details_->InsertMapping(kMimeTypeText, mem); + aurax11_details_->InsertMapping(kText, mem); + aurax11_details_->InsertMapping(kString, mem); + aurax11_details_->InsertMapping(kUtf8String, mem); } void Clipboard::WriteHTML(const char* markup_data, @@ -723,16 +710,14 @@ void Clipboard::WriteHTML(const char* markup_data, // TODO(estade): We need to expand relative links with |url_data|. static const char* html_prefix = "<meta http-equiv=\"content-type\" " "content=\"text/html; charset=utf-8\">"; - size_t html_prefix_len = strlen(html_prefix); - size_t total_len = html_prefix_len + markup_len + 1; - - char* data = new char[total_len]; - snprintf(data, total_len, "%s", html_prefix); - memcpy(data + html_prefix_len, markup_data, markup_len); + std::string data = html_prefix; + data += std::string(markup_data, markup_len); // Some programs expect NULL-terminated data. See http://crbug.com/42624 - data[total_len - 1] = '\0'; + data += '\0'; - aurax11_details_->InsertMapping(kMimeTypeHTML, data, total_len); + scoped_refptr<base::RefCountedMemory> mem( + base::RefCountedString::TakeString(&data)); + aurax11_details_->InsertMapping(kMimeTypeHTML, mem); } void Clipboard::WriteRTF(const char* rtf_data, size_t data_len) { @@ -746,18 +731,21 @@ void Clipboard::WriteBookmark(const char* title_data, // Write as a mozilla url (UTF16: URL, newline, title). string16 url = UTF8ToUTF16(std::string(url_data, url_len) + "\n"); string16 title = UTF8ToUTF16(std::string(title_data, title_len)); - int data_len = 2 * (title.length() + url.length()); - char* data = new char[data_len]; - memcpy(data, url.data(), 2 * url.length()); - memcpy(data + 2 * url.length(), title.data(), 2 * title.length()); - aurax11_details_->InsertMapping(kMimeTypeMozillaURL, data, data_len); + std::vector<unsigned char> data; + ui::AddString16ToVector(url, &data); + ui::AddString16ToVector(title, &data); + scoped_refptr<base::RefCountedMemory> mem( + base::RefCountedBytes::TakeVector(&data)); + + aurax11_details_->InsertMapping(kMimeTypeMozillaURL, mem); } // Write an extra flavor that signifies WebKit was the last to modify the // pasteboard. This flavor has no data. void Clipboard::WriteWebSmartPaste() { - aurax11_details_->InsertMapping(kMimeTypeWebkitSmartPaste, NULL, 0); + aurax11_details_->InsertMapping(kMimeTypeWebkitSmartPaste, + scoped_refptr<base::RefCountedMemory>()); } void Clipboard::WriteBitmap(const char* pixel_data, const char* size_data) { @@ -774,9 +762,11 @@ void Clipboard::WriteData(const FormatType& format, // Therefore we must upkeep their integrity. if (format.Equals(GetBitmapFormatType())) return; - char* data = new char[data_len]; - memcpy(data, data_data, data_len); - aurax11_details_->InsertMapping(format.ToString(), data, data_len); + + std::vector<unsigned char> bytes(data_data, data_data + data_len); + scoped_refptr<base::RefCountedMemory> mem( + base::RefCountedBytes::TakeVector(&bytes)); + aurax11_details_->InsertMapping(format.ToString(), mem); } // static diff --git a/ui/base/dragdrop/os_exchange_data_provider_aurax11.cc b/ui/base/dragdrop/os_exchange_data_provider_aurax11.cc index d760a72..7aed8d8 100644 --- a/ui/base/dragdrop/os_exchange_data_provider_aurax11.cc +++ b/ui/base/dragdrop/os_exchange_data_provider_aurax11.cc @@ -5,6 +5,7 @@ #include "ui/base/dragdrop/os_exchange_data_provider_aurax11.h" #include "base/logging.h" +#include "base/memory/ref_counted_memory.h" #include "base/message_loop/message_pump_aurax11.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" @@ -40,13 +41,13 @@ const char* kAtomsToCache[] = { OSExchangeDataProviderAuraX11::OSExchangeDataProviderAuraX11( ::Window x_window, - scoped_ptr<SelectionFormatMap> selection) + const SelectionFormatMap& selection) : x_display_(GetXDisplay()), x_root_window_(DefaultRootWindow(x_display_)), own_window_(false), x_window_(x_window), atom_cache_(x_display_, kAtomsToCache), - format_map_(selection.Pass()), + format_map_(selection), selection_owner_(x_display_, x_window_, atom_cache_.GetAtom(kDndSelection)) { // We don't know all possible MIME types at compile time. @@ -68,7 +69,7 @@ OSExchangeDataProviderAuraX11::OSExchangeDataProviderAuraX11() 0, NULL)), atom_cache_(x_display_, kAtomsToCache), - format_map_(new SelectionFormatMap), + format_map_(), selection_owner_(x_display_, x_window_, atom_cache_.GetAtom(kDndSelection)) { // We don't know all possible MIME types at compile time. @@ -87,8 +88,7 @@ OSExchangeDataProviderAuraX11::~OSExchangeDataProviderAuraX11() { } void OSExchangeDataProviderAuraX11::TakeOwnershipOfSelection() const { - selection_owner_.TakeOwnershipOfSelection( - scoped_ptr<SelectionFormatMap>(format_map_->Clone())); + selection_owner_.TakeOwnershipOfSelection(format_map_); } void OSExchangeDataProviderAuraX11::RetrieveTargets( @@ -96,29 +96,21 @@ void OSExchangeDataProviderAuraX11::RetrieveTargets( selection_owner_.RetrieveTargets(targets); } -scoped_ptr<SelectionFormatMap> -OSExchangeDataProviderAuraX11::CloneFormatMap() const { - // We clone the |selection_owner_|'s format map instead of our own in case +SelectionFormatMap OSExchangeDataProviderAuraX11::GetFormatMap() const { + // We return the |selection_owner_|'s format map instead of our own in case // ours has been modified since TakeOwnershipOfSelection() was called. - return selection_owner_.selection_format_map()->Clone(); + return selection_owner_.selection_format_map(); } void OSExchangeDataProviderAuraX11::SetString(const string16& text_data) { std::string utf8 = UTF16ToUTF8(text_data); + scoped_refptr<base::RefCountedMemory> mem( + base::RefCountedString::TakeString(&utf8)); - // Ownership of |data| is passed to |format_map_|. - size_t text_len = utf8.size(); - char* data = new char[text_len]; - memcpy(data, utf8.c_str(), text_len); - - format_map_->Insert( - atom_cache_.GetAtom(Clipboard::kMimeTypeText), data, text_len); - format_map_->Insert( - atom_cache_.GetAtom(kText), data, text_len); - format_map_->Insert( - atom_cache_.GetAtom(kString), data, text_len); - format_map_->Insert( - atom_cache_.GetAtom(kUtf8String), data, text_len); + format_map_.Insert(atom_cache_.GetAtom(Clipboard::kMimeTypeText), mem); + format_map_.Insert(atom_cache_.GetAtom(kText), mem); + format_map_.Insert(atom_cache_.GetAtom(kString), mem); + format_map_.Insert(atom_cache_.GetAtom(kUtf8String), mem); } void OSExchangeDataProviderAuraX11::SetURL(const GURL& url, @@ -146,9 +138,9 @@ bool OSExchangeDataProviderAuraX11::GetString(string16* result) const { std::vector< ::Atom> requested_types; ui::GetAtomIntersection(text_atoms, GetTargets(), &requested_types); - scoped_ptr<ui::SelectionData> data(format_map_->GetFirstOf(requested_types)); - if (data) { - std::string text = data->GetText(); + ui::SelectionData data(format_map_.GetFirstOf(requested_types)); + if (data.IsValid()) { + std::string text = data.GetText(); *result = UTF8ToUTF16(text); return true; } @@ -162,16 +154,16 @@ bool OSExchangeDataProviderAuraX11::GetURLAndTitle(GURL* url, std::vector< ::Atom> requested_types; ui::GetAtomIntersection(url_atoms, GetTargets(), &requested_types); - scoped_ptr<ui::SelectionData> data(format_map_->GetFirstOf(requested_types)); - if (data) { + ui::SelectionData data(format_map_.GetFirstOf(requested_types)); + if (data.IsValid()) { // TODO(erg): Technically, both of these forms can accept multiple URLs, // but that doesn't match the assumptions of the rest of the system which // expect single types. - if (data->type() == atom_cache_.GetAtom(kMimeTypeMozillaURL)) { + if (data.GetType() == atom_cache_.GetAtom(kMimeTypeMozillaURL)) { // Mozilla URLs are (UTF16: URL, newline, title). string16 unparsed; - data->AssignTo(&unparsed); + data.AssignTo(&unparsed); std::vector<string16> tokens; size_t num_tokens = Tokenize(unparsed, ASCIIToUTF16("\n"), &tokens); @@ -183,11 +175,11 @@ bool OSExchangeDataProviderAuraX11::GetURLAndTitle(GURL* url, NOTREACHED() << "Data that claimed to be a Mozilla URL has " << num_tokens << " tokens instead of 2."; } - } else if (data->type() == atom_cache_.GetAtom( + } else if (data.GetType() == atom_cache_.GetAtom( Clipboard::kMimeTypeURIList)) { // uri-lists are newline separated file lists in URL encoding. std::string unparsed; - data->AssignTo(&unparsed); + data.AssignTo(&unparsed); std::vector<std::string> tokens; size_t num_tokens = Tokenize(unparsed, "\n", &tokens); @@ -265,9 +257,9 @@ bool OSExchangeDataProviderAuraX11::GetHtml(string16* html, std::vector< ::Atom> requested_types; ui::GetAtomIntersection(url_atoms, GetTargets(), &requested_types); - scoped_ptr<ui::SelectionData> data(format_map_->GetFirstOf(requested_types)); - if (data) { - *html = data->GetHtml(); + ui::SelectionData data(format_map_.GetFirstOf(requested_types)); + if (data.IsValid()) { + *html = data.GetHtml(); *base_url = GURL(); return true; } @@ -318,7 +310,7 @@ bool OSExchangeDataProviderAuraX11::GetPlainTextURL(GURL* url) const { } std::vector< ::Atom> OSExchangeDataProviderAuraX11::GetTargets() const { - return format_map_->GetTypes(); + return format_map_.GetTypes(); } /////////////////////////////////////////////////////////////////////////////// diff --git a/ui/base/dragdrop/os_exchange_data_provider_aurax11.h b/ui/base/dragdrop/os_exchange_data_provider_aurax11.h index ea41131..09568e2 100644 --- a/ui/base/dragdrop/os_exchange_data_provider_aurax11.h +++ b/ui/base/dragdrop/os_exchange_data_provider_aurax11.h @@ -19,6 +19,7 @@ #include "ui/base/dragdrop/os_exchange_data.h" #include "ui/base/x/selection_owner.h" #include "ui/base/x/selection_requestor.h" +#include "ui/base/x/selection_utils.h" #include "ui/base/x/x11_atom_cache.h" #include "ui/gfx/image/image_skia.h" #include "ui/gfx/vector2d.h" @@ -35,7 +36,7 @@ class UI_EXPORT OSExchangeDataProviderAuraX11 // |x_window| is the window the cursor is over, and |selection| is the set of // data being offered. OSExchangeDataProviderAuraX11(::Window x_window, - scoped_ptr<SelectionFormatMap> selection); + const SelectionFormatMap& selection); // Creates a Provider for sending drag information. This creates its own, // hidden X11 window to own send data. @@ -52,7 +53,7 @@ class UI_EXPORT OSExchangeDataProviderAuraX11 void RetrieveTargets(std::vector<Atom>* targets) const; // Makes a copy of the format map currently being offered. - scoped_ptr<SelectionFormatMap> CloneFormatMap() const; + SelectionFormatMap GetFormatMap() const; // Overridden from OSExchangeData::Provider: virtual void SetString(const string16& data) OVERRIDE; @@ -119,7 +120,7 @@ class UI_EXPORT OSExchangeDataProviderAuraX11 // A representation of data. This is either passed to us from the other // process, or built up through a sequence of Set*() calls. It can be passed // to |selection_owner_| when we take the selection. - scoped_ptr<SelectionFormatMap> format_map_; + SelectionFormatMap format_map_; // Takes a snapshot of |format_map_| and offers it to other windows. mutable SelectionOwner selection_owner_; diff --git a/ui/base/x/selection_owner.cc b/ui/base/x/selection_owner.cc index a5b0f4e..54f59a1 100644 --- a/ui/base/x/selection_owner.cc +++ b/ui/base/x/selection_owner.cc @@ -40,19 +40,19 @@ SelectionOwner::~SelectionOwner() { void SelectionOwner::RetrieveTargets(std::vector<Atom>* targets) { targets->clear(); - for (SelectionFormatMap::const_iterator it = selection_data_->begin(); - it != selection_data_->end(); ++it) { + for (SelectionFormatMap::const_iterator it = format_map_.begin(); + it != format_map_.end(); ++it) { targets->push_back(it->first); } } void SelectionOwner::TakeOwnershipOfSelection( - scoped_ptr<SelectionFormatMap> data) { + const SelectionFormatMap& data) { XSetSelectionOwner(x_display_, selection_name_, x_window_, CurrentTime); if (XGetSelectionOwner(x_display_, selection_name_) == x_window_) { // The X server agrees that we are the selection owner. Commit our data. - selection_data_ = data.Pass(); + format_map_ = data; } } @@ -60,7 +60,7 @@ void SelectionOwner::Clear() { if (XGetSelectionOwner(x_display_, selection_name_) == x_window_) XSetSelectionOwner(x_display_, selection_name_, None, CurrentTime); - selection_data_.reset(); + format_map_ = SelectionFormatMap(); } void SelectionOwner::OnSelectionRequest(const XSelectionRequestEvent& event) { @@ -75,42 +75,39 @@ void SelectionOwner::OnSelectionRequest(const XSelectionRequestEvent& event) { reply.xselection.time = event.time; // Get the proper selection. - if (selection_data_.get()) { - Atom targets_atom = atom_cache_.GetAtom(kTargets); - if (event.target == targets_atom) { - // We have been asked for TARGETS. Send an atom array back with the data - // types we support. - std::vector<Atom> targets; - targets.push_back(targets_atom); - RetrieveTargets(&targets); - - XChangeProperty(x_display_, event.requestor, event.property, XA_ATOM, 32, + Atom targets_atom = atom_cache_.GetAtom(kTargets); + if (event.target == targets_atom) { + // We have been asked for TARGETS. Send an atom array back with the data + // types we support. + std::vector<Atom> targets; + targets.push_back(targets_atom); + RetrieveTargets(&targets); + + XChangeProperty(x_display_, event.requestor, event.property, XA_ATOM, 32, + PropModeReplace, + reinterpret_cast<unsigned char*>(&targets.front()), + targets.size()); + reply.xselection.property = event.property; + } else if (event.target == atom_cache_.GetAtom(kMultiple)) { + // TODO(erg): Theoretically, the spec claims I'm supposed to handle the + // MULTIPLE case, but I haven't seen it in the wild yet. + NOTIMPLEMENTED(); + } else { + // Try to find the data type in map. + SelectionFormatMap::const_iterator it = + format_map_.find(event.target); + if (it != format_map_.end()) { + XChangeProperty(x_display_, event.requestor, event.property, + event.target, 8, PropModeReplace, - reinterpret_cast<unsigned char*>(&targets.front()), - targets.size()); + const_cast<unsigned char*>( + reinterpret_cast<const unsigned char*>( + it->second->front())), + it->second->size()); reply.xselection.property = event.property; - } else if (event.target == atom_cache_.GetAtom(kMultiple)) { - // TODO(erg): Theoretically, the spec claims I'm supposed to handle the - // MULTIPLE case, but I haven't seen it in the wild yet. - NOTIMPLEMENTED(); - } else { - // Try to find the data type in map. - SelectionFormatMap::const_iterator it = - selection_data_->find(event.target); - if (it != selection_data_->end()) { - XChangeProperty(x_display_, event.requestor, event.property, - event.target, 8, - PropModeReplace, - reinterpret_cast<unsigned char*>(it->second.first), - it->second.second); - reply.xselection.property = event.property; - } - // I would put error logging here, but GTK ignores TARGETS and spams us - // looking for its own internal types. } - } else { - DLOG(ERROR) << "XWindow " << x_window_ << " received a SelectionRequest " - << "message when we don't have data to offer."; + // I would put error logging here, but GTK ignores TARGETS and spams us + // looking for its own internal types. } // Send off the reply. diff --git a/ui/base/x/selection_owner.h b/ui/base/x/selection_owner.h index a62be52..6c5c7f8 100644 --- a/ui/base/x/selection_owner.h +++ b/ui/base/x/selection_owner.h @@ -15,12 +15,11 @@ #include "base/basictypes.h" #include "base/callback.h" #include "ui/base/ui_export.h" +#include "ui/base/x/selection_utils.h" #include "ui/base/x/x11_atom_cache.h" namespace ui { -class SelectionFormatMap; - // Owns a specific X11 selection on an X window. // // The selection owner object keeps track of which xwindow is the current @@ -34,14 +33,14 @@ class UI_EXPORT SelectionOwner { ~SelectionOwner(); // Returns the current selection data. Useful for fast paths. - SelectionFormatMap* selection_format_map() { return selection_data_.get(); } + const SelectionFormatMap& selection_format_map() { return format_map_; } // Retrieves a list of types we're offering. void RetrieveTargets(std::vector<Atom>* targets); // Attempts to take ownership of the selection. If we're successful, present // |data| to other windows. - void TakeOwnershipOfSelection(scoped_ptr<SelectionFormatMap> data); + void TakeOwnershipOfSelection(const SelectionFormatMap& data); // Releases the selection (if we own it) and clears any data we own. void Clear(); @@ -61,7 +60,7 @@ class UI_EXPORT SelectionOwner { ::Atom selection_name_; // The data we are currently serving. - scoped_ptr<SelectionFormatMap> selection_data_; + SelectionFormatMap format_map_; X11AtomCache atom_cache_; diff --git a/ui/base/x/selection_requestor.cc b/ui/base/x/selection_requestor.cc index 1fd2872..405c059 100644 --- a/ui/base/x/selection_requestor.cc +++ b/ui/base/x/selection_requestor.cc @@ -38,7 +38,7 @@ SelectionRequestor::~SelectionRequestor() {} bool SelectionRequestor::PerformBlockingConvertSelection( Atom target, - unsigned char** out_data, + scoped_refptr<base::RefCountedMemory>* out_data, size_t* out_data_bytes, size_t* out_data_items, Atom* out_type) { @@ -73,11 +73,11 @@ bool SelectionRequestor::PerformBlockingConvertSelection( out_type); } -scoped_ptr<SelectionData> SelectionRequestor::RequestAndWaitForTypes( +SelectionData SelectionRequestor::RequestAndWaitForTypes( const std::vector< ::Atom>& types) { for (std::vector< ::Atom>::const_iterator it = types.begin(); it != types.end(); ++it) { - unsigned char* data = NULL; + scoped_refptr<base::RefCountedMemory> data; size_t data_bytes = 0; ::Atom type = None; if (PerformBlockingConvertSelection(*it, @@ -86,13 +86,11 @@ scoped_ptr<SelectionData> SelectionRequestor::RequestAndWaitForTypes( NULL, &type) && type == *it) { - scoped_ptr<SelectionData> data_out(new SelectionData); - data_out->Set(type, (char*)data, data_bytes, true); - return data_out.Pass(); + return SelectionData(type, data); } } - return scoped_ptr<SelectionData>(); + return SelectionData(); } void SelectionRequestor::OnSelectionNotify(const XSelectionEvent& event) { diff --git a/ui/base/x/selection_requestor.h b/ui/base/x/selection_requestor.h index 52ad1cf..318533a 100644 --- a/ui/base/x/selection_requestor.h +++ b/ui/base/x/selection_requestor.h @@ -14,6 +14,7 @@ #include "base/basictypes.h" #include "base/callback.h" +#include "base/memory/ref_counted_memory.h" #include "ui/base/ui_export.h" #include "ui/base/x/x11_atom_cache.h" @@ -39,16 +40,16 @@ class UI_EXPORT SelectionRequestor { // back. |out_data| is allocated with the X allocator and must be freed with // XFree(). |out_data_bytes| is the length in machine chars, while // |out_data_items| is the length in |out_type| items. - bool PerformBlockingConvertSelection(::Atom target, - unsigned char** out_data, - size_t* out_data_bytes, - size_t* out_data_items, - ::Atom* out_type); + bool PerformBlockingConvertSelection( + ::Atom target, + scoped_refptr<base::RefCountedMemory>* out_data, + size_t* out_data_bytes, + size_t* out_data_items, + ::Atom* out_type); // Returns the first of |types| offered by the current selection holder, or // returns NULL if none of those types are available. - scoped_ptr<SelectionData> RequestAndWaitForTypes( - const std::vector< ::Atom>& types); + SelectionData RequestAndWaitForTypes(const std::vector< ::Atom>& types); // It is our owner's responsibility to plumb X11 SelectionNotify events on // |xwindow_| to us. diff --git a/ui/base/x/selection_utils.cc b/ui/base/x/selection_utils.cc index 5dd6f68..560f494 100644 --- a/ui/base/x/selection_utils.cc +++ b/ui/base/x/selection_utils.cc @@ -58,56 +58,66 @@ void GetAtomIntersection(const std::vector< ::Atom>& one, } } -/////////////////////////////////////////////////////////////////////////////// +void AddString16ToVector(const string16& str, + std::vector<unsigned char>* bytes) { + const unsigned char* front = + reinterpret_cast<const unsigned char*>(str.data()); + bytes->insert(bytes->end(), front, front + (str.size() * 2)); +} -SelectionFormatMap::SelectionFormatMap() {} +std::string RefCountedMemoryToString( + const scoped_refptr<base::RefCountedMemory>& memory) { + if (!memory) { + NOTREACHED(); + return std::string(); + } -SelectionFormatMap::~SelectionFormatMap() { - // WriteText() inserts the same pointer multiple times for different - // representations; we need to dedupe it. - std::set<char*> to_delete; - for (InternalMap::iterator it = data_.begin(); it != data_.end(); ++it) - to_delete.insert(it->second.first); + size_t size = memory->size(); + if (!size) + return std::string(); - for (std::set<char*>::iterator it = to_delete.begin(); it != to_delete.end(); - ++it) { - delete [] *it; + const unsigned char* front = memory->front(); + return std::string(reinterpret_cast<const char*>(front), size); +} + +string16 RefCountedMemoryToString16( + const scoped_refptr<base::RefCountedMemory>& memory) { + if (!memory) { + NOTREACHED(); + return string16(); } + + size_t size = memory->size(); + if (!size) + return string16(); + + const unsigned char* front = memory->front(); + return string16(reinterpret_cast<const base::char16*>(front), size / 2); } -void SelectionFormatMap::Insert(::Atom atom, char* data, size_t size) { - // Views code often inserts the same content multiple times, so we have to - // free old data. Only call delete when it's the last pointer we have to that - // data. - InternalMap::iterator exists_it = data_.find(atom); - if (exists_it != data_.end()) { - int count = 0; - for (InternalMap::iterator it = data_.begin(); it != data_.end(); ++it) { - if (it->second.first == exists_it->second.first) - count++; - } +/////////////////////////////////////////////////////////////////////////////// - if (count == 1) - delete [] exists_it->second.first; - } +SelectionFormatMap::SelectionFormatMap() {} + +SelectionFormatMap::~SelectionFormatMap() {} - data_.insert(std::make_pair(atom, std::make_pair(data, size))); +void SelectionFormatMap::Insert( + ::Atom atom, + const scoped_refptr<base::RefCountedMemory>& item) { + data_.insert(std::make_pair(atom, item)); } -ui::SelectionData* SelectionFormatMap::GetFirstOf( +ui::SelectionData SelectionFormatMap::GetFirstOf( const std::vector< ::Atom>& requested_types) const { for (std::vector< ::Atom>::const_iterator it = requested_types.begin(); it != requested_types.end(); ++it) { const_iterator data_it = data_.find(*it); if (data_it != data_.end()) { - ui::SelectionData* data = new SelectionData; - data->Set(data_it->first, data_it->second.first, data_it->second.second, - false); - return data; + return SelectionData(data_it->first, data_it->second); } } - return NULL; + return SelectionData(); } std::vector< ::Atom> SelectionFormatMap::GetTypes() const { @@ -118,50 +128,60 @@ std::vector< ::Atom> SelectionFormatMap::GetTypes() const { return atoms; } -scoped_ptr<SelectionFormatMap> SelectionFormatMap::Clone() const { - scoped_ptr<SelectionFormatMap> ret(new SelectionFormatMap); - - for (const_iterator it = data_.begin(); it != data_.end(); ++it) { - char* data_copy = new char[it->second.second]; - memcpy(data_copy, it->second.first, it->second.second); - ret->Insert(it->first, data_copy, it->second.second); - } - - return ret.Pass(); -} - /////////////////////////////////////////////////////////////////////////////// SelectionData::SelectionData() : type_(None), - data_(NULL), - size_(0), - owned_(false), atom_cache_(ui::GetXDisplay(), kSelectionDataAtoms) { } -SelectionData::~SelectionData() { - if (owned_) - XFree(data_); +SelectionData::SelectionData( + ::Atom type, + const scoped_refptr<base::RefCountedMemory>& memory) + : type_(type), + memory_(memory), + atom_cache_(ui::GetXDisplay(), kSelectionDataAtoms) { +} + +SelectionData::SelectionData(const SelectionData& rhs) + : type_(rhs.type_), + memory_(rhs.memory_), + atom_cache_(ui::GetXDisplay(), kSelectionDataAtoms) { +} + +SelectionData::~SelectionData() {} + +SelectionData& SelectionData::operator=(const SelectionData& rhs) { + type_ = rhs.type_; + memory_ = rhs.memory_; + // TODO(erg): In some future where we have to support multiple X Displays, + // the following will also need to deal with the display. + return *this; } -void SelectionData::Set(::Atom type, char* data, size_t size, bool owned) { - if (owned_) - XFree(data_); +bool SelectionData::IsValid() const { + return type_ != None; +} - type_ = type; - data_ = data; - size_ = size; - owned_ = owned; +::Atom SelectionData::GetType() const { + return type_; +} + +const unsigned char* SelectionData::GetData() const { + return memory_ ? memory_->front() : NULL; +} + +size_t SelectionData::GetSize() const { + return memory_ ? memory_->size() : 0; } std::string SelectionData::GetText() const { if (type_ == atom_cache_.GetAtom(kUtf8String) || type_ == atom_cache_.GetAtom(kText)) { - return std::string(data_, size_); + return RefCountedMemoryToString(memory_); } else if (type_ == atom_cache_.GetAtom(kString)) { std::string result; - base::ConvertToUtf8AndNormalize(std::string(data_, size_), + base::ConvertToUtf8AndNormalize(RefCountedMemoryToString(memory_), base::kCodepageLatin1, &result); return result; @@ -177,14 +197,17 @@ string16 SelectionData::GetHtml() const { string16 markup; if (type_ == atom_cache_.GetAtom(Clipboard::kMimeTypeHTML)) { + const unsigned char* data = GetData(); + size_t size = GetSize(); + // If the data starts with 0xFEFF, i.e., Byte Order Mark, assume it is // UTF-16, otherwise assume UTF-8. - if (size_ >= 2 && - reinterpret_cast<const uint16_t*>(data_)[0] == 0xFEFF) { - markup.assign(reinterpret_cast<const uint16_t*>(data_) + 1, - (size_ / 2) - 1); + if (size >= 2 && + reinterpret_cast<const uint16_t*>(data)[0] == 0xFEFF) { + markup.assign(reinterpret_cast<const uint16_t*>(data) + 1, + (size / 2) - 1); } else { - UTF8ToUTF16(reinterpret_cast<const char*>(data_), size_, &markup); + UTF8ToUTF16(reinterpret_cast<const char*>(data), size, &markup); } // If there is a terminating NULL, drop it. @@ -199,11 +222,11 @@ string16 SelectionData::GetHtml() const { } void SelectionData::AssignTo(std::string* result) const { - result->assign(data_, size_); + *result = RefCountedMemoryToString(memory_); } void SelectionData::AssignTo(string16* result) const { - result->assign(reinterpret_cast<base::char16*>(data_), size_ / 2); + *result = RefCountedMemoryToString16(memory_); } } // namespace ui diff --git a/ui/base/x/selection_utils.h b/ui/base/x/selection_utils.h index d7abf3f..609ee9d 100644 --- a/ui/base/x/selection_utils.h +++ b/ui/base/x/selection_utils.h @@ -13,6 +13,7 @@ #include <map> #include "base/basictypes.h" +#include "base/memory/ref_counted_memory.h" #include "ui/base/clipboard/clipboard.h" #include "ui/base/ui_export.h" #include "ui/base/x/x11_atom_cache.h" @@ -36,6 +37,16 @@ UI_EXPORT void GetAtomIntersection(const std::vector< ::Atom>& one, const std::vector< ::Atom>& two, std::vector< ::Atom>* output); +// Takes the raw bytes of the string16 and copies them into |bytes|. +UI_EXPORT void AddString16ToVector(const string16& str, + std::vector<unsigned char>* bytes); + +UI_EXPORT std::string RefCountedMemoryToString( + const scoped_refptr<base::RefCountedMemory>& memory); + +UI_EXPORT string16 RefCountedMemoryToString16( + const scoped_refptr<base::RefCountedMemory>& memory); + /////////////////////////////////////////////////////////////////////////////// // Represents the selection in different data formats. Binary data passed in is @@ -43,27 +54,24 @@ UI_EXPORT void GetAtomIntersection(const std::vector< ::Atom>& one, class UI_EXPORT SelectionFormatMap { public: // Our internal data store, which we only expose through iterators. - typedef std::map< ::Atom, std::pair<char*, size_t> > InternalMap; - typedef std::map< ::Atom, std::pair<char*, size_t> >::const_iterator - const_iterator; + typedef std::map< ::Atom, scoped_refptr<base::RefCountedMemory> > InternalMap; + typedef InternalMap::const_iterator const_iterator; SelectionFormatMap(); ~SelectionFormatMap(); + // Copy and assignment deliberately open. // Adds the selection in the format |atom|. Ownership of |data| is passed to // us. - void Insert(::Atom atom, char* data, size_t size); + void Insert(::Atom atom, const scoped_refptr<base::RefCountedMemory>& item); // Returns the first of the requested_types or NULL if missing. - ui::SelectionData* GetFirstOf( + ui::SelectionData GetFirstOf( const std::vector< ::Atom>& requested_types) const; // Returns all the selected types. std::vector< ::Atom> GetTypes() const; - // Creates a copy of the selection data. - scoped_ptr<SelectionFormatMap> Clone() const; - // Pass through to STL map. Only allow non-mutation access. const_iterator begin() const { return data_.begin(); } const_iterator end() const { return data_.end(); } @@ -72,8 +80,6 @@ class UI_EXPORT SelectionFormatMap { private: InternalMap data_; - - DISALLOW_COPY_AND_ASSIGN(SelectionFormatMap); }; /////////////////////////////////////////////////////////////////////////////// @@ -83,13 +89,16 @@ class UI_EXPORT SelectionData { public: // |atom_cache| is still owned by caller. SelectionData(); + SelectionData(::Atom type, + const scoped_refptr<base::RefCountedMemory>& memory); + SelectionData(const SelectionData& rhs); ~SelectionData(); + SelectionData& operator=(const SelectionData& rhs); - ::Atom type() const { return type_; } - char* data() const { return data_; } - size_t size() const { return size_; } - - void Set(::Atom type, char* data, size_t size, bool owned); + bool IsValid() const; + ::Atom GetType() const; + const unsigned char* GetData() const; + size_t GetSize() const; // If |type_| is a string type, convert the data to UTF8 and return it. std::string GetText() const; @@ -104,13 +113,9 @@ class UI_EXPORT SelectionData { private: ::Atom type_; - char* data_; - size_t size_; - bool owned_; + scoped_refptr<base::RefCountedMemory> memory_; X11AtomCache atom_cache_; - - DISALLOW_COPY_AND_ASSIGN(SelectionData); }; } // namespace ui diff --git a/ui/base/x/x11_util.cc b/ui/base/x/x11_util.cc index 1ac4513..324cdd13 100644 --- a/ui/base/x/x11_util.cc +++ b/ui/base/x/x11_util.cc @@ -763,7 +763,7 @@ bool PropertyExists(XID window, const std::string& property_name) { bool GetRawBytesOfProperty(XID window, Atom property, - unsigned char** out_data, + scoped_refptr<base::RefCountedMemory>* out_data, size_t* out_data_bytes, size_t* out_data_items, Atom* out_type) { @@ -783,31 +783,33 @@ bool GetRawBytesOfProperty(XID window, if (prop_type == None) return false; + size_t bytes = 0; + // So even though we should theoretically have nbytes (and we can't + // pass NULL there), we need to manually calculate the byte length here + // because nbytes always returns zero. + switch (prop_format) { + case 8: + bytes = nitems; + break; + case 16: + bytes = sizeof(short) * nitems; + break; + case 32: + bytes = sizeof(long) * nitems; + break; + default: + NOTREACHED(); + break; + } + + if (out_data_bytes) + *out_data_bytes = bytes; + if (out_data) - *out_data = property_data; + *out_data = new XRefcountedMemory(property_data, bytes); else XFree(property_data); - if (out_data_bytes) { - // So even though we should theoretically have nbytes (and we can't - // pass NULL there), we need to manually calculate the byte length here - // because nbytes always returns zero. - switch (prop_format) { - case 8: - *out_data_bytes = nitems; - break; - case 16: - *out_data_bytes = sizeof(short) * nitems; - break; - case 32: - *out_data_bytes = sizeof(long) * nitems; - break; - default: - NOTREACHED(); - break; - } - } - if (out_data_items) *out_data_items = nitems; @@ -1501,6 +1503,18 @@ void InitXKeyEventForTesting(EventType type, event->xkey = key_event; } +const unsigned char* XRefcountedMemory::front() const { + return x11_data_; +} + +size_t XRefcountedMemory::size() const { + return length_; +} + +XRefcountedMemory::~XRefcountedMemory() { + XFree(x11_data_); +} + XScopedString::~XScopedString() { XFree(string_); } diff --git a/ui/base/x/x11_util.h b/ui/base/x/x11_util.h index 592e48a..c1c72ba 100644 --- a/ui/base/x/x11_util.h +++ b/ui/base/x/x11_util.h @@ -16,6 +16,7 @@ #include "base/basictypes.h" #include "base/event_types.h" +#include "base/memory/ref_counted_memory.h" #include "ui/base/events/event_constants.h" #include "ui/base/keycodes/keyboard_codes.h" #include "ui/base/ui_export.h" @@ -166,12 +167,13 @@ UI_EXPORT bool PropertyExists(XID window, const std::string& property_name); // Returns the raw bytes from a property with minimal // interpretation. |out_data| should be freed by XFree() after use. -UI_EXPORT bool GetRawBytesOfProperty(XID window, - Atom property, - unsigned char** out_data, - size_t* out_data_bytes, - size_t* out_data_items, - Atom* out_type); +UI_EXPORT bool GetRawBytesOfProperty( + XID window, + Atom property, + scoped_refptr<base::RefCountedMemory>* out_data, + size_t* out_data_bytes, + size_t* out_data_items, + Atom* out_type); // Get the value of an int, int array, atom array or string property. On // success, true is returned and the value is stored in |value|. @@ -333,6 +335,29 @@ UI_EXPORT void InitXKeyEventForTesting(EventType type, int flags, XEvent* event); +// Manages a piece of X11 allocated memory as a RefCountedMemory segment. This +// object takes ownership over the passed in memory and will free it with the +// X11 allocator when done. +class UI_EXPORT XRefcountedMemory : public base::RefCountedMemory { + public: + XRefcountedMemory(unsigned char* x11_data, size_t length) + : x11_data_(length ? x11_data : NULL), + length_(length) { + } + + // Overridden from RefCountedMemory: + virtual const unsigned char* front() const OVERRIDE; + virtual size_t size() const OVERRIDE; + + private: + virtual ~XRefcountedMemory(); + + unsigned char* x11_data_; + size_t length_; + + DISALLOW_COPY_AND_ASSIGN(XRefcountedMemory); +}; + // Keeps track of a string returned by an X function (e.g. XGetAtomName) and // makes sure it's XFree'd. class UI_EXPORT XScopedString { |