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 19namespace { 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. 23struct CLDMmapWrapper { 24 CLDMmapWrapper() { value = NULL; } 25 base::MemoryMappedFile* value; 26}; 27base::LazyInstance<CLDMmapWrapper>::Leaky g_cld_mmap = 28 LAZY_INSTANCE_INITIALIZER; 29 30} // namespace 31 32namespace translate { 33 34// Implementation of the static factory method from RendererCldDataProvider, 35// hooking up this specific implementation for all of Chromium. 36RendererCldDataProvider* 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 44DataFileRendererCldDataProvider::DataFileRendererCldDataProvider( 45 content::RenderViewObserver* render_view_observer) 46 : render_view_observer_(render_view_observer) { 47} 48 49DataFileRendererCldDataProvider::~DataFileRendererCldDataProvider() { 50} 51 52bool 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 62void 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 68bool 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 74void DataFileRendererCldDataProvider::SetCldAvailableCallback( 75 base::Callback<void(void)> callback) { 76 cld_available_callback_ = callback; 77} 78 79void 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 88void 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