Bug 656329 - Use a Honeycomb-style action bar on tablets (preffed off by default) [r=mfinkle]

This commit is contained in:
Matt Brubeck 2011-08-05 16:01:33 -07:00
parent f5be51a9c0
commit 7e48a023bc
14 changed files with 288 additions and 64 deletions

View File

@ -394,6 +394,8 @@ pref("dom.max_script_run_time", 20);
// JS error console
pref("devtools.errorconsole.enabled", false);
pref("browser.ui.layout.tablet", 0); // on: 1, off: 0, auto: -1
// kinetic tweakables
pref("browser.ui.kinetic.updateInterval", 16);
pref("browser.ui.kinetic.exponentialC", 1400);

View File

@ -3,16 +3,11 @@ var BookmarkPopup = {
delete this.box;
this.box = document.getElementById("bookmark-popup");
let [tabsSidebar, controlsSidebar] = [Elements.tabs.getBoundingClientRect(), Elements.controls.getBoundingClientRect()];
this.box.setAttribute(tabsSidebar.left < controlsSidebar.left ? "right" : "left", controlsSidebar.width - this.box.offset);
this.box.top = BrowserUI.starButton.getBoundingClientRect().top - this.box.offset;
// Hide the popup if there is any new page loading
let self = this;
messageManager.addMessageListener("pagehide", function(aMessage) {
self.hide();
});
return this.box;
},
@ -22,11 +17,25 @@ var BookmarkPopup = {
},
show : function show() {
this.box.hidden = false;
this.box.anchorTo(BrowserUI.starButton);
// Set the box position.
let button = document.getElementById("tool-star");
if (getComputedStyle(button).visibility == "visible") {
let [tabsSidebar, controlsSidebar] = [Elements.tabs.getBoundingClientRect(), Elements.controls.getBoundingClientRect()];
this.box.setAttribute(tabsSidebar.left < controlsSidebar.left ? "right" : "left", controlsSidebar.width - this.box.offset);
this.box.top = button.getBoundingClientRect().top - this.box.offset;
} else {
button = document.getElementById("tool-star2");
this.box.top = button.getBoundingClientRect().bottom - this.box.offset;
// include starButton here, so that click-to-dismiss works as expected
BrowserUI.pushPopup(this, [this.box, BrowserUI.starButton]);
let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIXULChromeRegistry);
this.box.setAttribute(chromeReg.isLocaleRTL("global") ? "left" : "right", this.box.offset);
}
this.box.hidden = false;
this.box.anchorTo(button);
// include the star button here, so that click-to-dismiss works as expected
BrowserUI.pushPopup(this, [this.box, button]);
},
toggle : function toggle() {

View File

@ -0,0 +1,72 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Mobile Browser.
*
* The Initial Developer of the Original Code is
* Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Matt Brubeck <mbrubeck@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
var TabsPopup = {
get box() {
delete this.box;
return this.box = document.getElementById("tabs-sidebar");
},
get list() {
delete this.list;
return this.list = document.getElementById("tabs");
},
get button() {
delete this.button;
return this.button = document.getElementById("tool-tabs");
},
hide: function hide() {
this.box.removeAttribute("open");
BrowserUI.popPopup(this);
},
show: function show() {
// Set the box position.
this.box.setAttribute("open", "true");
this.list.resize();
BrowserUI.pushPopup(this, [this.box, this.button]);
},
toggle: function toggle() {
if (this.box.hasAttribute("open"))
this.hide();
else
this.show();
}
};

View File

@ -108,6 +108,7 @@ XPCOMUtils.defineLazyGetter(this, "CommonUI", function() {
["SelectHelperUI", "chrome://browser/content/SelectHelperUI.js"],
["ContentPopupHelper", "chrome://browser/content/ContentPopupHelper.js"],
["SharingUI", "chrome://browser/content/SharingUI.js"],
["TabsPopup", "chrome://browser/content/TabsPopup.js"],
#ifdef MOZ_SERVICES_SYNC
["WeaveGlue", "chrome://browser/content/sync.js"],
#endif

View File

@ -436,11 +436,6 @@ var BrowserUI = {
return this._sidebarW = Elements.controls.getBoundingClientRect().width;
},
get starButton() {
delete this.starButton;
return this.starButton = document.getElementById("tool-star");
},
sizeControls: function(windowW, windowH) {
// tabs
document.getElementById("tabs").resize();
@ -543,6 +538,7 @@ var BrowserUI = {
WeaveGlue.init();
#endif
Services.prefs.addObserver("browser.ui.layout.tablet", BrowserUI, false);
Services.obs.addObserver(BrowserSearch, "browser-search-engine-modified", false);
messageManager.addMessageListener("Browser:MozApplicationManifest", OfflineApps);
@ -601,11 +597,25 @@ var BrowserUI = {
uninit: function() {
Services.obs.removeObserver(BrowserSearch, "browser-search-engine-modified");
Services.prefs.removeObserver("browser.ui.layout.tablet", BrowserUI);
messageManager.removeMessageListener("Browser:MozApplicationManifest", OfflineApps);
ExtensionsView.uninit();
ConsoleView.uninit();
},
observe: function observe(aSubject, aTopic, aData) {
if (aTopic == "nsPref:changed" && aData == "browser.ui.layout.tablet")
this.updateTabletLayout();
},
updateTabletLayout: function updateTabletLayout() {
let tabletPref = Services.prefs.getIntPref("browser.ui.layout.tablet");
if (tabletPref == 1 || (tabletPref == -1 && Util.isTablet()))
Elements.urlbarState.setAttribute("tablet", "true");
else
Elements.urlbarState.removeAttribute("tablet");
},
update: function(aState) {
let browser = Browser.selectedBrowser;
@ -753,18 +763,25 @@ var BrowserUI = {
updateStar: function() {
let uri = getBrowser().currentURI;
if (uri.spec == "about:blank") {
this.starButton.removeAttribute("starred");
this._setStar(false);
return;
}
PlacesUtils.asyncGetBookmarkIds(uri, function (aItemIds) {
if (aItemIds.length)
this.starButton.setAttribute("starred", "true");
else
this.starButton.removeAttribute("starred");
PlacesUtils.asyncGetBookmarkIds(uri, function(aItemIds) {
this._setStar(aItemIds.length > 0)
}, this);
},
_setStar: function _setStar(aIsStarred) {
let buttons = document.getElementsByClassName("tool-star");
for (let i = 0; i < buttons.length; i++) {
if (aIsStarred)
buttons[i].setAttribute("starred", "true");
else
buttons[i].removeAttribute("starred");
}
},
newTab: function newTab(aURI, aOwner) {
aURI = aURI || "about:blank";
let tab = Browser.addTab(aURI, true, aOwner);
@ -1139,6 +1156,7 @@ var BrowserUI = {
case "cmd_quit":
case "cmd_close":
case "cmd_menu":
case "cmd_showTabs":
case "cmd_newTab":
case "cmd_closeTab":
case "cmd_undoCloseTab":
@ -1207,8 +1225,7 @@ var BrowserUI = {
case "cmd_star":
{
BookmarkPopup.toggle();
if (!this.starButton.hasAttribute("starred"))
this.starButton.setAttribute("starred", "true");
this._setStar(true);
let bookmarkURI = browser.currentURI;
PlacesUtils.asyncGetBookmarkIds(bookmarkURI, function (aItemIds) {
@ -1276,6 +1293,9 @@ var BrowserUI = {
case "cmd_menu":
AppMenu.toggle();
break;
case "cmd_showTabs":
TabsPopup.toggle();
break;
case "cmd_newTab":
this.newTab();
break;

View File

@ -259,6 +259,8 @@ var Browser = {
if (fullscreen && w != screen.width)
return;
BrowserUI.updateTabletLayout();
let toolbarHeight = Math.round(document.getElementById("toolbar-main").getBoundingClientRect().height);
Browser.styles["window-width"].width = w + "px";
@ -1249,6 +1251,7 @@ Browser.MainDragger.prototype = {
let bcr = browser.getBoundingClientRect();
this._contentView = browser.getViewAt(clientX - bcr.left, clientY - bcr.top);
this._stopAtSidebar = 0;
this._panToolbars = !Elements.urlbarState.getAttribute("tablet");
if (this._sidebarTimeout) {
clearTimeout(this._sidebarTimeout);
this._sidebarTimeout = null;
@ -1265,23 +1268,28 @@ Browser.MainDragger.prototype = {
dragMove: function dragMove(dx, dy, scroller, aIsKinetic) {
let doffset = new Point(dx, dy);
let sidebarOffset = null;
// If the sidebars are showing, we pan them out of the way before panning the content.
// The panning distance that should be used for the sidebars in is stored in sidebarOffset,
// and subtracted from doffset.
let sidebarOffset = this._getSidebarOffset(doffset);
if (this._panToolbars) {
// If the sidebars are showing, we pan them out of the way before panning the content.
// The panning distance that should be used for the sidebars in is stored in sidebarOffset,
// and subtracted from doffset.
sidebarOffset = this._getSidebarOffset(doffset);
// If we started with one sidebar open, stop when we get to the other.
if (sidebarOffset.x != 0)
this._blockSidebars(sidebarOffset);
// If we started with one sidebar open, stop when we get to the other.
if (sidebarOffset.x != 0)
this._blockSidebars(sidebarOffset);
}
if (!this.contentMouseCapture)
this._panContent(doffset);
if (aIsKinetic && doffset.x != 0)
return false;
if (this._panToolbars) {
if (aIsKinetic && doffset.x != 0)
return false;
this._panChrome(doffset, sidebarOffset);
this._panChrome(doffset, sidebarOffset);
}
this._updateScrollbars();
@ -1858,7 +1866,8 @@ const ContentTouchHandler = {
// Check if the user touched near to one of the edges of the browser area
// or if the urlbar is showing
this.canCancelPan = (aX >= rect.left + kSafetyX) && (aX <= rect.right - kSafetyX) &&
(aY >= rect.top + kSafetyY) && bcr.top == 0;
(aY >= rect.top + kSafetyY) &&
(bcr.top == 0 || Elements.urlbarState.getAttribute("tablet"));
},
tapDown: function tapDown(aX, aY) {
@ -3063,7 +3072,12 @@ var ViewableAreaObserver = {
},
get height() {
return (this._height || window.innerHeight);
let height = (this._height || window.innerHeight);
if (Elements.urlbarState.getAttribute("tablet")) {
let toolbarHeight = Math.round(document.getElementById("toolbar-main").getBoundingClientRect().height);
height -= toolbarHeight;
}
return height;
},
_isKeyboardOpened: true,

View File

@ -102,6 +102,7 @@
<command id="cmd_openLocation" oncommand="CommandUpdater.doCommand(this.id);"/>
<!-- tabs -->
<command id="cmd_showTabs" label="&showTabs.label;" oncommand="CommandUpdater.doCommand(this.id);"/>
<command id="cmd_newTab" label="&newtab.label;" oncommand="CommandUpdater.doCommand(this.id);"/>
<command id="cmd_closeTab" label="&closetab.label;" oncommand="CommandUpdater.doCommand(this.id);"/>
#ifdef MOZ_SERVICES_SYNC
@ -195,7 +196,7 @@
</keyset>
<stack flex="1" id="stack">
<scrollbox id="controls-scrollbox" style="overflow: hidden; -moz-box-orient: horizontal; position: relative;" flex="1">
<scrollbox id="controls-scrollbox" style="overflow: hidden; -moz-box-orient: horizontal; position: relative;" flex="1" observes="bcast_urlbarState">
<vbox id="tabs-sidebar" class="sidebar" observes="bcast_uidiscovery">
<spacer class="toolbar-height"/>
<!-- Left toolbar -->
@ -218,7 +219,9 @@
<!-- Main Toolbar -->
<box id="toolbar-container" class="panel-dark toolbar-height">
<box id="toolbar-moveable-container" observes="bcast_uidiscovery">
<toolbar id="toolbar-main" class="panel-dark window-width">
<toolbar id="toolbar-main" class="panel-dark window-width" observes="bcast_urlbarState">
<toolbarbutton id="tool-back2" class="tool-back button-actionbar" command="cmd_back"/>
<toolbarbutton id="tool-forward2" class="tool-forward button-actionbar" command="cmd_forward"/>
#ifdef MOZ_PLATFORM_MAEMO
#if MOZ_PLATFORM_MAEMO != 6
<toolbarbutton id="tool-app-switch" oncommand="BrowserUI.switchTask();"/>
@ -257,6 +260,8 @@
<toolbarbutton id="tool-search" command="cmd_opensearch"/>
</hbox>
</hbox>
<toolbarbutton id="tool-star2" class="tool-star button-actionbar" command="cmd_star"/>
<toolbarbutton id="tool-tabs" class="button-actionbar" command="cmd_showTabs"/>
#ifndef ANDROID
<toolbarbutton id="tool-app-close" class="urlbar-button" command="cmd_close"/>
#endif
@ -265,7 +270,7 @@
</box>
<!-- Content viewport -->
<vbox id="content-viewport" class="window-width window-height">
<vbox id="content-viewport" class="viewable-width viewable-height">
<!-- Content viewport -->
<stack>
<deck id="browsers" flex="1" observes="bcast_uidiscovery"/>
@ -294,9 +299,9 @@
<spacer class="toolbar-height" mousethrough="always"/>
<vbox id="browser-controls" style="overflow: -moz-hidden-unscrollable;" class="panel-dark" flex="1">
<toolbarbutton id="tool-star" class="button-control" command="cmd_star"/>
<toolbarbutton id="tool-back" class="button-control" command="cmd_back"/>
<toolbarbutton id="tool-forward" class="button-control" command="cmd_forward"/>
<toolbarbutton id="tool-star" class="tool-star button-control" command="cmd_star"/>
<toolbarbutton id="tool-back" class="tool-back button-control" command="cmd_back"/>
<toolbarbutton id="tool-forward" class="tool-forward button-control" command="cmd_forward"/>
<toolbarspring/>
<toolbarbutton id="tool-panel-open" class="button-control" command="cmd_panel"/>
</vbox>

View File

@ -212,10 +212,13 @@
<method name="resize">
<body>
<![CDATA[
let container = this.parentNode.getBoundingClientRect();
let element = this._scrollbox.getBoundingClientRect();
let undo = this._tabsUndo.getBoundingClientRect();
let lastChild = this.parentNode.lastChild.getBoundingClientRect();
let container = Rect.fromRect(this.parentNode.getBoundingClientRect());
if (container.height == 0)
return; // Don't try to resize while collapsed.
let element = Rect.fromRect(this._scrollbox.getBoundingClientRect());
let undo = Rect.fromRect(this._tabsUndo.getBoundingClientRect());
let lastChild = Rect.fromRect(this.parentNode.lastChild.getBoundingClientRect());
let height = window.innerHeight - element.top - (lastChild.top - element.bottom) - lastChild.height;
this.children.style.height = height + "px";

View File

@ -30,6 +30,7 @@ chrome.jar:
content/OfflineApps.js (content/OfflineApps.js)
content/SelectHelperUI.js (content/SelectHelperUI.js)
content/SharingUI.js (content/SharingUI.js)
content/TabsPopup.js (content/TabsPopup.js)
* content/content.js (content/content.js)
content/commandUtil.js (content/commandUtil.js)
* content/bindings.xml (content/bindings.xml)

View File

@ -7,6 +7,7 @@
<!ENTITY go.label "Go">
<!ENTITY star.label "Star">
<!ENTITY showTabs.label "Show Tabs">
<!ENTITY newtab.label "New Tab">
<!ENTITY closetab.label "Close Tab">

View File

@ -323,7 +323,7 @@ toolbarbutton.urlbar-button {
background: #5e6166;
}
toolbarbutton.button-control {
.button-control {
padding: 0 !important;
min-width: @sidebar_width_minimum@ !important;
border-top: @border_width_tiny@ solid rgba(255,255,255,0.2) !important;
@ -334,34 +334,38 @@ toolbarbutton.button-control {
height: @sidebar_button_height@;
}
toolbarbutton.button-control:last-child {
.button-control:last-child {
border-bottom: 0 solid rgba(0,0,0,0.2) !important;
}
toolbarbutton.button-control[disabled="true"] {
.button-control[disabled="true"] {
opacity: 0.5;
}
toolbarbutton.button-control:not([disabled="true"]):hover:active {
.button-control:not([disabled="true"]):hover:active {
background-image: url("chrome://browser/skin/images/sidebarbutton-active-hdpi.png");
border-top: none;
}
#tool-star {
#tool-tabs {
list-style-image: url("chrome://browser/skin/images/tabs-hdpi.png");
}
.tool-star {
list-style-image: url("chrome://browser/skin/images/bookmark-default-hdpi.png");
}
#tool-star[starred="true"] {
.tool-star[starred="true"] {
list-style-image: url("chrome://browser/skin/images/bookmark-starred-hdpi.png");
}
#tool-back,
#tool-forward:-moz-locale-dir(rtl) {
.tool-back,
.tool-forward:-moz-locale-dir(rtl) {
list-style-image: url("chrome://browser/skin/images/back-default-hdpi.png");
}
#tool-back:-moz-locale-dir(rtl),
#tool-forward {
.tool-back:-moz-locale-dir(rtl),
.tool-forward {
list-style-image: url("chrome://browser/skin/images/forward-default-hdpi.png");
}
@ -1551,6 +1555,49 @@ setting {
to { -moz-transform: translateX(0); }
}
/* Tablet mode */
.button-actionbar {
visibility: collapse;
}
.button-actionbar[disabled="true"] {
opacity: 0.5;
}
.button-actionbar:hover:active {
background-color: #8db8d8;
}
#toolbar-main[tablet="true"] > .button-actionbar {
visibility: visible;
}
#toolbar-main[tablet="true"][mode="edit"] > .button-actionbar {
visibility: collapse;
}
#controls-scrollbox[tablet="true"] > #controls-sidebar {
visibility: collapse;
}
#controls-scrollbox[tablet="true"] > #tabs-sidebar {
border: none;
position: fixed;
top: -moz-calc(@touch_button_xlarge@ + @margin_normal@);
visibility: collapse;
}
#controls-scrollbox[tablet="true"] > #tabs-sidebar:-moz-locale-dir(ltr) {
right: 0;
}
#controls-scrollbox[tablet="true"] > #tabs-sidebar:-moz-locale-dir(rtl) {
left: 0;
}
#controls-scrollbox[tablet="true"] > #tabs-sidebar[open] {
visibility: visible;
}
/* Text selection handles */
#selectionhandle-start,
#selectionhandle-end {
min-width: 35px !important;

View File

@ -291,7 +291,7 @@ toolbarbutton.urlbar-button {
background: @color_background_default@;
}
toolbarbutton.button-control {
.button-control {
padding: 0 !important;
min-width: @sidebar_width_minimum@ !important;
border-top: @border_width_tiny@ solid @color_divider_border@ !important;
@ -302,20 +302,24 @@ toolbarbutton.button-control {
height: @sidebar_button_height@;
}
toolbarbutton.button-control:last-child {
.button-control:last-child {
border-bottom: 0 solid @color_divider_border@ !important;
}
toolbarbutton.button-control[disabled="true"] {
.button-control[disabled="true"] {
opacity: 0.5;
}
toolbarbutton.button-control:not([disabled="true"]):hover:active {
.button-control:not([disabled="true"]):hover:active {
background-color: @color_background_active@ !important;
border-top: none;
}
#tool-star {
#tool-tabs {
list-style-image: url("chrome://browser/skin/images/tabs-hdpi.png");
}
.tool-star {
list-style-image: url("chrome://browser/skin/images/bookmark-default-hdpi.png");
}
@ -323,13 +327,13 @@ toolbarbutton.button-control:not([disabled="true"]):hover:active {
list-style-image: url("chrome://browser/skin/images/bookmark-starred-hdpi.png");
}
#tool-back,
#tool-forward:-moz-locale-dir(rtl) {
.tool-back,
.tool-forward:-moz-locale-dir(rtl) {
list-style-image: url("chrome://browser/skin/images/back-default-hdpi.png");
}
#tool-back:-moz-locale-dir(rtl),
#tool-forward {
.tool-back:-moz-locale-dir(rtl),
.tool-forward {
list-style-image: url("chrome://browser/skin/images/forward-default-hdpi.png");
}
@ -1530,6 +1534,49 @@ setting {
to { -moz-transform: translateX(0); }
}
/* Tablet mode */
.button-actionbar {
visibility: collapse;
}
.button-actionbar[disabled="true"] {
opacity: 0.5;
}
.button-actionbar:hover:active {
background-color: #8db8d8;
}
#toolbar-main[tablet="true"] > .button-actionbar {
visibility: visible;
}
#toolbar-main[tablet="true"][mode="edit"] > .button-actionbar {
visibility: collapse;
}
#controls-scrollbox[tablet="true"] > #controls-sidebar {
visibility: collapse;
}
#controls-scrollbox[tablet="true"] > #tabs-sidebar {
border: none;
position: fixed;
top: -moz-calc(@touch_button_xlarge@ + @margin_normal@);
visibility: collapse;
}
#controls-scrollbox[tablet="true"] > #tabs-sidebar:-moz-locale-dir(ltr) {
right: 0;
}
#controls-scrollbox[tablet="true"] > #tabs-sidebar:-moz-locale-dir(rtl) {
left: 0;
}
#controls-scrollbox[tablet="true"] > #tabs-sidebar[open] {
visibility: visible;
}
/* Text selection handles */
#selectionhandle-start,
#selectionhandle-end {
min-width: 35px !important;
@ -1545,4 +1592,3 @@ setting {
#selectionhandle-end {
list-style-image: url("chrome://browser/skin/images/handle-end.png");
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 307 B

View File

@ -75,6 +75,7 @@ chrome.jar:
skin/images/back-default-hdpi.png (images/back-default-hdpi.png)
skin/images/allpages-48.png (images/allpages-48.png)
skin/images/history-48.png (images/history-48.png)
skin/images/tabs-hdpi.png (images/tabs-hdpi.png)
skin/images/bookmark-default-hdpi.png (images/bookmark-default-hdpi.png)
skin/images/bookmarks-48.png (images/bookmarks-48.png)
skin/images/bookmark-starred-hdpi.png (images/bookmark-starred-hdpi.png)
@ -250,6 +251,7 @@ chrome.jar:
skin/gingerbread/images/scrubber-hdpi.png (gingerbread/images/scrubber-hdpi.png)
skin/gingerbread/images/handle-start.png (gingerbread/images/handle-start.png)
skin/gingerbread/images/handle-end.png (gingerbread/images/handle-end.png)
skin/gingerbread/images/tabs-hdpi.png (images/tabs-hdpi.png)
skin/gingerbread/images/errorpage-warning.png (images/errorpage-warning.png)
skin/gingerbread/images/errorpage-larry-white.png (images/errorpage-larry-white.png)
skin/gingerbread/images/errorpage-larry-black.png (images/errorpage-larry-black.png)
@ -376,6 +378,7 @@ chrome.jar:
skin/honeycomb/images/scrubber-hdpi.png (honeycomb/images/scrubber-hdpi.png)
skin/honeycomb/images/handle-start.png (images/handle-start.png)
skin/honeycomb/images/handle-end.png (images/handle-end.png)
skin/honeycomb/images/tabs-hdpi.png (images/tabs-hdpi.png)
skin/honeycomb/images/errorpage-warning.png (images/errorpage-warning.png)
skin/honeycomb/images/errorpage-larry-white.png (images/errorpage-larry-white.png)
skin/honeycomb/images/errorpage-larry-black.png (images/errorpage-larry-black.png)