diff options
author | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 23:55:29 +0000 |
---|---|---|
committer | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 23:55:29 +0000 |
commit | 09911bf300f1a419907a9412154760efd0b7abc3 (patch) | |
tree | f131325fb4e2ad12c6d3504ab75b16dd92facfed /chrome/browser/icon_loader.cc | |
parent | 586acc5fe142f498261f52c66862fa417c3d52d2 (diff) | |
download | chromium_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.cc | 303 |
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; +} |