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 3 // found in the LICENSE file. 4 5 #include "data_file_renderer_cld_data_provider.h" 6 7 #include "base/basictypes.h" 8 #include "base/files/file.h" 9 #include "base/files/memory_mapped_file.h" 10 #include "base/lazy_instance.h" 11 #include "base/logging.h" 12 #include "components/translate/content/common/data_file_cld_data_provider_messages.h" 13 #include "content/public/renderer/render_view_observer.h" 14 #include "ipc/ipc_message.h" 15 #include "ipc/ipc_message_macros.h" 16 #include "ipc/ipc_platform_file.h" 17 #include "third_party/cld_2/src/public/compact_lang_det.h" 18 19 namespace { 20 21 // A struct that contains the pointer to the CLD mmap. Used so that we can 22 // leverage LazyInstance:Leaky to properly scope the lifetime of the mmap. 23 struct CLDMmapWrapper { 24 CLDMmapWrapper() { value = NULL; } 25 base::MemoryMappedFile* value; 26 }; 27 base::LazyInstance<CLDMmapWrapper>::Leaky g_cld_mmap = 28 LAZY_INSTANCE_INITIALIZER; 29 30 } // namespace 31 32 namespace translate { 33 34 // Implementation of the static factory method from RendererCldDataProvider, 35 // hooking up this specific implementation for all of Chromium. 36 RendererCldDataProvider* CreateRendererCldDataProviderFor( 37 content::RenderViewObserver* render_view_observer) { 38 // This log line is to help with determining which kind of provider has been 39 // configured. See also: chrome://translate-internals 40 VLOG(1) << "Creating DataFileRendererCldDataProvider"; 41 return new DataFileRendererCldDataProvider(render_view_observer); 42 } 43 44 DataFileRendererCldDataProvider::DataFileRendererCldDataProvider( 45 content::RenderViewObserver* render_view_observer) 46 : render_view_observer_(render_view_observer) { 47 } 48 49 DataFileRendererCldDataProvider::~DataFileRendererCldDataProvider() { 50 } 51 52 bool DataFileRendererCldDataProvider::OnMessageReceived( 53 const IPC::Message& message) { 54 bool handled = true; 55 IPC_BEGIN_MESSAGE_MAP(DataFileRendererCldDataProvider, message) 56 IPC_MESSAGE_HANDLER(ChromeViewMsg_CldDataFileAvailable, OnCldDataAvailable) 57 IPC_MESSAGE_UNHANDLED(handled = false) 58 IPC_END_MESSAGE_MAP() 59 return handled; 60 } 61 62 void DataFileRendererCldDataProvider::SendCldDataRequest() { 63 // Else, send the IPC message to the browser process requesting the data... 64 render_view_observer_->Send(new ChromeViewHostMsg_NeedCldDataFile( 65 render_view_observer_->routing_id())); 66 } 67 68 bool DataFileRendererCldDataProvider::IsCldDataAvailable() { 69 // This neatly removes the need for code that depends on the generalized 70 // RendererCldDataProvider to #ifdef on CLD2_DYNAMIC_MODE 71 return CLD2::isDataLoaded(); // ground truth, independent of our state. 72 } 73 74 void DataFileRendererCldDataProvider::SetCldAvailableCallback( 75 base::Callback<void(void)> callback) { 76 cld_available_callback_ = callback; 77 } 78 79 void DataFileRendererCldDataProvider::OnCldDataAvailable( 80 const IPC::PlatformFileForTransit ipc_file_handle, 81 const uint64 data_offset, 82 const uint64 data_length) { 83 LoadCldData(IPC::PlatformFileForTransitToFile(ipc_file_handle), 84 data_offset, 85 data_length); 86 } 87 88 void DataFileRendererCldDataProvider::LoadCldData(base::File file, 89 const uint64 data_offset, 90 const uint64 data_length) { 91 // Terminate immediately if data is already loaded. 92 if (IsCldDataAvailable()) 93 return; 94 95 if (!file.IsValid()) { 96 LOG(ERROR) << "Can't find the CLD data file."; 97 return; 98 } 99 100 // mmap the file 101 g_cld_mmap.Get().value = new base::MemoryMappedFile(); 102 bool initialized = g_cld_mmap.Get().value->Initialize(file.Pass()); 103 if (!initialized) { 104 LOG(ERROR) << "mmap initialization failed"; 105 delete g_cld_mmap.Get().value; 106 g_cld_mmap.Get().value = NULL; 107 return; 108 } 109 110 // Sanity checks 111 uint64 max_int32 = std::numeric_limits<int32>::max(); 112 if (data_length + data_offset > g_cld_mmap.Get().value->length() || 113 data_length > max_int32) { // max signed 32 bit integer 114 LOG(ERROR) << "Illegal mmap config: data_offset=" << data_offset 115 << ", data_length=" << data_length 116 << ", mmap->length()=" << g_cld_mmap.Get().value->length(); 117 delete g_cld_mmap.Get().value; 118 g_cld_mmap.Get().value = NULL; 119 return; 120 } 121 122 // Initialize the CLD subsystem... and it's all done! 123 const uint8* data_ptr = g_cld_mmap.Get().value->data() + data_offset; 124 CLD2::loadDataFromRawAddress(data_ptr, data_length); 125 DCHECK(CLD2::isDataLoaded()) << "Failed to load CLD data from mmap"; 126 if (!cld_available_callback_.is_null()) { 127 cld_available_callback_.Run(); 128 } 129 } 130 131 } // namespace translate 132