| 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 |
| 198 std::string Clipboard::FormatType::Serialize() const { |
| 199 return GdkAtomToString(data_); |
| 200 } |
| 201 |
| 202 // static |
| 203 Clipboard::FormatType Clipboard::FormatType::Deserialize( |
| 204 const std::string& serialization) { |
| 205 return FormatType(serialization); |
| 206 } |
| 207 |
| 208 bool Clipboard::FormatType::Equals(const FormatType& other) const { |
| 209 return data_ == other.data_; |
| 210 } |
| 211 |
| 183 Clipboard::Clipboard() : clipboard_data_(NULL) { | 212 Clipboard::Clipboard() : clipboard_data_(NULL) { |
| 184 #if !defined(USE_AURA) | |
| 185 clipboard_ = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); | 213 clipboard_ = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD); |
| 186 primary_selection_ = gtk_clipboard_get(GDK_SELECTION_PRIMARY); | 214 primary_selection_ = gtk_clipboard_get(GDK_SELECTION_PRIMARY); |
| 187 #endif | |
| 188 } | 215 } |
| 189 | 216 |
| 190 Clipboard::~Clipboard() { | 217 Clipboard::~Clipboard() { |
| 191 gtk_clipboard_store(clipboard_); | 218 gtk_clipboard_store(clipboard_); |
| 192 } | 219 } |
| 193 | 220 |
| 194 void Clipboard::WriteObjects(const ObjectMap& objects) { | 221 void Clipboard::WriteObjects(const ObjectMap& objects) { |
| 195 clipboard_data_ = new TargetMap(); | 222 clipboard_data_ = new TargetMap(); |
| 196 | 223 |
| 197 for (ObjectMap::const_iterator iter = objects.begin(); | 224 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"); | 322 string16 url = UTF8ToUTF16(std::string(url_data, url_len) + "\n"); |
| 296 string16 title = UTF8ToUTF16(std::string(title_data, title_len)); | 323 string16 title = UTF8ToUTF16(std::string(title_data, title_len)); |
| 297 int data_len = 2 * (title.length() + url.length()); | 324 int data_len = 2 * (title.length() + url.length()); |
| 298 | 325 |
| 299 char* data = new char[data_len]; | 326 char* data = new char[data_len]; |
| 300 memcpy(data, url.data(), 2 * url.length()); | 327 memcpy(data, url.data(), 2 * url.length()); |
| 301 memcpy(data + 2 * url.length(), title.data(), 2 * title.length()); | 328 memcpy(data + 2 * url.length(), title.data(), 2 * title.length()); |
| 302 InsertMapping(kMimeTypeMozillaURL, data, data_len); | 329 InsertMapping(kMimeTypeMozillaURL, data, data_len); |
| 303 } | 330 } |
| 304 | 331 |
| 305 void Clipboard::WriteData(const char* format_name, size_t format_len, | 332 void Clipboard::WriteData(const FormatType& format, |
| 306 const char* data_data, size_t data_len) { | 333 const char* data_data, |
| 307 std::string format(format_name, format_len); | 334 size_t data_len) { |
| 308 // We assume that certain mapping types are only written by trusted code. | 335 // We assume that certain mapping types are only written by trusted code. |
| 309 // Therefore we must upkeep their integrity. | 336 // Therefore we must upkeep their integrity. |
| 310 if (format == kMimeTypeBitmap) | 337 if (format.Equals(GetBitmapFormatType())) |
| 311 return; | 338 return; |
| 312 char* data = new char[data_len]; | 339 char* data = new char[data_len]; |
| 313 memcpy(data, data_data, data_len); | 340 memcpy(data, data_data, data_len); |
| 314 InsertMapping(format.c_str(), data, data_len); | 341 // TODO(dcheng): Maybe this map should use GdkAtoms... |
| 342 InsertMapping(GdkAtomToString(format.ToGdkAtom()).c_str(), data, data_len); |
| 315 } | 343 } |
| 316 | 344 |
| 317 // We do not use gtk_clipboard_wait_is_target_available because of | 345 // We do not use gtk_clipboard_wait_is_target_available because of |
| 318 // a bug with the gtk clipboard. It caches the available targets | 346 // a bug with the gtk clipboard. It caches the available targets |
| 319 // and does not always refresh the cache when it is appropriate. | 347 // and does not always refresh the cache when it is appropriate. |
| 320 bool Clipboard::IsFormatAvailable(const Clipboard::FormatType& format, | 348 bool Clipboard::IsFormatAvailable(const Clipboard::FormatType& format, |
| 321 Clipboard::Buffer buffer) const { | 349 Clipboard::Buffer buffer) const { |
| 322 GtkClipboard* clipboard = LookupBackingClipboard(buffer); | 350 GtkClipboard* clipboard = LookupBackingClipboard(buffer); |
| 323 if (clipboard == NULL) | 351 if (clipboard == NULL) |
| 324 return false; | 352 return false; |
| 325 | 353 |
| 326 bool format_is_plain_text = GetPlainTextFormatType() == format; | 354 bool format_is_plain_text = GetPlainTextFormatType().Equals(format); |
| 327 if (format_is_plain_text) { | 355 if (format_is_plain_text) { |
| 328 // This tries a number of common text targets. | 356 // This tries a number of common text targets. |
| 329 if (gtk_clipboard_wait_is_text_available(clipboard)) | 357 if (gtk_clipboard_wait_is_text_available(clipboard)) |
| 330 return true; | 358 return true; |
| 331 } | 359 } |
| 332 | 360 |
| 333 bool retval = false; | 361 bool retval = false; |
| 334 GdkAtom* targets = NULL; | 362 GdkAtom* targets = NULL; |
| 335 GtkSelectionData* data = | 363 GtkSelectionData* data = |
| 336 gtk_clipboard_wait_for_contents(clipboard, | 364 gtk_clipboard_wait_for_contents(clipboard, |
| (...skipping 13 matching lines...) Expand all Loading... |
| 350 if (num <= 0) { | 378 if (num <= 0) { |
| 351 if (format_is_plain_text) { | 379 if (format_is_plain_text) { |
| 352 gchar* text = gtk_clipboard_wait_for_text(clipboard); | 380 gchar* text = gtk_clipboard_wait_for_text(clipboard); |
| 353 if (text) { | 381 if (text) { |
| 354 g_free(text); | 382 g_free(text); |
| 355 retval = true; | 383 retval = true; |
| 356 } | 384 } |
| 357 } | 385 } |
| 358 } | 386 } |
| 359 | 387 |
| 360 GdkAtom format_atom = StringToGdkAtom(format); | |
| 361 | |
| 362 for (int i = 0; i < num; i++) { | 388 for (int i = 0; i < num; i++) { |
| 363 if (targets[i] == format_atom) { | 389 if (targets[i] == format.ToGdkAtom()) { |
| 364 retval = true; | 390 retval = true; |
| 365 break; | 391 break; |
| 366 } | 392 } |
| 367 } | 393 } |
| 368 | 394 |
| 369 g_free(targets); | 395 g_free(targets); |
| 370 gtk_selection_data_free(data); | 396 gtk_selection_data_free(data); |
| 371 | 397 |
| 372 return retval; | 398 return retval; |
| 373 } | 399 } |
| 374 | 400 |
| 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, | 401 void Clipboard::ReadAvailableTypes(Clipboard::Buffer buffer, |
| 381 std::vector<string16>* types, | 402 std::vector<string16>* types, |
| 382 bool* contains_filenames) const { | 403 bool* contains_filenames) const { |
| 383 if (!types || !contains_filenames) { | 404 if (!types || !contains_filenames) { |
| 384 NOTREACHED(); | 405 NOTREACHED(); |
| 385 return; | 406 return; |
| 386 } | 407 } |
| 387 | 408 |
| 388 types->clear(); | 409 types->clear(); |
| 389 if (IsFormatAvailable(GetPlainTextFormatType(), buffer)) | 410 if (IsFormatAvailable(GetPlainTextFormatType(), buffer)) |
| 390 types->push_back(UTF8ToUTF16(kMimeTypeText)); | 411 types->push_back(UTF8ToUTF16(kMimeTypeText)); |
| 391 if (IsFormatAvailable(GetHtmlFormatType(), buffer)) | 412 if (IsFormatAvailable(GetHtmlFormatType(), buffer)) |
| 392 types->push_back(UTF8ToUTF16(kMimeTypeHTML)); | 413 types->push_back(UTF8ToUTF16(kMimeTypeHTML)); |
| 393 if (IsFormatAvailable(GetBitmapFormatType(), buffer)) | 414 if (IsFormatAvailable(GetBitmapFormatType(), buffer)) |
| 394 types->push_back(UTF8ToUTF16(kMimeTypePNG)); | 415 types->push_back(UTF8ToUTF16(kMimeTypePNG)); |
| 395 *contains_filenames = false; | 416 *contains_filenames = false; |
| 396 | 417 |
| 397 GtkClipboard* clipboard = LookupBackingClipboard(buffer); | 418 GtkClipboard* clipboard = LookupBackingClipboard(buffer); |
| 398 if (!clipboard) | 419 if (!clipboard) |
| 399 return; | 420 return; |
| 400 | 421 |
| 401 GtkSelectionData* data = gtk_clipboard_wait_for_contents( | 422 GtkSelectionData* data = gtk_clipboard_wait_for_contents( |
| 402 clipboard, StringToGdkAtom(GetWebCustomDataFormatType())); | 423 clipboard, GetWebCustomDataFormatType().ToGdkAtom()); |
| 403 if (!data) | 424 if (!data) |
| 404 return; | 425 return; |
| 405 ReadCustomDataTypes(data->data, data->length, types); | 426 ReadCustomDataTypes(data->data, data->length, types); |
| 406 gtk_selection_data_free(data); | 427 gtk_selection_data_free(data); |
| 407 } | 428 } |
| 408 | 429 |
| 409 | 430 |
| 410 void Clipboard::ReadText(Clipboard::Buffer buffer, string16* result) const { | 431 void Clipboard::ReadText(Clipboard::Buffer buffer, string16* result) const { |
| 411 GtkClipboard* clipboard = LookupBackingClipboard(buffer); | 432 GtkClipboard* clipboard = LookupBackingClipboard(buffer); |
| 412 if (clipboard == NULL) | 433 if (clipboard == NULL) |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 451 markup->clear(); | 472 markup->clear(); |
| 452 if (src_url) | 473 if (src_url) |
| 453 src_url->clear(); | 474 src_url->clear(); |
| 454 *fragment_start = 0; | 475 *fragment_start = 0; |
| 455 *fragment_end = 0; | 476 *fragment_end = 0; |
| 456 | 477 |
| 457 GtkClipboard* clipboard = LookupBackingClipboard(buffer); | 478 GtkClipboard* clipboard = LookupBackingClipboard(buffer); |
| 458 if (clipboard == NULL) | 479 if (clipboard == NULL) |
| 459 return; | 480 return; |
| 460 GtkSelectionData* data = gtk_clipboard_wait_for_contents(clipboard, | 481 GtkSelectionData* data = gtk_clipboard_wait_for_contents(clipboard, |
| 461 StringToGdkAtom(GetHtmlFormatType())); | 482 GetHtmlFormatType().ToGdkAtom()); |
| 462 | 483 |
| 463 if (!data) | 484 if (!data) |
| 464 return; | 485 return; |
| 465 | 486 |
| 466 // If the data starts with 0xFEFF, i.e., Byte Order Mark, assume it is | 487 // If the data starts with 0xFEFF, i.e., Byte Order Mark, assume it is |
| 467 // UTF-16, otherwise assume UTF-8. | 488 // UTF-16, otherwise assume UTF-8. |
| 468 if (data->length >= 2 && | 489 if (data->length >= 2 && |
| 469 reinterpret_cast<uint16_t*>(data->data)[0] == 0xFEFF) { | 490 reinterpret_cast<uint16_t*>(data->data)[0] == 0xFEFF) { |
| 470 markup->assign(reinterpret_cast<uint16_t*>(data->data) + 1, | 491 markup->assign(reinterpret_cast<uint16_t*>(data->data) + 1, |
| 471 (data->length / 2) - 1); | 492 (data->length / 2) - 1); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 503 } | 524 } |
| 504 | 525 |
| 505 void Clipboard::ReadCustomData(Buffer buffer, | 526 void Clipboard::ReadCustomData(Buffer buffer, |
| 506 const string16& type, | 527 const string16& type, |
| 507 string16* result) const { | 528 string16* result) const { |
| 508 GtkClipboard* clipboard = LookupBackingClipboard(buffer); | 529 GtkClipboard* clipboard = LookupBackingClipboard(buffer); |
| 509 if (!clipboard) | 530 if (!clipboard) |
| 510 return; | 531 return; |
| 511 | 532 |
| 512 GtkSelectionData* data = gtk_clipboard_wait_for_contents( | 533 GtkSelectionData* data = gtk_clipboard_wait_for_contents( |
| 513 clipboard, StringToGdkAtom(GetWebCustomDataFormatType())); | 534 clipboard, GetWebCustomDataFormatType().ToGdkAtom()); |
| 514 if (!data) | 535 if (!data) |
| 515 return; | 536 return; |
| 516 ReadCustomDataForType(data->data, data->length, type, result); | 537 ReadCustomDataForType(data->data, data->length, type, result); |
| 517 gtk_selection_data_free(data); | 538 gtk_selection_data_free(data); |
| 518 } | 539 } |
| 519 | 540 |
| 520 void Clipboard::ReadBookmark(string16* title, std::string* url) const { | 541 void Clipboard::ReadBookmark(string16* title, std::string* url) const { |
| 521 // TODO(estade): implement this. | 542 // TODO(estade): implement this. |
| 522 NOTIMPLEMENTED(); | 543 NOTIMPLEMENTED(); |
| 523 } | 544 } |
| 524 | 545 |
| 525 void Clipboard::ReadData(const std::string& format, std::string* result) const { | 546 void Clipboard::ReadData(const FormatType& format, std::string* result) const { |
| 526 GtkSelectionData* data = | 547 GtkSelectionData* data = |
| 527 gtk_clipboard_wait_for_contents(clipboard_, StringToGdkAtom(format)); | 548 gtk_clipboard_wait_for_contents(clipboard_, format.ToGdkAtom()); |
| 528 if (!data) | 549 if (!data) |
| 529 return; | 550 return; |
| 530 result->assign(reinterpret_cast<char*>(data->data), data->length); | 551 result->assign(reinterpret_cast<char*>(data->data), data->length); |
| 531 gtk_selection_data_free(data); | 552 gtk_selection_data_free(data); |
| 532 } | 553 } |
| 533 | 554 |
| 534 uint64 Clipboard::GetSequenceNumber(Buffer buffer) { | 555 uint64 Clipboard::GetSequenceNumber(Buffer buffer) { |
| 535 if (buffer == BUFFER_STANDARD) | 556 if (buffer == BUFFER_STANDARD) |
| 536 return SelectionChangeObserver::GetInstance()->clipboard_sequence_number(); | 557 return SelectionChangeObserver::GetInstance()->clipboard_sequence_number(); |
| 537 else | 558 else |
| 538 return SelectionChangeObserver::GetInstance()->primary_sequence_number(); | 559 return SelectionChangeObserver::GetInstance()->primary_sequence_number(); |
| 539 } | 560 } |
| 540 | 561 |
| 541 // static | 562 //static |
| 542 Clipboard::FormatType Clipboard::GetPlainTextFormatType() { | 563 Clipboard::FormatType Clipboard::GetFormatType( |
| 543 return GdkAtomToString(GDK_TARGET_STRING); | 564 const std::string& format_string) { |
| 565 return FormatType::Deserialize(format_string); |
| 544 } | 566 } |
| 545 | 567 |
| 546 // static | 568 // static |
| 547 Clipboard::FormatType Clipboard::GetPlainTextWFormatType() { | 569 const Clipboard::FormatType& Clipboard::GetPlainTextFormatType() { |
| 570 CR_DEFINE_STATIC_LOCAL( |
| 571 FormatType, type, (GDK_TARGET_STRING)); |
| 572 return type; |
| 573 } |
| 574 |
| 575 // static |
| 576 const Clipboard::FormatType& Clipboard::GetPlainTextWFormatType() { |
| 548 return GetPlainTextFormatType(); | 577 return GetPlainTextFormatType(); |
| 549 } | 578 } |
| 550 | 579 |
| 551 // static | 580 // static |
| 552 Clipboard::FormatType Clipboard::GetHtmlFormatType() { | 581 const Clipboard::FormatType& Clipboard::GetHtmlFormatType() { |
| 553 return std::string(kMimeTypeHTML); | 582 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeHTML)); |
| 583 return type; |
| 554 } | 584 } |
| 555 | 585 |
| 556 // static | 586 // static |
| 557 Clipboard::FormatType Clipboard::GetBitmapFormatType() { | 587 const Clipboard::FormatType& Clipboard::GetBitmapFormatType() { |
| 558 return std::string(kMimeTypeBitmap); | 588 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeBitmap)); |
| 589 return type; |
| 559 } | 590 } |
| 560 | 591 |
| 561 // static | 592 // static |
| 562 Clipboard::FormatType Clipboard::GetWebKitSmartPasteFormatType() { | 593 const Clipboard::FormatType& Clipboard::GetWebKitSmartPasteFormatType() { |
| 563 return std::string(kMimeTypeWebkitSmartPaste); | 594 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebkitSmartPaste)); |
| 595 return type; |
| 564 } | 596 } |
| 565 | 597 |
| 566 // static | 598 // static |
| 567 Clipboard::FormatType Clipboard::GetWebCustomDataFormatType() { | 599 const Clipboard::FormatType& Clipboard::GetWebCustomDataFormatType() { |
| 568 return std::string(kMimeTypeWebCustomData); | 600 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebCustomData)); |
| 601 return type; |
| 569 } | 602 } |
| 570 | 603 |
| 571 void Clipboard::InsertMapping(const char* key, | 604 void Clipboard::InsertMapping(const char* key, |
| 572 char* data, | 605 char* data, |
| 573 size_t data_len) { | 606 size_t data_len) { |
| 574 DCHECK(clipboard_data_->find(key) == clipboard_data_->end()); | 607 DCHECK(clipboard_data_->find(key) == clipboard_data_->end()); |
| 575 (*clipboard_data_)[key] = std::make_pair(data, data_len); | 608 (*clipboard_data_)[key] = std::make_pair(data, data_len); |
| 576 } | 609 } |
| 577 | 610 |
| 578 GtkClipboard* Clipboard::LookupBackingClipboard(Buffer clipboard) const { | 611 GtkClipboard* Clipboard::LookupBackingClipboard(Buffer clipboard) const { |
| 579 switch (clipboard) { | 612 switch (clipboard) { |
| 580 case BUFFER_STANDARD: | 613 case BUFFER_STANDARD: |
| 581 return clipboard_; | 614 return clipboard_; |
| 582 case BUFFER_SELECTION: | 615 case BUFFER_SELECTION: |
| 583 return primary_selection_; | 616 return primary_selection_; |
| 584 default: | 617 default: |
| 585 NOTREACHED(); | 618 NOTREACHED(); |
| 586 return NULL; | 619 return NULL; |
| 587 } | 620 } |
| 588 } | 621 } |
| 589 | 622 |
| 590 } // namespace ui | 623 } // namespace ui |
| OLD | NEW |