~ubuntu-branches/ubuntu/natty/firefox/natty-updates

« back to all changes in this revision

Viewing changes to debian/globalmenu/components/src/uGlobalMenuObject.cpp

  • Committer: Package Import Robot
  • Author(s): Chris Coulson, Chris Coulson, Jamie Strandboge
  • Date: 2012-06-01 18:31:55 UTC
  • mfrom: (1.2.7)
  • Revision ID: package-import@ubuntu.com-20120601183155-4q12f7adnllql614
Tags: 13.0+build1-0ubuntu0.11.04.1
* New upstream stable release (FIREFOX_13_0_BUILD1)
  - see LP: #1007495 for USN information

[ Chris Coulson <chris.coulson@canonical.com> ]
* Update globalmenu-extension to 3.2.3
  - Reduce our memory footprint a bit, which wasn't really a lot anyway
  - Avoid the use of the component manager for accessing commonly used
    services, where "commonly used" means "accessed when building every
    menu item". This should save some CPU cycles when building or
    refreshing menus
  - Try to recycle menuitems when they are removed from a menu by
    adding contiguous blocks of removed items to a "free list" which
    is emptied asynchronously, and reusing the items in this list when
    new items are added in place of the removed items. This means that
    refreshing the history menu contents when the menu is opened no
    longer alters the menu structure, but results in a shifting of
    properties between existing nodes instead. This has a few benefits:
    + With no layout changes, unity-panel-service doesn't request
      the entire menu structure, which significantly reduces dbus traffic
      and makes it much faster to refresh the menu contents
    + The size of the menu doesn't change when it is refreshed, which
      eliminates the flicker that used to occur when opening the history
      menu.
  - Remove all use of the global observer service for sending our own
    internal notifications around
  - Clean up the way we ensure that the correct edit commands are
    enabled by just installing our own onpopupshowing handler rather
    than using an additional notification to fix things up after the
    default handler runs
  - Get rid of a static initializer
  - Don't support older than Firefox 11
  - Fix some GError leaks
  - Hide the internal menu when creating a native menu, rather than
    waiting for confirmation that the native menu is registered
    successfully. We don't try to create a native menu if we don't
    find a menu service to register the menu with anyway
  - Keep menu contents updated whilst the menu is open, rather than
    just whilst it is opening
  - Fix LP: #915888 - Handling of checkbox menuitems with a command
    node is wrong
* Refresh build-depends:
  - Bump minimum GTK version to 2.14 as we build with GIO support
  - Add minimum requirement for glib (2.18)
  - Drop libidl-dev, this doesn't appear to be needed now
  - Bump minimum NSPR version to 4.9.0 for --enable-system-nspr builds
  - Bump minimum sqlite version to 3.7.10 for --enable-system-sqlite
    builds
  - Bump minimum NSS version to 3.13.2 for --enable-system-nss builds
* Refresh patches:
  - update debian/patches/ubuntu-ua-string-changes.patch
  - update debian/patches/ubuntu-codes-google.patch
  - update debian/patches/firefox-kde.patch
  - update debian/patches/mozilla-kde.patch
  - update debian/patches/dont-include-hyphenation-patterns.patch
* Clean up the file exclude list and add comments for excluded files
  - update debian/build/create-tarball.py
* Make it easy to run Firefox in valgrind for builds that are compiled
  with explicit valgrind support
  - update debian/firefox.sh.in
* Bump debhelper compat to 7
  - update debian/apport/blacklist.in
  - update debian/apport/source_firefox.py.in
  - update debian/compat
  - update debian/config/mozconfig.in
  - update debian/control.in
  - update debian/firefox-dev.install.in
  - update debian/firefox-dev.links.in
  - update debian/firefox-globalmenu.dirs.in
  - update debian/firefox-gnome-support.install.in
  - update debian/firefox.dirs.in
  - update debian/firefox.install.in
  - update debian/firefox.links.in
  - update debian/firefox.postinst.in
  - update debian/firefox.preinst.in
  - update debian/firefox.sh.in
  - update debian/pkgconfig/libxul.pc.in
  - update debian/pkgconfig/mozilla-nspr.pc.in
  - update debian/pkgconfig/mozilla-plugin.pc.in
  - update debian/rules
  - update debian/usr.bin.firefox.apparmor.10.04
  - update debian/usr.bin.firefox.apparmor.10.10
  - update debian/usr.bin.firefox.apparmor.11.04
  - update debian/usr.bin.firefox.apparmor.9.10
* Override 2 embedded-library lintian errors
  - update debian/firefox.lintian-overrides.in
* Drop debian/patches/distro-locale-searchplugins after landing of
  bmo: #515232
* Don't hardcode general.useragent.locale to en-US, now that it's used
  for searchplugin localization. This means we can drop this pref from
  ubufox
  - add debian/patches/dont-override-general-useragent-locale.patch
  - update debian/patches/series
* Drop patches fixed upstream
  - remove debian/patches/no-sps-profiler-on-unsupported-archs.patch
  - remove debian/patches/avoid-dbus-roundtrip-for-httpchannel.patch
  - update debian/patches/series
