Home | History | Annotate | Download | only in renderer
      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