This commit is contained in:
Carsten "Tomcat" Book 2013-11-27 12:41:30 +01:00
Родитель 1b7988119a 8288f8888d
Коммит 3e96086d0c
17 изменённых файлов: 351 добавлений и 83 удалений

Просмотреть файл

@ -1,4 +1,4 @@
{
"revision": "70f416f866858cb2068bffa31118fc4b15b482c9",
"revision": "9ba62e3061abd5521ffbbee5386a0654f972f73b",
"repo_path": "/integration/gaia-central"
}

Просмотреть файл

@ -6,34 +6,55 @@
#expand <menu id="__ID_PREFIX__charsetMenu"
label="&charsetMenu.label;"
#ifndef OMIT_ACCESSKEYS
accesskey="&charsetMenu.accesskey;"
#endif
oncommand="MultiplexHandler(event)"
#ifdef OMIT_ACCESSKEYS
onpopupshowing="CharsetMenu.build(event);"
#else
onpopupshowing="CharsetMenu.build(event, true);"
#endif
onpopupshown="UpdateMenus(event);">
<menupopup>
<menu label="&charsetMenuAutodet.label;"
accesskey="&charsetMenuAutodet.accesskey;">
#ifndef OMIT_ACCESSKEYS
accesskey="&charsetMenuAutodet.accesskey;"
#endif
>
<menupopup>
<menuitem type="radio"
name="detectorGroup"
id="chardet.off"
#expand id="__ID_PREFIX__chardet.off"
label="&charsetMenuAutodet.off.label;"
accesskey="&charsetMenuAutodet.off.accesskey;"/>
#ifndef OMIT_ACCESSKEYS
accesskey="&charsetMenuAutodet.off.accesskey;"
#endif
/>
<menuitem type="radio"
name="detectorGroup"
id="chardet.ja_parallel_state_machine"
#expand id="__ID_PREFIX__chardet.ja_parallel_state_machine"
label="&charsetMenuAutodet.ja.label;"
accesskey="&charsetMenuAutodet.ja.accesskey;"/>
#ifndef OMIT_ACCESSKEYS
accesskey="&charsetMenuAutodet.ja.accesskey;"
#endif
/>
<menuitem type="radio"
name="detectorGroup"
id="chardet.ruprob"
#expand id="__ID_PREFIX__chardet.ruprob"
label="&charsetMenuAutodet.ru.label;"
accesskey="&charsetMenuAutodet.ru.accesskey;"/>
#ifndef OMIT_ACCESSKEYS
accesskey="&charsetMenuAutodet.ru.accesskey;"
#endif
/>
<menuitem type="radio"
name="detectorGroup"
id="chardet.ukprob"
#expand id="__ID_PREFIX__chardet.ukprob"
label="&charsetMenuAutodet.uk.label;"
accesskey="&charsetMenuAutodet.uk.accesskey;"/>
#ifndef OMIT_ACCESSKEYS
accesskey="&charsetMenuAutodet.uk.accesskey;"
#endif
/>
</menupopup>
</menu>
<menuseparator/>

Просмотреть файл