* Apport hook improvements:
  - Add support for reporting preference defaults that are set by extensions
  - When reporting preferences, record the source of each preference
  - Report plugin packages for plugins that are installed with the
    package manager
  - Add some addon manager related prefs to the whitelist
  - Display additional metadata in the extensions report
  - Take "default-to-compatible" in to account when determining whether
    the user is running incompatible addons
  - Attach submitted crash ID's to bug reports
  - Report if files in the profile folder have broken permissions
* Update compare-locales to 0.9.5
* Fix make-makefile test failure when the build directory contains
  perl regexp control characters
  - add debian/patches/make-makefile-test-fix.patch
  - update debian/patches/series
* Fix for NSS libs not being signed, breaking FIPS
  - update debian/rules

[ Jamie Strandboge <jamie@ubuntu.com> ]
* adjust apparmor profile to deny reads to @{PROC}/[0-9]*/net/dev. Patch 
  thanks to James Troup (LP: #955066)
* adjust apparmor profile to deny reads to @{PROC}/[0-9]*/net/wireless.
  Patch thanks to James Troup (LP: #974141)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
 
/* ***** BEGIN LICENSE BLOCK *****
3
 
 *       Version: MPL 1.1/GPL 2.0/LGPL 2.1
4
 
 *
5
 
 * The contents of this file are subject to the Mozilla Public License Version
6
 
 * 1.1 (the "License"); you may not use this file except in compliance with
7
 
 * the License. You may obtain a copy of the License at
8
 
 * http://www.mozilla.org/MPL/
9
 
 * 
10
 
 * Software distributed under the License is distributed on an "AS IS" basis,
11
 
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12
 
 * for the specific language governing rights and limitations under the
13
 
 * License.
14
 
 *
15
 
 * The Original Code is globalmenu-extension.
16
 
 *
17
 
 * The Initial Developer of the Original Code is
18
 
 * Canonical Ltd.
19
 
 * Portions created by the Initial Developer are Copyright (C) 2010
20
 
 * the Initial Developer. All Rights Reserved.
21
 
 *
22
 
 * Contributor(s):
23
 
 * Chris Coulson <chris.coulson@canonical.com>
24
 
 *
25
 
 * Alternatively, the contents of this file may be used under the terms of
26
 
 * either the GNU General Public License Version 2 or later (the "GPL"), or
27
 
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28
 
 * in which case the provisions of the GPL or the LGPL are applicable instead
29
 
 * of those above. If you wish to allow use of your version of this file only
30
 
 * under the terms of either the GPL or the LGPL, and not to allow others to
31
 
 * use your version of this file under the terms of the MPL, indicate your
32
 
 * decision by deleting the provisions above and replace them with the notice
33
 
 * and other provisions required by the GPL or the LGPL. If you do not delete
34
 
 * the provisions above, a recipient may use your version of this file under
35
 
 * the terms of any one of the MPL, the GPL or the LGPL.
36
 
 * 
37
 
 * ***** END LICENSE BLOCK ***** */
38
 
 
39
 
#include <prtypes.h>
40
 
#include <nsStringAPI.h>
41
 
#include <nsIURI.h>
42
 
#include <nsILoadGroup.h>
43
 
#include <nsServiceManagerUtils.h>
44
 
#include <imgIContainer.h>
45
 
#include <nsNetError.h>
46
 
#include <nsNetUtil.h>
47
 
#include <nsIImageToPixbuf.h>
48
 
#if MOZILLA_BRANCH_MAJOR_VERSION < 11
49
 
# include <nsIDOMNSElement.h>
50
 
#endif
51
 
#if MOZILLA_BRANCH_MAJOR_VERSION == 13
52
 
# include <nsIDOMNSElement.h>
53
 
#endif
54
 
#include <nsIDOMDOMTokenList.h>
55
 
#include <nsIDOMDocument.h>
56
 
#include <nsIDOMWindow.h>
57
 
#include <nsIDOMElement.h>
58
 
#include <nsIDOMCSSStyleDeclaration.h>
59
 
#include <nsIDOMCSSValue.h>
60
 
#include <nsIDOMCSSPrimitiveValue.h>
61
 
#include <nsIDOMRect.h>
62
 
#include <nsICaseConversion.h>
63
 
#include <nsUnicharUtilCIID.h>
64
 
 
65
 
#include <libdbusmenu-gtk/menuitem.h>
66
 
#include <gtk/gtk.h>
67
 
 
68
 
#include "uGlobalMenuObject.h"
69
 
#include "uGlobalMenuBar.h"
70
 
#include "uWidgetAtoms.h"
71
 
 
72
 
#include "uDebug.h"
73
 
#include "compat.h"
74
 
 
75
 
#define MAX_LABEL_NCHARS 40
76
 
 
77
 
typedef nsresult (nsIDOMRect::*GetRectSideMethod)(nsIDOMCSSPrimitiveValue**);
78
 
 
79
 
NS_IMPL_ISUPPORTS3(uGlobalMenuIconLoader, imgIDecoderObserver, imgIContainerObserver, nsIRunnable)
80
 
 
81
 
// Yes, we're abusing PRPackedBool a bit here. We initialize it to a value
82
 
// that is neither true or false, so that we don't need another static member
83
 
// to indicate the intialization status of it.
84
 
PRPackedBool uGlobalMenuIconLoader::sImagesInMenus = -1;
85
 
nsCOMPtr<imgILoader> uGlobalMenuIconLoader::sLoader = 0;
86
 
 
87
 
PRBool
88
 
uGlobalMenuIconLoader::ShouldShowIcon()
89
 
{
90
 
  // Ideally, we want to get the visibility of the XUL image in our menu item,
91
 
  // but that is anonymous content which is only created when the frame is drawn
92
 
  // (which obviously never happens here).
93
 
  // As an alternative, we get the user setting for menus-have-icons from
94
 
  // nsILookAndFeel. If menu icons are to be hidden, we hide everything except
95
 
  // for menuitems with the menuitem-with-favicon class. This is basically
96
 
  // how the visibility gets set anyway (see chrome://toolkit/content/xul.css),
97
 
  // which should work in most cases. But, I guess a theme could override this,
98
 
  // and then we ignore the users theme settings. Oh well......
99
 
 
100
 
  if (sImagesInMenus == static_cast<PRPackedBool>(-1)) {
101
 
    // We could get the correct GtkSettings by getting the GdkScreen that our
102
 
    // top-level window is on. However, I don't think this matters, as
103
 
    // nsILookAndFeel never had per-screen settings
104
 
    GtkSettings *settings = gtk_settings_get_default();
105
 
    gboolean menus_have_icons;
106
 
    g_object_get(settings, "gtk-menu-images", &menus_have_icons, NULL);
107
 
 
108
 
    sImagesInMenus = !!menus_have_icons;
109
 
  }
110
 
 
111
 
  if (sImagesInMenus) {
112
 
    return PR_TRUE;
113
 
  }
114
 
 
115
 
  return mMenuItem->WithFavicon();
116
 
}
117
 
 
118
 
void
119
 
uGlobalMenuIconLoader::LoadIcon()
120
 
{
121
 
  NS_DispatchToCurrentThread(this);
122
 
}
123
 
 
124
 
static PRInt32
125
 
GetDOMRectSide(nsIDOMRect* aRect, GetRectSideMethod aMethod)
126
 
{
127
 
  nsCOMPtr<nsIDOMCSSPrimitiveValue> dimensionValue;
128
 
  (aRect->*aMethod)(getter_AddRefs(dimensionValue));
129
 
  if (!dimensionValue)
130
 
    return -1;
131
 
 
132
 
  PRUint16 primitiveType;
133
 
  nsresult rv = dimensionValue->GetPrimitiveType(&primitiveType);
134
 
  if (NS_FAILED(rv) || primitiveType != nsIDOMCSSPrimitiveValue::CSS_PX)
135
 
    return -1;
136
 
 
137
 
  float dimension = 0;
138
 
  rv = dimensionValue->GetFloatValue(nsIDOMCSSPrimitiveValue::CSS_PX,
139
 
                                     &dimension);
140
 
  if (NS_FAILED(rv))
141
 
    return -1;
142
 
 
143
 
  return NSToIntRound(dimension);
144
 
}
145
 
 
146
 
NS_IMETHODIMP
147
 
uGlobalMenuIconLoader::Run()
148
 
{
149
 
  TRACE_WITH_MENUOBJECT(mMenuItem);
150
 
  // Some of this is borrowed from widget/src/cocoa/nsMenuItemIconX.mm
151
 
  if (mIconRequest) {
152
 
    mIconRequest->Cancel(NS_BINDING_ABORTED);
153
 
    mIconRequest = nsnull;
154
 
  }
155
 
 
156
 
  if (!mMenuItem) {
157
 
    // Our menu item got destroyed already
158
 
    return NS_OK;
159
 
  }
160
 
 
161
 
  mMenuItem->GetContent(getter_AddRefs(mContent));
162
 
 
163
 
  nsIDocument *doc = mContent->GetCurrentDoc();
164
 
  if (!doc) {
165
 
    // We might have been removed from the menu, in which case we will
166
 
    // no longer be in a document
167
 
    return NS_OK;
168
 
  }
169
 
 
170
 
  if (!ShouldShowIcon()) {
171
 
    ClearIcon();
172
 
    return NS_OK;
173
 
  }
174
 
 
175
 
  mIconLoaded = PR_FALSE;
176
 
 
177
 
  nsAutoString uriString;
178
 
  PRBool hasImage = mContent->GetAttr(kNameSpaceID_None, uWidgetAtoms::image,
179
 
                                      uriString);
180
 
 
181
 
  nsresult rv;
182
 
  nsCOMPtr<nsIDOMRect> domRect;
183
 
 
184
 
  if (!hasImage) {
185
 
    DEBUG_WITH_MENUOBJECT(mMenuItem, "Menuitem does not have an image");
186
 
    nsCOMPtr<nsIDOMCSSStyleDeclaration> cssStyleDecl;
187
 
    nsCOMPtr<nsIDOMWindow> domWin;
188
 
    nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(doc);
189
 
    if (domDoc) {
190
 
      domDoc->GetDefaultView(getter_AddRefs(domWin));
191
 
      if (domWin) {
192
 
        nsCOMPtr<nsIDOMElement> domElement = do_QueryInterface(mContent);
193
 
        if (domElement) {
194
 
          domWin->GetComputedStyle(domElement, EmptyString(),
195
 
                                   getter_AddRefs(cssStyleDecl));
196
 
        }
197
 
      }
198
 
    }
199
 
 
200
 
    if (!cssStyleDecl) {
201
 
      return NS_ERROR_FAILURE;
202
 
    }
203
 
 
204
 
    nsCOMPtr<nsIDOMCSSValue> cssValue;
205
 
    nsCOMPtr<nsIDOMCSSPrimitiveValue> primitiveValue;
206
 
    PRUint16 primitiveType;
207
 
    cssStyleDecl->GetPropertyCSSValue(NS_LITERAL_STRING("list-style-image"),
208
 
                                      getter_AddRefs(cssValue));
209
 
    if (cssValue) {
210
 
      primitiveValue = do_QueryInterface(cssValue);
211
 
      if (primitiveValue) {
212
 
        primitiveValue->GetPrimitiveType(&primitiveType);
213
 
        if (primitiveType == nsIDOMCSSPrimitiveValue::CSS_URI) {
214
 
          rv = primitiveValue->GetStringValue(uriString);
215
 
          if (NS_SUCCEEDED(rv)) {
216
 
            hasImage = PR_TRUE;
217
 
          }
218
 
        } else {
219
 
          NS_WARNING("list-style-image has wrong primitive type");
220
 
        }
221
 
      }
222
 
    }
223
 
 
224
 
    if (!hasImage) {
225
 
      return NS_OK;
226
 
    }
227
 
 
228
 
    cssStyleDecl->GetPropertyCSSValue(NS_LITERAL_STRING("-moz-image-region"),
229
 
                                      getter_AddRefs(cssValue));
230
 
    if (cssValue) {
231
 
      primitiveValue = do_QueryInterface(cssValue);
232
 
      if (primitiveValue) {
233
 
        primitiveValue->GetPrimitiveType(&primitiveType);
234
 
        if (primitiveType == nsIDOMCSSPrimitiveValue::CSS_RECT) {
235
 
          primitiveValue->GetRectValue(getter_AddRefs(domRect));
236
 
        }
237
 
      }
238
 
    }
239
 
  }
240
 
 
241
 
  DEBUG_WITH_MENUOBJECT(mMenuItem, "Icon URI: %s", DEBUG_CSTR_FROM_UTF16(uriString));
242
 
  nsCOMPtr<nsIURI> uri;
243
 
  rv = NS_NewURI(getter_AddRefs(uri), uriString);
244
 
  if (NS_FAILED(rv)) {
245
 
    NS_WARNING("Failed to create new URI");
246
 
    ClearIcon();
247
 
    return NS_OK;
248
 
  }
249
 
 
250
 
  if (!sLoader) {
251
 
    sLoader = do_GetService("@mozilla.org/image/loader;1");
252
 
  }
253
 
 
254
 
  NS_ASSERTION(sLoader, "No icon loader");
255
 
  if (!sLoader) {
256
 
    return NS_OK;
257
 
  }
258
 
 
259
 
  nsCOMPtr<nsILoadGroup> loadGroup = doc->GetDocumentLoadGroup();
260
 
 
261
 
#if MOZILLA_BRANCH_MAJOR_VERSION >= 8
262
 
  rv = sLoader->LoadImage(uri, nsnull, nsnull, nsnull, loadGroup, this,
263
 
#else
264
 
  rv = sLoader->LoadImage(uri, nsnull, nsnull, loadGroup, this,
265
 
#endif
266
 
                          nsnull, nsIRequest::LOAD_NORMAL, nsnull,
267
 
                          nsnull, nsnull, getter_AddRefs(mIconRequest));
268
 
  NS_ENSURE_SUCCESS(rv, rv);
269
 
 
270
 
  mIconRequest->RequestDecode();
271
 
 
272
 
  mImageRect.SetEmpty();
273
 
 
274
 
  if (domRect) {
275
 
    PRInt32 bottom = GetDOMRectSide(domRect, &nsIDOMRect::GetBottom);
276
 
    PRInt32 right = GetDOMRectSide(domRect, &nsIDOMRect::GetRight);
277
 
    PRInt32 top = GetDOMRectSide(domRect, &nsIDOMRect::GetTop);
278
 
    PRInt32 left = GetDOMRectSide(domRect, &nsIDOMRect::GetLeft);
279
 
 
280
 
    if (top < 0 || left < 0 || bottom <= top || right <= left) {
281
 
      return NS_ERROR_FAILURE;
282
 
    }
283
 
 
284
 
    mImageRect.SetRect(left, top, right - left, bottom - top);
285
 
  }
286
 
 
287
 
  return NS_OK;
288
 
}
289
 
 
290
 
void
291
 
uGlobalMenuIconLoader::ClearIcon()
292
 
{
293
 
  dbusmenu_menuitem_property_remove(mMenuItem->GetDbusMenuItem(),
294
 
                                    DBUSMENU_MENUITEM_PROP_ICON_DATA);
295
 
}
296
 
 
297
 
NS_IMETHODIMP
298
 
uGlobalMenuIconLoader::OnStartRequest(imgIRequest *aRequest)
299
 
{
300
 
  return NS_ERROR_NOT_IMPLEMENTED;
301
 
}
302
 
 
303
 
NS_IMETHODIMP
304
 
uGlobalMenuIconLoader::OnStartDecode(imgIRequest *aRequest)
305
 
{
306
 
  return NS_ERROR_NOT_IMPLEMENTED;
307
 
}
308
 
 
309
 
NS_IMETHODIMP
310
 
uGlobalMenuIconLoader::OnStartContainer(imgIRequest *aRequest, imgIContainer *aContainer)
311
 
{
312
 
  TRACE_WITH_MENUOBJECT(mMenuItem);
313
 
  return NS_ERROR_NOT_IMPLEMENTED;
314
 
}
315
 
 
316
 
NS_IMETHODIMP
317
 
uGlobalMenuIconLoader::OnStartFrame(imgIRequest *aRequest, PRUint32 aFrame)
318
 
{
319
 
  return NS_ERROR_NOT_IMPLEMENTED;
320
 
}
321
 
 
322
 
NS_IMETHODIMP
323
 
uGlobalMenuIconLoader::OnDataAvailable(imgIRequest *aRequest,
324
 
                                       MOZ_API_BOOL aCurrentFrame,
325
 
                                       const nsIntRect *aRect)
326
 
{
327
 
  return NS_ERROR_NOT_IMPLEMENTED;
328
 
}
329
 
 
330
 
NS_IMETHODIMP
331
 
uGlobalMenuIconLoader::OnStopFrame(imgIRequest *aRequest, PRUint32 aFrame)
332
 
{
333
 
  TRACE_WITH_MENUOBJECT(mMenuItem);
334
 
  if (aRequest != mIconRequest) {
335
 
    return NS_ERROR_FAILURE;
336
 
  }
337
 
 
338
 
  if (mIconLoaded) {
339
 
    DEBUG_WITH_MENUOBJECT(mMenuItem, "Icon is already loaded");
340
 
    return NS_OK;
341
 
  }
342
 
 
343
 
  mIconLoaded = PR_TRUE;
344
 
 
345
 
  nsCOMPtr<imgIContainer> img;
346
 
  aRequest->GetImage(getter_AddRefs(img));
347
 
  if (!img) {
348
 
    NS_WARNING("Failed to get image");
349
 
    return NS_ERROR_FAILURE;
350
 
  }
351
 
 
352
 
  PRInt32 origWidth;
353
 
  PRInt32 origHeight;
354
 
  img->GetWidth(&origWidth);
355
 
  img->GetHeight(&origHeight);
356
 
 
357
 
  PRBool needsClip = PR_FALSE;
358
 
 
359
 
  if (!mImageRect.IsEmpty()) {
360
 
    if (mImageRect.XMost() > origWidth || mImageRect.YMost() > origHeight) {
361
 
      NS_WARNING("-moz-image-region is larger than image");
362
 
      return NS_ERROR_FAILURE;
363
 
    }
364
 
 
365
 
    if (!(mImageRect.x == 0 && mImageRect.y == 0 &&
366
 
         mImageRect.width == origWidth && mImageRect.height == origHeight)) {
367
 
      needsClip = PR_TRUE;
368
 
    }
369
 
  }
370
 
 
371
 
  if ((!needsClip && (origWidth > 100 || origHeight > 100)) ||
372
 
     (needsClip && (mImageRect.width > 100 || mImageRect.height > 100))) {
373
 
    /* The icon data needs to go across DBus. Make sure the icon
374
 
     * data isn't too large, else our connection gets terminated and
375
 
     * GDbus helpfully aborts the application. Thank you :)
376
 
     */
377
 
    NS_WARNING("Icon data too large");
378
 
    ClearIcon();
379
 
    return NS_OK;
380
 
  }
381
 
 
382
 
  nsCOMPtr<imgIContainer> clippedImg;
383
 
  if (needsClip) {
384
 
    nsresult rv = img->ExtractFrame(0, mImageRect, 0,
385
 
                                    getter_AddRefs(clippedImg));
386
 
    if (NS_FAILED(rv)) {
387
 
      NS_WARNING("Failed to clip icon");
388
 
      return NS_ERROR_FAILURE;
389
 
    }
390
 
  }
391
 
 
392
 
  nsCOMPtr<nsIImageToPixbuf> converter =
393
 
    do_GetService("@mozilla.org/widget/image-to-gdk-pixbuf;1");
394
 
  NS_ASSERTION(converter, "No image converter");
395
 
  if (!converter) {
396
 
    return NS_ERROR_FAILURE;
397
 
  }
398
 
 
399
 
  GdkPixbuf *pixbuf =
400
 
    converter->ConvertImageToPixbuf(clippedImg ? clippedImg : img);
401
 
  if (pixbuf) {
402
 
    dbusmenu_menuitem_property_set_image(mMenuItem->GetDbusMenuItem(),
403
 
                                         DBUSMENU_MENUITEM_PROP_ICON_DATA,
404
 
                                         pixbuf);
405
 
    g_object_unref(pixbuf);
406
 
  } else {
407
 
    ClearIcon();
408
 
  }
409
 
 
410
 
  return NS_OK;
411
 
}
412
 
 
413
 
NS_IMETHODIMP
414
 
uGlobalMenuIconLoader::OnStopContainer(imgIRequest *aRequest,
415
 
                                       imgIContainer *aContainer)
416
 
{
417
 
  return NS_ERROR_NOT_IMPLEMENTED;
418
 
}
419
 
 
420
 
NS_IMETHODIMP
421
 
uGlobalMenuIconLoader::OnStopDecode(imgIRequest *aRequest, nsresult status,
422
 
                                    const PRUnichar *statusArg)
423
 
{
424
 
  TRACE_WITH_MENUOBJECT(mMenuItem);
425
 
  return NS_ERROR_NOT_IMPLEMENTED;
426
 
}
427
 
 
428
 
NS_IMETHODIMP
429
 
uGlobalMenuIconLoader::OnStopRequest(imgIRequest *aRequest, MOZ_API_BOOL aIsLastPart)
430
 
{
431
 
  TRACE_WITH_MENUOBJECT(mMenuItem);
432
 
 
433
 
  if (mIconRequest) {
434
 
    mIconRequest->Cancel(NS_BINDING_ABORTED);
435
 
    mIconRequest = nsnull;
436
 
  }
437
 
 
438
 
  return NS_OK;
439
 
}
440
 
 
441
 
NS_IMETHODIMP
442
 
uGlobalMenuIconLoader::OnDiscard(imgIRequest *aRequest)
443
 
{
444
 
  return NS_ERROR_NOT_IMPLEMENTED;
445
 
}
446
 
 
447
 
NS_IMETHODIMP
448
 
#if MOZILLA_BRANCH_MAJOR_VERSION >= 12
449
 
uGlobalMenuIconLoader::FrameChanged(imgIRequest *aRequest,
450
 
                                    imgIContainer *aContainer,
451
 
#else
452
 
uGlobalMenuIconLoader::FrameChanged(imgIContainer *aContainer,
453
 
#endif
454
 
                                    const nsIntRect *aDirtyRect)
455
 
{
456
 
  return NS_ERROR_NOT_IMPLEMENTED;
457
 
}
458
 
 
459
 
#if MOZILLA_BRANCH_MAJOR_VERSION >= 11
460
 
NS_IMETHODIMP
461
 
uGlobalMenuIconLoader::OnImageIsAnimated(imgIRequest* aRequest)
462
 
{
463
 
  return NS_OK;
464
 
}
465
 
#endif
466
 
 
467
 
void
468
 
uGlobalMenuIconLoader::Destroy()
469
 
{
470
 
  TRACE_WITH_MENUOBJECT(mMenuItem);
471
 
  if (mIconRequest) {
472
 
    mIconRequest->Cancel(NS_BINDING_ABORTED);
473
 
    mIconRequest = nsnull;
474
 
  }
475
 
 
476
 
  mMenuItem = nsnull;
477
 
}
478
 
 
479
 
void
480
 
uGlobalMenuObject::GetContent(nsIContent **_retval)
481
 
{
482
 
  if (!_retval) {
483
 
    return;
484
 
  }
485
 
  *_retval = mContent;
486
 
  NS_IF_ADDREF(*_retval);
487
 
}
488
 
 
489
 
void
490
 
uGlobalMenuObject::SyncLabelFromContent(nsIContent *aContent)
491
 
{
492
 
  TRACE_WITH_THIS_MENUOBJECT();
493
 
  // Gecko stores the label and access key in separate attributes
494
 
  // so we need to convert label="Foo"/accesskey="F" in to
495
 
  // label="_Foo" for dbusmenu
496
 
 
497
 
  nsAutoString label;
498
 
  if (aContent && aContent->GetAttr(kNameSpaceID_None,
499
 
                                    uWidgetAtoms::label, label)) {
500
 
    UGM_BLOCK_EVENTS_FOR_CURRENT_SCOPE();
501
 
    DEBUG_WITH_CONTENT(aContent, "Content has label \"%s\"", DEBUG_CSTR_FROM_UTF16(label));
502
 
    mContent->SetAttr(kNameSpaceID_None, uWidgetAtoms::label, label, MOZ_API_TRUE);
503
 
  } else {
504
 
    mContent->GetAttr(kNameSpaceID_None, uWidgetAtoms::label, label);
505
 
  }
506
 
 
507
 
  nsAutoString accesskey;
508
 
  mContent->GetAttr(kNameSpaceID_None, uWidgetAtoms::accesskey, accesskey);
509
 
 
510
 
  const PRUnichar *tmp = accesskey.BeginReading();
511
 
  PRUnichar keyUpper;
512
 
  PRUnichar keyLower;
513
 
  // XXX: I think we need to link against libxul.so to get ToLowerCase
514
 
  //      and ToUpperCase from nsUnicharUtils.h
515
 
  nsCOMPtr<nsICaseConversion> converter =
516
 
    do_GetService(NS_UNICHARUTIL_CONTRACTID);
517
 
  if (converter) {
518
 
    converter->ToUpper(*tmp, &keyUpper);
519
 
    converter->ToLower(*tmp, &keyLower);
520
 
  } else {
521
 
    if (*tmp < 256) {
522
 
      keyUpper = toupper(char(*tmp));
523
 
      keyLower = tolower(char(*tmp));
524
 
    } else {
525
 
      NS_WARNING("accesskey matching is case-sensitive when it shouldn't be");
526
 
      keyUpper = *tmp;
527
 
      keyLower = *tmp;
528
 
    }
529
 
  }
530
 
 
531
 
  PRUnichar *cur = label.BeginWriting();
532
 
  PRUnichar *end = label.EndWriting();
533
 
  int length = label.Length();
534
 
  int pos = 0;
535
 
  PRBool foundAccessKey = PR_FALSE;
536
 
 
537
 
  while (cur < end) {
538
 
    if (*cur != PRUnichar('_')) {
539
 
      if ((*cur != keyLower && *cur != keyUpper) || foundAccessKey) {
540
 
        cur++;
541
 
        pos++;
542
 
        continue;
543
 
      }
544
 
      foundAccessKey = PR_TRUE;
545
 
    }
546
 
 
547
 
    length += 1;
548
 
    label.SetLength(length);
549
 
    int newLength = label.Length();
550
 
    if (length != newLength)
551
 
      break; 
552
 
     
553
 
    cur = label.BeginWriting() + pos;
554
 
    end = label.EndWriting();
555
 
    memmove(cur + 1, cur, (length - 1 - pos) * sizeof(PRUnichar));
556
 
//                   \^/
557
 
    *cur = PRUnichar('_'); // Yeah!
558
 
//                    v
559
 
 
560
 
    cur += 2;
561
 
    pos += 2;
562
 
  }
563
 
 
564
 
  // Ellipsize long labels. I've picked an arbitrary length here
565
 
  if (length > MAX_LABEL_NCHARS) {
566
 
    cur = label.BeginWriting();
567
 
    for (PRUint32 i = 1; i < 4; i++) {
568
 
      *(cur + (MAX_LABEL_NCHARS - i)) = PRUnichar('.');
569
 
    }
570
 
    *(cur + MAX_LABEL_NCHARS) = nsnull;
571
 
    label.SetLength(MAX_LABEL_NCHARS);
572
 
  }
573
 
 
574
 
  nsCAutoString clabel;
575
 
  CopyUTF16toUTF8(label, clabel);
576
 
  DEBUG_WITH_THIS_MENUOBJECT("Setting label to \"%s\"", clabel.get());
577
 
  dbusmenu_menuitem_property_set(mDbusMenuItem,
578
 
                                 DBUSMENU_MENUITEM_PROP_LABEL,
579
 
                                 clabel.get());
580
 
}
581
 
 
582
 
void
583
 
uGlobalMenuObject::SyncLabelFromContent()
584
 
{
585
 
  SyncLabelFromContent(nsnull);
586
 
}
587
 
 
588
 
// Synchronize the 'hidden' attribute on the DOM node with the
589
 
// 'visible' property on the dbusmenu node
590
 
void
591
 
uGlobalMenuObject::SyncVisibilityFromContent()
592
 
{
593
 
  TRACE_WITH_THIS_MENUOBJECT();
594
 
  mContentVisible = !IsHidden();
595
 
  PRBool realVis = (!mMenuBar || !ShouldShowOnlyForKb() ||
596
 
                    mMenuBar->OpenedByKeyboard()) ?
597
 
                    mContentVisible : PR_FALSE;
598
 
  DEBUG_WITH_THIS_MENUOBJECT("Setting %s", realVis ? "visible" : "hidden");
599
 
 
600
 
  dbusmenu_menuitem_property_set_bool(mDbusMenuItem,
601
 
                                      DBUSMENU_MENUITEM_PROP_VISIBLE,
602
 
                                      realVis);
603
 
}
604
 
 
605
 
void
606
 
uGlobalMenuObject::SyncSensitivityFromContent(nsIContent *aContent)
607
 
{
608
 
  TRACE_WITH_THIS_MENUOBJECT();
609
 
 
610
 
  nsIContent *content;
611
 
  if (aContent) {
612
 
    content = aContent;
613
 
  } else {
614
 
    content = mContent;
615
 
  }
616
 
  PRBool disabled = content->AttrValueIs(kNameSpaceID_None,
617
 
                                         uWidgetAtoms::disabled,
618
 
                                         uWidgetAtoms::_true,
619
 
                                         eCaseMatters);
620
 
  DEBUG_WITH_THIS_MENUOBJECT("Setting %s", disabled ? "disabled" : "enabled");
621
 
 
622
 
  if (aContent) {
623
 
    UGM_BLOCK_EVENTS_FOR_CURRENT_SCOPE();
624
 
    if (disabled) {
625
 
      mContent->SetAttr(kNameSpaceID_None, uWidgetAtoms::disabled,
626
 
                        NS_LITERAL_STRING("true"), MOZ_API_TRUE);
627
 
    } else {
628
 
      mContent->UnsetAttr(kNameSpaceID_None, uWidgetAtoms::disabled, MOZ_API_TRUE);
629
 
    }
630
 
  }
631
 
 
632
 
  dbusmenu_menuitem_property_set_bool(mDbusMenuItem,
633
 
                                      DBUSMENU_MENUITEM_PROP_ENABLED,
634
 
                                      !disabled);
635
 
}
636
 
 
637
 
void
638
 
uGlobalMenuObject::SyncSensitivityFromContent()
639
 
{
640
 
  SyncSensitivityFromContent(nsnull);
641
 
}
642
 
 
643
 
void
644
 
uGlobalMenuObject::UpdateInfoFromContentClass()
645
 
{
646
 
  TRACE_WITH_THIS_MENUOBJECT();
647
 
  nsCOMPtr<nsIDOMNSElement> element(do_QueryInterface(mContent));
648
 
  if (!element) {
649
 
    return;
650
 
  }
651
 
 
652
 
  nsCOMPtr<nsIDOMDOMTokenList> classes;
653
 
  element->GetClassList(getter_AddRefs(classes));
654
 
  if (!classes) {
655
 
    return;
656
 
  }
657
 
 
658
 
  MOZ_API_BOOL tmp;
659
 
  classes->Contains(NS_LITERAL_STRING("show-only-for-keyboard"),
660
 
                    &tmp);
661
 
  mShowOnlyForKb = !!tmp;
662
 
 
663
 
  classes->Contains(NS_LITERAL_STRING("menuitem-with-favicon"),
664
 
                    &tmp);
665
 
  mWithFavicon = !!tmp;
666
 
 
667
 
  DEBUG_WITH_THIS_MENUOBJECT("show-only-for-keyboard class? %s", mShowOnlyForKb ? "Yes" : "No");
668
 
  DEBUG_WITH_THIS_MENUOBJECT("menuitem-with-favicon class? %s", mWithFavicon ? "Yes" : "No");
669
 
}
670
 
 
671
 
PRBool
672
 
uGlobalMenuObject::IsHidden()
673
 
{
674
 
  return mContent->AttrValueIs(kNameSpaceID_None, uWidgetAtoms::hidden,
675
 
                               uWidgetAtoms::_true, eCaseMatters) ||
676
 
         mContent->AttrValueIs(kNameSpaceID_None, uWidgetAtoms::collapsed,
677
 
                               uWidgetAtoms::_true, eCaseMatters);
678
 
}
679
 
 
680
 
void
681
 
uGlobalMenuObject::UpdateVisibility()
682
 
{
683
 
  TRACE_WITH_THIS_MENUOBJECT();
684
 
  if (!mMenuBar) {
685
 
    return;
686
 
  }
687
 
 
688
 
  PRBool newVis = (!ShouldShowOnlyForKb() || mMenuBar->OpenedByKeyboard()) ?
689
 
                   mContentVisible : PR_FALSE;
690
 
 
691
 
  DEBUG_WITH_THIS_MENUOBJECT("Setting %s", newVis ? "visible" : "hidden");
692
 
  dbusmenu_menuitem_property_set_bool(mDbusMenuItem,
693
 
                                      DBUSMENU_MENUITEM_PROP_VISIBLE,
694
 
                                      newVis);
695
 
}
696
 
 
697
 
void
698
 
uGlobalMenuObject::SyncIconFromContent()
699
 
{
700
 
  TRACE_WITH_THIS_MENUOBJECT();
701
 
  if (!mIconLoader) {
702
 
    mIconLoader = new uGlobalMenuIconLoader(this);
703
 
  }
704
 
 
705
 
  mIconLoader->LoadIcon();
706
 
}
707
 
 
708
 
void
709
 
uGlobalMenuObject::DestroyIconLoader()
710
 
{
711
 
  if (mIconLoader) {
712
 
    mIconLoader->Destroy();
713
 
  }
714
 
}