| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "content/browser/renderer_host/sandbox_ipc_linux.h" | 5 #include "content/browser/renderer_host/sandbox_ipc_linux.h" |
| 6 | 6 |
| 7 #include <fcntl.h> | 7 #include <fcntl.h> |
| 8 #include <fontconfig/fontconfig.h> | |
| 9 #include <sys/poll.h> | 8 #include <sys/poll.h> |
| 10 #include <sys/socket.h> | 9 #include <sys/socket.h> |
| 11 #include <sys/stat.h> | 10 #include <sys/stat.h> |
| 12 | 11 |
| 13 #include "base/command_line.h" | 12 #include "base/command_line.h" |
| 14 #include "base/files/scoped_file.h" | 13 #include "base/files/scoped_file.h" |
| 15 #include "base/linux_util.h" | 14 #include "base/linux_util.h" |
| 16 #include "base/memory/scoped_vector.h" | 15 #include "base/memory/scoped_vector.h" |
| 17 #include "base/memory/shared_memory.h" | 16 #include "base/memory/shared_memory.h" |
| 18 #include "base/posix/eintr_wrapper.h" | 17 #include "base/posix/eintr_wrapper.h" |
| 19 #include "base/posix/unix_domain_socket_linux.h" | 18 #include "base/posix/unix_domain_socket_linux.h" |
| 20 #include "base/process/launch.h" | 19 #include "base/process/launch.h" |
| 21 #include "base/strings/string_number_conversions.h" | 20 #include "base/strings/string_number_conversions.h" |
| 21 #include "content/browser/renderer_host/font_utils_linux.h" |
| 22 #include "content/common/font_config_ipc_linux.h" | 22 #include "content/common/font_config_ipc_linux.h" |
| 23 #include "content/common/sandbox_linux/sandbox_linux.h" | 23 #include "content/common/sandbox_linux/sandbox_linux.h" |
| 24 #include "content/common/set_process_title.h" | 24 #include "content/common/set_process_title.h" |
| 25 #include "content/public/common/content_switches.h" | 25 #include "content/public/common/content_switches.h" |
| 26 #include "ppapi/c/trusted/ppb_browser_font_trusted.h" | 26 #include "ppapi/c/trusted/ppb_browser_font_trusted.h" |
| 27 #include "third_party/WebKit/public/platform/linux/WebFontInfo.h" | 27 #include "third_party/WebKit/public/platform/linux/WebFontInfo.h" |
| 28 #include "third_party/WebKit/public/web/WebKit.h" | 28 #include "third_party/WebKit/public/web/WebKit.h" |
| 29 #include "third_party/npapi/bindings/npapi_extensions.h" | 29 #include "third_party/npapi/bindings/npapi_extensions.h" |
| 30 #include "third_party/skia/include/ports/SkFontConfigInterface.h" | 30 #include "third_party/skia/include/ports/SkFontConfigInterface.h" |
| 31 #include "ui/gfx/font_render_params_linux.h" | 31 #include "ui/gfx/font_render_params_linux.h" |
| 32 | 32 |
| 33 using blink::WebCString; | 33 using blink::WebCString; |
| 34 using blink::WebFontInfo; | 34 using blink::WebFontInfo; |
| 35 using blink::WebUChar; | 35 using blink::WebUChar; |
| 36 using blink::WebUChar32; | 36 using blink::WebUChar32; |
| 37 | 37 |
| 38 namespace { | |
| 39 | |
| 40 // MSCharSetToFontconfig translates a Microsoft charset identifier to a | |
| 41 // fontconfig language set by appending to |langset|. | |
| 42 // Returns true if |langset| is Latin/Greek/Cyrillic. | |
| 43 bool MSCharSetToFontconfig(FcLangSet* langset, unsigned fdwCharSet) { | |
| 44 // We have need to translate raw fdwCharSet values into terms that | |
| 45 // fontconfig can understand. (See the description of fdwCharSet in the MSDN | |
| 46 // documentation for CreateFont: | |
| 47 // http://msdn.microsoft.com/en-us/library/dd183499(VS.85).aspx ) | |
| 48 // | |
| 49 // Although the argument is /called/ 'charset', the actual values conflate | |
| 50 // character sets (which are sets of Unicode code points) and character | |
| 51 // encodings (which are algorithms for turning a series of bits into a | |
| 52 // series of code points.) Sometimes the values will name a language, | |
| 53 // sometimes they'll name an encoding. In the latter case I'm assuming that | |
| 54 // they mean the set of code points in the domain of that encoding. | |
| 55 // | |
| 56 // fontconfig deals with ISO 639-1 language codes: | |
| 57 // http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes | |
| 58 // | |
| 59 // So, for each of the documented fdwCharSet values I've had to take a | |
| 60 // guess at the set of ISO 639-1 languages intended. | |
| 61 | |
| 62 bool is_lgc = false; | |
| 63 switch (fdwCharSet) { | |
| 64 case NPCharsetAnsi: | |
| 65 // These values I don't really know what to do with, so I'm going to map | |
| 66 // them to English also. | |
| 67 case NPCharsetDefault: | |
| 68 case NPCharsetMac: | |
| 69 case NPCharsetOEM: | |
| 70 case NPCharsetSymbol: | |
| 71 is_lgc = true; | |
| 72 FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("en")); | |
| 73 break; | |
| 74 case NPCharsetBaltic: | |
| 75 // The three baltic languages. | |
| 76 is_lgc = true; | |
| 77 FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("et")); | |
| 78 FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("lv")); | |
| 79 FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("lt")); | |
| 80 break; | |
| 81 case NPCharsetChineseBIG5: | |
| 82 FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("zh-tw")); | |
| 83 break; | |
| 84 case NPCharsetGB2312: | |
| 85 FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("zh-cn")); | |
| 86 break; | |
| 87 case NPCharsetEastEurope: | |
| 88 // A scattering of eastern European languages. | |
| 89 is_lgc = true; | |
| 90 FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("pl")); | |
| 91 FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("cs")); | |
| 92 FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("sk")); | |
| 93 FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("hu")); | |
| 94 FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("hr")); | |
| 95 break; | |
| 96 case NPCharsetGreek: | |
| 97 is_lgc = true; | |
| 98 FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("el")); | |
| 99 break; | |
| 100 case NPCharsetHangul: | |
| 101 case NPCharsetJohab: | |
| 102 // Korean | |
| 103 FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("ko")); | |
| 104 break; | |
| 105 case NPCharsetRussian: | |
| 106 is_lgc = true; | |
| 107 FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("ru")); | |
| 108 break; | |
| 109 case NPCharsetShiftJIS: | |
| 110 // Japanese | |
| 111 FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("ja")); | |
| 112 break; | |
| 113 case NPCharsetTurkish: | |
| 114 is_lgc = true; | |
| 115 FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("tr")); | |
| 116 break; | |
| 117 case NPCharsetVietnamese: | |
| 118 is_lgc = true; | |
| 119 FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("vi")); | |
| 120 break; | |
| 121 case NPCharsetArabic: | |
| 122 FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("ar")); | |
| 123 break; | |
| 124 case NPCharsetHebrew: | |
| 125 FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("he")); | |
| 126 break; | |
| 127 case NPCharsetThai: | |
| 128 FcLangSetAdd(langset, reinterpret_cast<const FcChar8*>("th")); | |
| 129 break; | |
| 130 // default: | |
| 131 // Don't add any languages in that case that we don't recognise the | |
| 132 // constant. | |
| 133 } | |
| 134 return is_lgc; | |
| 135 } | |
| 136 | |
| 137 } // namespace | |
| 138 | |
| 139 namespace content { | 38 namespace content { |
| 140 | 39 |
| 141 SandboxIPCHandler::SandboxIPCHandler(int lifeline_fd, int browser_socket) | 40 SandboxIPCHandler::SandboxIPCHandler(int lifeline_fd, int browser_socket) |
| 142 : lifeline_fd_(lifeline_fd), browser_socket_(browser_socket) { | 41 : lifeline_fd_(lifeline_fd), browser_socket_(browser_socket) { |
| 143 // FontConfig doesn't provide a standard property to control subpixel | 42 // FontConfig doesn't provide a standard property to control subpixel |
| 144 // positioning, so we pass the current setting through to WebKit. | 43 // positioning, so we pass the current setting through to WebKit. |
| 145 WebFontInfo::setSubpixelPositioning( | 44 WebFontInfo::setSubpixelPositioning( |
| 146 gfx::GetDefaultWebkitSubpixelPositioning()); | 45 gfx::GetDefaultWebkitSubpixelPositioning()); |
| 147 } | 46 } |
| 148 | 47 |
| (...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 428 shm_fd = shm.handle().fd; | 327 shm_fd = shm.handle().fd; |
| 429 Pickle reply; | 328 Pickle reply; |
| 430 SendRendererReply(fds, reply, shm_fd); | 329 SendRendererReply(fds, reply, shm_fd); |
| 431 } | 330 } |
| 432 | 331 |
| 433 void SandboxIPCHandler::HandleMatchWithFallback( | 332 void SandboxIPCHandler::HandleMatchWithFallback( |
| 434 int fd, | 333 int fd, |
| 435 const Pickle& pickle, | 334 const Pickle& pickle, |
| 436 PickleIterator iter, | 335 PickleIterator iter, |
| 437 const std::vector<base::ScopedFD*>& fds) { | 336 const std::vector<base::ScopedFD*>& fds) { |
| 438 // Unlike the other calls, for which we are an indirection in front of | |
| 439 // WebKit or Skia, this call is always made via this sandbox helper | |
| 440 // process. Therefore the fontconfig code goes in here directly. | |
| 441 | |
| 442 std::string face; | 337 std::string face; |
| 443 bool is_bold, is_italic; | 338 bool is_bold, is_italic; |
| 444 uint32 charset, fallback_family; | 339 uint32 charset, fallback_family; |
| 445 | 340 |
| 446 if (!pickle.ReadString(&iter, &face) || face.empty() || | 341 if (!pickle.ReadString(&iter, &face) || face.empty() || |
| 447 !pickle.ReadBool(&iter, &is_bold) || | 342 !pickle.ReadBool(&iter, &is_bold) || |
| 448 !pickle.ReadBool(&iter, &is_italic) || | 343 !pickle.ReadBool(&iter, &is_italic) || |
| 449 !pickle.ReadUInt32(&iter, &charset) || | 344 !pickle.ReadUInt32(&iter, &charset) || |
| 450 !pickle.ReadUInt32(&iter, &fallback_family)) { | 345 !pickle.ReadUInt32(&iter, &fallback_family)) { |
| 451 return; | 346 return; |
| 452 } | 347 } |
| 453 | 348 |
| 454 FcLangSet* langset = FcLangSetCreate(); | 349 int font_fd = MatchFontFaceWithFallback( |
| 455 bool is_lgc = MSCharSetToFontconfig(langset, charset); | 350 face, is_bold, is_italic, charset, fallback_family); |
| 456 | |
| 457 FcPattern* pattern = FcPatternCreate(); | |
| 458 FcPatternAddString( | |
| 459 pattern, FC_FAMILY, reinterpret_cast<const FcChar8*>(face.c_str())); | |
| 460 | |
| 461 // TODO(thestig) Check if we can access Chrome's per-script font preference | |
| 462 // here and select better default fonts for non-LGC case. | |
| 463 std::string generic_font_name; | |
| 464 if (is_lgc) { | |
| 465 switch (fallback_family) { | |
| 466 case PP_BROWSERFONT_TRUSTED_FAMILY_SERIF: | |
| 467 generic_font_name = "Times New Roman"; | |
| 468 break; | |
| 469 case PP_BROWSERFONT_TRUSTED_FAMILY_SANSSERIF: | |
| 470 generic_font_name = "Arial"; | |
| 471 break; | |
| 472 case PP_BROWSERFONT_TRUSTED_FAMILY_MONOSPACE: | |
| 473 generic_font_name = "Courier New"; | |
| 474 break; | |
| 475 } | |
| 476 } | |
| 477 if (!generic_font_name.empty()) { | |
| 478 const FcChar8* fc_generic_font_name = | |
| 479 reinterpret_cast<const FcChar8*>(generic_font_name.c_str()); | |
| 480 FcPatternAddString(pattern, FC_FAMILY, fc_generic_font_name); | |
| 481 } | |
| 482 | |
| 483 if (is_bold) | |
| 484 FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD); | |
| 485 if (is_italic) | |
| 486 FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); | |
| 487 FcPatternAddLangSet(pattern, FC_LANG, langset); | |
| 488 FcPatternAddBool(pattern, FC_SCALABLE, FcTrue); | |
| 489 FcConfigSubstitute(NULL, pattern, FcMatchPattern); | |
| 490 FcDefaultSubstitute(pattern); | |
| 491 | |
| 492 FcResult result; | |
| 493 FcFontSet* font_set = FcFontSort(0, pattern, 0, 0, &result); | |
| 494 int font_fd = -1; | |
| 495 int good_enough_index = -1; | |
| 496 bool good_enough_index_set = false; | |
| 497 | |
| 498 if (font_set) { | |
| 499 for (int i = 0; i < font_set->nfont; ++i) { | |
| 500 FcPattern* current = font_set->fonts[i]; | |
| 501 | |
| 502 // Older versions of fontconfig have a bug where they cannot select | |
| 503 // only scalable fonts so we have to manually filter the results. | |
| 504 FcBool is_scalable; | |
| 505 if (FcPatternGetBool(current, FC_SCALABLE, 0, &is_scalable) != | |
| 506 FcResultMatch || | |
| 507 !is_scalable) { | |
| 508 continue; | |
| 509 } | |
| 510 | |
| 511 FcChar8* c_filename; | |
| 512 if (FcPatternGetString(current, FC_FILE, 0, &c_filename) != | |
| 513 FcResultMatch) { | |
| 514 continue; | |
| 515 } | |
| 516 | |
| 517 // We only want to return sfnt (TrueType) based fonts. We don't have a | |
| 518 // very good way of detecting this so we'll filter based on the | |
| 519 // filename. | |
| 520 bool is_sfnt = false; | |
| 521 static const char kSFNTExtensions[][5] = {".ttf", ".otc", ".TTF", ".ttc", | |
| 522 ""}; | |
| 523 const size_t filename_len = strlen(reinterpret_cast<char*>(c_filename)); | |
| 524 for (unsigned j = 0;; j++) { | |
| 525 if (kSFNTExtensions[j][0] == 0) { | |
| 526 // None of the extensions matched. | |
| 527 break; | |
| 528 } | |
| 529 const size_t ext_len = strlen(kSFNTExtensions[j]); | |
| 530 if (filename_len > ext_len && | |
| 531 memcmp(c_filename + filename_len - ext_len, | |
| 532 kSFNTExtensions[j], | |
| 533 ext_len) == 0) { | |
| 534 is_sfnt = true; | |
| 535 break; | |
| 536 } | |
| 537 } | |
| 538 | |
| 539 if (!is_sfnt) | |
| 540 continue; | |
| 541 | |
| 542 // This font is good enough to pass muster, but we might be able to do | |
| 543 // better with subsequent ones. | |
| 544 if (!good_enough_index_set) { | |
| 545 good_enough_index = i; | |
| 546 good_enough_index_set = true; | |
| 547 } | |
| 548 | |
| 549 FcValue matrix; | |
| 550 bool have_matrix = FcPatternGet(current, FC_MATRIX, 0, &matrix) == 0; | |
| 551 | |
| 552 if (is_italic && have_matrix) { | |
| 553 // we asked for an italic font, but fontconfig is giving us a | |
| 554 // non-italic font with a transformation matrix. | |
| 555 continue; | |
| 556 } | |
| 557 | |
| 558 FcValue embolden; | |
| 559 const bool have_embolden = | |
| 560 FcPatternGet(current, FC_EMBOLDEN, 0, &embolden) == 0; | |
| 561 | |
| 562 if (is_bold && have_embolden) { | |
| 563 // we asked for a bold font, but fontconfig gave us a non-bold font | |
| 564 // and asked us to apply fake bolding. | |
| 565 continue; | |
| 566 } | |
| 567 | |
| 568 font_fd = open(reinterpret_cast<char*>(c_filename), O_RDONLY); | |
| 569 if (font_fd >= 0) | |
| 570 break; | |
| 571 } | |
| 572 } | |
| 573 | |
| 574 if (font_fd == -1 && good_enough_index_set) { | |
| 575 // We didn't find a font that we liked, so we fallback to something | |
| 576 // acceptable. | |
| 577 FcPattern* current = font_set->fonts[good_enough_index]; | |
| 578 FcChar8* c_filename; | |
| 579 FcPatternGetString(current, FC_FILE, 0, &c_filename); | |
| 580 font_fd = open(reinterpret_cast<char*>(c_filename), O_RDONLY); | |
| 581 } | |
| 582 | |
| 583 if (font_set) | |
| 584 FcFontSetDestroy(font_set); | |
| 585 FcPatternDestroy(pattern); | |
| 586 | 351 |
| 587 Pickle reply; | 352 Pickle reply; |
| 588 SendRendererReply(fds, reply, font_fd); | 353 SendRendererReply(fds, reply, font_fd); |
| 589 | 354 |
| 590 if (font_fd >= 0) { | 355 if (font_fd >= 0) { |
| 591 if (IGNORE_EINTR(close(font_fd)) < 0) | 356 if (IGNORE_EINTR(close(font_fd)) < 0) |
| 592 PLOG(ERROR) << "close"; | 357 PLOG(ERROR) << "close"; |
| 593 } | 358 } |
| 594 } | 359 } |
| 595 | 360 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 641 } | 406 } |
| 642 | 407 |
| 643 void SandboxIPCHandler::EnsureWebKitInitialized() { | 408 void SandboxIPCHandler::EnsureWebKitInitialized() { |
| 644 if (webkit_platform_support_) | 409 if (webkit_platform_support_) |
| 645 return; | 410 return; |
| 646 webkit_platform_support_.reset(new BlinkPlatformImpl); | 411 webkit_platform_support_.reset(new BlinkPlatformImpl); |
| 647 blink::initializeWithoutV8(webkit_platform_support_.get()); | 412 blink::initializeWithoutV8(webkit_platform_support_.get()); |
| 648 } | 413 } |
| 649 | 414 |
| 650 } // namespace content | 415 } // namespace content |
| OLD | NEW |