@ -378,6 +378,7 @@
<constructor><![CDATA[
// Reading these immediately so nobody messes with them anymore:
this._delegatingToolbar = this.getAttribute("toolbar-delegate");
this._wasCollapsed = this.getAttribute("collapsed");
// Leaving those in here to unbreak some code:
if (document.readyState == "complete") {
this._init();
@ -409,8 +410,17 @@
}
// pass the current set of children for comparison with placements:
let children = [node.id for (node of this.childNodes)
if (node.getAttribute("skipintoolbarset") != "true" && node.id)];
let children = [];
for (node of this.childNodes) {
if (node.getAttribute("skipintoolbarset") != "true" && node.id) {
// Force everything to be removable so that buildArea can chuck stuff
// out if the user has customized things / we've been here before:
if (!this._whiteListed.has(node.id)) {
node.setAttribute("removable", "true");
}
children.push(node);
}
}
CustomizableUI.registerToolbarNode(this, children);
this.evictNodes();
// We can't easily use |this| or strong bindings for the observer fn here
@ -455,20 +465,28 @@
}
const kItemMaxWidth = 100;
let oldParent = aNode.parentNode;
aNode.setAttribute("removable", "true");
try {
aNode.setAttribute("removable", "true");
let nodeWidth = aNode.getBoundingClientRect().width;
if (nodeWidth == 0 || nodeWidth > kItemMaxWidth) {
throw new Error(aNode.id + " is too big (" + nodeWidth +
"px wide), moving to the palette");
let movedOut = false;
if (!this._wasCollapsed) {
try {
let nodeWidth = aNode.getBoundingClientRect().width;
if (nodeWidth == 0 || nodeWidth > kItemMaxWidth) {
throw new Error(aNode.id + " is too big (" + nodeWidth +
"px wide), moving to the palette");
}
CustomizableUI.addWidgetToArea(aNode.id, this._delegatingToolbar);
movedOut = true;
} catch (ex) {
// This will throw if the node is too big, or can't be moved there for
// some reason. Report this:
Cu.reportError(ex);
}
CustomizableUI.addWidgetToArea(aNode.id, this._delegatingToolbar);
} catch (ex) {
Cu.reportError(ex);
// This will throw if the node is too big, or can't be moved there for
// some reason. Try to remove it anyway:
}
/* We won't have moved the widget if either the add-on bar was collapsed,
* or if it was too wide to be inserted into the navbar. */
if (!movedOut) {
try {
CustomizableUI.removeWidgetFromArea(aNode.id);
} catch (ex) {

Просмотреть файл

@ -238,9 +238,19 @@ Editor.prototype = {
cm.on("focus", () => this.emit("focus"));
cm.on("change", () => this.emit("change"));
cm.on("gutterClick", (cm, line) => this.emit("gutterClick", line));
cm.on("cursorActivity", (cm) => this.emit("cursorActivity"));
cm.on("gutterClick", (cm, line, gutter, ev) => {
let head = { line: line, ch: 0 };
let tail = { line: line, ch: this.getText(line).length };
// Shift-click on a gutter selects the whole line.
if (ev.shiftKey)
return void cm.setSelection(head, tail);
this.emit("gutterClick", line);
});
win.CodeMirror.defineExtension("l10n", (name) => {
return L10N.GetStringFromName(name);
});

Просмотреть файл

@ -31,6 +31,13 @@ function test() {
ed.dropSelection();
is(ed.getSelection(), "", "dropSelection");
// Check that shift-click on a gutter selects the whole line (bug 919707)
let iframe = win.document.querySelector("iframe");
let gutter = iframe.contentWindow.document.querySelector(".CodeMirror-gutters");
EventUtils.sendMouseEvent({ type: "mousedown", shiftKey: true }, gutter, iframe.contentWindow);
is(ed.getSelection(), "Hello.", "shift-click");
teardown(ed, win);
});
}

Просмотреть файл

@ -82,7 +82,7 @@ const kPinned = [
];
this.CharsetMenu = Object.freeze({
build: function BuildCharsetMenu(event) {
build: function BuildCharsetMenu(event, showAccessKeys) {
let parent = event.target;
if (parent.lastChild.localName != "menuseparator") {
// Detector menu or charset menu already built
@ -100,11 +100,13 @@ this.CharsetMenu = Object.freeze({
// Localization error but put *something* in the menu to recover.
menuItem.setAttribute("label", encoding);
}
try {
menuItem.setAttribute("accesskey",
gBundle.GetStringFromName(encoding + ".key"));
} catch (e) {
// Some items intentionally don't have an accesskey
if (showAccessKeys) {
try {
menuItem.setAttribute("accesskey",
gBundle.GetStringFromName(encoding + ".key"));
} catch (e) {
// Some items intentionally don't have an accesskey
}
}
menuItem.setAttribute("id", "charset." + encoding);
return menuItem;

Просмотреть файл

@ -39,5 +39,38 @@ public class AboutPages {
}
return url.startsWith(READER);
}
private static final String[] DEFAULT_ICON_PAGES = new String[] {
HOME,
ADDONS,
CONFIG,
DOWNLOADS,
FIREFOX,
HEALTHREPORT,
UPDATER
};
/**
* Callers must not modify the returned array.
*/
public static String[] getDefaultIconPages() {
return DEFAULT_ICON_PAGES;
}
public static boolean isDefaultIconPage(final String url) {
if (url == null ||
!url.startsWith("about:")) {
return false;
}
// TODO: it'd be quicker to not compare the "about:" part every time.
for (int i = 0; i < DEFAULT_ICON_PAGES.length; ++i) {
if (DEFAULT_ICON_PAGES[i].equals(url)) {
return true;
}
}
return false;
}
}

Просмотреть файл

@ -197,10 +197,24 @@ abstract public class BrowserApp extends GeckoApp
@Override
public void onTabChanged(Tab tab, Tabs.TabEvents msg, Object data) {
if (tab == null) {
// Only RESTORED is allowed a null tab: it's the only event that
// isn't tied to a specific tab.
if (msg != Tabs.TabEvents.RESTORED) {
throw new IllegalArgumentException("onTabChanged:" + msg + " must specify a tab.");
}
return;
}
Log.d(LOGTAG, "BrowserApp.onTabChanged: " + tab.getId() + ": " + msg);
switch(msg) {
// We don't get a LOCATION_CHANGE event for the first about:home
// load, because the previous and current URIs are the
// same. That means it's OK to trigger a new favicon load
// at this point.
case LOCATION_CHANGE:
if (Tabs.getInstance().isSelectedTab(tab)) {
maybeCancelFaviconLoad(tab);
loadFavicon(tab);
}
// fall through
case SELECTED:
@ -241,9 +255,6 @@ abstract public class BrowserApp extends GeckoApp
invalidateOptionsMenu();
}
break;
case PAGE_SHOW:
loadFavicon(tab);
break;
case LINK_FAVICON:
// If tab is not loading and the favicon is updated, we
// want to load the image straight away. If tab is still
@ -1229,7 +1240,7 @@ abstract public class BrowserApp extends GeckoApp
@Override
public void addTab() {
Tabs.getInstance().loadUrl(AboutPages.HOME, Tabs.LOADURL_NEW_TAB);
super.loadHomePage(Tabs.LOADURL_NEW_TAB);
}
@Override
@ -1401,7 +1412,7 @@ abstract public class BrowserApp extends GeckoApp
}
private void openReadingList() {
Tabs.getInstance().loadUrl(AboutPages.HOME, Tabs.LOADURL_READING_LIST);
super.loadHomePage(Tabs.LOADURL_READING_LIST);
}
/* Favicon stuff. */
@ -1428,10 +1439,13 @@ abstract public class BrowserApp extends GeckoApp
private void maybeCancelFaviconLoad(Tab tab) {
int faviconLoadId = tab.getFaviconLoadId();
// Cancel pending favicon load task
Favicons.cancelFaviconLoad(faviconLoadId);
if (Favicons.NOT_LOADING == faviconLoadId) {
return;
}
// Reset favicon load state
// Cancel load task and reset favicon load state if it wasn't already
// in NOT_LOADING state.
Favicons.cancelFaviconLoad(faviconLoadId);
tab.setFaviconLoadId(Favicons.NOT_LOADING);
}

Просмотреть файл

@ -1354,8 +1354,8 @@ abstract public class GeckoApp
if (url == null) {
if (!mShouldRestore) {
// Show about:home if we aren't restoring previous session and
// there's no external URL
Tab tab = Tabs.getInstance().loadUrl(AboutPages.HOME, Tabs.LOADURL_NEW_TAB);
// there's no external URL.
loadHomePage(Tabs.LOADURL_NEW_TAB);
}
} else {
// If given an external URL, load it
@ -1364,6 +1364,14 @@ abstract public class GeckoApp
}
}
protected Tab loadHomePage() {
return loadHomePage(Tabs.LOADURL_NONE);
}
protected Tab loadHomePage(int flags) {
return Tabs.getInstance().loadUrl(AboutPages.HOME, flags);
}
private void initialize() {
mInitialized = true;

Просмотреть файл

@ -627,6 +627,12 @@ public class Tab {
final String uri = message.getString("uri");
final String oldUrl = getURL();
mEnteringReaderMode = ReaderModeUtils.isEnteringReaderMode(oldUrl, uri);
if (TextUtils.equals(oldUrl, uri)) {
Log.d(LOGTAG, "Ignoring location change event: URIs are the same.");
return;
}
updateURL(uri);
updateUserSearch(message.getString("userSearch"));
@ -639,7 +645,13 @@ public class Tab {
}
setContentType(message.getString("contentType"));
// We can unconditionally clear the favicon here: we already
// short-circuited for both cases in which this was a (pseudo-)
// spurious location change, so we're definitely loading a new page.
// The same applies to all of the other fields we're wiping out.
clearFavicon();
setHasFeeds(false);
updateTitle(null);
updateIdentityData(null);

Просмотреть файл

@ -382,6 +382,7 @@ public class Tabs implements GeckoEventListener {
@Override
public void handleMessage(String event, JSONObject message) {
Log.d(LOGTAG, "handleMessage: " + event);
try {
if (event.equals("Session:RestoreEnd")) {
notifyListeners(null, TabEvents.RESTORED);
@ -562,6 +563,11 @@ public class Tabs implements GeckoEventListener {
// Throws if not initialized.
public void notifyListeners(final Tab tab, final TabEvents msg, final Object data) {
if (tab == null &&
msg != TabEvents.RESTORED) {
throw new IllegalArgumentException("onTabChanged:" + msg + " must specify a tab.");
}
ThreadUtils.postToUiThread(new Runnable() {
@Override
public void run() {
@ -660,8 +666,8 @@ public class Tabs implements GeckoEventListener {
*
* @param url URL of page to load, or search term used if searchEngine is given
*/
public void loadUrl(String url) {
loadUrl(url, LOADURL_NONE);
public Tab loadUrl(String url) {
return loadUrl(url, LOADURL_NONE);
}
/**
@ -731,13 +737,34 @@ public class Tabs implements GeckoEventListener {
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Tab:Load", args.toString()));
if ((added != null) && !delayLoad && !background) {
if (added == null) {
return null;
}
if (!delayLoad && !background) {
selectTab(added.getId());
}
// TODO: surely we could just fetch *any* cached icon?
if (AboutPages.isDefaultIconPage(url)) {
Log.d(LOGTAG, "Setting about: tab favicon inline.");
added.updateFavicon(getAboutPageFavicon(url));
}
return added;
}
/**
* These favicons are only used for the URL bar, so
* we fetch with that size.
*
* This method completes on the calling thread.
*/
private Bitmap getAboutPageFavicon(final String url) {
int faviconSize = Math.round(mAppContext.getResources().getDimension(R.dimen.browser_toolbar_favicon_size));
return Favicons.getCachedFaviconForSize(url, faviconSize);
}
/**
* Open the url as a new tab, and mark the selected tab as its "parent".
*

Просмотреть файл

@ -6,23 +6,28 @@
package org.mozilla.gecko.favicons;
import org.mozilla.gecko.AboutPages;
import org.mozilla.gecko.AppConstants;
import org.mozilla.gecko.R;
import org.mozilla.gecko.Tab;
import org.mozilla.gecko.Tabs;
import org.mozilla.gecko.db.BrowserDB;
import org.mozilla.gecko.favicons.cache.FaviconCache;
import org.mozilla.gecko.gfx.BitmapUtils;
import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.util.GeckoJarReader;
import org.mozilla.gecko.util.NonEvictingLruCache;
import org.mozilla.gecko.util.ThreadUtils;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.text.TextUtils;
import android.util.Log;
import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
@ -32,6 +37,9 @@ import java.util.Set;
public class Favicons {
private static final String LOGTAG = "GeckoFavicons";
// A magic URL representing the app's own favicon, used for about: pages.
private static final String BUILT_IN_FAVICON_URL = "about:favicon";
// Size of the favicon bitmap cache, in bytes (Counting payload only).
public static final int FAVICON_CACHE_SIZE_BYTES = 512 * 1024;
@ -97,6 +105,20 @@ public class Favicons {
return NOT_LOADING;
}
/**
* Only returns a non-null Bitmap if the entire path is cached -- the
* page URL to favicon URL, and the favicon URL to in-memory bitmaps.
*
* Returns null otherwise.
*/
public static Bitmap getCachedFaviconForSize(final String pageURL, int targetSize) {
final String faviconURL = sPageURLMappings.get(pageURL);
if (faviconURL == null) {
return null;
}
return getSizedFaviconFromCache(faviconURL, targetSize);
}
/**
* Get a Favicon as close as possible to the target dimensions for the URL provided.
* If a result is instantly available from the cache, it is returned and the listener is invoked.
@ -113,8 +135,13 @@ public class Favicons {
* LOADED if the value could be dispatched on the current thread.
*/
public static int getFaviconForSize(String pageURL, String faviconURL, int targetSize, int flags, OnFaviconLoadedListener listener) {
// If there's no favicon URL given, try and hit the cache with the default one.
// Do we know the favicon URL for this page already?
String cacheURL = faviconURL;
if (cacheURL == null) {
cacheURL = sPageURLMappings.get(pageURL);
}
// If there's no favicon URL given, try and hit the cache with the default one.
if (cacheURL == null) {
cacheURL = guessDefaultFaviconURL(pageURL);
}
@ -262,8 +289,8 @@ public class Favicons {
sFaviconsCache.putSingleFavicon(pageUrl, image);
}
public static void putFaviconsInMemCache(String pageUrl, Iterator<Bitmap> images) {
sFaviconsCache.putFavicons(pageUrl, images);
public static void putFaviconsInMemCache(String pageUrl, Iterator<Bitmap> images, boolean permanently) {
sFaviconsCache.putFavicons(pageUrl, images, permanently);
}
public static void clearMemCache() {
@ -328,16 +355,49 @@ public class Favicons {
* @param context A reference to the GeckoApp instance.
*/
public static void attachToContext(Context context) throws Exception {
final Resources res = context.getResources();
sContext = context;
// Decode the default Favicon ready for use.
sDefaultFavicon = BitmapFactory.decodeResource(context.getResources(), R.drawable.favicon);
sDefaultFavicon = BitmapFactory.decodeResource(res, R.drawable.favicon);
if (sDefaultFavicon == null) {
throw new Exception("Null default favicon was returned from the resources system!");
}
sDefaultFaviconSize = context.getResources().getDimensionPixelSize(R.dimen.favicon_bg);
sFaviconsCache = new FaviconCache(FAVICON_CACHE_SIZE_BYTES, context.getResources().getDimensionPixelSize(R.dimen.favicon_largest_interesting_size));
sDefaultFaviconSize = res.getDimensionPixelSize(R.dimen.favicon_bg);
sFaviconsCache = new FaviconCache(FAVICON_CACHE_SIZE_BYTES, res.getDimensionPixelSize(R.dimen.favicon_largest_interesting_size));
// Initialize page mappings for each of our special pages.
for (String url : AboutPages.getDefaultIconPages()) {
sPageURLMappings.putWithoutEviction(url, BUILT_IN_FAVICON_URL);
}
// Load and cache the built-in favicon in each of its sizes.
// TODO: don't open the zip twice!
ArrayList<Bitmap> toInsert = new ArrayList<Bitmap>(2);
toInsert.add(loadBrandingBitmap(context, "favicon64.png"));
toInsert.add(loadBrandingBitmap(context, "favicon32.png"));
putFaviconsInMemCache(BUILT_IN_FAVICON_URL, toInsert.iterator(), true);
}
/**
* Compute a string like:
* "jar:jar:file:///data/app/org.mozilla.firefox-1.apk!/assets/omni.ja!/chrome/chrome/content/branding/favicon64.png"
*/
private static String getBrandingBitmapPath(Context context, String name) {
final String apkPath = context.getPackageResourcePath();
return "jar:jar:" + new File(apkPath).toURI() + "!/" +
AppConstants.OMNIJAR_NAME + "!/" +
"chrome/chrome/content/branding/" + name;
}
private static Bitmap loadBrandingBitmap(Context context, String name) {
Bitmap b = GeckoJarReader.getBitmap(context.getResources(),
getBrandingBitmapPath(context, name));
if (b == null) {
throw new IllegalStateException("Bitmap " + name + " missing from JAR!");
}
return b;
}
/**

Просмотреть файл

@ -23,6 +23,9 @@ import java.util.concurrent.atomic.AtomicInteger;
* The collection of FaviconsForURL objects currently in the cache is stored in mBackingMap, keyed
* by favicon URL.
*
* A second map exists for permanent cache entries -- ones that are never expired. These entries
* are assumed to be disjoint from those in the normal cache, and this map is checked first.
*
* FaviconsForURL provides a method for obtaining the smallest icon larger than a given size - the
* most appropriate icon for a particular size.
* It also distinguishes between "primary" favicons (Ones that have merely been extracted from a
@ -106,6 +109,9 @@ public class FaviconCache {
// for the least larger payload currently present.
private final ConcurrentHashMap<String, FaviconsForURL> mBackingMap = new ConcurrentHashMap<String, FaviconsForURL>();
// And the same, but never evicted.
private final ConcurrentHashMap<String, FaviconsForURL> mPermanentBackingMap = new ConcurrentHashMap<String, FaviconsForURL>();
// A linked list used to implement a queue, defining the LRU properties of the cache. Elements
// contained within the various FaviconsForURL objects are held here, the least recently used
// of which at the end of the list. When space needs to be reclaimed, the appropriate bitmap is
@ -117,7 +123,7 @@ public class FaviconCache {
// the primary bitmap most suited to the requested size (in cases where multiple primary bitmaps
// are provided by the underlying file format).
// Current size, in bytes, of the bitmap data present in the cache.
// Current size, in bytes, of the bitmap data present in the LRU cache.
private final AtomicInteger mCurrentSize = new AtomicInteger(0);
// The maximum quantity, in bytes, of bitmap data which may be stored in the cache.
@ -216,6 +222,8 @@ public class FaviconCache {
try {
// If we don't have it in the cache, it certainly isn't a known failure.
// Non-evictable favicons are never failed, so we don't need to
// check mPermanentBackingMap.
if (!mBackingMap.containsKey(faviconURL)) {
return false;
}
@ -304,18 +312,24 @@ public class FaviconCache {
boolean doingWrites = false;
boolean shouldComputeColour = false;
boolean isAborting = false;
boolean wasPermanent = false;
FaviconsForURL container;
final Bitmap newBitmap;
final FaviconsForURL container;
startRead();
try {
if (!mBackingMap.containsKey(faviconURL)) {
return null;
container = mPermanentBackingMap.get(faviconURL);
if (container == null) {
container = mBackingMap.get(faviconURL);
if (container == null) {
// We don't have it!
return null;
}
} else {
wasPermanent = true;
}
container = mBackingMap.get(faviconURL);
FaviconCacheElement cacheElement;
int cacheElementIndex = container.getNextHighestIndex(targetSize);
@ -412,9 +426,10 @@ public class FaviconCache {
// This way, subsequent requests hit straight away.
FaviconCacheElement newElement = container.addSecondary(newBitmap, targetSize);
setMostRecentlyUsed(newElement);
mCurrentSize.addAndGet(newElement.sizeOf());
if (!wasPermanent) {
setMostRecentlyUsed(newElement);
mCurrentSize.addAndGet(newElement.sizeOf());
}
} finally {
finishWrite();
}
@ -432,14 +447,18 @@ public class FaviconCache {
startRead();
try {
if (!mBackingMap.containsKey(key)) {
FaviconsForURL element = mPermanentBackingMap.get(key);
if (element == null) {
element = mBackingMap.get(key);
}
if (element == null) {
Log.w(LOGTAG, "Cannot compute dominant color of non-cached favicon. Cache fullness " +
mCurrentSize.get() + '/' + mMaxSizeBytes);
finishRead();
return 0xFFFFFF;
}
FaviconsForURL element = mBackingMap.get(key);
return element.ensureDominantColor();
} finally {
@ -543,8 +562,9 @@ public class FaviconCache {
*
* @param faviconURL The URL from which the favicons originate.
* @param favicons A List of favicons decoded from this URL.
* @param permanently If true, the added favicons are never subject to eviction.
*/
public void putFavicons(String faviconURL, Iterator<Bitmap> favicons) {
public void putFavicons(String faviconURL, Iterator<Bitmap> favicons, boolean permanently) {
// We don't know how many icons we'll have - let's just take a guess.
FaviconsForURL toInsert = new FaviconsForURL(5 * NUM_FAVICON_SIZES);
int sizeGained = 0;
@ -567,8 +587,10 @@ public class FaviconCache {
// without taking the write lock, via the magic of the reordering semaphore.
mReorderingSemaphore.acquireUninterruptibly();
try {
for (FaviconCacheElement newElement : toInsert.mFavicons) {
mOrdering.offer(newElement);
if (!permanently) {
for (FaviconCacheElement newElement : toInsert.mFavicons) {
mOrdering.offer(newElement);
}
}
} catch (Exception e) {
abortingRead = true;
@ -585,10 +607,14 @@ public class FaviconCache {
}
try {
mCurrentSize.addAndGet(sizeGained);
if (permanently) {
mPermanentBackingMap.put(faviconURL, toInsert);
} else {
mCurrentSize.addAndGet(sizeGained);
// Update the value in the LruCache...
recordRemoved(mBackingMap.put(faviconURL, toInsert));
// Update the value in the LruCache...
recordRemoved(mBackingMap.put(faviconURL, toInsert));
}
} finally {
finishWrite();
}
@ -631,10 +657,12 @@ public class FaviconCache {
public void evictAll() {
startWrite();
// Note that we neither clear, nor track the size of, the permanent map.
try {
mCurrentSize.set(0);
mBackingMap.clear();
mOrdering.clear();
} finally {
finishWrite();
}

Просмотреть файл

@ -115,8 +115,12 @@ public class BrowserToolbar extends GeckoRelativeLayout
private ShapedButton mTabs;
private ImageButton mBack;
private ImageButton mForward;
private ImageButton mFavicon;
private ImageButton mStop;
// To de-bounce sets.
private Bitmap mLastFavicon;
private ImageButton mFavicon;
private ImageButton mSiteSecurity;
private PageActionLayout mPageActionLayout;
private Animation mProgressSpinner;
@ -428,7 +432,7 @@ public class BrowserToolbar extends GeckoRelativeLayout
mFavicon.setOnClickListener(faviconListener);
mSiteSecurity.setOnClickListener(faviconListener);
mStop.setOnClickListener(new Button.OnClickListener() {
@Override
public void onClick(View v) {
@ -532,6 +536,7 @@ public class BrowserToolbar extends GeckoRelativeLayout
@Override
public void onTabChanged(Tab tab, Tabs.TabEvents msg, Object data) {
Log.d(LOGTAG, "onTabChanged: " + msg);
final Tabs tabs = Tabs.getInstance();
// These conditions are split into three phases:
@ -583,7 +588,12 @@ public class BrowserToolbar extends GeckoRelativeLayout
case LOCATION_CHANGE:
// A successful location change will cause Tab to notify
// us of a title change, so we don't update the title here.
refresh();
// And there's no point in refreshing the UI
// if the page is the same.
final String oldURL = (String) data;
if (!TextUtils.equals(oldURL, tab.getURL())) {
refresh();
}
break;
case CLOSED:
@ -741,12 +751,15 @@ public class BrowserToolbar extends GeckoRelativeLayout
}
public void setProgressVisibility(boolean visible) {
Log.d(LOGTAG, "setProgressVisibility: " + visible);
// The "Throbber start" and "Throbber stop" log messages in this method
// are needed by S1/S2 tests (http://mrcote.info/phonedash/#).
// See discussion in Bug 804457. Bug 805124 tracks paring these down.
if (visible) {
mFavicon.setImageResource(R.drawable.progress_spinner);
//To stop the glitch caused by mutiple start() calls.
mLastFavicon = null;
// To stop the glitch caused by multiple start() calls.
if (!mSpinnerVisible) {
setPageActionVisibility(true);
mFavicon.setAnimation(mProgressSpinner);
@ -756,8 +769,9 @@ public class BrowserToolbar extends GeckoRelativeLayout
Log.i(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - Throbber start");
} else {
Tab selectedTab = Tabs.getInstance().getSelectedTab();
if (selectedTab != null)
if (selectedTab != null) {
setFavicon(selectedTab.getFavicon());
}
if (mSpinnerVisible) {
setPageActionVisibility(false);
@ -868,15 +882,15 @@ public class BrowserToolbar extends GeckoRelativeLayout
setContentDescription(title != null ? title : mTitle.getHint());
}
// Sets the toolbar title according to the selected tab, obeying the mShowUrl prference.
// Sets the toolbar title according to the selected tab, obeying the mShowUrl preference.
private void updateTitle() {
Tab tab = Tabs.getInstance().getSelectedTab();
final Tab tab = Tabs.getInstance().getSelectedTab();
// Keep the title unchanged if there's no selected tab, or if the tab is entering reader mode.
if (tab == null || tab.isEnteringReaderMode()) {
return;
}
String url = tab.getURL();
final String url = tab.getURL();
if (!isEditing()) {
mUrlEditLayout.setText(url);
@ -923,8 +937,17 @@ public class BrowserToolbar extends GeckoRelativeLayout
}
private void setFavicon(Bitmap image) {
if (Tabs.getInstance().getSelectedTab().getState() == Tab.STATE_LOADING)
Log.d(LOGTAG, "setFavicon(" + image + ")");
if (Tabs.getInstance().getSelectedTab().getState() == Tab.STATE_LOADING) {
return;
}
if (image == mLastFavicon) {
Log.d(LOGTAG, "Ignoring favicon set: new favicon is identical to previous favicon.");
return;
}
mLastFavicon = image; // Cache the original so we can debounce without scaling.
if (image != null) {
image = Bitmap.createScaledBitmap(image, mFaviconSize, mFaviconSize, false);
@ -933,7 +956,7 @@ public class BrowserToolbar extends GeckoRelativeLayout
mFavicon.setImageDrawable(null);
}
}
private void setSecurityMode(String mode) {
int imageLevel = SiteIdentityPopup.getSecurityImageLevel(mode);
mSiteSecurity.setImageLevel(imageLevel);
@ -1571,6 +1594,7 @@ public class BrowserToolbar extends GeckoRelativeLayout
@Override
public void handleMessage(String event, JSONObject message) {
Log.d(LOGTAG, "handleMessage: " + event);
if (event.equals("Reader:Click")) {
Tab tab = Tabs.getInstance().getSelectedTab();
if (tab != null) {

Просмотреть файл

@ -16,7 +16,6 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>&abouthome.title;</title>
<link rel="icon" type="image/png" sizes="64x64" href="chrome://branding/content/favicon64.png" />
</head>
<body>
</body>

Просмотреть файл

@ -4388,11 +4388,16 @@ var BrowserEventHandler = {
element = ElementTouchHelper.anyElementFromPoint(x, y);
}
// Was the element already focused before it was clicked?
let isFocused = (element == BrowserApp.getFocusedInput(BrowserApp.selectedBrowser, true));
this._sendMouseEvent("mousemove", element, x, y);
this._sendMouseEvent("mousedown", element, x, y);
this._sendMouseEvent("mouseup", element, x, y);
SelectionHandler.attachCaret(element);
// If the element was previously focused, show the caret attached to it.
if (isFocused)
SelectionHandler.attachCaret(element);
// scrollToFocusedInput does its own checks to find out if an element should be zoomed into
BrowserApp.scrollToFocusedInput(BrowserApp.selectedBrowser);

Просмотреть файл

@ -300,9 +300,9 @@ select[disabled] > button {
*:-moz-any-link:active,
*[role=button]:active,
button:not([disabled]):active,
input:not([disabled]):active,
input:not(:focus):not([disabled]):active,
select:not([disabled]):active,
textarea:not([disabled]):active,
textarea:not(:focus):not([disabled]):active,
option:active,
label:active,
xul|menulist:active {