summaryrefslogtreecommitdiffstats
path: root/chrome/browser/icon_loader.cc
diff options
context:
space:
mode:
authorinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-26 23:55:29 +0000
committerinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-26 23:55:29 +0000
commit09911bf300f1a419907a9412154760efd0b7abc3 (patch)
treef131325fb4e2ad12c6d3504ab75b16dd92facfed /chrome/browser/icon_loader.cc
parent586acc5fe142f498261f52c66862fa417c3d52d2 (diff)
downloadchromium_src-09911bf300f1a419907a9412154760efd0b7abc3.zip
chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.gz
chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.bz2
Add chrome to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/icon_loader.cc')
-rw-r--r--chrome/browser/icon_loader.cc303
1 files changed, 303 insertions, 0 deletions
diff --git a/chrome/browser/icon_loader.cc b/chrome/browser/icon_loader.cc
new file mode 100644
index 0000000..822bce3
--- /dev/null
+++ b/chrome/browser/icon_loader.cc
@@ -0,0 +1,303 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "chrome/browser/icon_loader.h"
+
+#include <windows.h>
+#include <shellapi.h>
+
+#include "base/file_util.h"
+#include "base/gfx/size.h"
+#include "base/message_loop.h"
+#include "base/ref_counted.h"
+#include "base/string_util.h"
+#include "base/task.h"
+#include "base/thread.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/common/gfx/icon_util.h"
+
+#include "SkBitmap.h"
+
+namespace {
+class IconLoaderProcessor :
+ public base::RefCountedThreadSafe<IconLoaderProcessor> {
+ public:
+ explicit IconLoaderProcessor(IconLoader* target)
+ : target_(target),
+ bitmap_(NULL),
+ small_icon_(NULL),
+ large_icon_(NULL),
+ loading_from_resource_(target->loading_from_resource_),
+ icon_type_(target->icon_type_),
+ icon_size_(target->icon_size_) {
+ DCHECK(target);
+ path_ = target->path_;
+ target_message_loop_ = MessageLoop::current();
+ }
+
+ virtual ~IconLoaderProcessor() {
+ delete bitmap_;
+ if (small_icon_)
+ ::DestroyIcon(small_icon_);
+ if (large_icon_) {
+ ::DestroyIcon(large_icon_);
+ }
+ }
+
+ // Loads the icon with the specified dimensions.
+ HICON LoadSizedIcon(int width, int height) {
+ return static_cast<HICON>(LoadImage(NULL,
+ path_.c_str(),
+ width, height,
+ IMAGE_ICON,
+ LR_LOADTRANSPARENT | LR_LOADFROMFILE));
+ }
+
+ // Invoked from the original thread.
+ void Cancel() {
+ target_ = NULL;
+ }
+
+ // Invoked in the file thread. Never access target_ from this method.
+ void ReadIcon() {
+ if (loading_from_resource_)
+ ReadIconFromFileResource();
+ else
+ ReadIconFile();
+
+ target_message_loop_->PostTask(FROM_HERE, NewRunnableMethod(
+ this, &IconLoaderProcessor::NotifyFetcher));
+ }
+
+ // Invoked on the file thread to read a normal .ico file.
+ void ReadIconFile() {
+ // We start by loading the same icon image in the two desired dimensions,
+ // based on the dimensions we get back when we query the system.
+ int small_width = ::GetSystemMetrics(SM_CXSMICON);
+ int small_height = ::GetSystemMetrics(SM_CYSMICON);
+ int large_width = ::GetSystemMetrics(SM_CXICON);
+ int large_height = ::GetSystemMetrics(SM_CYICON);
+ small_icon_ = LoadSizedIcon(small_width, small_height);
+ large_icon_ = LoadSizedIcon(large_width, large_height);
+
+ // TODO(idana): Bug 991356. Currently, if the client asks for the icon in
+ // the form of an SkBitmap object, then we try converting the large icon
+ // into an SkBitmap, if the icon was successfully loaded. If the large icon
+ // is not available, we convert the small icon. The problem with converting
+ // the small or the large icon is that the resulting image is going to have
+ // the same dimensions as the icon (for example, 32X32 pixels). This can be
+ // problematic if, for example, the client tries to display the resulting
+ // image as a thumbnail. This will result in the client streching the
+ // bitmap from 32X32 to 128X128 which will decrease the image's quality.
+ //
+ // Since it is possible for web applications to define large .PNG images as
+ // their icons, the resulting .ico files created for these web applications
+ // contain icon images in sizes much larger the the system default sizes
+ // for icons. We can solve the aforementioned limitation by allowing the
+ // client to specify the size of the resulting image, when requesting an
+ // SkBitmap. The IconLoader code can then load a larger icon from the .ico
+ // file.
+ //
+ // Note that currently the components in Chrome that deal with SkBitmaps
+ // that represent application icons use the images to display icon size
+ // images and therefore the limitation above doesn't really manifest
+ // itself.
+ HICON icon_to_convert = NULL;
+ gfx::Size s;
+ if (icon_type_ == IconLoader::SK_BITMAP) {
+ if (large_icon_) {
+ icon_to_convert = large_icon_;
+ s.SetSize(large_width, large_height);
+ } else if (small_icon_) {
+ icon_to_convert = small_icon_;
+ s.SetSize(small_width, small_height);
+ }
+ }
+
+ if (icon_to_convert) {
+ bitmap_ = IconUtil::CreateSkBitmapFromHICON(icon_to_convert, s);
+ DCHECK(bitmap_);
+ if (small_icon_)
+ ::DestroyIcon(small_icon_);
+ if (large_icon_)
+ ::DestroyIcon(large_icon_);
+
+ small_icon_ = NULL;
+ large_icon_ = NULL;
+ }
+ }
+
+ void ReadIconFromFileResource() {
+ int size = 0;
+ switch (icon_size_) {
+ case IconLoader::SMALL:
+ size = SHGFI_SMALLICON;
+ break;
+ case IconLoader::NORMAL:
+ size = 0;
+ break;
+ case IconLoader::LARGE:
+ size = SHGFI_LARGEICON;
+ break;
+ default:
+ NOTREACHED();
+ }
+ SHFILEINFO file_info = { 0 };
+ if (!SHGetFileInfo(path_.c_str(), FILE_ATTRIBUTE_NORMAL, &file_info,
+ sizeof(SHFILEINFO),
+ SHGFI_ICON | size | SHGFI_USEFILEATTRIBUTES))
+ return;
+
+ ICONINFO icon_info = { 0 };
+ BITMAP bitmap_info = { 0 };
+
+ BOOL r = ::GetIconInfo(file_info.hIcon, &icon_info);
+ DCHECK(r);
+ r = ::GetObject(icon_info.hbmMask, sizeof(bitmap_info), &bitmap_info);
+ DCHECK(r);
+
+ gfx::Size icon_size(bitmap_info.bmWidth, bitmap_info.bmHeight);
+ bitmap_ = IconUtil::CreateSkBitmapFromHICON(file_info.hIcon, icon_size);
+ }
+
+ // Invoked in the target thread.
+ void NotifyFetcher() {
+ if (target_) {
+ switch (target_->icon_type_) {
+ case IconLoader::SK_BITMAP:
+ if (target_->OnLoadComplete(bitmap_)) {
+ // Receiver took ownership of the bitmap.
+ bitmap_ = NULL;
+ }
+ break;
+ case IconLoader::WINDOWS_HICON:
+ if (target_->OnLoadComplete(small_icon_, large_icon_)) {
+ // Receiver took ownership of the icons.
+ small_icon_ = NULL;
+ large_icon_ = NULL;
+ }
+ break;
+ default:
+ NOTREACHED();
+ }
+ }
+ }
+
+ private:
+ // The message loop object of the thread in which we notify the delegate.
+ MessageLoop* target_message_loop_;
+
+ // The corresponding file fetcher or NULL if this task has been canceled.
+ IconLoader* target_;
+
+ // The path of the file.
+ std::wstring path_;
+
+ // Fields from IconLoader that we need to copy as we cannot access them
+ // directly from the target_ in a thread-safe way.
+ bool loading_from_resource_;
+ IconLoader::IconSize icon_size_;
+ IconLoader::IconType icon_type_;
+
+ // The result bitmap.
+ SkBitmap* bitmap_;
+
+ // The result small icon.
+ HICON small_icon_;
+
+ // The result large icon.
+ HICON large_icon_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(IconLoaderProcessor);
+};
+}
+
+// static
+IconLoader* IconLoader::CreateIconLoaderForFile(const std::wstring& path,
+ IconType icon_type,
+ Delegate* delegate) {
+ // Note: the icon size is unused in this case.
+ return new IconLoader(path, icon_type, false, IconLoader::NORMAL, delegate);
+}
+
+// static
+IconLoader* IconLoader::CreateIconLoaderForFileResource(
+ const std::wstring& path, IconSize size, Delegate* delegate) {
+ return new IconLoader(path, IconLoader::SK_BITMAP, true, size, delegate);
+}
+
+IconLoader::IconLoader(const std::wstring& path,
+ IconType type,
+ bool from_resource,
+ IconSize size,
+ Delegate* delegate)
+ : path_(path),
+ icon_type_(type),
+ loading_from_resource_(from_resource),
+ icon_size_(size),
+ delegate_(delegate),
+ processor_(NULL) {
+ DCHECK(delegate_);
+}
+
+IconLoader::~IconLoader() {
+ Cancel();
+}
+
+void IconLoader::Start() {
+ processor_ = new IconLoaderProcessor(this);
+ processor_->AddRef();
+ g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE,
+ NewRunnableMethod(processor_, &IconLoaderProcessor::ReadIcon));
+}
+
+void IconLoader::Cancel() {
+ if (processor_) {
+ processor_->Cancel();
+ processor_->Release();
+ processor_ = NULL;
+ }
+ delegate_ = NULL;
+}
+
+bool IconLoader::OnLoadComplete(SkBitmap* bitmap) {
+ if (delegate_) {
+ return delegate_->OnSkBitmapLoaded(this, bitmap);
+ // We are likely deleted after this point.
+ }
+ return false;
+}
+
+bool IconLoader::OnLoadComplete(HICON small_icon, HICON large_icon) {
+ if (delegate_) {
+ return delegate_->OnHICONLoaded(this, small_icon, large_icon);
+ // We are likely deleted after this point.
+ }
+ return false;
+}