diff options
author | estade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-25 23:48:44 +0000 |
---|---|---|
committer | estade@chromium.org <estade@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-06-25 23:48:44 +0000 |
commit | cd43e6e776b2283f555f1b59bef06d135504f66f (patch) | |
tree | 1d1a074deebfef562a534f79bd0128ed2aa48ba1 | |
parent | 05d94e79f64a6562ea646e5b3f2e9c6e7b1cc011 (diff) | |
download | chromium_src-cd43e6e776b2283f555f1b59bef06d135504f66f.zip chromium_src-cd43e6e776b2283f555f1b59bef06d135504f66f.tar.gz chromium_src-cd43e6e776b2283f555f1b59bef06d135504f66f.tar.bz2 |
Add a function to ResourceBundle to allow loading images that will mirror in RTL. Use this function for custom buttons and for the Off the Record avatar.
for reference, this will be a bit different than Views, which does it per class rather than per image: http://dev.chromium.org/developers/design-documents/ui-mirroring-infrastructure
Review URL: http://codereview.chromium.org/147157
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@19309 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | app/resource_bundle.h | 10 | ||||
-rw-r--r-- | app/resource_bundle_linux.cc | 43 | ||||
-rw-r--r-- | chrome/browser/gtk/browser_titlebar.cc | 61 | ||||
-rw-r--r-- | chrome/browser/gtk/browser_titlebar.h | 3 | ||||
-rw-r--r-- | chrome/browser/gtk/custom_button.cc | 16 | ||||
-rw-r--r-- | chrome/browser/gtk/custom_button.h | 2 |
6 files changed, 63 insertions, 72 deletions
diff --git a/app/resource_bundle.h b/app/resource_bundle.h index ed17616..c718b9a 100644 --- a/app/resource_bundle.h +++ b/app/resource_bundle.h @@ -123,6 +123,16 @@ class ResourceBundle { // pointer to a shared empty placeholder bitmap so it will be visible what // is missing. GdkPixbuf* GetPixbufNamed(int resource_id); + + // As above, but flips it in RTL locales. Note that this will add the flipped + // pixbuf to the same cache used by GetPixbufNamed(). + GdkPixbuf* GetRTLEnabledPixbufNamed(int resource_id); + + private: + // Shared implementation for the above two functions. + GdkPixbuf* GetPixbufImpl(int resource_id, bool rtl_enabled); + + public: #endif // TODO(glen): Move these into theme provider (dialogs still depend on diff --git a/app/resource_bundle_linux.cc b/app/resource_bundle_linux.cc index 9d46fb7..47d893d 100644 --- a/app/resource_bundle_linux.cc +++ b/app/resource_bundle_linux.cc @@ -25,7 +25,7 @@ namespace { // Convert the raw image data into a GdkPixbuf. The GdkPixbuf that is returned // has a ref count of 1 so the caller must call g_object_unref to free the // memory. -GdkPixbuf* LoadPixbuf(std::vector<unsigned char>& data) { +GdkPixbuf* LoadPixbuf(std::vector<unsigned char>& data, bool rtl_enabled) { ScopedGObject<GdkPixbufLoader>::Type loader(gdk_pixbuf_loader_new()); bool ok = gdk_pixbuf_loader_write(loader.get(), static_cast<guint8*>(data.data()), data.size(), NULL); @@ -40,12 +40,18 @@ GdkPixbuf* LoadPixbuf(std::vector<unsigned char>& data) { if (!pixbuf) return NULL; - // The pixbuf is owned by the loader, so add a ref so when we delete the - // loader (when the ScopedGObject goes out of scope), the pixbuf still - // exists. - g_object_ref(pixbuf); - - return pixbuf; + if ((l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT) && + rtl_enabled) { + // |pixbuf| will get unreffed and destroyed (see below). The returned value + // has ref count 1. + return gdk_pixbuf_flip(pixbuf, TRUE); + } else { + // The pixbuf is owned by the loader, so add a ref so when we delete the + // loader (when the ScopedGObject goes out of scope), the pixbuf still + // exists. + g_object_ref(pixbuf); + return pixbuf; + } } } // namespace @@ -158,11 +164,14 @@ string16 ResourceBundle::GetLocalizedString(int message_id) { return msg; } -GdkPixbuf* ResourceBundle::GetPixbufNamed(int resource_id) { +GdkPixbuf* ResourceBundle::GetPixbufImpl(int resource_id, bool rtl_enabled) { + // Use the negative |resource_id| for the key for BIDI-aware images. + int key = rtl_enabled ? -resource_id : resource_id; + // Check to see if we already have the pixbuf in the cache. { AutoLock lock_scope(lock_); - GdkPixbufMap::const_iterator found = gdk_pixbufs_.find(resource_id); + GdkPixbufMap::const_iterator found = gdk_pixbufs_.find(key); if (found != gdk_pixbufs_.end()) return found->second; } @@ -170,19 +179,19 @@ GdkPixbuf* ResourceBundle::GetPixbufNamed(int resource_id) { std::vector<unsigned char> data; LoadImageResourceBytes(resource_id, &data); - GdkPixbuf* pixbuf = LoadPixbuf(data); + GdkPixbuf* pixbuf = LoadPixbuf(data, rtl_enabled); // We loaded successfully. Cache the pixbuf. if (pixbuf) { AutoLock lock_scope(lock_); // Another thread raced us, and has already cached the pixbuf. - if (gdk_pixbufs_.count(resource_id)) { + if (gdk_pixbufs_.count(key)) { g_object_unref(pixbuf); - return gdk_pixbufs_[resource_id]; + return gdk_pixbufs_[key]; } - gdk_pixbufs_[resource_id] = pixbuf; + gdk_pixbufs_[key] = pixbuf; return pixbuf; } @@ -206,3 +215,11 @@ GdkPixbuf* ResourceBundle::GetPixbufNamed(int resource_id) { return empty_bitmap; } } + +GdkPixbuf* ResourceBundle::GetPixbufNamed(int resource_id) { + return GetPixbufImpl(resource_id, false); +} + +GdkPixbuf* ResourceBundle::GetRTLEnabledPixbufNamed(int resource_id) { + return GetPixbufImpl(resource_id, true); +} diff --git a/chrome/browser/gtk/browser_titlebar.cc b/chrome/browser/gtk/browser_titlebar.cc index 7ebf916..2efc2bf 100644 --- a/chrome/browser/gtk/browser_titlebar.cc +++ b/chrome/browser/gtk/browser_titlebar.cc @@ -52,7 +52,7 @@ GdkPixbuf* GetOTRAvatar() { static GdkPixbuf* otr_avatar = NULL; if (!otr_avatar) { ResourceBundle& rb = ResourceBundle::GetSharedInstance(); - otr_avatar = rb.GetPixbufNamed(IDR_OTR_ICON); + otr_avatar = rb.GetRTLEnabledPixbufNamed(IDR_OTR_ICON); } return otr_avatar; } @@ -69,12 +69,12 @@ void BrowserTitlebar::Init() { // The widget hierarchy is shown below. // // +- HBox (container_) -----------------------------------------------------+ - // |+- Fixed -++- Alignment --------------++- VBox (titlebar_buttons_box_) -+| - // ||(spy_guy)|| (titlebar_alignment_) ||+- HBox -----------------------+|| - // || || |||+- button -++- button -+ ||| - // || ||+- TabStripGtk ---------+|||| minimize || restore | ... ||| - // || )8\ ||| tab tab tabclose ||||+----------++----------+ ||| - // || ||+------------------------+||+------------------------------+|| + // |+- Algn. -++- Alignment --------------++- VBox (titlebar_buttons_box_) -+| + // ||+ Image +|| (titlebar_alignment_) ||+- HBox -----------------------+|| + // |||spy_guy||| |||+- button -++- button -+ ||| + // ||| |||+- TabStripGtk ---------+|||| minimize || restore | ... ||| + // ||| )8\ |||| tab tab tabclose ||||+----------++----------+ ||| + // ||+-------+||+------------------------+||+------------------------------+|| // |+---------++--------------------------++--------------------------------+| // +-------------------------------------------------------------------------+ container_ = gtk_hbox_new(FALSE, 0); @@ -83,11 +83,16 @@ void BrowserTitlebar::Init() { G_CALLBACK(OnWindowStateChanged), this); if (browser_window_->browser()->profile()->IsOffTheRecord()) { - GtkWidget* spy_guy = gtk_fixed_new(); - gtk_widget_set_size_request(spy_guy, gdk_pixbuf_get_width(GetOTRAvatar()) + - 2 * kOTRSideSpacing, -1); - gtk_box_pack_start(GTK_BOX(container_), spy_guy, FALSE, FALSE, 0); - g_signal_connect(spy_guy, "expose-event", G_CALLBACK(OnAvatarExpose), this); + GtkWidget* spy_guy = gtk_image_new_from_pixbuf(GetOTRAvatar()); + gtk_misc_set_alignment(GTK_MISC(spy_guy), 0.0, 1.0); + GtkWidget* spy_frame = gtk_alignment_new(0.0, 0.0, 1.0, 1.0); + // We use this alignment rather than setting padding on the GtkImage because + // the image's intrinsic padding doesn't clip the pixbuf during painting. + gtk_alignment_set_padding(GTK_ALIGNMENT(spy_frame), kOTRMaximizedTopSpacing, + kOTRBottomSpacing, kOTRSideSpacing, kOTRSideSpacing); + gtk_widget_set_size_request(spy_guy, -1, 0); + gtk_container_add(GTK_CONTAINER(spy_frame), spy_guy); + gtk_box_pack_start(GTK_BOX(container_), spy_frame, FALSE, FALSE, 0); } // We use an alignment to control the titlebar height. @@ -248,35 +253,3 @@ void BrowserTitlebar::ExecuteCommand(int command_id) { NOTREACHED(); } } - -// static -gboolean BrowserTitlebar::OnAvatarExpose( - GtkWidget* widget, GdkEventExpose* event, BrowserTitlebar* titlebar) { - cairo_t* cairo_context = gdk_cairo_create(GDK_DRAWABLE(widget->window)); - cairo_translate(cairo_context, widget->allocation.x, widget->allocation.y); - - if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT) { - cairo_translate(cairo_context, widget->allocation.width, 0.0f); - cairo_scale(cairo_context, -1.0f, 1.0f); - } - - // Set up a clip rect. - const int clip_x = kOTRSideSpacing; - const int clip_width = gdk_pixbuf_get_width(GetOTRAvatar()); - const int clip_y = kOTRMaximizedTopSpacing; - const int clip_height = widget->allocation.height - kOTRMaximizedTopSpacing - - kOTRBottomSpacing; - cairo_rectangle(cairo_context, clip_x, clip_y, clip_width, clip_height); - cairo_clip(cairo_context); - - // Drawing origin, which is calculated relative to the bottom. - const int x = clip_x; - const int y = widget->allocation.height - kOTRBottomSpacing - - gdk_pixbuf_get_height(GetOTRAvatar()); - - gdk_cairo_set_source_pixbuf(cairo_context, GetOTRAvatar(), x, y); - cairo_paint(cairo_context); - cairo_destroy(cairo_context); - - return TRUE; -} diff --git a/chrome/browser/gtk/browser_titlebar.h b/chrome/browser/gtk/browser_titlebar.h index 12c4ab8..1dc8121 100644 --- a/chrome/browser/gtk/browser_titlebar.h +++ b/chrome/browser/gtk/browser_titlebar.h @@ -66,9 +66,6 @@ class BrowserTitlebar : public MenuGtk::Delegate { virtual bool IsItemChecked(int command_id) const; virtual void ExecuteCommand(int command_id); - static gboolean OnAvatarExpose( - GtkWidget* widget, GdkEventExpose* event, BrowserTitlebar* titlebar); - // Pointers to the browser window that owns us and it's GtkWindow. BrowserWindowGtk* browser_window_; GtkWindow* window_; diff --git a/chrome/browser/gtk/custom_button.cc b/chrome/browser/gtk/custom_button.cc index bed3128..e047202 100644 --- a/chrome/browser/gtk/custom_button.cc +++ b/chrome/browser/gtk/custom_button.cc @@ -18,13 +18,15 @@ CustomDrawButtonBase::CustomDrawButtonBase( : paint_override_(-1) { // Load the button images from the resource bundle. ResourceBundle& rb = ResourceBundle::GetSharedInstance(); - pixbufs_[GTK_STATE_NORMAL] = normal_id ? rb.GetPixbufNamed(normal_id) : NULL; - pixbufs_[GTK_STATE_ACTIVE] = active_id ? rb.GetPixbufNamed(active_id) : NULL; + pixbufs_[GTK_STATE_NORMAL] = + normal_id ? rb.GetRTLEnabledPixbufNamed(normal_id) : NULL; + pixbufs_[GTK_STATE_ACTIVE] = + active_id ? rb.GetRTLEnabledPixbufNamed(active_id) : NULL; pixbufs_[GTK_STATE_PRELIGHT] = - highlight_id ? rb.GetPixbufNamed(highlight_id) : NULL; + highlight_id ? rb.GetRTLEnabledPixbufNamed(highlight_id) : NULL; pixbufs_[GTK_STATE_SELECTED] = NULL; pixbufs_[GTK_STATE_INSENSITIVE] = - depressed_id ? rb.GetPixbufNamed(depressed_id) : NULL; + depressed_id ? rb.GetRTLEnabledPixbufNamed(depressed_id) : NULL; } CustomDrawButtonBase::~CustomDrawButtonBase() { @@ -43,12 +45,6 @@ gboolean CustomDrawButtonBase::OnExpose(GtkWidget* widget, GdkEventExpose* e) { cairo_t* cairo_context = gdk_cairo_create(GDK_DRAWABLE(widget->window)); cairo_translate(cairo_context, widget->allocation.x, widget->allocation.y); - - if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT) { - cairo_translate(cairo_context, widget->allocation.width, 0.0f); - cairo_scale(cairo_context, -1.0f, 1.0f); - } - gdk_cairo_set_source_pixbuf(cairo_context, pixbuf, 0, 0); cairo_paint(cairo_context); cairo_destroy(cairo_context); diff --git a/chrome/browser/gtk/custom_button.h b/chrome/browser/gtk/custom_button.h index 10cd1e6..0e54732 100644 --- a/chrome/browser/gtk/custom_button.h +++ b/chrome/browser/gtk/custom_button.h @@ -13,8 +13,6 @@ #include "base/scoped_ptr.h" #include "chrome/common/owned_widget_gtk.h" -class NineBox; - // These classes implement two kinds of custom-drawn buttons. They're // used on the toolbar and the bookmarks bar. |