Replace image_messages.h with Mojo service
Implement ImageDownloader service and register it into RenderFrame
ServiceRegistry. This Mojo service will do the job did by
ImageLoadingHelper before.
Re-use mojom files:
third_party/mojo_services/src/geometry/public/interfaces/
geometry.mojom
skia/public/interfaces/bitmap.mojom
TBR=rockot@chromium.org,amistry@google.com,darin@chromium.org,nasko@chromium.org
BUG=
Review URL: https://codereview.chromium.org/1085783002
Cr-Commit-Position: refs/heads/master@{#337370}
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 474f562..9211dc1 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -116,6 +116,9 @@
"//device/bluetooth",
"//gin",
"//mojo/application/public/interfaces",
+ "//mojo/common:url_type_converters",
+ "//mojo/converters/geometry",
+ "//skia/public",
"//storage/browser",
"//storage/common",
"//third_party/WebKit/public:image_resources",
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index e24f00c8..45b08917 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -1873,6 +1873,9 @@
#endif
service_registry_.reset();
+
+ // Disconnect with ImageDownloader Mojo service in RenderFrame.
+ mojo_image_downloader_.reset();
}
bool RenderFrameHostImpl::IsFocused() {
@@ -1885,6 +1888,15 @@
frame_tree_->GetFocusedFrame()->IsDescendantOf(frame_tree_node()));
}
+const image_downloader::ImageDownloaderPtr&
+RenderFrameHostImpl::GetMojoImageDownloader() {
+ if (!mojo_image_downloader_.get()) {
+ GetServiceRegistry()->ConnectToRemoteService(
+ mojo::GetProxy(&mojo_image_downloader_));
+ }
+ return mojo_image_downloader_;
+}
+
void RenderFrameHostImpl::UpdateCrossProcessIframeAccessibility(
const std::map<int32, int>& node_to_frame_routing_id_map) {
for (const auto& iter : node_to_frame_routing_id_map) {
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index d34b4ef3..72e39da 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -20,6 +20,7 @@
#include "content/common/content_export.h"
#include "content/common/frame_message_enums.h"
#include "content/common/frame_replication_state.h"
+#include "content/common/image_downloader/image_downloader.mojom.h"
#include "content/common/mojo/service_registry_impl.h"
#include "content/common/navigation_params.h"
#include "content/public/browser/render_frame_host.h"
@@ -445,6 +446,9 @@
// addition, its associated RenderWidgetHost has to be focused.
bool IsFocused();
+ // Returns the Mojo ImageDownloader service pointer.
+ const image_downloader::ImageDownloaderPtr& GetMojoImageDownloader();
+
protected:
friend class RenderFrameHostFactory;
@@ -735,6 +739,9 @@
// The frame's Mojo Shell service.
scoped_ptr<FrameMojoShell> frame_mojo_shell_;
+ // Holder of Mojo connection with ImageDownloader service in RenderFrame.
+ image_downloader::ImageDownloaderPtr mojo_image_downloader_;
+
// NOTE: This must be the last member.
base::WeakPtrFactory<RenderFrameHostImpl> weak_ptr_factory_;
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 55d2e571..3df8edb 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -62,7 +62,6 @@
#include "content/common/browser_plugin/browser_plugin_constants.h"
#include "content/common/browser_plugin/browser_plugin_messages.h"
#include "content/common/frame_messages.h"
-#include "content/common/image_messages.h"
#include "content/common/input_messages.h"
#include "content/common/ssl_status_serialization.h"
#include "content/common/view_messages.h"
@@ -97,11 +96,15 @@
#include "content/public/common/url_constants.h"
#include "content/public/common/url_utils.h"
#include "content/public/common/web_preferences.h"
+#include "mojo/common/url_type_converters.h"
+#include "mojo/converters/geometry/geometry_type_converters.h"
#include "net/base/net_util.h"
#include "net/http/http_cache.h"
#include "net/http/http_transaction_factory.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
+#include "skia/public/type_converters.h"
+#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/layout.h"
#include "ui/gfx/display.h"
#include "ui/gfx/screen.h"
@@ -135,19 +138,19 @@
base::LazyInstance<std::vector<WebContentsImpl::CreatedCallback> >
g_created_callbacks = LAZY_INSTANCE_INITIALIZER;
-static int StartDownload(RenderFrameHost* rfh,
- const GURL& url,
- bool is_favicon,
- uint32_t max_bitmap_size,
- bool bypass_cache) {
- static int g_next_image_download_id = 0;
- rfh->Send(new ImageMsg_DownloadImage(rfh->GetRoutingID(),
- ++g_next_image_download_id,
- url,
- is_favicon,
- max_bitmap_size,
- bypass_cache));
- return g_next_image_download_id;
+static void DidDownloadImage(const WebContents::ImageDownloadCallback& callback,
+ int id,
+ const GURL& image_url,
+ image_downloader::DownloadResultPtr result) {
+ DCHECK(result);
+
+ const std::vector<SkBitmap> images =
+ result->images.To<std::vector<SkBitmap>>();
+ const std::vector<gfx::Size> original_image_sizes =
+ result->original_image_sizes.To<std::vector<gfx::Size>>();
+
+ callback.Run(id, result->http_status_code, image_url, images,
+ original_image_sizes);
}
void NotifyCacheOnIO(
@@ -611,7 +614,6 @@
OnBrowserPluginMessage(render_frame_host,
message))
#endif
- IPC_MESSAGE_HANDLER(ImageHostMsg_DidDownloadImage, OnDidDownloadImage)
IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateFaviconURL, OnUpdateFaviconURL)
IPC_MESSAGE_HANDLER(ViewHostMsg_ShowValidationMessage,
OnShowValidationMessage)
@@ -2593,15 +2595,27 @@
color_chooser_info_.reset();
}
-int WebContentsImpl::DownloadImage(const GURL& url,
- bool is_favicon,
- uint32_t max_bitmap_size,
- bool bypass_cache,
- const ImageDownloadCallback& callback) {
- int id = StartDownload(GetMainFrame(), url, is_favicon, max_bitmap_size,
- bypass_cache);
- image_download_map_[id] = callback;
- return id;
+int WebContentsImpl::DownloadImage(
+ const GURL& url,
+ bool is_favicon,
+ uint32_t max_bitmap_size,
+ bool bypass_cache,
+ const WebContents::ImageDownloadCallback& callback) {
+ static int next_image_download_id = 0;
+ const image_downloader::ImageDownloaderPtr& mojo_image_downloader =
+ GetMainFrame()->GetMojoImageDownloader();
+ image_downloader::DownloadRequestPtr req =
+ image_downloader::DownloadRequest::New();
+
+ req->url = mojo::String::From(url);
+ req->is_favicon = is_favicon;
+ req->max_bitmap_size = max_bitmap_size;
+ req->bypass_cache = bypass_cache;
+
+ mojo_image_downloader->DownloadImage(
+ req.Pass(),
+ base::Bind(&DidDownloadImage, callback, ++next_image_download_id, url));
+ return next_image_download_id;
}
bool WebContentsImpl::IsSubframe() const {
@@ -3176,28 +3190,6 @@
}
#endif // defined(ENABLE_PLUGINS)
-void WebContentsImpl::OnDidDownloadImage(
- int id,
- int http_status_code,
- const GURL& image_url,
- const std::vector<SkBitmap>& bitmaps,
- const std::vector<gfx::Size>& original_bitmap_sizes) {
- if (bitmaps.size() != original_bitmap_sizes.size())
- return;
-
- ImageDownloadMap::iterator iter = image_download_map_.find(id);
- if (iter == image_download_map_.end()) {
- // Currently WebContents notifies us of ANY downloads so that it is
- // possible to get here.
- return;
- }
- if (!iter->second.is_null()) {
- iter->second.Run(
- id, http_status_code, image_url, bitmaps, original_bitmap_sizes);
- }
- image_download_map_.erase(id);
-}
-
void WebContentsImpl::OnUpdateFaviconURL(
const std::vector<FaviconURL>& candidates) {
// We get updated favicon URLs after the page stops loading. If a cross-site
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index b41a3507..8f3c90a7 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -856,11 +856,6 @@
void OnBrowserPluginMessage(RenderFrameHost* render_frame_host,
const IPC::Message& message);
#endif // defined(ENABLE_PLUGINS)
- void OnDidDownloadImage(int id,
- int http_status_code,
- const GURL& image_url,
- const std::vector<SkBitmap>& bitmaps,
- const std::vector<gfx::Size>& original_bitmap_sizes);
void OnUpdateFaviconURL(const std::vector<FaviconURL>& candidates);
void OnFirstVisuallyNonEmptyPaint();
void OnMediaPlayingNotification(int64 player_cookie,
@@ -1242,10 +1237,6 @@
// completed making layout changes to effect an exit from fullscreen mode.
bool fullscreen_widget_had_focus_at_shutdown_;
- // Maps the ids of pending image downloads to their callbacks
- typedef std::map<int, ImageDownloadCallback> ImageDownloadMap;
- ImageDownloadMap image_download_map_;
-
// Whether this WebContents is responsible for displaying a subframe in a
// different process from its parent page.
bool is_subframe_;
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index 5a383d1..ca573cd 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -489,6 +489,7 @@
"application_setup.mojom",
"background_sync_service.mojom",
"geolocation_service.mojom",
+ "image_downloader/image_downloader.mojom",
"permission_service.mojom",
"presentation/presentation_service.mojom",
"process_control.mojom",
@@ -502,5 +503,7 @@
deps = [
"//content/public/common:mojo_bindings",
"//mojo/application/public/interfaces",
+ "//skia/public/interfaces",
+ "//ui/mojo/geometry:interfaces",
]
}
diff --git a/content/common/content_message_generator.h b/content/common/content_message_generator.h
index 803e5f6..eebe1d5 100644
--- a/content/common/content_message_generator.h
+++ b/content/common/content_message_generator.h
@@ -28,7 +28,6 @@
#include "content/common/gamepad_messages.h"
#include "content/common/geofencing_messages.h"
#include "content/common/gpu/gpu_messages.h"
-#include "content/common/image_messages.h"
#include "content/common/indexed_db/indexed_db_messages.h"
#include "content/common/input_messages.h"
#include "content/common/manifest_manager_messages.h"
diff --git a/content/common/image_downloader/image_downloader.mojom b/content/common/image_downloader/image_downloader.mojom
new file mode 100644
index 0000000..7f3d289
--- /dev/null
+++ b/content/common/image_downloader/image_downloader.mojom
@@ -0,0 +1,28 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module image_downloader;
+
+import "skia/public/interfaces/bitmap.mojom";
+import "ui/mojo/geometry/geometry.mojom";
+
+struct DownloadRequest {
+ string url;
+ bool is_favicon;
+ uint32 max_bitmap_size;
+ bool bypass_cache;
+};
+
+struct DownloadResult {
+ int32 http_status_code;
+ array<skia.Bitmap> images;
+ array<mojo.Size> original_image_sizes;
+};
+
+interface ImageDownloader {
+ // Fetch and decode an image from a given URL.
+ // Returns the decoded images, or http_status_code to indicate error.
+ // Each call is independent, overlapping calls are possible.
+ DownloadImage(DownloadRequest request) => (DownloadResult result);
+};
diff --git a/content/common/image_messages.h b/content/common/image_messages.h
deleted file mode 100644
index 8e8279f..0000000
--- a/content/common/image_messages.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Multiply-included message file, no traditional include guard.
-#include <vector>
-
-#include "ipc/ipc_message.h"
-#include "ipc/ipc_message_macros.h"
-#include "ipc/ipc_param_traits.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/gfx/geometry/size.h"
-
-#define IPC_MESSAGE_START ImageMsgStart
-
-// Messages sent from the browser to the renderer.
-
-// Requests the renderer to download the specified image, decode it,
-// and send the image data back via ImageHostMsg_DidDownloadImage.
-IPC_MESSAGE_ROUTED5(ImageMsg_DownloadImage,
- int /* Identifier for the request */,
- GURL /* URL of the image */,
- bool /* is favicon (turn off cookies) */,
- uint32_t /* Maximal bitmap size in pixel. The results are
- filtered according the max size. If there are no
- bitmaps at the passed in GURL <= max size, the
- smallest bitmap is resized to the max size and
- is the only result. A max size of zero means
- that the max size is unlimited. */,
- bool /* bypass cache */)
-
-// Messages sent from the renderer to the browser.
-
-IPC_MESSAGE_ROUTED5(ImageHostMsg_DidDownloadImage,
- int /* Identifier of the request */,
- int /* HTTP response status */,
- GURL /* URL of the image */,
- std::vector<SkBitmap> /* bitmap data */,
- /* The sizes in pixel of the bitmaps before they were
- resized due to the maximal bitmap size passed to
- ImageMsg_DownloadImage. Each entry in the bitmaps vector
- corresponds to an entry in the sizes vector. If a bitmap
- was resized, there should be a single returned bitmap. */
- std::vector<gfx::Size>)
diff --git a/content/content.gyp b/content/content.gyp
index 41beae7..85ed59f 100644
--- a/content/content.gyp
+++ b/content/content.gyp
@@ -434,12 +434,14 @@
'../mojo/mojo_base.gyp:mojo_application_bindings',
'../mojo/mojo_base.gyp:mojo_system_java',
'../net/net.gyp:net',
+ '../skia/skia.gyp:skia_mojo',
'../third_party/mojo/mojo_public.gyp:mojo_bindings_java',
'../ui/android/ui_android.gyp:ui_java',
'../ui/touch_selection/ui_touch_selection.gyp:selection_event_type_java',
'../ui/touch_selection/ui_touch_selection.gyp:touch_handle_orientation_java',
'../third_party/android_tools/android_tools.gyp:android_support_v13_javalib',
'../third_party/WebKit/public/blink_headers.gyp:blink_headers_java',
+ '../ui/mojo/geometry/mojo_bindings.gyp:mojo_geometry_bindings',
'common_aidl',
'console_message_level_java',
'content_common',
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index d2888f8..db8c43d 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -12,6 +12,7 @@
'../device/vibration/vibration.gyp:device_vibration_mojo_bindings',
'../google_apis/google_apis.gyp:google_apis',
'../mojo/mojo_base.gyp:mojo_application_base',
+ '../mojo/mojo_base.gyp:mojo_geometry_lib',
'../mojo/mojo_base.gyp:mojo_url_type_converters',
'../mojo/mojo_services.gyp:network_service_bindings_lib',
'../mojo/mojo_services.gyp:updater_bindings_lib',
@@ -19,6 +20,7 @@
'../net/net.gyp:net',
'../net/net.gyp:net_extras',
'../skia/skia.gyp:skia',
+ '../skia/skia.gyp:skia_mojo',
'../sql/sql.gyp:sql',
'../third_party/mojo/mojo_public.gyp:mojo_cpp_bindings',
'../third_party/re2/re2.gyp:re2',
diff --git a/content/content_common.gypi b/content/content_common.gypi
index 57c6a5d..31072e5 100644
--- a/content/content_common.gypi
+++ b/content/content_common.gypi
@@ -359,7 +359,6 @@
'common/host_discardable_shared_memory_manager.h',
'common/host_shared_bitmap_manager.cc',
'common/host_shared_bitmap_manager.h',
- 'common/image_messages.h',
'common/indexed_db/indexed_db_constants.h',
'common/indexed_db/indexed_db_key.cc',
'common/indexed_db/indexed_db_key.h',
diff --git a/content/content_common_mojo_bindings.gyp b/content/content_common_mojo_bindings.gyp
index 2bd97b4..f4175a3 100644
--- a/content/content_common_mojo_bindings.gyp
+++ b/content/content_common_mojo_bindings.gyp
@@ -14,6 +14,7 @@
'common/application_setup.mojom',
'common/background_sync_service.mojom',
'common/geolocation_service.mojom',
+ 'common/image_downloader/image_downloader.mojom',
'common/permission_service.mojom',
'common/presentation/presentation_service.mojom',
'common/process_control.mojom',
@@ -38,7 +39,9 @@
'content_common_mojo_bindings_mojom',
'../mojo/mojo_base.gyp:mojo_application_bindings',
'../mojo/mojo_base.gyp:mojo_environment_chromium',
+ '../skia/skia.gyp:skia_mojo',
'../third_party/mojo/mojo_public.gyp:mojo_cpp_bindings',
+ '../ui/mojo/geometry/mojo_bindings.gyp:mojo_geometry_bindings',
]
},
]
diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi
index 4cfd238..675b6a6 100644
--- a/content/content_renderer.gypi
+++ b/content/content_renderer.gypi
@@ -19,8 +19,11 @@
'../media/blink/media_blink.gyp:media_blink',
'../media/media.gyp:media',
'../mojo/mojo_base.gyp:mojo_environment_chromium',
+ '../mojo/mojo_base.gyp:mojo_geometry_lib',
+ '../mojo/mojo_base.gyp:mojo_url_type_converters',
'../net/net.gyp:net',
'../skia/skia.gyp:skia',
+ '../skia/skia.gyp:skia_mojo',
'../storage/storage_common.gyp:storage_common',
'../third_party/WebKit/public/blink.gyp:blink',
'../third_party/icu/icu.gyp:icui18n',
@@ -198,8 +201,8 @@
'renderer/history_serialization.h',
'renderer/idle_user_detector.cc',
'renderer/idle_user_detector.h',
- 'renderer/image_loading_helper.cc',
- 'renderer/image_loading_helper.h',
+ 'renderer/image_downloader/image_downloader_impl.cc',
+ 'renderer/image_downloader/image_downloader_impl.h',
'renderer/ime_event_guard.cc',
'renderer/ime_event_guard.h',
'renderer/in_process_renderer_thread.cc',
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index 9c8e19e..e4a9a0b 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -44,12 +44,16 @@
"//media/blink",
"//mojo/application/public/interfaces",
"//mojo/environment:chromium",
+ "//mojo/common:url_type_converters",
+ "//mojo/converters/geometry",
"//net",
"//skia",
+ "//skia/public",
"//storage/common",
"//third_party/icu",
"//third_party/libjingle",
"//third_party/mojo/src/mojo/edk/js",
+ "//third_party/mojo/src/mojo/public/cpp/bindings",
"//third_party/mojo/src/mojo/public/js",
"//third_party/npapi",
"//third_party/WebKit/public:blink",
diff --git a/content/renderer/DEPS b/content/renderer/DEPS
index 1156983..5ea2ee71 100644
--- a/content/renderer/DEPS
+++ b/content/renderer/DEPS
@@ -12,7 +12,7 @@
"+gin",
"+jingle/glue",
"+media", # For audio input/output and audio/video decoding.
- "+mojo/application/public/interfaces",
+ "+mojo",
"-storage/browser",
"+third_party/hyphen/hyphen.h",
"+third_party/libjingle",
diff --git a/content/renderer/image_downloader/image_downloader_impl.cc b/content/renderer/image_downloader/image_downloader_impl.cc
new file mode 100644
index 0000000..c969418b
--- /dev/null
+++ b/content/renderer/image_downloader/image_downloader_impl.cc
@@ -0,0 +1,224 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/image_downloader/image_downloader_impl.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "content/child/image_decoder.h"
+#include "content/public/renderer/render_frame.h"
+#include "content/renderer/fetchers/multi_resolution_image_resource_fetcher.h"
+#include "mojo/common/url_type_converters.h"
+#include "mojo/converters/geometry/geometry_type_converters.h"
+#include "net/base/data_url.h"
+#include "skia/ext/image_operations.h"
+#include "skia/public/type_converters.h"
+#include "third_party/WebKit/public/platform/WebURLRequest.h"
+#include "third_party/WebKit/public/platform/WebVector.h"
+#include "third_party/WebKit/public/web/WebLocalFrame.h"
+#include "third_party/WebKit/public/web/WebView.h"
+#include "ui/gfx/favicon_size.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/skbitmap_operations.h"
+#include "url/url_constants.h"
+
+using blink::WebFrame;
+using blink::WebVector;
+using blink::WebURL;
+using blink::WebURLRequest;
+
+namespace {
+
+// Decodes a data: URL image or returns an empty image in case of failure.
+SkBitmap ImageFromDataUrl(const GURL& url) {
+ std::string mime_type, char_set, data;
+ if (net::DataURL::Parse(url, &mime_type, &char_set, &data) && !data.empty()) {
+ // Decode the image using Blink's image decoder.
+ content::ImageDecoder decoder(
+ gfx::Size(gfx::kFaviconSize, gfx::kFaviconSize));
+ const unsigned char* src_data =
+ reinterpret_cast<const unsigned char*>(data.data());
+
+ return decoder.Decode(src_data, data.size());
+ }
+ return SkBitmap();
+}
+
+// Proportionally resizes the |image| to fit in a box of size
+// |max_image_size|.
+SkBitmap ResizeImage(const SkBitmap& image, uint32_t max_image_size) {
+ if (max_image_size == 0)
+ return image;
+ uint32_t max_dimension = std::max(image.width(), image.height());
+ if (max_dimension <= max_image_size)
+ return image;
+ // Proportionally resize the minimal image to fit in a box of size
+ // max_image_size.
+ return skia::ImageOperations::Resize(
+ image, skia::ImageOperations::RESIZE_BEST,
+ static_cast<uint64_t>(image.width()) * max_image_size / max_dimension,
+ static_cast<uint64_t>(image.height()) * max_image_size / max_dimension);
+}
+
+// Filters the array of bitmaps, removing all images that do not fit in a box of
+// size |max_image_size|. Returns the result if it is not empty. Otherwise,
+// find the smallest image in the array and resize it proportionally to fit
+// in a box of size |max_image_size|.
+// Sets |original_image_sizes| to the sizes of |images| before resizing.
+void FilterAndResizeImagesForMaximalSize(
+ const std::vector<SkBitmap>& unfiltered,
+ uint32_t max_image_size,
+ std::vector<SkBitmap>* images,
+ std::vector<gfx::Size>* original_image_sizes) {
+ images->clear();
+ original_image_sizes->clear();
+
+ if (!unfiltered.size())
+ return;
+
+ if (max_image_size == 0)
+ max_image_size = std::numeric_limits<uint32_t>::max();
+
+ const SkBitmap* min_image = NULL;
+ uint32_t min_image_size = std::numeric_limits<uint32_t>::max();
+ // Filter the images by |max_image_size|, and also identify the smallest image
+ // in case all the images are bigger than |max_image_size|.
+ for (std::vector<SkBitmap>::const_iterator it = unfiltered.begin();
+ it != unfiltered.end(); ++it) {
+ const SkBitmap& image = *it;
+ uint32_t current_size = std::max(it->width(), it->height());
+ if (current_size < min_image_size) {
+ min_image = ℑ
+ min_image_size = current_size;
+ }
+ if (static_cast<uint32_t>(image.width()) <= max_image_size &&
+ static_cast<uint32_t>(image.height()) <= max_image_size) {
+ images->push_back(image);
+ original_image_sizes->push_back(gfx::Size(image.width(), image.height()));
+ }
+ }
+ DCHECK(min_image);
+ if (images->size())
+ return;
+ // Proportionally resize the minimal image to fit in a box of size
+ // |max_image_size|.
+ images->push_back(ResizeImage(*min_image, max_image_size));
+ original_image_sizes->push_back(
+ gfx::Size(min_image->width(), min_image->height()));
+}
+
+} // namespace
+
+namespace content {
+
+ImageDownloaderImpl::ImageDownloaderImpl(
+ RenderFrame* render_frame,
+ mojo::InterfaceRequest<image_downloader::ImageDownloader> request)
+ : RenderFrameObserver(render_frame), binding_(this, request.Pass()) {
+ DCHECK(render_frame);
+}
+
+ImageDownloaderImpl::~ImageDownloaderImpl() {
+}
+
+// static
+void ImageDownloaderImpl::CreateMojoService(
+ RenderFrame* render_frame,
+ mojo::InterfaceRequest<image_downloader::ImageDownloader> request) {
+ DVLOG(1) << "ImageDownloaderImpl::CreateService";
+ DCHECK(render_frame);
+
+ new ImageDownloaderImpl(render_frame, request.Pass());
+}
+
+// ImageDownloader methods:
+void ImageDownloaderImpl::DownloadImage(
+ image_downloader::DownloadRequestPtr req,
+ const DownloadImageCallback& callback) {
+ const GURL image_url = req->url.To<GURL>();
+ bool is_favicon = req->is_favicon;
+ uint32_t max_image_size = req->max_bitmap_size;
+ bool bypass_cache = req->bypass_cache;
+
+ std::vector<SkBitmap> result_images;
+ std::vector<gfx::Size> result_original_image_sizes;
+
+ if (image_url.SchemeIs(url::kDataScheme)) {
+ SkBitmap data_image = ImageFromDataUrl(image_url);
+ if (!data_image.empty()) {
+ result_images.push_back(ResizeImage(data_image, max_image_size));
+ result_original_image_sizes.push_back(
+ gfx::Size(data_image.width(), data_image.height()));
+ }
+ } else {
+ if (FetchImage(image_url, is_favicon, max_image_size, bypass_cache,
+ callback)) {
+ // Will complete asynchronously via ImageDownloaderImpl::DidFetchImage
+ return;
+ }
+ }
+
+ ReplyDownloadResult(0, result_images, result_original_image_sizes, callback);
+}
+
+bool ImageDownloaderImpl::FetchImage(const GURL& image_url,
+ bool is_favicon,
+ uint32_t max_image_size,
+ bool bypass_cache,
+ const DownloadImageCallback& callback) {
+ blink::WebLocalFrame* frame = render_frame()->GetWebFrame();
+ DCHECK(frame);
+
+ // Create an image resource fetcher and assign it with a call back object.
+ image_fetchers_.push_back(new MultiResolutionImageResourceFetcher(
+ image_url, frame, 0, is_favicon ? WebURLRequest::RequestContextFavicon
+ : WebURLRequest::RequestContextImage,
+ bypass_cache ? WebURLRequest::ReloadBypassingCache
+ : WebURLRequest::UseProtocolCachePolicy,
+ base::Bind(&ImageDownloaderImpl::DidFetchImage, base::Unretained(this),
+ max_image_size, callback)));
+ return true;
+}
+
+void ImageDownloaderImpl::DidFetchImage(
+ uint32_t max_image_size,
+ const DownloadImageCallback& callback,
+ MultiResolutionImageResourceFetcher* fetcher,
+ const std::vector<SkBitmap>& images) {
+ std::vector<SkBitmap> result_images;
+ std::vector<gfx::Size> result_original_image_sizes;
+ FilterAndResizeImagesForMaximalSize(images, max_image_size, &result_images,
+ &result_original_image_sizes);
+
+ ReplyDownloadResult(fetcher->http_status_code(), result_images,
+ result_original_image_sizes, callback);
+
+ // Remove the image fetcher from our pending list. We're in the callback from
+ // MultiResolutionImageResourceFetcher, best to delay deletion.
+ ImageResourceFetcherList::iterator iter =
+ std::find(image_fetchers_.begin(), image_fetchers_.end(), fetcher);
+ if (iter != image_fetchers_.end()) {
+ image_fetchers_.weak_erase(iter);
+ base::MessageLoop::current()->DeleteSoon(FROM_HERE, fetcher);
+ }
+}
+
+void ImageDownloaderImpl::ReplyDownloadResult(
+ int32_t http_status_code,
+ const std::vector<SkBitmap>& result_images,
+ const std::vector<gfx::Size>& result_original_image_sizes,
+ const DownloadImageCallback& callback) {
+ image_downloader::DownloadResultPtr result =
+ image_downloader::DownloadResult::New();
+
+ result->http_status_code = http_status_code;
+ result->images = mojo::Array<skia::BitmapPtr>::From(result_images);
+ result->original_image_sizes =
+ mojo::Array<mojo::SizePtr>::From(result_original_image_sizes);
+
+ callback.Run(result.Pass());
+}
+
+} // namespace content
diff --git a/content/renderer/image_downloader/image_downloader_impl.h b/content/renderer/image_downloader/image_downloader_impl.h
new file mode 100644
index 0000000..1dba6d25
--- /dev/null
+++ b/content/renderer/image_downloader/image_downloader_impl.h
@@ -0,0 +1,88 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_RENDERER_IMAGE_DOWNLOADER_IMAGE_DOWNLOADER_IMPL_H_
+#define CONTENT_RENDERER_IMAGE_DOWNLOADER_IMAGE_DOWNLOADER_IMPL_H_
+
+#include <vector>
+
+#include "base/memory/scoped_vector.h"
+#include "content/common/image_downloader/image_downloader.mojom.h"
+#include "content/public/renderer/render_frame_observer.h"
+#include "third_party/mojo/src/mojo/public/cpp/bindings/strong_binding.h"
+#include "url/gurl.h"
+
+class SkBitmap;
+
+namespace gfx {
+class Size;
+}
+
+namespace content {
+
+class MultiResolutionImageResourceFetcher;
+class RenderFrame;
+
+class ImageDownloaderImpl : public image_downloader::ImageDownloader,
+ public RenderFrameObserver {
+ public:
+ static void CreateMojoService(
+ RenderFrame* render_frame,
+ mojo::InterfaceRequest<image_downloader::ImageDownloader> request);
+
+ private:
+ ImageDownloaderImpl(
+ RenderFrame* render_frame,
+ mojo::InterfaceRequest<image_downloader::ImageDownloader> request);
+ ~ImageDownloaderImpl() override;
+
+ // ImageDownloader methods:
+ void DownloadImage(image_downloader::DownloadRequestPtr req,
+ const DownloadImageCallback& callback) override;
+
+ // Requests to fetch an image. When done, the ImageDownloaderImpl
+ // is notified by way of DidFetchImage. Returns true if the
+ // request was successfully started, false otherwise.
+ // If the image is a favicon, cookies will not be
+ // sent nor accepted during download. If the image has multiple frames, all
+ // the frames whose size <= |max_image_size| are returned. If all of the
+ // frames are larger than |max_image_size|, the smallest frame is resized to
+ // |max_image_size| and is the only result. |max_image_size| == 0 is
+ // interpreted as no max image size.
+ bool FetchImage(const GURL& image_url,
+ bool is_favicon,
+ uint32_t max_image_size,
+ bool bypass_cache,
+ const DownloadImageCallback& callback);
+
+ // This callback is triggered when FetchImage completes, either
+ // succesfully or with a failure. See FetchImage for more
+ // details.
+ void DidFetchImage(uint32_t max_image_size,
+ const DownloadImageCallback& callback,
+ MultiResolutionImageResourceFetcher* fetcher,
+ const std::vector<SkBitmap>& images);
+
+ // Reply download result
+ void ReplyDownloadResult(
+ int32_t http_status_code,
+ const std::vector<SkBitmap>& result_images,
+ const std::vector<gfx::Size>& result_original_image_sizes,
+ const DownloadImageCallback& callback);
+
+ // We use StrongBinding to ensure deletion of "this" when connection closed
+ mojo::StrongBinding<ImageDownloader> binding_;
+
+ typedef ScopedVector<MultiResolutionImageResourceFetcher>
+ ImageResourceFetcherList;
+
+ // ImageResourceFetchers schedule via FetchImage.
+ ImageResourceFetcherList image_fetchers_;
+
+ DISALLOW_COPY_AND_ASSIGN(ImageDownloaderImpl);
+};
+
+} // namespace content
+
+#endif // CONTENT_RENDERER_IMAGE_DOWNLOADER_IMAGE_DOWNLOADER_IMPL_H_
diff --git a/content/renderer/image_loading_helper.cc b/content/renderer/image_loading_helper.cc
deleted file mode 100644
index afd0fee..0000000
--- a/content/renderer/image_loading_helper.cc
+++ /dev/null
@@ -1,207 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/renderer/image_loading_helper.h"
-
-#include "base/bind.h"
-#include "base/message_loop/message_loop.h"
-#include "content/child/image_decoder.h"
-#include "content/common/image_messages.h"
-#include "content/public/renderer/render_frame.h"
-#include "content/renderer/fetchers/multi_resolution_image_resource_fetcher.h"
-#include "net/base/data_url.h"
-#include "skia/ext/image_operations.h"
-#include "third_party/WebKit/public/platform/WebURLRequest.h"
-#include "third_party/WebKit/public/platform/WebVector.h"
-#include "third_party/WebKit/public/web/WebLocalFrame.h"
-#include "third_party/WebKit/public/web/WebView.h"
-#include "ui/gfx/favicon_size.h"
-#include "ui/gfx/geometry/size.h"
-#include "ui/gfx/skbitmap_operations.h"
-#include "url/url_constants.h"
-
-using blink::WebFrame;
-using blink::WebVector;
-using blink::WebURL;
-using blink::WebURLRequest;
-
-namespace {
-
-// Proportionally resizes the |image| to fit in a box of size
-// |max_image_size|.
-SkBitmap ResizeImage(const SkBitmap& image, uint32_t max_image_size) {
- if (max_image_size == 0)
- return image;
- uint32_t max_dimension = std::max(image.width(), image.height());
- if (max_dimension <= max_image_size)
- return image;
- // Proportionally resize the minimal image to fit in a box of size
- // max_image_size.
- return skia::ImageOperations::Resize(
- image,
- skia::ImageOperations::RESIZE_BEST,
- static_cast<uint64_t>(image.width()) * max_image_size / max_dimension,
- static_cast<uint64_t>(image.height()) * max_image_size / max_dimension);
-}
-
-// Filters the array of bitmaps, removing all images that do not fit in a box of
-// size |max_image_size|. Returns the result if it is not empty. Otherwise,
-// find the smallest image in the array and resize it proportionally to fit
-// in a box of size |max_image_size|.
-// Sets |original_image_sizes| to the sizes of |images| before resizing.
-void FilterAndResizeImagesForMaximalSize(
- const std::vector<SkBitmap>& unfiltered,
- uint32_t max_image_size,
- std::vector<SkBitmap>* images,
- std::vector<gfx::Size>* original_image_sizes) {
- images->clear();
- original_image_sizes->clear();
-
- if (!unfiltered.size())
- return;
-
- if (max_image_size == 0)
- max_image_size = std::numeric_limits<uint32_t>::max();
-
- const SkBitmap* min_image = NULL;
- uint32_t min_image_size = std::numeric_limits<uint32_t>::max();
- // Filter the images by |max_image_size|, and also identify the smallest image
- // in case all the images are bigger than |max_image_size|.
- for (std::vector<SkBitmap>::const_iterator it = unfiltered.begin();
- it != unfiltered.end();
- ++it) {
- const SkBitmap& image = *it;
- uint32_t current_size = std::max(it->width(), it->height());
- if (current_size < min_image_size) {
- min_image = ℑ
- min_image_size = current_size;
- }
- if (static_cast<uint32_t>(image.width()) <= max_image_size &&
- static_cast<uint32_t>(image.height()) <= max_image_size) {
- images->push_back(image);
- original_image_sizes->push_back(gfx::Size(image.width(), image.height()));
- }
- }
- DCHECK(min_image);
- if (images->size())
- return;
- // Proportionally resize the minimal image to fit in a box of size
- // |max_image_size|.
- images->push_back(ResizeImage(*min_image, max_image_size));
- original_image_sizes->push_back(
- gfx::Size(min_image->width(), min_image->height()));
-}
-
-} // namespace
-
-namespace content {
-
-ImageLoadingHelper::ImageLoadingHelper(RenderFrame* render_frame)
- : RenderFrameObserver(render_frame) {
-}
-
-ImageLoadingHelper::~ImageLoadingHelper() {
-}
-
-void ImageLoadingHelper::OnDownloadImage(
- int id,
- const GURL& image_url,
- bool is_favicon,
- uint32_t max_image_size,
- bool bypass_cache) {
- std::vector<SkBitmap> result_images;
- std::vector<gfx::Size> result_original_image_sizes;
- if (image_url.SchemeIs(url::kDataScheme)) {
- SkBitmap data_image = ImageFromDataUrl(image_url);
- if (!data_image.empty()) {
- result_images.push_back(ResizeImage(data_image, max_image_size));
- result_original_image_sizes.push_back(
- gfx::Size(data_image.width(), data_image.height()));
- }
- } else {
- if (DownloadImage(id, image_url, is_favicon, max_image_size,
- bypass_cache)) {
- // Will complete asynchronously via ImageLoadingHelper::DidDownloadImage
- return;
- }
- }
-
- Send(new ImageHostMsg_DidDownloadImage(routing_id(),
- id,
- 0,
- image_url,
- result_images,
- result_original_image_sizes));
-}
-
-bool ImageLoadingHelper::DownloadImage(
- int id,
- const GURL& image_url,
- bool is_favicon,
- uint32_t max_image_size,
- bool bypass_cache) {
- // Create an image resource fetcher and assign it with a call back object.
- image_fetchers_.push_back(new MultiResolutionImageResourceFetcher(
- image_url, render_frame()->GetWebFrame(), id,
- is_favicon ? WebURLRequest::RequestContextFavicon
- : WebURLRequest::RequestContextImage,
- bypass_cache ? WebURLRequest::ReloadBypassingCache
- : WebURLRequest::UseProtocolCachePolicy,
- base::Bind(&ImageLoadingHelper::DidDownloadImage, base::Unretained(this),
- max_image_size)));
- return true;
-}
-
-void ImageLoadingHelper::DidDownloadImage(
- uint32_t max_image_size,
- MultiResolutionImageResourceFetcher* fetcher,
- const std::vector<SkBitmap>& images) {
- std::vector<SkBitmap> result_images;
- std::vector<gfx::Size> result_original_image_sizes;
- FilterAndResizeImagesForMaximalSize(images, max_image_size, &result_images,
- &result_original_image_sizes);
-
- // Notify requester of image download status.
- Send(new ImageHostMsg_DidDownloadImage(
- routing_id(),
- fetcher->id(),
- fetcher->http_status_code(),
- fetcher->image_url(),
- result_images,
- result_original_image_sizes));
-
- // Remove the image fetcher from our pending list. We're in the callback from
- // MultiResolutionImageResourceFetcher, best to delay deletion.
- ImageResourceFetcherList::iterator iter =
- std::find(image_fetchers_.begin(), image_fetchers_.end(), fetcher);
- if (iter != image_fetchers_.end()) {
- image_fetchers_.weak_erase(iter);
- base::MessageLoop::current()->DeleteSoon(FROM_HERE, fetcher);
- }
-}
-
-SkBitmap ImageLoadingHelper::ImageFromDataUrl(const GURL& url) const {
- std::string mime_type, char_set, data;
- if (net::DataURL::Parse(url, &mime_type, &char_set, &data) && !data.empty()) {
- // Decode the image using WebKit's image decoder.
- ImageDecoder decoder(gfx::Size(gfx::kFaviconSize, gfx::kFaviconSize));
- const unsigned char* src_data =
- reinterpret_cast<const unsigned char*>(&data[0]);
-
- return decoder.Decode(src_data, data.size());
- }
- return SkBitmap();
-}
-
-bool ImageLoadingHelper::OnMessageReceived(const IPC::Message& message) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(ImageLoadingHelper, message)
- IPC_MESSAGE_HANDLER(ImageMsg_DownloadImage, OnDownloadImage)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
-
- return handled;
-}
-
-} // namespace content
diff --git a/content/renderer/image_loading_helper.h b/content/renderer/image_loading_helper.h
deleted file mode 100644
index d5daf8fa..0000000
--- a/content/renderer/image_loading_helper.h
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_RENDERER_IMAGE_LOADING_HELPER_H_
-#define CONTENT_RENDERER_IMAGE_LOADING_HELPER_H_
-
-#include <string>
-#include <vector>
-
-#include "base/memory/scoped_vector.h"
-#include "content/public/renderer/render_frame_observer.h"
-#include "url/gurl.h"
-
-class SkBitmap;
-
-namespace content {
-
-class MultiResolutionImageResourceFetcher;
-
-// This class deals with image downloading.
-// One instance of ImageLoadingHelper is owned by RenderFrame.
-class ImageLoadingHelper : public RenderFrameObserver {
- public:
- explicit ImageLoadingHelper(RenderFrame* render_frame);
-
- private:
- ~ImageLoadingHelper() override;
-
- // Message handler.
- void OnDownloadImage(int id,
- const GURL& image_url,
- bool is_favicon,
- uint32_t max_image_size,
- bool bypass_cache);
-
- // Requests to download an image. When done, the ImageLoadingHelper
- // is notified by way of DidDownloadImage. Returns true if the
- // request was successfully started, false otherwise. id is used to
- // uniquely identify the request and passed back to the
- // DidDownloadImage method. If the image is a favicon, cookies will not be
- // sent nor accepted during download. If the image has multiple frames, all
- // the frames whose size <= |max_image_size| are returned. If all of the
- // frames are larger than |max_image_size|, the smallest frame is resized to
- // |max_image_size| and is the only result. |max_image_size| == 0 is
- // interpreted as no max image size.
- bool DownloadImage(int id,
- const GURL& image_url,
- bool is_favicon,
- uint32_t max_image_size,
- bool bypass_cache);
-
- // This callback is triggered when DownloadImage completes, either
- // succesfully or with a failure. See DownloadImage for more
- // details.
- void DidDownloadImage(
- uint32_t max_image_size,
- MultiResolutionImageResourceFetcher* fetcher,
- const std::vector<SkBitmap>& images);
-
- // Decodes a data: URL image or returns an empty image in case of failure.
- SkBitmap ImageFromDataUrl(const GURL&) const;
-
- // RenderFrameObserver implementation.
- bool OnMessageReceived(const IPC::Message& message) override;
-
- typedef ScopedVector<MultiResolutionImageResourceFetcher>
- ImageResourceFetcherList;
-
- // ImageResourceFetchers schedule via DownloadImage.
- ImageResourceFetcherList image_fetchers_;
-
- DISALLOW_COPY_AND_ASSIGN(ImageLoadingHelper);
-};
-
-} // namespace content
-
-#endif // CONTENT_RENDERER_IMAGE_LOADING_HELPER_H_
-
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 2e7d77a..afaffcd 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -72,7 +72,7 @@
#include "content/renderer/gpu/gpu_benchmarking_extension.h"
#include "content/renderer/history_controller.h"
#include "content/renderer/history_serialization.h"
-#include "content/renderer/image_loading_helper.h"
+#include "content/renderer/image_downloader/image_downloader_impl.h"
#include "content/renderer/ime_event_guard.h"
#include "content/renderer/internal_document_state_data.h"
#include "content/renderer/manifest/manifest_manager.h"
@@ -741,15 +741,14 @@
#endif
new SharedWorkerRepository(this);
- if (!frame_->parent())
- new ImageLoadingHelper(this);
-
if (is_local_root_ && !render_frame_proxy_) {
// DevToolsAgent is a RenderFrameObserver, and will destruct itself
// when |this| is deleted.
devtools_agent_ = new DevToolsAgent(this);
}
+ RegisterMojoServices();
+
// We delay calling this until we have the WebFrame so that any observer or
// embedder can call GetWebFrame on any RenderFrame.
GetContentClient()->renderer()->RenderFrameCreated(this);
@@ -5008,4 +5007,13 @@
return cdm_factory_.get();
}
+void RenderFrameImpl::RegisterMojoServices() {
+ // Only main frame have ImageDownloader service.
+ if (!frame_->parent()) {
+ GetServiceRegistry()->AddService<image_downloader::ImageDownloader>(
+ base::Bind(&ImageDownloaderImpl::CreateMojoService,
+ base::Unretained(this)));
+ }
+}
+
} // namespace content
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index d6bcafd..4259baa 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -823,6 +823,8 @@
media::CdmFactory* GetCdmFactory();
+ void RegisterMojoServices();
+
// Stores the WebLocalFrame we are associated with. This is null from the
// constructor until SetWebFrame is called, and it is null after
// frameDetached is called until destruction (which is asynchronous in the
diff --git a/content/test/test_web_contents.cc b/content/test/test_web_contents.cc
index 65bb578..f93024c 100644
--- a/content/test/test_web_contents.cc
+++ b/content/test/test_web_contents.cc
@@ -64,6 +64,15 @@
GetRenderManager()->pending_frame_host());
}
+int TestWebContents::DownloadImage(const GURL& url,
+ bool is_favicon,
+ uint32_t max_bitmap_size,
+ bool bypass_cache,
+ const ImageDownloadCallback& callback) {
+ static int g_next_image_download_id = 0;
+ return ++g_next_image_download_id;
+}
+
void TestWebContents::TestDidNavigate(RenderFrameHost* render_frame_host,
int page_id,
int nav_entry_id,
diff --git a/content/test/test_web_contents.h b/content/test/test_web_contents.h
index 798a54d..fd3a3be4 100644
--- a/content/test/test_web_contents.h
+++ b/content/test/test_web_contents.h
@@ -35,6 +35,12 @@
// WebContentsImpl overrides (returning the same values, but in Test* types)
TestRenderFrameHost* GetMainFrame() override;
TestRenderViewHost* GetRenderViewHost() const override;
+ // Overrides to avoid establishing Mojo connection with renderer process.
+ int DownloadImage(const GURL& url,
+ bool is_favicon,
+ uint32_t max_bitmap_size,
+ bool bypass_cache,
+ const ImageDownloadCallback& callback) override;
// WebContentsTester implementation.
void CommitPendingNavigation() override;
diff --git a/ipc/ipc_message_start.h b/ipc/ipc_message_start.h
index bd47f20..b37c5c9 100644
--- a/ipc/ipc_message_start.h
+++ b/ipc/ipc_message_start.h
@@ -53,7 +53,6 @@
ExtensionMsgStart,
VideoCaptureMsgStart,
QuotaMsgStart,
- ImageMsgStart,
TextInputClientMsgStart,
ChromeUtilityMsgStart,
MediaStreamMsgStart,
diff --git a/mojo/mojo_base.gyp b/mojo/mojo_base.gyp
index 70948a1..1e3b181 100644
--- a/mojo/mojo_base.gyp
+++ b/mojo/mojo_base.gyp
@@ -84,6 +84,25 @@
],
},
{
+ # GN version: //mojo/converters/geometry
+ 'target_name': 'mojo_geometry_lib',
+ 'type': '<(component)',
+ 'defines': [
+ 'MOJO_GEOMETRY_IMPLEMENTATION',
+ ],
+ 'dependencies': [
+ '../ui/mojo/geometry/mojo_bindings.gyp:mojo_geometry_bindings',
+ '../ui/gfx/gfx.gyp:gfx_geometry',
+ 'mojo_environment_chromium',
+ '<(mojo_system_for_component)',
+ ],
+ 'sources': [
+ 'converters/geometry/geometry_type_converters.cc',
+ 'converters/geometry/geometry_type_converters.h',
+ 'converters/geometry/mojo_geometry_export.h',
+ ],
+ },
+ {
# GN version: //mojo/common:mojo_common_unittests
'target_name': 'mojo_common_unittests',
'type': 'executable',
diff --git a/ui/mojo/geometry/mojo_bindings.gyp b/ui/mojo/geometry/mojo_bindings.gyp
new file mode 100644
index 0000000..e5bfe67
--- /dev/null
+++ b/ui/mojo/geometry/mojo_bindings.gyp
@@ -0,0 +1,27 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ # GN version: //ui/mojo/geometry
+ 'target_name': 'mojo_geometry_bindings_mojom',
+ 'type': 'none',
+ 'variables': {
+ 'mojom_files': [
+ 'geometry.mojom',
+ ],
+ },
+ 'includes': [ '../../../third_party/mojo/mojom_bindings_generator_explicit.gypi' ],
+ },
+ {
+ 'target_name': 'mojo_geometry_bindings',
+ 'type': 'static_library',
+ 'dependencies': [
+ 'mojo_geometry_bindings_mojom',
+ '../../../third_party/mojo/mojo_public.gyp:mojo_cpp_bindings',
+ ],
+ },
+ ],
+}