| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/base/clipboard/clipboard.h" | 5 #include "ui/base/clipboard/clipboard.h" |
| 6 | 6 |
| 7 #include <gtk/gtk.h> | 7 #include <gtk/gtk.h> |
| 8 #include <X11/extensions/Xfixes.h> | 8 #include <X11/extensions/Xfixes.h> |
| 9 #include <X11/Xatom.h> | 9 #include <X11/Xatom.h> |
| 10 #include <map> | 10 #include <map> |
| 11 #include <set> | 11 #include <set> |
| 12 #include <string> | 12 #include <string> |
| 13 #include <utility> | 13 #include <utility> |
| 14 | 14 |
| 15 #include "base/basictypes.h" |
| 15 #include "base/file_path.h" | 16 #include "base/file_path.h" |
| 16 #include "base/logging.h" | 17 #include "base/logging.h" |
| 17 #include "base/memory/singleton.h" | 18 #include "base/memory/singleton.h" |
| 18 #include "base/utf_string_conversions.h" | 19 #include "base/utf_string_conversions.h" |
| 19 #include "third_party/skia/include/core/SkBitmap.h" | 20 #include "third_party/skia/include/core/SkBitmap.h" |
| 20 #include "ui/base/clipboard/custom_data_helper.h" | 21 #include "ui/base/clipboard/custom_data_helper.h" |
| 21 #include "ui/base/gtk/gtk_signal.h" | 22 #include "ui/base/gtk/gtk_signal.h" |
| 22 #include "ui/base/x/x11_util.h" | 23 #include "ui/base/x/x11_util.h" |
| 23 #include "ui/gfx/canvas_skia.h" | 24 #include "ui/gfx/canvas_skia.h" |
| 24 #include "ui/gfx/gtk_util.h" | 25 #include "ui/gfx/gtk_util.h" |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 173 delete map; | 174 delete map; |
| 174 } | 175 } |
| 175 | 176 |
| 176 // Called on GdkPixbuf destruction; see WriteBitmap(). | 177 // Called on GdkPixbuf destruction; see WriteBitmap(). |
| 177 void GdkPixbufFree(guchar* pixels, gpointer data) { | 178 void GdkPixbufFree(guchar* pixels, gpointer data) { |
| 178 free(pixels); | 179 free(pixels); |
| 179 } | 180 } |
| 180 | 181 |
| 181 } // namespace | 182 } // namespace |
| 182 | 183 |
| 184 Clipboard::FormatType::FormatType() { |
| 185 } |
| 186 |
| 187 Clipboard::FormatType::FormatType(const std::string& format_string) |
| 188 : data_(StringToGdkAtom(format_string)) { |
| 189 } |
| 190 |
| 191 Clipboard::FormatType::FormatType(const GdkAtom& native_format) |
| 192 : data_(native_format) { |
| 193 } |
| 194 |
| 195 Clipboard::FormatType::~FormatType() { |
| 196 } |
| 197 |
| 183 Clipboard::Clipboard() : clipboard_data_(NULL) { | 198 Clipboard::Clipboard() : clipboard_data_(NULL) { |
| 184 #if !defined(USE_AURA) | |
| 185 clipboard_ = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); | 199 clipboard_ = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); |
| 186 primary_selection_ = gtk_clipboard_get(GDK_SELECTION_PRIMARY); | 200 primary_selection_ = gtk_clipboard_get(GDK_SELECTION_PRIMARY); |
| 187 #endif | |
| 188 } | 201 } |
| 189 | 202 |
| 190 Clipboard::~Clipboard() { | 203 Clipboard::~Clipboard() { |
| 191 gtk_clipboard_store(clipboard_); | 204 gtk_clipboard_store(clipboard_); |
| 192 } | 205 } |
| 193 | 206 |
| 194 void Clipboard::WriteObjects(const ObjectMap& objects) { | 207 void Clipboard::WriteObjects(const ObjectMap& objects) { |
| 195 clipboard_data_ = new TargetMap(); | 208 clipboard_data_ = new TargetMap(); |
| 196 | 209 |
| 197 for (ObjectMap::const_iterator iter = objects.begin(); | 210 for (ObjectMap::const_iterator iter = objects.begin(); |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 295 string16 url = UTF8ToUTF16(std::string(url_data, url_len) + "\n"); | 308 string16 url = UTF8ToUTF16(std::string(url_data, url_len) + "\n"); |
| 296 string16 title = UTF8ToUTF16(std::string(title_data, title_len)); | 309 string16 title = UTF8ToUTF16(std::string(title_data, title_len)); |
| 297 int data_len = 2 * (title.length() + url.length()); | 310 int data_len = 2 * (title.length() + url.length()); |
| 298 | 311 |
| 299 char* data = new char[data_len]; | 312 char* data = new char[data_len]; |
| 300 memcpy(data, url.data(), 2 * url.length()); | 313 memcpy(data, url.data(), 2 * url.length()); |
| 301 memcpy(data + 2 * url.length(), title.data(), 2 * title.length()); | 314 memcpy(data + 2 * url.length(), title.data(), 2 * title.length()); |
| 302 InsertMapping(kMimeTypeMozillaURL, data, data_len); | 315 InsertMapping(kMimeTypeMozillaURL, data, data_len); |
| 303 } | 316 } |
| 304 | 317 |
| 305 void Clipboard::WriteData(const char* format_name, size_t format_len, | 318 void Clipboard::WriteData(const FormatType& format, |
| 306 const char* data_data, size_t data_len) { | 319 const char* data_data, |
| 307 std::string format(format_name, format_len); | 320 size_t data_len) { |
| 308 // We assume that certain mapping types are only written by trusted code. | 321 // We assume that certain mapping types are only written by trusted code. |
| 309 // Therefore we must upkeep their integrity. | 322 // Therefore we must upkeep their integrity. |
| 310 if (format == kMimeTypeBitmap) | 323 if (format.data() == GetBitmapFormatType().data()) |
| 311 return; | 324 return; |
| 312 char* data = new char[data_len]; | 325 char* data = new char[data_len]; |
| 313 memcpy(data, data_data, data_len); | 326 memcpy(data, data_data, data_len); |
| 314 InsertMapping(format.c_str(), data, data_len); | 327 InsertMapping(GdkAtomToString(format.data()).c_str(), data, data_len); |
| 315 } | 328 } |
| 316 | 329 |
| 317 // We do not use gtk_clipboard_wait_is_target_available because of | 330 // We do not use gtk_clipboard_wait_is_target_available because of |
| 318 // a bug with the gtk clipboard. It caches the available targets | 331 // a bug with the gtk clipboard. It caches the available targets |
| 319 // and does not always refresh the cache when it is appropriate. | 332 // and does not always refresh the cache when it is appropriate. |
| 320 bool Clipboard::IsFormatAvailable(const Clipboard::FormatType& format, | 333 bool Clipboard::IsFormatAvailable(const Clipboard::FormatType& format, |
| 321 Clipboard::Buffer buffer) const { | 334 Clipboard::Buffer buffer) const { |
| 322 GtkClipboard* clipboard = LookupBackingClipboard(buffer); | 335 GtkClipboard* clipboard = LookupBackingClipboard(buffer); |
| 323 if (clipboard == NULL) | 336 if (clipboard == NULL) |
| 324 return false; | 337 return false; |
| 325 | 338 |
| 326 bool format_is_plain_text = GetPlainTextFormatType() == format; | 339 bool format_is_plain_text = |
| 340 GetPlainTextFormatType().data() == format.data(); |
| 327 if (format_is_plain_text) { | 341 if (format_is_plain_text) { |
| 328 // This tries a number of common text targets. | 342 // This tries a number of common text targets. |
| 329 if (gtk_clipboard_wait_is_text_available(clipboard)) | 343 if (gtk_clipboard_wait_is_text_available(clipboard)) |
| 330 return true; | 344 return true; |
| 331 } | 345 } |
| 332 | 346 |
| 333 bool retval = false; | 347 bool retval = false; |
| 334 GdkAtom* targets = NULL; | 348 GdkAtom* targets = NULL; |
| 335 GtkSelectionData* data = | 349 GtkSelectionData* data = |
| 336 gtk_clipboard_wait_for_contents(clipboard, | 350 gtk_clipboard_wait_for_contents(clipboard, |
| (...skipping 13 matching lines...) Expand all Loading... |
| 350 if (num <= 0) { | 364 if (num <= 0) { |
| 351 if (format_is_plain_text) { | 365 if (format_is_plain_text) { |
| 352 gchar* text = gtk_clipboard_wait_for_text(clipboard); | 366 gchar* text = gtk_clipboard_wait_for_text(clipboard); |
| 353 if (text) { | 367 if (text) { |
| 354 g_free(text); | 368 g_free(text); |
| 355 retval = true; | 369 retval = true; |
| 356 } | 370 } |
| 357 } | 371 } |
| 358 } | 372 } |
| 359 | 373 |
| 360 GdkAtom format_atom = StringToGdkAtom(format); | |
| 361 | |
| 362 for (int i = 0; i < num; i++) { | 374 for (int i = 0; i < num; i++) { |
| 363 if (targets[i] == format_atom) { | 375 if (targets[i] == format.data()) { |
| 364 retval = true; | 376 retval = true; |
| 365 break; | 377 break; |
| 366 } | 378 } |
| 367 } | 379 } |
| 368 | 380 |
| 369 g_free(targets); | 381 g_free(targets); |
| 370 gtk_selection_data_free(data); | 382 gtk_selection_data_free(data); |
| 371 | 383 |
| 372 return retval; | 384 return retval; |
| 373 } | 385 } |
| 374 | 386 |
| 375 bool Clipboard::IsFormatAvailableByString(const std::string& format, | |
| 376 Clipboard::Buffer buffer) const { | |
| 377 return IsFormatAvailable(format, buffer); | |
| 378 } | |
| 379 | |
| 380 void Clipboard::ReadAvailableTypes(Clipboard::Buffer buffer, | 387 void Clipboard::ReadAvailableTypes(Clipboard::Buffer buffer, |
| 381 std::vector<string16>* types, | 388 std::vector<string16>* types, |
| 382 bool* contains_filenames) const { | 389 bool* contains_filenames) const { |
| 383 if (!types || !contains_filenames) { | 390 if (!types || !contains_filenames) { |
| 384 NOTREACHED(); | 391 NOTREACHED(); |
| 385 return; | 392 return; |
| 386 } | 393 } |
| 387 | 394 |
| 388 types->clear(); | 395 types->clear(); |
| 389 if (IsFormatAvailable(GetPlainTextFormatType(), buffer)) | 396 if (IsFormatAvailable(GetPlainTextFormatType(), buffer)) |
| 390 types->push_back(UTF8ToUTF16(kMimeTypeText)); | 397 types->push_back(UTF8ToUTF16(kMimeTypeText)); |
| 391 if (IsFormatAvailable(GetHtmlFormatType(), buffer)) | 398 if (IsFormatAvailable(GetHtmlFormatType(), buffer)) |
| 392 types->push_back(UTF8ToUTF16(kMimeTypeHTML)); | 399 types->push_back(UTF8ToUTF16(kMimeTypeHTML)); |
| 393 if (IsFormatAvailable(GetBitmapFormatType(), buffer)) | 400 if (IsFormatAvailable(GetBitmapFormatType(), buffer)) |
| 394 types->push_back(UTF8ToUTF16(kMimeTypePNG)); | 401 types->push_back(UTF8ToUTF16(kMimeTypePNG)); |
| 395 *contains_filenames = false; | 402 *contains_filenames = false; |
| 396 | 403 |
| 397 GtkClipboard* clipboard = LookupBackingClipboard(buffer); | 404 GtkClipboard* clipboard = LookupBackingClipboard(buffer); |
| 398 if (!clipboard) | 405 if (!clipboard) |
| 399 return; | 406 return; |
| 400 | 407 |
| 401 GtkSelectionData* data = gtk_clipboard_wait_for_contents( | 408 GtkSelectionData* data = gtk_clipboard_wait_for_contents( |
| 402 clipboard, StringToGdkAtom(GetWebCustomDataFormatType())); | 409 clipboard, GetWebCustomDataFormatType().data()); |
| 403 if (!data) | 410 if (!data) |
| 404 return; | 411 return; |
| 405 ReadCustomDataTypes(data->data, data->length, types); | 412 ReadCustomDataTypes(data->data, data->length, types); |
| 406 gtk_selection_data_free(data); | 413 gtk_selection_data_free(data); |
| 407 } | 414 } |
| 408 | 415 |
| 409 | 416 |
| 410 void Clipboard::ReadText(Clipboard::Buffer buffer, string16* result) const { | 417 void Clipboard::ReadText(Clipboard::Buffer buffer, string16* result) const { |
| 411 GtkClipboard* clipboard = LookupBackingClipboard(buffer); | 418 GtkClipboard* clipboard = LookupBackingClipboard(buffer); |
| 412 if (clipboard == NULL) | 419 if (clipboard == NULL) |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 451 markup->clear(); | 458 markup->clear(); |
| 452 if (src_url) | 459 if (src_url) |
| 453 src_url->clear(); | 460 src_url->clear(); |
| 454 *fragment_start = 0; | 461 *fragment_start = 0; |
| 455 *fragment_end = 0; | 462 *fragment_end = 0; |
| 456 | 463 |
| 457 GtkClipboard* clipboard = LookupBackingClipboard(buffer); | 464 GtkClipboard* clipboard = LookupBackingClipboard(buffer); |
| 458 if (clipboard == NULL) | 465 if (clipboard == NULL) |
| 459 return; | 466 return; |
| 460 GtkSelectionData* data = gtk_clipboard_wait_for_contents(clipboard, | 467 GtkSelectionData* data = gtk_clipboard_wait_for_contents(clipboard, |
| 461 StringToGdkAtom(GetHtmlFormatType())); | 468 GetHtmlFormatType().data()); |
| 462 | 469 |
| 463 if (!data) | 470 if (!data) |
| 464 return; | 471 return; |
| 465 | 472 |
| 466 // If the data starts with 0xFEFF, i.e., Byte Order Mark, assume it is | 473 // If the data starts with 0xFEFF, i.e., Byte Order Mark, assume it is |
| 467 // UTF-16, otherwise assume UTF-8. | 474 // UTF-16, otherwise assume UTF-8. |
| 468 if (data->length >= 2 && | 475 if (data->length >= 2 && |
| 469 reinterpret_cast<uint16_t*>(data->data)[0] == 0xFEFF) { | 476 reinterpret_cast<uint16_t*>(data->data)[0] == 0xFEFF) { |
| 470 markup->assign(reinterpret_cast<uint16_t*>(data->data) + 1, | 477 markup->assign(reinterpret_cast<uint16_t*>(data->data) + 1, |
| 471 (data->length / 2) - 1); | 478 (data->length / 2) - 1); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 503 } | 510 } |
| 504 | 511 |
| 505 void Clipboard::ReadCustomData(Buffer buffer, | 512 void Clipboard::ReadCustomData(Buffer buffer, |
| 506 const string16& type, | 513 const string16& type, |
| 507 string16* result) const { | 514 string16* result) const { |
| 508 GtkClipboard* clipboard = LookupBackingClipboard(buffer); | 515 GtkClipboard* clipboard = LookupBackingClipboard(buffer); |
| 509 if (!clipboard) | 516 if (!clipboard) |
| 510 return; | 517 return; |
| 511 | 518 |
| 512 GtkSelectionData* data = gtk_clipboard_wait_for_contents( | 519 GtkSelectionData* data = gtk_clipboard_wait_for_contents( |
| 513 clipboard, StringToGdkAtom(GetWebCustomDataFormatType())); | 520 clipboard, GetWebCustomDataFormatType().data()); |
| 514 if (!data) | 521 if (!data) |
| 515 return; | 522 return; |
| 516 ReadCustomDataForType(data->data, data->length, type, result); | 523 ReadCustomDataForType(data->data, data->length, type, result); |
| 517 gtk_selection_data_free(data); | 524 gtk_selection_data_free(data); |
| 518 } | 525 } |
| 519 | 526 |
| 520 void Clipboard::ReadBookmark(string16* title, std::string* url) const { | 527 void Clipboard::ReadBookmark(string16* title, std::string* url) const { |
| 521 // TODO(estade): implement this. | 528 // TODO(estade): implement this. |
| 522 NOTIMPLEMENTED(); | 529 NOTIMPLEMENTED(); |
| 523 } | 530 } |
| 524 | 531 |
| 525 void Clipboard::ReadData(const std::string& format, std::string* result) const { | 532 void Clipboard::ReadData(const FormatType& format, std::string* result) const { |
| 526 GtkSelectionData* data = | 533 GtkSelectionData* data = |
| 527 gtk_clipboard_wait_for_contents(clipboard_, StringToGdkAtom(format)); | 534 gtk_clipboard_wait_for_contents(clipboard_, format.data()); |
| 528 if (!data) | 535 if (!data) |
| 529 return; | 536 return; |
| 530 result->assign(reinterpret_cast<char*>(data->data), data->length); | 537 result->assign(reinterpret_cast<char*>(data->data), data->length); |
| 531 gtk_selection_data_free(data); | 538 gtk_selection_data_free(data); |
| 532 } | 539 } |
| 533 | 540 |
| 534 uint64 Clipboard::GetSequenceNumber(Buffer buffer) { | 541 uint64 Clipboard::GetSequenceNumber(Buffer buffer) { |
| 535 if (buffer == BUFFER_STANDARD) | 542 if (buffer == BUFFER_STANDARD) |
| 536 return SelectionChangeObserver::GetInstance()->clipboard_sequence_number(); | 543 return SelectionChangeObserver::GetInstance()->clipboard_sequence_number(); |
| 537 else | 544 else |
| 538 return SelectionChangeObserver::GetInstance()->primary_sequence_number(); | 545 return SelectionChangeObserver::GetInstance()->primary_sequence_number(); |
| 539 } | 546 } |
| 540 | 547 |
| 541 // static | 548 //static |
| 542 Clipboard::FormatType Clipboard::GetPlainTextFormatType() { | 549 Clipboard::FormatType Clipboard::RegisterFormatType( |
| 543 return GdkAtomToString(GDK_TARGET_STRING); | 550 const std::string& format_string) { |
| 551 return StringToFormatType(format_string); |
| 544 } | 552 } |
| 545 | 553 |
| 546 // static | 554 // static |
| 547 Clipboard::FormatType Clipboard::GetPlainTextWFormatType() { | 555 std::string Clipboard::FormatTypeToString(const FormatType& type) { |
| 556 return GdkAtomToString(type.data()); |
| 557 } |
| 558 |
| 559 // static |
| 560 Clipboard::FormatType Clipboard::StringToFormatType( |
| 561 const std::string& format_string) { |
| 562 return FormatType(StringToGdkAtom(format_string)); |
| 563 } |
| 564 |
| 565 // static |
| 566 const Clipboard::FormatType& Clipboard::GetPlainTextFormatType() { |
| 567 CR_DEFINE_STATIC_LOCAL( |
| 568 FormatType, type, (GDK_TARGET_STRING)); |
| 569 return type; |
| 570 } |
| 571 |
| 572 // static |
| 573 const Clipboard::FormatType& Clipboard::GetPlainTextWFormatType() { |
| 548 return GetPlainTextFormatType(); | 574 return GetPlainTextFormatType(); |
| 549 } | 575 } |
| 550 | 576 |
| 551 // static | 577 // static |
| 552 Clipboard::FormatType Clipboard::GetHtmlFormatType() { | 578 const Clipboard::FormatType& Clipboard::GetHtmlFormatType() { |
| 553 return std::string(kMimeTypeHTML); | 579 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeHTML)); |
| 580 return type; |
| 554 } | 581 } |
| 555 | 582 |
| 556 // static | 583 // static |
| 557 Clipboard::FormatType Clipboard::GetBitmapFormatType() { | 584 const Clipboard::FormatType& Clipboard::GetBitmapFormatType() { |
| 558 return std::string(kMimeTypeBitmap); | 585 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeBitmap)); |
| 586 return type; |
| 559 } | 587 } |
| 560 | 588 |
| 561 // static | 589 // static |
| 562 Clipboard::FormatType Clipboard::GetWebKitSmartPasteFormatType() { | 590 const Clipboard::FormatType& Clipboard::GetWebKitSmartPasteFormatType() { |
| 563 return std::string(kMimeTypeWebkitSmartPaste); | 591 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebkitSmartPaste)); |
| 592 return type; |
| 564 } | 593 } |
| 565 | 594 |
| 566 // static | 595 // static |
| 567 Clipboard::FormatType Clipboard::GetWebCustomDataFormatType() { | 596 const Clipboard::FormatType& Clipboard::GetWebCustomDataFormatType() { |
| 568 return std::string(kMimeTypeWebCustomData); | 597 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebCustomData)); |
| 598 return type; |
| 569 } | 599 } |
| 570 | 600 |
| 571 void Clipboard::InsertMapping(const char* key, | 601 void Clipboard::InsertMapping(const char* key, |
| 572 char* data, | 602 char* data, |
| 573 size_t data_len) { | 603 size_t data_len) { |
| 574 DCHECK(clipboard_data_->find(key) == clipboard_data_->end()); | 604 DCHECK(clipboard_data_->find(key) == clipboard_data_->end()); |
| 575 (*clipboard_data_)[key] = std::make_pair(data, data_len); | 605 (*clipboard_data_)[key] = std::make_pair(data, data_len); |
| 576 } | 606 } |
| 577 | 607 |
| 578 GtkClipboard* Clipboard::LookupBackingClipboard(Buffer clipboard) const { | 608 GtkClipboard* Clipboard::LookupBackingClipboard(Buffer clipboard) const { |
| 579 switch (clipboard) { | 609 switch (clipboard) { |
| 580 case BUFFER_STANDARD: | 610 case BUFFER_STANDARD: |
| 581 return clipboard_; | 611 return clipboard_; |
| 582 case BUFFER_SELECTION: | 612 case BUFFER_SELECTION: |
| 583 return primary_selection_; | 613 return primary_selection_; |
| 584 default: | 614 default: |
| 585 NOTREACHED(); | 615 NOTREACHED(); |
| 586 return NULL; | 616 return NULL; |
| 587 } | 617 } |
| 588 } | 618 } |
| 589 | 619 |
| 590 } // namespace ui | 620 } // namespace ui |
| OLD | NEW |