Merge mozilla-central into mozilla-inbound

This commit is contained in:
Ehsan Akhgari 2011-06-09 09:26:52 -04:00
commit 1601471f11
101 changed files with 2517 additions and 1033 deletions

View File

@ -90,7 +90,7 @@ nsApplicationAccessible *nsAccessNode::gApplicationAccessible = nsnull;
////////////////////////////////////////////////////////////////////////////////
// nsAccessible. nsISupports
NS_IMPL_CYCLE_COLLECTION_0(nsAccessNode)
NS_IMPL_CYCLE_COLLECTION_1(nsAccessNode, mContent)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsAccessNode)
NS_INTERFACE_MAP_ENTRY(nsIAccessNode)

View File

@ -138,19 +138,21 @@ nsDocAccessible::~nsDocAccessible()
NS_IMPL_CYCLE_COLLECTION_CLASS(nsDocAccessible)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsDocAccessible, nsAccessible)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDocument)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mNotificationController,
NotificationController)
PRUint32 i, length = tmp->mChildDocuments.Length();
for (i = 0; i < length; ++i) {
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mChildDocuments[i]");
cb.NoteXPCOMChild(static_cast<nsIAccessible*>(tmp->mChildDocuments[i].get()));
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mChildDocuments[i],
nsIAccessible)
}
CycleCollectorTraverseCache(tmp->mAccessibleCache, &cb);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsDocAccessible, nsAccessible)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDocument)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mNotificationController)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSTARRAY(mChildDocuments)
tmp->mDependentIDsHash.Clear();

View File

@ -637,9 +637,26 @@ nsXULTreeItemAccessibleBase::
////////////////////////////////////////////////////////////////////////////////
// nsXULTreeItemAccessibleBase: nsISupports implementation
NS_IMPL_ISUPPORTS_INHERITED1(nsXULTreeItemAccessibleBase,
nsAccessible,
nsXULTreeItemAccessibleBase)
NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULTreeItemAccessibleBase)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXULTreeItemAccessibleBase,
nsAccessible)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mTree)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mTreeView)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsXULTreeItemAccessibleBase,
nsAccessible)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mTree)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mTreeView)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsXULTreeItemAccessibleBase)
NS_INTERFACE_TABLE_INHERITED1(nsXULTreeItemAccessibleBase,
nsXULTreeItemAccessibleBase)
NS_INTERFACE_TABLE_TAIL_INHERITING(nsAccessible)
NS_IMPL_ADDREF_INHERITED(nsXULTreeItemAccessibleBase, nsAccessible)
NS_IMPL_RELEASE_INHERITED(nsXULTreeItemAccessibleBase, nsAccessible)
////////////////////////////////////////////////////////////////////////////////
// nsXULTreeItemAccessibleBase: nsIAccessible implementation
@ -1043,6 +1060,22 @@ nsXULTreeItemAccessibleBase::IsExpandable()
return PR_FALSE;
}
void
nsXULTreeItemAccessibleBase::GetCellName(nsITreeColumn* aColumn,
nsAString& aName)
{
mTreeView->GetCellText(mRow, aColumn, aName);
// If there is still no name try the cell value:
// This is for graphical cells. We need tree/table view implementors to
// implement FooView::GetCellValue to return a meaningful string for cases
// where there is something shown in the cell (non-text) such as a star icon;
// in which case GetCellValue for that cell would return "starred" or
// "flagged" for example.
if (aName.IsEmpty())
mTreeView->GetCellValue(mRow, aColumn, aName);
}
////////////////////////////////////////////////////////////////////////////////
// nsXULTreeItemAccessible
@ -1057,6 +1090,26 @@ nsXULTreeItemAccessible::
mColumn = nsCoreUtils::GetFirstSensibleColumn(mTree);
}
////////////////////////////////////////////////////////////////////////////////
// nsXULTreeItemAccessible: nsISupports implementation
NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULTreeItemAccessible)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXULTreeItemAccessible,
nsXULTreeItemAccessibleBase)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mColumn)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsXULTreeItemAccessible,
nsXULTreeItemAccessibleBase)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mColumn)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsXULTreeItemAccessible)
NS_INTERFACE_MAP_END_INHERITING(nsXULTreeItemAccessibleBase)
NS_IMPL_ADDREF_INHERITED(nsXULTreeItemAccessible, nsXULTreeItemAccessibleBase)
NS_IMPL_RELEASE_INHERITED(nsXULTreeItemAccessible, nsXULTreeItemAccessibleBase)
////////////////////////////////////////////////////////////////////////////////
// nsXULTreeItemAccessible: nsIAccessible implementation
@ -1068,16 +1121,7 @@ nsXULTreeItemAccessible::GetName(nsAString& aName)
if (IsDefunct())
return NS_ERROR_FAILURE;
mTreeView->GetCellText(mRow, mColumn, aName);
// If there is still no name try the cell value:
// This is for graphical cells. We need tree/table view implementors to implement
// FooView::GetCellValue to return a meaningful string for cases where there is
// something shown in the cell (non-text) such as a star icon; in which case
// GetCellValue for that cell would return "starred" or "flagged" for example.
if (aName.IsEmpty())
mTreeView->GetCellValue(mRow, mColumn, aName);
GetCellName(mColumn, aName);
return NS_OK;
}

View File

@ -177,8 +177,10 @@ public:
nsAccessible *aParent, nsITreeBoxObject *aTree,
nsITreeView *aTreeView, PRInt32 aRow);
// nsISupports
// nsISupports and cycle collection
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsXULTreeItemAccessibleBase,
nsAccessibleWrap)
// nsIAccessible
NS_IMETHOD GetFocusedChild(nsIAccessible **aFocusedChild);
@ -244,6 +246,11 @@ protected:
*/
PRBool IsExpandable();
/**
* Return name for cell at the given column.
*/
void GetCellName(nsITreeColumn* aColumn, nsAString& aName);
nsCOMPtr<nsITreeBoxObject> mTree;
nsCOMPtr<nsITreeView> mTreeView;
PRInt32 mRow;
@ -263,6 +270,11 @@ public:
nsAccessible *aParent, nsITreeBoxObject *aTree,
nsITreeView *aTreeView, PRInt32 aRow);
// nsISupports and cycle collection
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsXULTreeItemAccessible,
nsXULTreeItemAccessibleBase)
NS_IMETHOD GetName(nsAString& aName);
// nsAccessNode

View File

@ -628,12 +628,12 @@ nsXULTreeGridRowAccessible::
NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULTreeGridRowAccessible)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXULTreeGridRowAccessible,
nsAccessible)
nsXULTreeItemAccessibleBase)
CycleCollectorTraverseCache(tmp->mAccessibleCache, &cb);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsXULTreeGridRowAccessible,
nsAccessible)
nsXULTreeItemAccessibleBase)
ClearCache(tmp->mAccessibleCache);
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
@ -665,6 +665,25 @@ nsXULTreeGridRowAccessible::NativeRole()
return nsIAccessibleRole::ROLE_ROW;
}
NS_IMETHODIMP
nsXULTreeGridRowAccessible::GetName(nsAString& aName)
{
aName.Truncate();
if (IsDefunct())
return NS_ERROR_FAILURE;
nsCOMPtr<nsITreeColumns> columns;
mTree->GetColumns(getter_AddRefs(columns));
if (columns) {
nsCOMPtr<nsITreeColumn> primaryColumn;
columns->GetPrimaryColumn(getter_AddRefs(primaryColumn));
if (primaryColumn)
GetCellName(primaryColumn, aName);
}
return NS_OK;
}
nsAccessible*
nsXULTreeGridRowAccessible::GetChildAtPoint(PRInt32 aX, PRInt32 aY,
EWhichChildAtPoint aWhichChild)
@ -797,10 +816,29 @@ nsXULTreeGridCellAccessible(nsIContent *aContent, nsIWeakReference *aShell,
////////////////////////////////////////////////////////////////////////////////
// nsXULTreeGridCellAccessible: nsISupports implementation
NS_IMPL_ISUPPORTS_INHERITED2(nsXULTreeGridCellAccessible,
nsLeafAccessible,
nsIAccessibleTableCell,
nsXULTreeGridCellAccessible)
NS_IMPL_CYCLE_COLLECTION_CLASS(nsXULTreeGridCellAccessible)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsXULTreeGridCellAccessible,
nsLeafAccessible)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mTree)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mTreeView)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mColumn)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsXULTreeGridCellAccessible,
nsLeafAccessible)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mTree)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mTreeView)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mColumn)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsXULTreeGridCellAccessible)
NS_INTERFACE_TABLE_INHERITED2(nsXULTreeGridCellAccessible,
nsIAccessibleTableCell,
nsXULTreeGridCellAccessible)
NS_INTERFACE_TABLE_TAIL_INHERITING(nsLeafAccessible)
NS_IMPL_ADDREF_INHERITED(nsXULTreeGridCellAccessible, nsLeafAccessible)
NS_IMPL_RELEASE_INHERITED(nsXULTreeGridCellAccessible, nsLeafAccessible)
////////////////////////////////////////////////////////////////////////////////
// nsXULTreeGridCellAccessible: nsIAccessible implementation

View File

@ -86,13 +86,14 @@ public:
// nsISupports and cycle collection
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsXULTreeGridRowAccessible,
nsAccessible)
nsXULTreeItemAccessibleBase)
// nsAccessNode
virtual void Shutdown();
// nsAccessible
virtual PRUint32 NativeRole();
NS_IMETHOD GetName(nsAString& aName);
virtual nsAccessible* GetChildAtPoint(PRInt32 aX, PRInt32 aY,
EWhichChildAtPoint aWhichChild);
@ -139,6 +140,8 @@ public:
// nsISupports
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsXULTreeGridCellAccessible,
nsLeafAccessible)
// nsIAccessible
NS_IMETHOD GetFocusedChild(nsIAccessible **aFocusedChild);

View File

@ -57,6 +57,7 @@ _TEST_FILES =\
test_list.html \
test_markup.html \
test_nsRootAcc.xul \
test_tree.xul \
markuprules.xml \
$(NULL)

View File

@ -0,0 +1,200 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
type="text/css"?>
<?xml-stylesheet href="general.css"
type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
title="Accessibility Name Calculating Test.">
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
<script type="application/javascript"
src="../treeview.js" />
<script type="application/javascript"
src="../common.js"></script>
<script type="application/javascript"
src="../role.js"></script>
<script type="application/javascript"
src="../name.js"></script>
<script type="application/javascript"
src="../events.js"></script>
<script type="application/javascript">
<![CDATA[
function treeTester(aID)
{
this.DOMNode = getNode(aID);
this.invoke = function treeTester_invoke()
{
this.DOMNode.treeBoxObject.view = new nsTreeTreeView();
}
this.check = function treeTester_check(aEvent)
{
var tree = {
role: ROLE_OUTLINE,
children: [
{
role: ROLE_LIST
},
{
role: ROLE_OUTLINEITEM,
children: [],
name: "row1col"
},
{
role: ROLE_OUTLINEITEM,
children: [],
name: "row2_col"
},
{
role: ROLE_OUTLINEITEM,
children: [],
name: "row2.1_col"
},
{
role: ROLE_OUTLINEITEM,
children: [],
name: "row2.2_col"
},
{
role: ROLE_OUTLINEITEM,
children: [],
name: "row3_col"
},
{
role: ROLE_OUTLINEITEM,
children: [],
name: "row4col"
}
]
};
testAccessibleTree(this.DOMNode, tree);
}
this.getID = function treeTester_getID()
{
return "Tree name testing for " + aID;
}
}
function tableTester(aID)
{
this.DOMNode = getNode(aID);
this.invoke = function tableTester_invoke()
{
this.DOMNode.treeBoxObject.view = new nsTableTreeView(2);
}
this.check = function tableTester_check(aEvent)
{
var tree = {
role: ROLE_TREE_TABLE,
children: [
{
role: ROLE_LIST
},
{
role: ROLE_ROW,
children: [
{
role: ROLE_GRID_CELL,
children: [],
name: "row0_col1"
},
{
role: ROLE_GRID_CELL,
children: [],
name: "row0_col2"
}
],
name: "row0_col1"
},
{
role: ROLE_ROW,
children: [
{
role: ROLE_GRID_CELL,
children: [],
name: "row1_col1"
},
{
role: ROLE_GRID_CELL,
children: [],
name: "row1_col2"
}
],
name: "row1_col1"
}
]
};
testAccessibleTree(this.DOMNode, tree);
}
this.getID = function tableTester_getID()
{
return "Tree name testing for " + aID;
}
}
var gQueue = null;
function doTest()
{
var gQueue = new eventQueue(EVENT_REORDER);
gQueue.push(new treeTester("tree"));
gQueue.push(new tableTester("table"));
gQueue.invoke(); // Will call SimpleTest.finish()
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
]]>
</script>
<hbox flex="1" style="overflow: auto;">
<body xmlns="http://www.w3.org/1999/xhtml">
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=546812"
title="Treegrid row accessible shouldn't inherit name from tree accessible">
Mozilla Bug 546812
</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
<vbox flex="1">
<tree id="tree" flex="1">
<treecols>
<treecol id="col" flex="1" primary="true" label="column"/>
</treecols>
<treechildren/>
</tree>
<tree id="table" flex="1">
<treecols>
<treecol id="col1" flex="1" label="column" primary="true"/>
<treecol id="col2" flex="1" label="column 2"/>
</treecols>
<treechildren/>
</tree>
</vbox> <!-- close tests area -->
</hbox> <!-- close main area -->
</window>

View File

@ -47,6 +47,9 @@ const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
const FEEDWRITER_CID = Components.ID("{49bb6593-3aff-4eb3-a068-2712c28bd58e}");
const FEEDWRITER_CONTRACTID = "@mozilla.org/browser/feeds/result-writer;1";
function LOG(str) {
var prefB = Cc["@mozilla.org/preferences-service;1"].
getService(Ci.nsIPrefBranch);
@ -1377,17 +1380,12 @@ FeedWriter.prototype = {
});
},
// nsIClassInfo
getInterfaces: function FW_getInterfaces(countRef) {
var interfaces = [Ci.nsIFeedWriter, Ci.nsIClassInfo, Ci.nsISupports];
countRef.value = interfaces.length;
return interfaces;
},
getHelperForLanguage: function FW_getHelperForLanguage(language) null,
classID: Components.ID("{49bb6593-3aff-4eb3-a068-2712c28bd58e}"),
implementationLanguage: Ci.nsIProgrammingLanguage.JAVASCRIPT,
flags: Ci.nsIClassInfo.DOM_OBJECT,
QueryInterface: XPCOMUtils.generateQI([Ci.nsIFeedWriter, Ci.nsIClassInfo,
classID: FEEDWRITER_CID,
classInfo: XPCOMUtils.generateCI({classID: FEEDWRITER_CID,
contractID: FEEDWRITER_CONTRACTID,
interfaces: [Ci.nsIFeedWriter],
flags: Ci.nsIClassInfo.DOM_OBJECT}),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIFeedWriter,
Ci.nsIDOMEventListener, Ci.nsIObserver,
Ci.nsINavHistoryObserver])
};

View File

@ -911,23 +911,14 @@ WebContentConverterRegistrar.prototype = {
return this.QueryInterface(iid);
},
/**
* See nsIClassInfo
*/
getInterfaces: function WCCR_getInterfaces(countRef) {
var interfaces =
[Ci.nsIWebContentConverterService, Ci.nsIWebContentHandlerRegistrar,
Ci.nsIObserver, Ci.nsIClassInfo, Ci.nsIFactory, Ci.nsISupports];
countRef.value = interfaces.length;
return interfaces;
},
getHelperForLanguage: function WCCR_getHelperForLanguage(language) {
return null;
},
classID: WCCR_CLASSID,
implementationLanguage: Ci.nsIProgrammingLanguage.JAVASCRIPT,
flags: Ci.nsIClassInfo.DOM_OBJECT,
classInfo: XPCOMUtils.generateCI({classID: WCCR_CLASSID,
contractID: WCCR_CONTRACTID,
interfaces: [Ci.nsIWebContentConverterService,
Ci.nsIWebContentHandlerRegistrar,
Ci.nsIObserver, Ci.nsIFactory],
flags: Ci.nsIClassInfo.DOM_OBJECT}),
/**
* See nsISupports
*/
@ -935,9 +926,7 @@ WebContentConverterRegistrar.prototype = {
[Ci.nsIWebContentConverterService,
Ci.nsIWebContentHandlerRegistrar,
Ci.nsIObserver,
Ci.nsIClassInfo,
Ci.nsIFactory,
Ci.nsISupports]),
Ci.nsIFactory]),
_xpcom_categories: [{
category: "app-startup",

View File

@ -653,6 +653,11 @@ PlacesViewBase.prototype = {
this._result = null;
}
if (this._controller) {
this._viewElt.controllers.removeController(this._controller);
this._controller = null;
}
delete this._viewElt._placesView;
},

View File

@ -21,6 +21,7 @@
*
* Contributor(s):
* Dietrich Ayala <dietrich@mozilla.com>
* Marco Bonardo <mak77@bonardo.net>
*
* 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
@ -36,265 +37,365 @@
*
* ***** END LICENSE BLOCK ***** */
// get history service
try {
var histsvc = Cc["@mozilla.org/browser/nav-history-service;1"].getService(Ci.nsINavHistoryService);
} catch(ex) {
do_throw("Could not get nav-history-service\n");
}
// An object representing the contents of bookmarks.preplaces.html.
let test_bookmarks = {
menu: [
{ title: "Mozilla Firefox",
children: [
{ title: "Help and Tutorials",
url: "http://en-us.www.mozilla.com/en-US/firefox/help/",
icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg=="
},
{ title: "Customize Firefox",
url: "http://en-us.www.mozilla.com/en-US/firefox/customize/",
icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg=="
},
{ title: "Get Involved",
url: "http://en-us.www.mozilla.com/en-US/firefox/community/",
icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg=="
},
{ title: "About Us",
url: "http://en-us.www.mozilla.com/en-US/about/",
icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg=="
},
],
},
{ title: "test",
description: "folder test comment",
dateAdded: 1177541020000000,
lastModified: 1177541050000000,
children: [
{ title: "test post keyword",
description: "item description",
dateAdded: 1177375336000000,
lastModified: 1177375423000000,
keyword: "test",
sidebar: true,
postData: "hidden1%3Dbar&text1%3D%25s",
charset: "ISO-8859-1",
},
]
},
],
toolbar: [
{ title: "Getting Started",
url: "http://en-us.www.mozilla.com/en-US/firefox/central/",
icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg=="
},
{ title: "Latest Headlines",
description: "Livemark test comment",
url: "http://en-us.fxfeeds.mozilla.com/en-US/firefox/livebookmarks/",
feedUrl: "http://en-us.fxfeeds.mozilla.com/en-US/firefox/headlines.xml",
}
],
unfiled: [
{ title: "Example.tld",
url: "http://example.tld/",
},
],
};
// Get bookmark service
try {
var bmsvc = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].getService(Ci.nsINavBookmarksService);
} catch(ex) {
do_throw("Could not get nav-bookmarks-service\n");
}
// Pre-Places bookmarks.html file pointer.
let gBookmarksFileOld;
// Places bookmarks.html file pointer.
let gBookmarksFileNew;
// Get annotation service
try {
var annosvc = Cc["@mozilla.org/browser/annotation-service;1"].getService(Ci.nsIAnnotationService);
} catch(ex) {
do_throw("Could not get annotation service\n");
}
let importer = Cc["@mozilla.org/browser/places/import-export-service;1"].
getService(Ci.nsIPlacesImportExportService);
// Get livemark service
try {
var livemarksvc = Cc["@mozilla.org/browser/livemark-service;2"].getService(Ci.nsILivemarkService);
} catch(ex) {
do_throw("Could not get livemark service\n");
}
function run_test()
{
// Avoid creating smart bookmarks during the test.
Services.prefs.setIntPref("browser.places.smartBookmarksVersion", -1);
// Get favicon service
try {
var iconsvc = Cc["@mozilla.org/browser/favicon-service;1"].getService(Ci.nsIFaviconService);
} catch(ex) {
do_throw("Could not get favicon service\n");
}
// File pointer to legacy bookmarks file.
gBookmarksFileOld = do_get_file("bookmarks.preplaces.html");
// Get io service
try {
var iosvc = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
} catch (ex) {
do_throw("Could not get io service\n");
}
const DESCRIPTION_ANNO = "bookmarkProperties/description";
const LOAD_IN_SIDEBAR_ANNO = "bookmarkProperties/loadInSidebar";
const POST_DATA_ANNO = "bookmarkProperties/POSTData";
const TEST_FAVICON_PAGE_URL = "http://en-US.www.mozilla.com/en-US/firefox/central/";
const TEST_FAVICON_DATA_URL = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg==";
// main
function run_test() {
// get places import/export service
var importer = Cc["@mozilla.org/browser/places/import-export-service;1"].getService(Ci.nsIPlacesImportExportService);
// avoid creating the places smart folder during tests
Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch).
setIntPref("browser.places.smartBookmarksVersion", -1);
// file pointer to legacy bookmarks file
var bookmarksFileOld = do_get_file("bookmarks.preplaces.html");
// file pointer to a new places-exported bookmarks file
var bookmarksFileNew = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
bookmarksFileNew.append("bookmarks.exported.html");
// create bookmarks.exported.html
if (bookmarksFileNew.exists())
bookmarksFileNew.remove(false);
bookmarksFileNew.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, 0600);
if (!bookmarksFileNew.exists())
// File pointer to a new Places-exported bookmarks file.
gBookmarksFileNew = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
gBookmarksFileNew.append("bookmarks.exported.html");
if (gBookmarksFileNew.exists()) {
gBookmarksFileNew.remove(false);
}
gBookmarksFileNew.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, 0600);
if (!gBookmarksFileNew.exists()) {
do_throw("couldn't create file: bookmarks.exported.html");
}
// This test must be the first one, since it setups the new bookmarks.html.
// Test importing a pre-Places canonical bookmarks file.
// 1. import bookmarks.preplaces.html
// 2. run the test-suite
// Note: we do not empty the db before this import to catch bugs like 380999
try {
importer.importHTMLFromFile(bookmarksFileOld, true);
importer.importHTMLFromFile(gBookmarksFileOld, true);
} catch(ex) { do_throw("couldn't import legacy bookmarks file: " + ex); }
testCanonicalBookmarks(bmsvc.bookmarksMenuFolder);
// Test exporting a Places canonical bookmarks file.
// 1. export to bookmarks.exported.html
// 2. empty bookmarks db
// 3. import bookmarks.exported.html
// 4. run the test-suite
testImportedBookmarks();
// Prepare for next tests.
try {
importer.exportHTMLToFile(bookmarksFileNew);
importer.exportHTMLToFile(gBookmarksFileNew);
} catch(ex) { do_throw("couldn't export to file: " + ex); }
bmsvc.removeFolderChildren(bmsvc.bookmarksMenuFolder);
bmsvc.removeFolderChildren(bmsvc.toolbarFolder);
try {
importer.importHTMLFromFile(bookmarksFileNew, true);
} catch(ex) { do_throw("couldn't import the exported file: " + ex); }
testCanonicalBookmarks(bmsvc.bookmarksMenuFolder);
/*
// XXX import-to-folder tests disabled due to bug 363634
remove_all_bookmarks();
run_next_test();
}
add_test(function test_import_new()
{
// Test importing a Places bookmarks.html file.
// 1. import bookmarks.exported.html
// 2. run the test-suite
try {
importer.importHTMLFromFile(gBookmarksFileNew, true);
} catch(ex) { do_throw("couldn't import the exported file: " + ex); }
testImportedBookmarks();
remove_all_bookmarks();
run_next_test();
});
add_test(function test_emptytitle_export()
{
// Test exporting and importing with an empty-titled bookmark.
// 1. import bookmarks
// 1. create an empty-titled bookmark.
// 2. export to bookmarks.exported.html
// 3. empty bookmarks db
// 4. import bookmarks.exported.html
// 5. run the test-suite
try {
importer.importHTMLFromFile(gBookmarksFileNew, true);
} catch(ex) { do_throw("couldn't import the exported file: " + ex); }
const NOTITLE_URL = "http://notitle.mozilla.org/";
let id = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
NetUtil.newURI(NOTITLE_URL),
PlacesUtils.bookmarks.DEFAULT_INDEX,
"");
test_bookmarks.unfiled.push({ title: "", url: NOTITLE_URL });
try {
importer.exportHTMLToFile(gBookmarksFileNew);
} catch(ex) { do_throw("couldn't export to file: " + ex); }
remove_all_bookmarks();
try {
importer.importHTMLFromFile(gBookmarksFileNew, true);
} catch(ex) { do_throw("couldn't import the exported file: " + ex); }
testImportedBookmarks();
// Cleanup.
test_bookmarks.unfiled.pop();
PlacesUtils.bookmarks.removeItem(id);
try {
importer.exportHTMLToFile(gBookmarksFileNew);
} catch(ex) { do_throw("couldn't export to file: " + ex); }
remove_all_bookmarks();
run_next_test();
});
add_test(function test_import_preplaces_to_folder()
{
// Test importing a pre-Places canonical bookmarks file to a specific folder.
// 1. create a new folder
// 2. import bookmarks.preplaces.html to that folder
// 3. run the test-suite
var testFolder = bmsvc.createFolder(bmsvc.bookmarksMenuFolder, "test-import", bmsvc.DEFAULT_INDEX);
try {
importer.importHTMLFromFileToFolder(bookmarksFileOld, testFolder, false);
} catch(ex) { do_throw("couldn't import the exported file to folder: " + ex); }
testCanonicalBookmarks(testFolder);
bmsvc.removeFolder(testFolder);
let testFolder = PlacesUtils.bookmarks.createFolder(
PlacesUtils.bookmarksMenuFolderId, "test-import",
PlacesUtils.bookmarks.DEFAULT_INDEX
);
try {
importer.importHTMLFromFileToFolder(gBookmarksFileOld, testFolder, false);
} catch(ex) { do_throw("couldn't import the exported file to folder: " + ex); }
// Import-to-folder creates subfolders for toolbar and unfiled.
testImportedBookmarksToFolder(testFolder);
remove_all_bookmarks();
run_next_test();
});
add_test(function test_import_to_folder()
{
// Test importing a Places canonical bookmarks file to a specific folder.
// 1. create a new folder
// 2. import bookmarks.exported.html to that folder
// 3. run the test-suite
var testFolder = bmsvc.createFolder(bmsvc.bookmarksMenuFolder, "test-import", bmsvc.DEFAULT_INDEX);
try {
importer.importHTMLFromFileToFolder(bookmarksFileNew, testFolder, false);
} catch(ex) { do_throw("couldn't import the exported file to folder: " + ex); }
testCanonicalBookmarks(testFolder);
bmsvc.removeFolder(testFolder);
// XXX Disabled due to bug 381129 - separators will be duplicated on re-import
let testFolder = PlacesUtils.bookmarks.createFolder(
PlacesUtils.bookmarksMenuFolderId, "test-import",
PlacesUtils.bookmarks.DEFAULT_INDEX
);
try {
importer.importHTMLFromFileToFolder(gBookmarksFileNew, testFolder, false);
} catch(ex) { do_throw("couldn't import the exported file to folder: " + ex); }
// Import-to-folder creates subfolders for toolbar and unfiled.
testImportedBookmarksToFolder(testFolder);
remove_all_bookmarks();
run_next_test();
});
add_test(function test_import_ontop()
{
// Test importing the exported bookmarks.html file *on top of* the existing
// bookmarks. This tests import of IDs. If we support IDs correctly, there
// should be no difference after the import.
// bookmarks.
// 1. empty bookmarks db
// 2. import the exported bookmarks file
// 3. export to file
// 3. import the exported bookmarks file
// 4. run the test-suite
bmsvc.removeFolderChildren(bmsvc.bookmarksMenuFolder);
try {
importer.importHTMLFromFile(bookmarksFileNew, true);
importer.importHTMLFromFile(gBookmarksFileNew, true);
} catch(ex) { do_throw("couldn't import the exported file: " + ex); }
try {
importer.exportHTMLToFile(bookmarksFileNew);
importer.exportHTMLToFile(gBookmarksFileNew);
} catch(ex) { do_throw("couldn't export to file: " + ex); }
try {
importer.importHTMLFromFile(bookmarksFileNew, true);
importer.importHTMLFromFile(gBookmarksFileNew, true);
} catch(ex) { do_throw("couldn't import the exported file: " + ex); }
testCanonicalBookmarks(bmsvc.bookmarksMenuFolder);
*/
/*
XXX if there are new fields we add to the bookmarks HTML format
then test them here
Test importing a Places canonical bookmarks file
1. empty the bookmarks datastore
2. import bookmarks.places.html
3. run the test-suite
4. run the additional-test-suite
*/
testImportedBookmarks();
remove_all_bookmarks();
run_next_test();
});
function testImportedBookmarks()
{
for (let group in test_bookmarks) {
let root;
switch (group) {
case "menu":
root = PlacesUtils.getFolderContents(PlacesUtils.bookmarksMenuFolderId).root;
break;
case "toolbar":
root = PlacesUtils.getFolderContents(PlacesUtils.toolbarFolderId).root;
break;
case "unfiled":
root = PlacesUtils.getFolderContents(PlacesUtils.unfiledBookmarksFolderId).root;
break;
}
let items = test_bookmarks[group];
do_check_eq(root.childCount, items.length);
items.forEach(function (item, index) checkItem(item, root.getChild(index)));
root.containerOpen = false;
}
}
// Tests a bookmarks datastore that has a set of bookmarks, etc
// that flex each supported field and feature.
function testCanonicalBookmarks(aFolder) {
// query to see if the deleted folder and items have been imported
var query = histsvc.getNewQuery();
query.setFolders([aFolder], 1);
var result = histsvc.executeQuery(query, histsvc.getNewQueryOptions());
var rootNode = result.root;
rootNode.containerOpen = true;
function testImportedBookmarksToFolder(aFolder)
{
root = PlacesUtils.getFolderContents(aFolder).root;
// 6-2: the toolbar folder and unfiled bookmarks folder imported to the
// corresponding places folders
do_check_eq(rootNode.childCount, DEFAULT_BOOKMARKS_ON_MENU + 1);
// Menu bookmarks are put directly into the folder, while other roots are
// imported into subfolders.
let rootFolderCount = test_bookmarks.menu.length;
// get test folder
var testFolder = rootNode.getChild(DEFAULT_BOOKMARKS_ON_MENU);
do_check_eq(testFolder.type, testFolder.RESULT_TYPE_FOLDER);
do_check_eq(testFolder.title, "test");
for (let i = 0; i < root.childCount; i++) {
let child = root.getChild(i);
if (i < rootFolderCount) {
checkItem(test_bookmarks.menu[i], child);
}
else {
let container = child.QueryInterface(Ci.nsINavHistoryContainerResultNode);
let group = /Toolbar/.test(container.title) ? test_bookmarks.toolbar
: test_bookmarks.unfiled;
container.containerOpen = true;
print(container.title);
for (let t = 0; t < container.childCount; t++) {
print(group[t].title + " " + container.getChild(t).title);
checkItem(group[t], container.getChild(t));
}
container.containerOpen = false;
}
}
// add date
do_check_eq(bmsvc.getItemDateAdded(testFolder.itemId)/1000000, 1177541020);
// last modified
do_check_eq(bmsvc.getItemLastModified(testFolder.itemId)/1000000, 1177541050);
testFolder = testFolder.QueryInterface(Ci.nsINavHistoryQueryResultNode);
do_check_eq(testFolder.hasChildren, true);
// folder description
do_check_true(annosvc.itemHasAnnotation(testFolder.itemId,
DESCRIPTION_ANNO));
do_check_eq("folder test comment",
annosvc.getItemAnnotation(testFolder.itemId, DESCRIPTION_ANNO));
// open test folder, and test the children
testFolder.containerOpen = true;
var cc = testFolder.childCount;
// XXX Bug 380468
// do_check_eq(cc, 2);
do_check_eq(cc, 1);
// test bookmark 1
var testBookmark1 = testFolder.getChild(0);
// url
do_check_eq("http://test/post", testBookmark1.uri);
// title
do_check_eq("test post keyword", testBookmark1.title);
// keyword
do_check_eq("test", bmsvc.getKeywordForBookmark(testBookmark1.itemId));
// sidebar
do_check_true(annosvc.itemHasAnnotation(testBookmark1.itemId,
LOAD_IN_SIDEBAR_ANNO));
// add date
do_check_eq(testBookmark1.dateAdded/1000000, 1177375336);
// last modified
do_check_eq(testBookmark1.lastModified/1000000, 1177375423);
// post data
do_check_true(annosvc.itemHasAnnotation(testBookmark1.itemId,
POST_DATA_ANNO));
do_check_eq("hidden1%3Dbar&text1%3D%25s",
annosvc.getItemAnnotation(testBookmark1.itemId, POST_DATA_ANNO));
// last charset
var testURI = uri(testBookmark1.uri);
do_check_eq("ISO-8859-1", histsvc.getCharsetForURI(testURI));
// description
do_check_true(annosvc.itemHasAnnotation(testBookmark1.itemId,
DESCRIPTION_ANNO));
do_check_eq("item description",
annosvc.getItemAnnotation(testBookmark1.itemId,
DESCRIPTION_ANNO));
// clean up
testFolder.containerOpen = false;
rootNode.containerOpen = false;
query.setFolders([bmsvc.toolbarFolder], 1);
result = histsvc.executeQuery(query, histsvc.getNewQueryOptions());
// bookmarks toolbar
var toolbar = result.root;
toolbar.containerOpen = true;
do_check_eq(toolbar.childCount, 2);
// livemark
var livemark = toolbar.getChild(1);
// title
do_check_eq("Latest Headlines", livemark.title);
// livemark check
do_check_true(livemarksvc.isLivemark(livemark.itemId));
// site url
do_check_eq("http://en-us.fxfeeds.mozilla.com/en-US/firefox/livebookmarks/",
livemarksvc.getSiteURI(livemark.itemId).spec);
// feed url
do_check_eq("http://en-us.fxfeeds.mozilla.com/en-US/firefox/headlines.xml",
livemarksvc.getFeedURI(livemark.itemId).spec);
toolbar.containerOpen = false;
// unfiled bookmarks
query.setFolders([bmsvc.unfiledBookmarksFolder], 1);
result = histsvc.executeQuery(query, histsvc.getNewQueryOptions());
var unfiledBookmarks = result.root;
unfiledBookmarks.containerOpen = true;
do_check_eq(unfiledBookmarks.childCount, 1);
unfiledBookmarks.containerOpen = false;
// favicons
var faviconURI = iconsvc.getFaviconForPage(uri(TEST_FAVICON_PAGE_URL));
var dataURL = iconsvc.getFaviconDataAsDataURL(faviconURI);
do_check_eq(TEST_FAVICON_DATA_URL, dataURL);
root.containerOpen = false;
}
function checkItem(aExpected, aNode)
{
let id = aNode.itemId;
for (prop in aExpected) {
switch (prop) {
case "title":
do_check_eq(aNode.title, aExpected.title);
break;
case "description":
do_check_eq(PlacesUtils.annotations
.getItemAnnotation(id, PlacesUIUtils.DESCRIPTION_ANNO),
aExpected.description);
break;
case "dateAdded":
do_check_eq(PlacesUtils.bookmarks.getItemDateAdded(id),
aExpected.dateAdded);
break;
case "lastModified":
do_check_eq(PlacesUtils.bookmarks.getItemLastModified(id),
aExpected.lastModified);
break;
case "url":
if (!PlacesUtils.livemarks.isLivemark(id))
do_check_eq(aNode.uri, aExpected.url);
break;
case "icon":
let faviconURI = PlacesUtils.favicons.getFaviconForPage(
NetUtil.newURI(aExpected.url)
);
let dataURL = PlacesUtils.favicons.getFaviconDataAsDataURL(faviconURI);
// Avoid do_check_eq for console spam.
do_check_true(dataURL == aExpected.icon);
break;
case "keyword":
break;
case "sidebar":
do_check_eq(PlacesUtils.annotations
.itemHasAnnotation(id, PlacesUIUtils.LOAD_IN_SIDEBAR_ANNO),
aExpected.sidebar);
break;
case "postData":
do_check_eq(PlacesUtils.annotations
.getItemAnnotation(id, PlacesUtils.POST_DATA_ANNO),
aExpected.postData);
break;
case "charset":
do_check_eq(PlacesUtils.history.getCharsetForURI(NetUtil.newURI(aNode.uri)),
aExpected.charset);
break;
case "feedUrl":
do_check_true(PlacesUtils.livemarks.isLivemark(id));
do_check_eq(PlacesUtils.livemarks.getSiteURI(id).spec,
aExpected.url);
do_check_eq(PlacesUtils.livemarks.getFeedURI(id).spec,
aExpected.feedUrl);
break;
case "children":
let folder = aNode.QueryInterface(Ci.nsINavHistoryContainerResultNode);
do_check_eq(folder.hasChildren, aExpected.children.length > 0);
folder.containerOpen = true;
do_check_eq(folder.childCount, aExpected.children.length);
aExpected.children.forEach(function (item, index) checkItem(item, folder.getChild(index)));
folder.containerOpen = false;
break;
default:
throw new Error("Unknown property");
}
};
}

View File

@ -46,8 +46,8 @@ Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
const DEBUG = false; /* set to false to suppress debug messages */
const SIDEBAR_CONTRACTID = "@mozilla.org/sidebar;1";
const SIDEBAR_CID = Components.ID("{22117140-9c6e-11d3-aaf1-00805f8a4905}");
const nsISupports = Components.interfaces.nsISupports;
const nsISidebar = Components.interfaces.nsISidebar;
const nsISidebarExternal = Components.interfaces.nsISidebarExternal;
const nsIClassInfo = Components.interfaces.nsIClassInfo;
@ -214,32 +214,13 @@ function (aSearchURL)
return 0;
}
// property of nsIClassInfo
nsSidebar.prototype.flags = nsIClassInfo.DOM_OBJECT;
nsSidebar.prototype.classInfo = XPCOMUtils.generateCI({classID: SIDEBAR_CID,
contractID: SIDEBAR_CONTRACTID,
classDescription: "Sidebar",
interfaces: [nsISidebar, nsISidebarExternal],
flags: nsIClassInfo.DOM_OBJECT});
// property of nsIClassInfo
nsSidebar.prototype.classDescription = "Sidebar";
// method of nsIClassInfo
nsSidebar.prototype.getInterfaces = function(count) {
var interfaceList = [nsISidebar, nsISidebarExternal, nsIClassInfo];
count.value = interfaceList.length;
return interfaceList;
}
// method of nsIClassInfo
nsSidebar.prototype.getHelperForLanguage = function(count) {return null;}
nsSidebar.prototype.QueryInterface =
function (iid) {
if (iid.equals(nsISidebar) ||
iid.equals(nsISidebarExternal) ||
iid.equals(nsIClassInfo) ||
iid.equals(nsISupports))
return this;
throw Components.results.NS_ERROR_NO_INTERFACE;
};
nsSidebar.prototype.QueryInterface = XPCOMUtils.generateQI([nsISidebar, nsISidebarExternal]);
var NSGetFactory = XPCOMUtils.generateNSGetFactory([nsSidebar]);

View File

@ -40,6 +40,9 @@ const Cc = Components.classes;
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
const APPLICATION_CID = Components.ID("fe74cf80-aa2d-11db-abbd-0800200c9a66");
const APPLICATION_CONTRACTID = "@mozilla.org/fuel/application;1";
//=================================================
// Singleton that holds services and utilities
var Utilities = {
@ -668,21 +671,22 @@ function Application() {
// Application implementation
Application.prototype = {
// for nsIClassInfo + XPCOMUtils
classID: Components.ID("fe74cf80-aa2d-11db-abbd-0800200c9a66"),
classID: APPLICATION_CID,
// redefine the default factory for XPCOMUtils
_xpcom_factory: ApplicationFactory,
// for nsISupports
QueryInterface : XPCOMUtils.generateQI([Ci.fuelIApplication, Ci.extIApplication,
Ci.nsIObserver, Ci.nsIClassInfo]),
Ci.nsIObserver]),
getInterfaces : function app_gi(aCount) {
var interfaces = [Ci.fuelIApplication, Ci.extIApplication, Ci.nsIObserver,
Ci.nsIClassInfo];
aCount.value = interfaces.length;
return interfaces;
},
// for nsIClassInfo
classInfo: XPCOMUtils.generateCI({classID: APPLICATION_CID,
contractID: APPLICATION_CONTRACTID,
interfaces: [Ci.fuelIApplication,
Ci.extIApplication,
Ci.nsIObserver],
flags: Ci.nsIClassInfo.SINGLETON}),
// for nsIObserver
observe: function app_observe(aSubject, aTopic, aData) {

View File

@ -1722,7 +1722,6 @@ GK_ATOM(columnSetFrame, "ColumnSetFrame")
GK_ATOM(comboboxControlFrame, "ComboboxControlFrame")
GK_ATOM(comboboxDisplayFrame, "ComboboxDisplayFrame")
GK_ATOM(deckFrame, "DeckFrame")
GK_ATOM(directionalFrame, "DirectionalFrame")
GK_ATOM(fieldSetFrame, "FieldSetFrame")
GK_ATOM(frameSetFrame, "FrameSetFrame")
GK_ATOM(gfxButtonControlFrame, "gfxButtonControlFrame")

View File

@ -133,6 +133,13 @@ public:
static ImageCache* gImageCache = nsnull;
class CanvasImageCacheShutdownObserver : public nsIObserver
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
};
void
CanvasImageCache::NotifyDrawImage(nsIDOMElement* aImage,
nsHTMLCanvasElement* aCanvas,
@ -142,6 +149,7 @@ CanvasImageCache::NotifyDrawImage(nsIDOMElement* aImage,
{
if (!gImageCache) {
gImageCache = new ImageCache();
nsContentUtils::RegisterShutdownObserver(new CanvasImageCacheShutdownObserver());
}
ImageCacheEntry* entry = gImageCache->mCache.PutEntry(ImageCacheKey(aImage, aCanvas));
@ -186,11 +194,21 @@ CanvasImageCache::Lookup(nsIDOMElement* aImage,
return entry->mData->mSurface;
}
void
CanvasImageCache::Shutdown()
NS_IMPL_ISUPPORTS1(CanvasImageCacheShutdownObserver, nsIObserver)
NS_IMETHODIMP
CanvasImageCacheShutdownObserver::Observe(nsISupports *aSubject,
const char *aTopic,
const PRUnichar *aData)
{
delete gImageCache;
gImageCache = nsnull;
if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
delete gImageCache;
gImageCache = nsnull;
nsContentUtils::UnregisterShutdownObserver(this);
}
return NS_OK;
}
}

View File

@ -69,8 +69,6 @@ public:
static gfxASurface* Lookup(nsIDOMElement* aImage,
nsHTMLCanvasElement* aCanvas,
gfxIntSize* aSize);
static void Shutdown();
};
}

View File

@ -40,8 +40,8 @@
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
const EXSLT_REGEXP_CID = Components.ID("{18a03189-067b-4978-b4f1-bafe35292ed6}");
const EXSLT_REGEXP_CONTRACTID = "@mozilla.org/exslt/regexp;1";
const CATMAN_CONTRACTID = "@mozilla.org/categorymanager;1";
const NODESET_CONTRACTID = "@mozilla.org/transformiix-nodeset;1";
const Ci = Components.interfaces;
@ -55,32 +55,11 @@ var SingletonInstance = null;
txEXSLTRegExFunctions.prototype = {
classID: EXSLT_REGEXP_CID,
QueryInterface: function(iid) {
if (iid.equals(Ci.nsISupports) ||
iid.equals(Ci.nsIClassInfo) ||
iid.equals(Ci.txIEXSLTRegExFunctions))
return this;
throw Components.results.NS_ERROR_NO_INTERFACE;
},
// nsIClassInfo
getInterfaces: function(countRef) {
var interfaces = [
Ci.txIEXSLTRegExFunctions
];
countRef.value = interfaces.length;
return interfaces;
},
getHelperForLanguage: function(language) {
return null;
},
implementationLanguage: Ci.nsIProgrammingLanguage.JAVASCRIPT,
flags: 0,
QueryInterface: XPCOMUtils.generateQI([Ci.txIEXSLTRegExFunctions]),
classInfo: XPCOMUtils.generateCI({classID: EXSLT_REGEXP_CID,
contractID: EXSLT_REGEXP_CONTRACTID,
interfaces: [Ci.txIEXSLTRegExFunctions]}),
// txIEXSLTRegExFunctions
match: function(context, str, regex, flags) {

View File

@ -114,6 +114,8 @@ CPPSRCS = \
# static lib.
FORCE_STATIC_LIB = 1
include $(topsrcdir)/config/config.mk
include $(topsrcdir)/ipc/chromium/chromium-config.mk
include $(topsrcdir)/config/rules.mk
LOCAL_INCLUDES += \

View File

@ -46,6 +46,9 @@
#define FORCE_PR_LOG 1
#endif
#include "base/histogram.h"
#include "base/logging.h"
#include "nsIBrowserDOMWindow.h"
#include "nsIComponentManager.h"
#include "nsIContent.h"
@ -108,6 +111,7 @@
#include "nsIViewManager.h"
#include "nsIScriptChannel.h"
#include "nsIOfflineCacheUpdate.h"
#include "nsITimedChannel.h"
#include "nsCPrefetchService.h"
#include "nsJSON.h"
#include "IHistory.h"
@ -6046,6 +6050,20 @@ nsDocShell::EndPageLoad(nsIWebProgress * aProgress,
nsresult rv = aChannel->GetURI(getter_AddRefs(url));
if (NS_FAILED(rv)) return rv;
nsCOMPtr<nsITimedChannel> timingChannel =
do_QueryInterface(aChannel);
if (timingChannel) {
mozilla::TimeStamp channelCreationTime;
rv = timingChannel->GetChannelCreation(&channelCreationTime);
if (NS_SUCCEEDED(rv) && !channelCreationTime.IsNull()) {
PRUint32 interval = (PRUint32)
(mozilla::TimeStamp::Now() - channelCreationTime)
.ToMilliseconds();
UMA_HISTOGRAM_TIMES("HTTP: Total page load time (ms)",
base::TimeDelta::FromMilliseconds(interval));
}
}
// clean up reload state for meta charset
if (eCharsetReloadRequested == mCharsetReloadState)
mCharsetReloadState = eCharsetReloadStopOrigional;

View File

@ -300,6 +300,8 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBRequest,
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnSuccessListener)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnErrorListener)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mSource)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR_AMBIGUOUS(mTransaction,
nsPIDOMEventTarget)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBRequest,
@ -311,6 +313,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBRequest,
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnSuccessListener)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnErrorListener)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mSource)
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mTransaction)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBRequest)

View File

@ -68,21 +68,12 @@ function GeoPositionCoordsObject(latitude, longitude, altitude, accuracy, altitu
GeoPositionCoordsObject.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMGeoPositionCoords, Ci.nsIClassInfo]),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMGeoPositionCoords]),
// Class Info is required to be able to pass objects back into the DOM.
getInterfaces: function(countRef) {
var interfaces = [Ci.nsIDOMGeoPositionCoords, Ci.nsIClassInfo, Ci.nsISupports];
countRef.value = interfaces.length;
return interfaces;
},
getHelperForLanguage: function(language) null,
contractID: null,
classDescription: "Geoposition Coordinate Object",
classID: null,
implementationLanguage: Ci.nsIProgrammingLanguage.JAVASCRIPT,
flags: Ci.nsIClassInfo.DOM_OBJECT,
classInfo: XPCOMUtils.generateCI({interfaces: [Ci.nsIDOMGeoPositionCoords],
flags: Ci.nsIClassInfo.DOM_OBJECT,
classDescription: "Geoposition Coordinate Object"}),
latitude: null,
longitude: null,
@ -101,21 +92,12 @@ function GeoPositionObject(latitude, longitude, altitude, accuracy, altitudeAccu
GeoPositionObject.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMGeoPosition, Ci.nsIClassInfo]),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMGeoPosition]),
// Class Info is required to be able to pass objects back into the DOM.
getInterfaces: function(countRef) {
var interfaces = [Ci.nsIDOMGeoPosition, Ci.nsIClassInfo, Ci.nsISupports];
countRef.value = interfaces.length;
return interfaces;
},
getHelperForLanguage: function(language) null,
contractID: null,
classDescription: "Geoposition Object",
classID: null,
implementationLanguage: Ci.nsIProgrammingLanguage.JAVASCRIPT,
flags: Ci.nsIClassInfo.DOM_OBJECT,
classInfo: XPCOMUtils.generateCI({interfaces: [Ci.nsIDOMGeoPosition],
flags: Ci.nsIClassInfo.DOM_OBJECT,
classDescription: "Geoposition Object"}),
coords: null,
timestamp: null,

View File

@ -35,17 +35,10 @@ function WifiGeoAddressObject(streetNumber, street, premises, city, county, regi
WifiGeoAddressObject.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMGeoPositionAddress, Ci.nsIClassInfo]),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMGeoPositionAddress]),
getInterfaces: function(countRef) {
var interfaces = [Ci.nsIDOMGeoPositionAddress, Ci.nsIClassInfo, Ci.nsISupports];
countRef.value = interfaces.length;
return interfaces;
},
getHelperForLanguage: function(language) null,
implementationLanguage: Ci.nsIProgrammingLanguage.JAVASCRIPT,
flags: Ci.nsIClassInfo.DOM_OBJECT,
classInfo: XPCOMUtils.generateCI({interfaces: [Ci.nsIDOMGeoPositionAddress],
flags: Ci.nsIClassInfo.DOM_OBJECT})
};
function WifiGeoCoordsObject(lat, lon, acc, alt, altacc) {
@ -58,18 +51,11 @@ function WifiGeoCoordsObject(lat, lon, acc, alt, altacc) {
WifiGeoCoordsObject.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMGeoPositionCoords, Ci.nsIClassInfo]),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMGeoPositionCoords]),
getInterfaces: function(countRef) {
var interfaces = [Ci.nsIDOMGeoPositionCoords, Ci.nsIClassInfo, Ci.nsISupports];
countRef.value = interfaces.length;
return interfaces;
},
getHelperForLanguage: function(language) null,
classDescription: "wifi geo position coords object",
implementationLanguage: Ci.nsIProgrammingLanguage.JAVASCRIPT,
flags: Ci.nsIClassInfo.DOM_OBJECT,
classInfo: XPCOMUtils.generateCI({interfaces: [Ci.nsIDOMGeoPositionCoords],
flags: Ci.nsIClassInfo.DOM_OBJECT,
classDescription: "wifi geo position coords object"}),
latitude: 0,
longitude: 0,
@ -107,19 +93,12 @@ function WifiGeoPositionObject(location) {
WifiGeoPositionObject.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMGeoPosition, Ci.nsIClassInfo]),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMGeoPosition]),
// Class Info is required to be able to pass objects back into the DOM.
getInterfaces: function(countRef) {
var interfaces = [Ci.nsIDOMGeoPosition, Ci.nsIClassInfo, Ci.nsISupports];
countRef.value = interfaces.length;
return interfaces;
},
getHelperForLanguage: function(language) null,
classDescription: "wifi geo location position object",
implementationLanguage: Ci.nsIProgrammingLanguage.JAVASCRIPT,
flags: Ci.nsIClassInfo.DOM_OBJECT,
classInfo: XPCOMUtils.generateCI({interfaces: [Ci.nsIDOMGeoPosition],
flags: Ci.nsIClassInfo.DOM_OBJECT,
classDescription: "wifi geo location position object"}),
coords: null,
timestamp: 0,

View File

@ -130,6 +130,7 @@ struct _cairo_d2d_surface {
/** Indicates if text rendering is initialized */
enum TextRenderingState {
TEXT_RENDERING_UNINITIALIZED,
TEXT_RENDERING_NO_CLEARTYPE,
TEXT_RENDERING_NORMAL,
TEXT_RENDERING_GDI_CLASSIC
};

View File

@ -4105,26 +4105,23 @@ _cairo_d2d_show_glyphs (void *surface,
cairo_clip_t *clip,
int *remaining_glyphs)
{
if (((cairo_surface_t*)surface)->type != CAIRO_SURFACE_TYPE_D2D) {
if (((cairo_surface_t*)surface)->type != CAIRO_SURFACE_TYPE_D2D ||
scaled_font->backend->type != CAIRO_FONT_TYPE_DWRITE)
{
return CAIRO_INT_STATUS_UNSUPPORTED;
}
cairo_d2d_surface_t *d2dsurf = static_cast<cairo_d2d_surface_t*>(surface);
cairo_bool_t forceGDIClassic =
scaled_font->backend->type == CAIRO_FONT_TYPE_DWRITE &&
reinterpret_cast<cairo_dwrite_scaled_font_t*>(scaled_font)->force_GDI_classic;
cairo_d2d_surface_t::TextRenderingState textRenderingState =
(forceGDIClassic ? cairo_d2d_surface_t::TEXT_RENDERING_GDI_CLASSIC : cairo_d2d_surface_t::TEXT_RENDERING_NORMAL);
reinterpret_cast<cairo_dwrite_scaled_font_t*>(scaled_font)->rendering_mode;
if (d2dsurf->textRenderingState != textRenderingState) {
RefPtr<IDWriteRenderingParams> params =
DWriteFactory::RenderingParams(forceGDIClassic);
DWriteFactory::RenderingParams(textRenderingState);
d2dsurf->rt->SetTextRenderingParams(params);
d2dsurf->textRenderingState = textRenderingState;
}
cairo_int_status_t status = CAIRO_INT_STATUS_UNSUPPORTED;
if (scaled_font->backend->type == CAIRO_FONT_TYPE_DWRITE) {
status = (cairo_int_status_t)
_cairo_dwrite_show_glyphs_on_d2d_surface(surface, op, source, glyphs, num_glyphs, scaled_font, clip);
}
cairo_int_status_t status = (cairo_int_status_t)
_cairo_dwrite_show_glyphs_on_d2d_surface(surface, op, source, glyphs, num_glyphs, scaled_font, clip);
return status;
}

View File

@ -119,7 +119,8 @@ private:
IDWriteFactory *DWriteFactory::mFactoryInstance = NULL;
IDWriteFontCollection *DWriteFactory::mSystemCollection = NULL;
IDWriteRenderingParams *DWriteFactory::mRenderingParams = NULL;
IDWriteRenderingParams *DWriteFactory::mDefaultRenderingParams = NULL;
IDWriteRenderingParams *DWriteFactory::mCustomClearTypeRenderingParams = NULL;
IDWriteRenderingParams *DWriteFactory::mForceGDIClassicRenderingParams = NULL;
FLOAT DWriteFactory::mGamma = -1.0;
FLOAT DWriteFactory::mEnhancedContrast = -1.0;
@ -468,7 +469,7 @@ _cairo_dwrite_font_face_scaled_font_create (void *abstract_face,
// this means that if cleartype settings are changed but the scaled_fonts
// are re-used, they might not adhere to the new system setting until re-
// creation.
switch (_cairo_win32_get_system_text_quality()) {
switch (cairo_win32_get_system_text_quality()) {
case CLEARTYPE_QUALITY:
default_quality = CAIRO_ANTIALIAS_SUBPIXEL;
break;
@ -496,7 +497,9 @@ _cairo_dwrite_font_face_scaled_font_create (void *abstract_face,
}
dwriteFont->manual_show_glyphs_allowed = TRUE;
dwriteFont->force_GDI_classic = FALSE;
dwriteFont->rendering_mode =
default_quality == CAIRO_ANTIALIAS_SUBPIXEL ?
cairo_d2d_surface_t::TEXT_RENDERING_NORMAL : cairo_d2d_surface_t::TEXT_RENDERING_NO_CLEARTYPE;
return _cairo_scaled_font_set_metrics (*font, &extents);
}
@ -1083,14 +1086,18 @@ void
cairo_dwrite_scaled_font_set_force_GDI_classic(cairo_scaled_font_t *dwrite_scaled_font, cairo_bool_t force)
{
cairo_dwrite_scaled_font_t *font = reinterpret_cast<cairo_dwrite_scaled_font_t*>(dwrite_scaled_font);
font->force_GDI_classic = force;
if (force && font->rendering_mode == cairo_d2d_surface_t::TEXT_RENDERING_NORMAL) {
font->rendering_mode = cairo_d2d_surface_t::TEXT_RENDERING_GDI_CLASSIC;
} else if (!force && font->rendering_mode == cairo_d2d_surface_t::TEXT_RENDERING_GDI_CLASSIC) {
font->rendering_mode = cairo_d2d_surface_t::TEXT_RENDERING_NORMAL;
}
}
cairo_bool_t
cairo_dwrite_scaled_font_get_force_GDI_classic(cairo_scaled_font_t *dwrite_scaled_font)
{
cairo_dwrite_scaled_font_t *font = reinterpret_cast<cairo_dwrite_scaled_font_t*>(dwrite_scaled_font);
return font->force_GDI_classic;
return font->rendering_mode == cairo_d2d_surface_t::TEXT_RENDERING_GDI_CLASSIC;
}
void
@ -1100,6 +1107,12 @@ cairo_dwrite_set_cleartype_params(FLOAT gamma, FLOAT contrast, FLOAT level,
DWriteFactory::SetRenderingParams(gamma, contrast, level, geometry, mode);
}
int
cairo_dwrite_get_cleartype_rendering_mode()
{
return DWriteFactory::GetClearTypeRenderingMode();
}
cairo_int_status_t
_dwrite_draw_glyphs_to_gdi_surface_gdi(cairo_win32_surface_t *surface,
DWRITE_MATRIX *transform,
@ -1113,7 +1126,7 @@ _dwrite_draw_glyphs_to_gdi_surface_gdi(cairo_win32_surface_t *surface,
IDWriteBitmapRenderTarget *rt;
IDWriteRenderingParams *params =
DWriteFactory::RenderingParams(scaled_font->force_GDI_classic);
DWriteFactory::RenderingParams(scaled_font->rendering_mode);
gdiInterop->CreateBitmapRenderTarget(surface->dc,
area.right - area.left,
@ -1414,8 +1427,7 @@ DWriteFactory::CreateRenderingParams()
return;
}
RefPtr<IDWriteRenderingParams> defaultParams;
Instance()->CreateRenderingParams(&defaultParams);
Instance()->CreateRenderingParams(&mDefaultRenderingParams);
// For EnhancedContrast, we override the default if the user has not set it
// in the registry (by using the ClearType Tuner).
@ -1427,7 +1439,7 @@ DWriteFactory::CreateRenderingParams()
if (RegOpenKeyExA(ENHANCED_CONTRAST_REGISTRY_KEY,
0, KEY_READ, &hKey) == ERROR_SUCCESS)
{
contrast = defaultParams->GetEnhancedContrast();
contrast = mDefaultRenderingParams->GetEnhancedContrast();
RegCloseKey(hKey);
} else {
contrast = 1.0;
@ -1437,18 +1449,20 @@ DWriteFactory::CreateRenderingParams()
// For parameters that have not been explicitly set via the SetRenderingParams API,
// we copy values from default params (or our overridden value for contrast)
FLOAT gamma =
mGamma >= 1.0 && mGamma <= 2.2 ? mGamma : defaultParams->GetGamma();
mGamma >= 1.0 && mGamma <= 2.2 ?
mGamma : mDefaultRenderingParams->GetGamma();
FLOAT clearTypeLevel =
mClearTypeLevel >= 0.0 && mClearTypeLevel <= 1.0 ? mClearTypeLevel : defaultParams->GetClearTypeLevel();
mClearTypeLevel >= 0.0 && mClearTypeLevel <= 1.0 ?
mClearTypeLevel : mDefaultRenderingParams->GetClearTypeLevel();
DWRITE_PIXEL_GEOMETRY pixelGeometry =
mPixelGeometry >= DWRITE_PIXEL_GEOMETRY_FLAT && mPixelGeometry <= DWRITE_PIXEL_GEOMETRY_BGR ?
(DWRITE_PIXEL_GEOMETRY)mPixelGeometry : defaultParams->GetPixelGeometry();
(DWRITE_PIXEL_GEOMETRY)mPixelGeometry : mDefaultRenderingParams->GetPixelGeometry();
DWRITE_RENDERING_MODE renderingMode =
mRenderingMode >= DWRITE_RENDERING_MODE_DEFAULT && mRenderingMode <= DWRITE_RENDERING_MODE_CLEARTYPE_NATURAL_SYMMETRIC ?
(DWRITE_RENDERING_MODE)mRenderingMode : defaultParams->GetRenderingMode();
(DWRITE_RENDERING_MODE)mRenderingMode : mDefaultRenderingParams->GetRenderingMode();
Instance()->CreateCustomRenderingParams(gamma, contrast, clearTypeLevel,
pixelGeometry, renderingMode,
&mRenderingParams);
&mCustomClearTypeRenderingParams);
Instance()->CreateCustomRenderingParams(gamma, contrast, clearTypeLevel,
pixelGeometry, DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC,
&mForceGDIClassicRenderingParams);

View File

@ -36,7 +36,6 @@
#include <dwrite.h>
#include <D2d1.h>
// DirectWrite is not available on all platforms.
typedef HRESULT (WINAPI*DWriteCreateFactoryFunc)(
__in DWRITE_FACTORY_TYPE factoryType,
@ -52,7 +51,7 @@ struct _cairo_dwrite_scaled_font {
cairo_antialias_t antialias_mode;
DWRITE_MEASURING_MODE measuring_mode;
cairo_bool_t manual_show_glyphs_allowed;
cairo_bool_t force_GDI_classic;
cairo_d2d_surface_t::TextRenderingState rendering_mode;
};
typedef struct _cairo_dwrite_scaled_font cairo_dwrite_scaled_font_t;
@ -103,13 +102,22 @@ public:
return family;
}
static IDWriteRenderingParams *RenderingParams(cairo_bool_t forceGDIClassic)
static IDWriteRenderingParams *RenderingParams(cairo_d2d_surface_t::TextRenderingState mode)
{
if (!mRenderingParams || !mForceGDIClassicRenderingParams) {
if (!mDefaultRenderingParams ||
!mForceGDIClassicRenderingParams ||
!mCustomClearTypeRenderingParams)
{
CreateRenderingParams();
}
IDWriteRenderingParams *params =
forceGDIClassic ? mForceGDIClassicRenderingParams : mRenderingParams;
IDWriteRenderingParams *params;
if (mode == cairo_d2d_surface_t::TEXT_RENDERING_NO_CLEARTYPE) {
params = mDefaultRenderingParams;
} else if (mode == cairo_d2d_surface_t::TEXT_RENDERING_GDI_CLASSIC && mRenderingMode < 0) {
params = mForceGDIClassicRenderingParams;
} else {
params = mCustomClearTypeRenderingParams;
}
if (params) {
params->AddRef();
}
@ -127,15 +135,23 @@ public:
mClearTypeLevel = aClearTypeLevel;
mPixelGeometry = aPixelGeometry;
mRenderingMode = aRenderingMode;
// discard any current RenderingParams object
if (mRenderingParams) {
mRenderingParams->Release();
mRenderingParams = NULL;
// discard any current RenderingParams objects
if (mCustomClearTypeRenderingParams) {
mCustomClearTypeRenderingParams->Release();
mCustomClearTypeRenderingParams = NULL;
}
if (mForceGDIClassicRenderingParams) {
mForceGDIClassicRenderingParams->Release();
mForceGDIClassicRenderingParams = NULL;
}
if (mDefaultRenderingParams) {
mDefaultRenderingParams->Release();
mDefaultRenderingParams = NULL;
}
}
static int GetClearTypeRenderingMode() {
return mRenderingMode;
}
private:
@ -143,7 +159,8 @@ private:
static IDWriteFactory *mFactoryInstance;
static IDWriteFontCollection *mSystemCollection;
static IDWriteRenderingParams *mRenderingParams;
static IDWriteRenderingParams *mDefaultRenderingParams;
static IDWriteRenderingParams *mCustomClearTypeRenderingParams;
static IDWriteRenderingParams *mForceGDIClassicRenderingParams;
static FLOAT mGamma;
static FLOAT mEnhancedContrast;

View File

@ -258,7 +258,7 @@ _have_cleartype_quality (void)
}
BYTE
_cairo_win32_get_system_text_quality (void)
cairo_win32_get_system_text_quality (void)
{
BOOL font_smoothing;
UINT smoothing_type;
@ -325,7 +325,7 @@ _win32_scaled_font_create (LOGFONTW *logfont,
* here is the hint_metrics options.
*/
if (options->antialias == CAIRO_ANTIALIAS_DEFAULT)
f->quality = _cairo_win32_get_system_text_quality ();
f->quality = cairo_win32_get_system_text_quality ();
else {
switch (options->antialias) {
case CAIRO_ANTIALIAS_NONE:

View File

@ -216,9 +216,6 @@ _cairo_win32_scaled_font_is_type1 (cairo_scaled_font_t *scaled_font);
cairo_bool_t
_cairo_win32_scaled_font_is_bitmap (cairo_scaled_font_t *scaled_font);
BYTE
_cairo_win32_get_system_text_quality (void);
#ifdef WINCE
// These are the required stubs for windows mobile

View File

@ -80,6 +80,8 @@ cairo_win32_surface_set_can_convert_to_dib (cairo_surface_t *surface, cairo_bool
cairo_public cairo_status_t
cairo_win32_surface_get_can_convert_to_dib (cairo_surface_t *surface, cairo_bool_t *can_convert);
BYTE cairo_win32_get_system_text_quality (void);
#if CAIRO_HAS_WIN32_FONT
/*
@ -135,6 +137,9 @@ cairo_dwrite_scaled_font_get_force_GDI_classic(cairo_scaled_font_t *dwrite_scale
void
cairo_dwrite_set_cleartype_params(FLOAT gamma, FLOAT contrast, FLOAT level, int geometry, int mode);
int
cairo_dwrite_get_cleartype_rendering_mode();
#endif /* CAIRO_HAS_DWRITE_FONT */
#if CAIRO_HAS_D2D_SURFACE

View File

@ -694,7 +694,8 @@ bool
gfxDWriteFont::GetForceGDIClassic()
{
return static_cast<gfxDWriteFontEntry*>(mFontEntry.get())->GetForceGDIClassic() &&
GetAdjustedSize() <=
cairo_dwrite_get_cleartype_rendering_mode() < 0 &&
GetAdjustedSize() <=
gfxDWriteFontList::PlatformFontList()->GetForceGDIClassicMaxFontSize();
}

View File

@ -68,6 +68,19 @@
* "nsIFoo",
* "nsIBar" ]),
*
* // [optional] classInfo implementation, e.g. using the generateCI helper.
* // Will be automatically returned from QueryInterface if that was
* // generated with the generateQI helper.
* classInfo: XPCOMUtils.generateCI(
* {classID: Components.ID("{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"),
* contractID: "@example.com/xxx;1",
* classDescription: "unique text description",
* interfaces: [Components.interfaces.nsIObserver,
* Components.interfaces.nsIMyInterface,
* "nsIFoo",
* "nsIBar"],
* flags: Ci.nsIClassInfo.SINGLETON}),
*
* // The following properties were used prior to Mozilla 2, but are no
* // longer supported. They may still be included for compatibility with
* // prior versions of XPCOMUtils. In Mozilla 2, this information is
@ -122,12 +135,44 @@ var XPCOMUtils = {
* assigned to the 'QueryInterface' property of a JS object. When invoked on
* that object, it checks if the given iid is listed in the |interfaces|
* param, and if it is, returns |this| (the object it was called on).
* If the JS object has a classInfo property it'll be returned for the
* nsIClassInfo IID, generateCI can be used to generate the classInfo
* property.
*/
generateQI: function XPCU_generateQI(interfaces) {
/* Note that Ci[Ci.x] == Ci.x for all x */
return makeQI([Ci[i].name for each (i in interfaces) if (Ci[i])]);
},
/**
* Generate a ClassInfo implementation for a component. The returned object
* must be assigned to the 'classInfo' property of a JS object. The first and
* only argument should be an object that contains a number of optional
* properties: "interfaces", "contractID", "classDescription", "classID" and
* "flags". The values of the properties will be returned as the values of the
* various properties of the nsIClassInfo implementation.
*/
generateCI: function XPCU_generateCI(classInfo)
{
if (QueryInterface in classInfo)
throw Error("In generateCI, don't use a component for generating classInfo");
/* Note that Ci[Ci.x] == Ci.x for all x */
var _interfaces = [Ci[i] for each (i in classInfo.interfaces) if (Ci[i])];
return {
getInterfaces: function XPCU_getInterfaces(countRef) {
countRef.value = _interfaces.length;
return _interfaces;
},
getHelperForLanguage: function XPCU_getHelperForLanguage(language) null,
contractID: classInfo.contractID,
classDescription: classInfo.classDescription,
classID: classInfo.classID,
implementationLanguage: Ci.nsIProgrammingLanguage.JAVASCRIPT,
flags: classInfo.flags,
QueryInterface: this.generateQI([Ci.nsIClassInfo])
};
},
/**
* Generate a NSGetFactory function given an array of components.
*/
@ -281,6 +326,8 @@ function makeQI(interfaceNames) {
return function XPCOMUtils_QueryInterface(iid) {
if (iid.equals(Ci.nsISupports))
return this;
if (iid.equals(Ci.nsIClassInfo) && "classInfo" in this)
return this.classInfo;
for each(let interfaceName in interfaceNames) {
if (Ci[interfaceName].equals(iid))
return this;

View File

@ -76,6 +76,31 @@ function test_generateQI_string_names()
}
function test_generateCI()
{
const classID = Components.ID("562dae2e-7cff-432b-995b-3d4c03fa2b89");
const classDescription = "generateCI test component";
const flags = Components.interfaces.nsIClassInfo.DOM_OBJECT;
var x = {
QueryInterface: XPCOMUtils.generateQI([]),
classInfo: XPCOMUtils.generateCI({classID: classID,
interfaces: [],
flags: flags,
classDescription: classDescription})
};
try {
var ci = x.QueryInterface(Components.interfaces.nsIClassInfo);
ci = ci.QueryInterface(Components.interfaces.nsISupports);
ci = ci.QueryInterface(Components.interfaces.nsIClassInfo);
do_check_eq(ci.classID, classID);
do_check_eq(ci.flags, flags);
do_check_eq(ci.classDescription, classDescription);
} catch(e) {
do_throw("Classinfo for x should not be missing or broken");
}
}
function test_defineLazyGetter()
{
let accessCount = 0;
@ -186,6 +211,7 @@ function test_categoryRegistration()
let tests = [
test_generateQI_string_names,
test_generateCI,
test_defineLazyGetter,
test_defineLazyServiceGetter,
test_categoryRegistration,

View File

@ -0,0 +1,28 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type">
<title>CSS Writing Modes Module Level 3</title>
<script type="text/javascript">
function boom() {
document.getElementById("example").style.fontSize = "larger";
}
</script>
</head>
<body onload=boom()>
<div id="example">
<p>א</p>
<pre><code>
&lt;HEBREW&gt;
&lt;PAR&gt;HEBREW1 HEBREW2 english3 HEBREW4 HEBREW5&lt;/PAR&gt;
&lt;PAR&gt;HEBREW6 &lt;EMPH&gt;HEBREW7&lt;/EMPH&gt; HEBREW8&lt;/PAR&gt;
&lt;/HEBREW&gt;
&lt;ENGLISH&gt;
&lt;PAR&gt;english9 english10 english11 HEBREW12 HEBREW13&lt;/PAR&gt;
&lt;PAR&gt;english14 english15 english16&lt;/PAR&gt;
&lt;PAR&gt;english17 &lt;HE-QUO&gt;HEBREW18 english19 HEBREW20&lt;/HE-QUO&gt;&lt;/PAR&gt;
&lt;/ENGLISH&gt;
</code></pre>
</div>
</body>
</html>

View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html style="direction: rtl; -moz-column-width: 1px;"><head><script>
function boom()
{
document.documentElement.offsetHeight;
document.body.style.unicodeBidi = "bidi-override";
document.documentElement.offsetHeight;
}
</script></head><body style="white-space: pre;" onload="boom();">
H
</body></html>

View File

@ -0,0 +1,14 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script>
function boom()
{
document.body.offsetHeight;
document.body.appendChild(document.createTextNode('Y'));
}
</script>
</head>
<body style="white-space: pre;" onload="boom();">&#x000D;&#x064C;</body>
</html>

View File

@ -0,0 +1,3 @@
<html xmlns="http://www.w3.org/1999/xhtml" style="direction: rtl;"><body style="-moz-column-width: 1px; word-wrap: break-word; white-space: pre-wrap;" onload="document.documentElement.offsetHeight; document.body.style.wordWrap='';">
xy</body></html>

View File

@ -35,6 +35,7 @@ load 243159-2.xhtml
asserts(1) load 243519-1.html # bug 536692
load 244490-1.html
load 254367-1.html
load 263359-1.html
load 265027-1.html
load 265736-1.html
load 265736-2.html
@ -327,4 +328,7 @@ load 629035-1.html
load 629908-1.html
load 635329.html
== 640272.html 640272-ref.html
load 645193.html
load 650475.xhtml
load 650489.xhtml
load 653133-1.html

View File

@ -47,7 +47,6 @@
#include "nsRenderingContext.h"
#include "nsIServiceManager.h"
#include "nsFrameManager.h"
#include "nsBidiFrames.h"
#include "nsBidiUtils.h"
#include "nsCSSFrameConstructor.h"
#include "nsHTMLContainerFrame.h"
@ -56,6 +55,7 @@
#include "nsContainerFrame.h"
#include "nsFirstLetterFrame.h"
#include "gfxUnicodeProperties.h"
#include "nsTextFrame.h"
#undef NOISY_BIDI
#undef REALLY_NOISY_BIDI
@ -75,8 +75,7 @@ static const PRUnichar ALEF = 0x05D0;
#define CHAR_IS_HEBREW(c) ((0x0590 <= (c)) && ((c)<= 0x05FF))
// Note: The above code are moved from gfx/src/windows/nsRenderingContextWin.cpp
nsIFrame*
NS_NewDirectionalFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, PRUnichar aChar);
#define NS_BIDI_CONTROL_FRAME ((nsIFrame*)0xfffb1d1)
nsBidiPresUtils::nsBidiPresUtils() : mArraySize(8),
mIndexMap(nsnull),
@ -166,22 +165,31 @@ SplitInlineAncestors(nsIFrame* aFrame)
return NS_OK;
}
// Convert bidi continuations to fluid continuations for a frame and all of its
// inline ancestors.
static void
MakeContinuationFluid(nsIFrame* aFrame, nsIFrame* aNext)
{
NS_ASSERTION (!aFrame->GetNextInFlow() || aFrame->GetNextInFlow() == aNext,
"next-in-flow is not next continuation!");
aFrame->SetNextInFlow(aNext);
NS_ASSERTION (!aNext->GetPrevInFlow() || aNext->GetPrevInFlow() == aFrame,
"prev-in-flow is not prev continuation!");
aNext->SetPrevInFlow(aFrame);
}
// If aFrame is the last child of its parent, convert bidi continuations to
// fluid continuations for all of its inline ancestors.
static void
JoinInlineAncestors(nsIFrame* aFrame)
{
nsIFrame* frame = aFrame;
if (aFrame->GetNextSibling()) {
return;
}
nsIFrame* frame = aFrame->GetParent();
while (frame && IsBidiSplittable(frame)) {
nsIFrame* next = frame->GetNextContinuation();
if (next) {
NS_ASSERTION (!frame->GetNextInFlow() || frame->GetNextInFlow() == next,
"next-in-flow is not next continuation!");
frame->SetNextInFlow(next);
NS_ASSERTION (!next->GetPrevInFlow() || next->GetPrevInFlow() == frame,
"prev-in-flow is not prev continuation!");
next->SetPrevInFlow(frame);
MakeContinuationFluid(frame, next);
}
// Join the parent only as long as we're its last child.
if (frame->GetNextSibling())
@ -191,8 +199,9 @@ JoinInlineAncestors(nsIFrame* aFrame)
}
static nsresult
CreateBidiContinuation(nsIFrame* aFrame,
nsIFrame** aNewFrame)
CreateContinuation(nsIFrame* aFrame,
nsIFrame** aNewFrame,
PRBool aIsFluid)
{
NS_PRECONDITION(aNewFrame, "null OUT ptr");
NS_PRECONDITION(aFrame, "null ptr");
@ -201,10 +210,10 @@ CreateBidiContinuation(nsIFrame* aFrame,
nsPresContext *presContext = aFrame->PresContext();
nsIPresShell *presShell = presContext->PresShell();
NS_ASSERTION(presShell, "PresShell must be set on PresContext before calling nsBidiPresUtils::CreateBidiContinuation");
NS_ASSERTION(presShell, "PresShell must be set on PresContext before calling nsBidiPresUtils::CreateContinuation");
nsIFrame* parent = aFrame->GetParent();
NS_ASSERTION(parent, "Couldn't get frame parent in nsBidiPresUtils::CreateBidiContinuation");
NS_ASSERTION(parent, "Couldn't get frame parent in nsBidiPresUtils::CreateContinuation");
nsresult rv = NS_OK;
@ -215,12 +224,12 @@ CreateBidiContinuation(nsIFrame* aFrame,
parent->GetStyleDisplay()->IsFloating()) {
nsFirstLetterFrame* letterFrame = do_QueryFrame(parent);
rv = letterFrame->CreateContinuationForFloatingParent(presContext, aFrame,
aNewFrame, PR_FALSE);
aNewFrame, aIsFluid);
return rv;
}
rv = presShell->FrameConstructor()->
CreateContinuingFrame(presContext, aFrame, parent, aNewFrame, PR_FALSE);
CreateContinuingFrame(presContext, aFrame, parent, aNewFrame, aIsFluid);
if (NS_FAILED(rv)) {
return rv;
}
@ -232,11 +241,13 @@ CreateBidiContinuation(nsIFrame* aFrame,
if (NS_FAILED(rv)) {
return rv;
}
// Split inline ancestor frames
rv = SplitInlineAncestors(aFrame);
if (NS_FAILED(rv)) {
return rv;
if (!aIsFluid) {
// Split inline ancestor frames
rv = SplitInlineAncestors(aFrame);
if (NS_FAILED(rv)) {
return rv;
}
}
return NS_OK;
@ -287,7 +298,7 @@ AdvanceLineIteratorToFrame(nsIFrame* aFrame,
*
* Walk through the descendants of aBlockFrame and build:
* * mLogicalFrames: an nsTArray of nsIFrame* pointers in logical order
* * mBuffer: an nsAutoString containing a representation of
* * mBuffer: an nsString containing a representation of
* the content of the frames.
* In the case of text frames, this is the actual text context of the
* frames, but some other elements are represented in a symbolic form which
@ -317,93 +328,19 @@ nsBidiPresUtils::Resolve(nsBlockFrame* aBlockFrame)
{
mLogicalFrames.Clear();
mContentToFrameIndex.Clear();
mLinePerFrame.Clear();
mBuffer.SetLength(0);
mEmbeddingStack.Clear();
nsPresContext *presContext = aBlockFrame->PresContext();
nsIPresShell* shell = presContext->PresShell();
nsStyleContext* styleContext = aBlockFrame->GetStyleContext();
// handle bidi-override being set on the block itself before calling
// InitLogicalArray.
const nsStyleVisibility* vis = aBlockFrame->GetStyleVisibility();
const nsStyleTextReset* text = aBlockFrame->GetStyleTextReset();
if (text->mUnicodeBidi == NS_STYLE_UNICODE_BIDI_OVERRIDE) {
nsIFrame *directionalFrame = nsnull;
mParaLevel = (NS_STYLE_DIRECTION_RTL == vis->mDirection) ?
NSBIDI_RTL : NSBIDI_LTR;
if (NS_STYLE_DIRECTION_RTL == vis->mDirection) {
directionalFrame = NS_NewDirectionalFrame(shell, styleContext, kRLO);
}
else if (NS_STYLE_DIRECTION_LTR == vis->mDirection) {
directionalFrame = NS_NewDirectionalFrame(shell, styleContext, kLRO);
}
if (directionalFrame) {
mLogicalFrames.AppendElement(directionalFrame);
}
}
for (nsBlockFrame* block = aBlockFrame; block;
block = static_cast<nsBlockFrame*>(block->GetNextContinuation())) {
block->RemoveStateBits(NS_BLOCK_NEEDS_BIDI_RESOLUTION);
InitLogicalArray(block->GetFirstChild(nsnull));
}
if (text->mUnicodeBidi == NS_STYLE_UNICODE_BIDI_OVERRIDE) {
nsIFrame* directionalFrame = NS_NewDirectionalFrame(shell, styleContext, kPDF);
if (directionalFrame) {
mLogicalFrames.AppendElement(directionalFrame);
}
}
CreateBlockBuffer();
PRInt32 bufferLength = mBuffer.Length();
if (bufferLength < 1) {
mSuccess = NS_OK;
return mSuccess;
}
PRInt32 runCount;
PRUint8 embeddingLevel;
nsBidiLevel paraLevel = embeddingLevel =
(NS_STYLE_DIRECTION_RTL == vis->mDirection)
? NSBIDI_RTL : NSBIDI_LTR;
mSuccess = mBidiEngine->SetPara(mBuffer.get(), bufferLength, paraLevel, nsnull);
if (NS_FAILED(mSuccess) ) {
return mSuccess;
}
mSuccess = mBidiEngine->CountRuns(&runCount);
if (NS_FAILED(mSuccess) ) {
return mSuccess;
}
PRInt32 runLength = 0; // the length of the current run of text
PRInt32 lineOffset = 0; // the start of the current run
PRInt32 logicalLimit = 0; // the end of the current run + 1
PRInt32 numRun = -1;
PRInt32 fragmentLength = 0; // the length of the current text frame
PRInt32 frameIndex = -1; // index to the frames in mLogicalFrames
PRInt32 frameCount = mLogicalFrames.Length();
PRInt32 contentOffset = 0; // offset of current frame in its content node
PRBool isTextFrame = PR_FALSE;
nsIFrame* frame = nsnull;
nsIContent* content = nsnull;
PRInt32 contentTextLength;
nsIAtom* frameType = nsnull;
FramePropertyTable *propTable = presContext->PropertyTable();
nsBlockInFlowLineIterator lineIter(aBlockFrame, aBlockFrame->begin_lines(), PR_FALSE);
if (lineIter.GetLine() == aBlockFrame->end_lines()) {
// Advance to first valid line (might be in a next-continuation)
lineIter.Next();
}
nsIFrame* prevFrame = nsnull;
PRBool lineNeedsUpdate = PR_FALSE;
PRBool isVisual = presContext->IsVisualMode();
if (isVisual) {
mIsVisual = presContext->IsVisualMode();
if (mIsVisual) {
/**
* Drill up in content to detect whether this is an element that needs to be
* rendered with logical order even on visual pages.
@ -418,13 +355,94 @@ nsBidiPresUtils::Resolve(nsBlockFrame* aBlockFrame)
* element appears in a visual page, it will be generated by an XBL binding
* and contain localized text which will be in logical order.
*/
for (content = aBlockFrame->GetContent() ; content; content = content->GetParent()) {
if (content->IsNodeOfType(nsINode::eHTML_FORM_CONTROL) || content->IsXUL()) {
isVisual = PR_FALSE;
for (nsIContent* content = aBlockFrame->GetContent() ; content;
content = content->GetParent()) {
if (content->IsNodeOfType(nsINode::eHTML_FORM_CONTROL) ||
content->IsXUL()) {
mIsVisual = PR_FALSE;
break;
}
}
}
// handle bidi-override being set on the block itself before calling
// TraverseFrames.
const nsStyleTextReset* text = aBlockFrame->GetStyleTextReset();
PRUnichar ch = 0;
if (text->mUnicodeBidi == NS_STYLE_UNICODE_BIDI_OVERRIDE) {
if (NS_STYLE_DIRECTION_RTL == vis->mDirection) {
ch = kRLO;
}
else if (NS_STYLE_DIRECTION_LTR == vis->mDirection) {
ch = kLRO;
}
if (ch != 0) {
mLogicalFrames.AppendElement(NS_BIDI_CONTROL_FRAME);
mLinePerFrame.AppendElement((nsLineBox*)nsnull);
mBuffer.Append(ch);
mEmbeddingStack.AppendElement(ch);
}
}
mPrevContent = nsnull;
for (nsBlockFrame* block = aBlockFrame; block;
block = static_cast<nsBlockFrame*>(block->GetNextContinuation())) {
block->RemoveStateBits(NS_BLOCK_NEEDS_BIDI_RESOLUTION);
nsBlockInFlowLineIterator lineIter(block, block->begin_lines(), PR_FALSE);
mPrevFrame = nsnull;
TraverseFrames(aBlockFrame, &lineIter, block->GetFirstChild(nsnull));
}
if (ch != 0) {
mLogicalFrames.AppendElement(NS_BIDI_CONTROL_FRAME);
mLinePerFrame.AppendElement((nsLineBox*)nsnull);
mBuffer.Append(kPDF);
NS_ASSERTION(mEmbeddingStack.Length(), "embedding/override underflow");
mEmbeddingStack.TruncateLength(mEmbeddingStack.Length() - 1);
}
ResolveParagraph(aBlockFrame);
return mSuccess;
}
void
nsBidiPresUtils::ResolveParagraph(nsBlockFrame* aBlockFrame)
{
nsPresContext *presContext = aBlockFrame->PresContext();
PRInt32 bufferLength = mBuffer.Length();
if (bufferLength < 1) {
mSuccess = NS_OK;
return;
}
mBuffer.ReplaceChar("\t\r\n", kSpace);
PRInt32 runCount;
PRUint8 embeddingLevel = mParaLevel;
mSuccess = mBidiEngine->SetPara(mBuffer.get(), bufferLength, mParaLevel, nsnull);
if (NS_FAILED(mSuccess) ) {
return;
}
mSuccess = mBidiEngine->CountRuns(&runCount);
if (NS_FAILED(mSuccess) ) {
return;
}
PRInt32 runLength = 0; // the length of the current run of text
PRInt32 lineOffset = 0; // the start of the current run
PRInt32 logicalLimit = 0; // the end of the current run + 1
PRInt32 numRun = -1;
PRInt32 fragmentLength = 0; // the length of the current text frame
PRInt32 frameIndex = -1; // index to the frames in mLogicalFrames
PRInt32 frameCount = mLogicalFrames.Length();
PRInt32 contentOffset = 0; // offset of current frame in its content node
PRBool isTextFrame = PR_FALSE;
nsIFrame* frame = nsnull;
nsIContent* content = nsnull;
PRInt32 contentTextLength;
FramePropertyTable *propTable = presContext->PropertyTable();
nsLineBox* currentLine = nsnull;
#ifdef DEBUG
#ifdef NOISY_BIDI
@ -444,9 +462,17 @@ nsBidiPresUtils::Resolve(nsBlockFrame* aBlockFrame)
break;
}
frame = mLogicalFrames[frameIndex];
frameType = frame->GetType();
lineNeedsUpdate = PR_TRUE;
if (nsGkAtoms::textFrame == frameType) {
if (frame == NS_BIDI_CONTROL_FRAME ||
nsGkAtoms::textFrame != frame->GetType()) {
/*
* Any non-text frame corresponds to a single character in the text buffer
* (a bidi control character, LINE SEPARATOR, or OBJECT SUBSTITUTE)
*/
isTextFrame = PR_FALSE;
fragmentLength = 1;
}
else {
currentLine = mLinePerFrame[frameIndex];
content = frame->GetContent();
if (!content) {
mSuccess = NS_OK;
@ -460,7 +486,7 @@ nsBidiPresUtils::Resolve(nsBlockFrame* aBlockFrame)
propTable->Set(frame, nsIFrame::EmbeddingLevelProperty(),
NS_INT32_TO_PTR(embeddingLevel));
propTable->Set(frame, nsIFrame::BaseLevelProperty(),
NS_INT32_TO_PTR(paraLevel));
NS_INT32_TO_PTR(mParaLevel));
continue;
}
PRInt32 start, end;
@ -471,14 +497,6 @@ nsBidiPresUtils::Resolve(nsBlockFrame* aBlockFrame)
contentOffset = start;
isTextFrame = PR_TRUE;
}
else {
/*
* Any non-text frame corresponds to a single character in the text buffer
* (a bidi control character, LINE SEPARATOR, or OBJECT SUBSTITUTE)
*/
isTextFrame = PR_FALSE;
fragmentLength = 1;
}
} // if (fragmentLength <= 0)
if (runLength <= 0) {
@ -492,13 +510,12 @@ nsBidiPresUtils::Resolve(nsBlockFrame* aBlockFrame)
break;
}
runLength = logicalLimit - lineOffset;
if (isVisual) {
embeddingLevel = paraLevel;
if (mIsVisual) {
embeddingLevel = mParaLevel;
}
} // if (runLength <= 0)
if (nsGkAtoms::directionalFrame == frameType) {
frame->Destroy();
if (frame == NS_BIDI_CONTROL_FRAME) {
frame = nsnull;
++lineOffset;
}
@ -506,18 +523,14 @@ nsBidiPresUtils::Resolve(nsBlockFrame* aBlockFrame)
propTable->Set(frame, nsIFrame::EmbeddingLevelProperty(),
NS_INT32_TO_PTR(embeddingLevel));
propTable->Set(frame, nsIFrame::BaseLevelProperty(),
NS_INT32_TO_PTR(paraLevel));
NS_INT32_TO_PTR(mParaLevel));
if (isTextFrame) {
if ( (runLength > 0) && (runLength < fragmentLength) ) {
/*
* The text in this frame continues beyond the end of this directional run.
* Create a non-fluid continuation frame for the next directional run.
*/
if (lineNeedsUpdate) {
AdvanceLineIteratorToFrame(frame, &lineIter, prevFrame);
lineNeedsUpdate = PR_FALSE;
}
lineIter.GetLine()->MarkDirty();
currentLine->MarkDirty();
nsIFrame* nextBidi;
PRInt32 runEnd = contentOffset + runLength;
EnsureBidiContinuation(frame, &nextBidi, frameIndex,
@ -553,12 +566,17 @@ nsBidiPresUtils::Resolve(nsBlockFrame* aBlockFrame)
*/
PRInt32 newIndex = frameIndex;
do {
} while (mLogicalFrames[++newIndex]->GetType() == nsGkAtoms::directionalFrame);
RemoveBidiContinuation(frame, frameIndex, newIndex, lineOffset);
} else if (runLength == fragmentLength) {
} while (++newIndex < frameCount &&
mLogicalFrames[newIndex] == NS_BIDI_CONTROL_FRAME);
if (newIndex < frameCount) {
RemoveBidiContinuation(frame, frameIndex, newIndex, lineOffset);
}
} else if (runLength == fragmentLength &&
numRun + 1 < runCount) {
/*
* The directional run ends at the end of the frame. Make sure that
* the next frame is a non-fluid continuation
* If the directional run ends at the end of the frame, and this is
* not the end of our paragraph, make sure that the next frame is a
* non-fluid continuation
*/
nsIFrame* next = frame->GetNextInFlow();
if (next) {
@ -567,29 +585,25 @@ nsBidiPresUtils::Resolve(nsBlockFrame* aBlockFrame)
}
}
frame->AdjustOffsetsForBidi(contentOffset, contentOffset + fragmentLength);
if (lineNeedsUpdate) {
AdvanceLineIteratorToFrame(frame, &lineIter, prevFrame);
lineNeedsUpdate = PR_FALSE;
}
lineIter.GetLine()->MarkDirty();
currentLine->MarkDirty();
}
} // isTextFrame
else {
++lineOffset;
}
} // not directionalFrame
} // not bidi control frame
PRInt32 temp = runLength;
runLength -= fragmentLength;
fragmentLength -= temp;
if (frame && fragmentLength <= 0) {
// If the frame is at the end of a run, split all ancestor inlines that
// need splitting.
// If the frame is at the end of a run, and this is not the end of our
// paragrah, split all ancestor inlines that need splitting.
// To determine whether we're at the end of the run, we check that we've
// finished processing the current run, and that the current frame
// doesn't have a fluid continuation (it could have a fluid continuation
// of zero length, so testing runLength alone is not sufficient).
if (runLength <= 0 && !frame->GetNextInFlow()) {
if (numRun + 1 < runCount && runLength <= 0 && !frame->GetNextInFlow()) {
nsIFrame* child = frame;
nsIFrame* parent = frame->GetParent();
// As long as we're on the last sibling, the parent doesn't have to be split.
@ -611,12 +625,11 @@ nsBidiPresUtils::Resolve(nsBlockFrame* aBlockFrame)
if (parent && IsBidiSplittable(parent))
SplitInlineAncestors(child);
}
else if (!frame->GetNextSibling()) {
// We're not at an end of a run, and |frame| is the last child of its parent.
// If its ancestors happen to have bidi continuations, convert them into
// fluid continuations.
nsIFrame* parent = frame->GetParent();
JoinInlineAncestors(parent);
else {
// We're not at an end of a run. If |frame| is the last child of its
// parent, and its ancestors happen to have bidi continuations, convert
// them into fluid continuations.
JoinInlineAncestors(frame);
}
}
} // for
@ -628,8 +641,6 @@ nsBidiPresUtils::Resolve(nsBlockFrame* aBlockFrame)
printf("===\n");
#endif
#endif
return mSuccess;
}
// Should this frame be treated as a leaf (e.g. when building mLogicalFrames)?
@ -640,16 +651,25 @@ PRBool IsBidiLeaf(nsIFrame* aFrame) {
}
void
nsBidiPresUtils::InitLogicalArray(nsIFrame* aCurrentFrame)
nsBidiPresUtils::TraverseFrames(nsBlockFrame* aBlockFrame,
nsBlockInFlowLineIterator* aLineIter,
nsIFrame* aCurrentFrame)
{
if (!aCurrentFrame)
return;
nsIPresShell* shell = aCurrentFrame->PresContext()->PresShell();
nsStyleContext* styleContext;
for (nsIFrame* childFrame = aCurrentFrame; childFrame;
childFrame = childFrame->GetNextSibling()) {
nsIFrame* childFrame = aCurrentFrame;
do {
/*
* It's important to get the next sibling and next continuation *before*
* handling the frame: If we encounter a forced paragraph break and call
* ResolveParagraph within this loop, doing GetNextSibling and
* GetNextContinuation after that could return a bidi continuation that had
* just been split from the original childFrame and we would process it
* twice.
*/
nsIFrame* nextSibling = childFrame->GetNextSibling();
PRBool isLastFrame = !childFrame->GetNextContinuation();
// If the real frame for a placeholder is a first letter frame, we need to
// drill down into it and include its contents in Bidi resolution.
@ -671,8 +691,6 @@ nsBidiPresUtils::InitLogicalArray(nsIFrame* aCurrentFrame)
case NS_STYLE_UNICODE_BIDI_NORMAL:
break;
case NS_STYLE_UNICODE_BIDI_EMBED:
styleContext = frame->GetStyleContext();
if (NS_STYLE_DIRECTION_RTL == vis->mDirection) {
ch = kRLE;
}
@ -681,8 +699,6 @@ nsBidiPresUtils::InitLogicalArray(nsIFrame* aCurrentFrame)
}
break;
case NS_STYLE_UNICODE_BIDI_OVERRIDE:
styleContext = frame->GetStyleContext();
if (NS_STYLE_DIRECTION_RTL == vis->mDirection) {
ch = kRLO;
}
@ -692,13 +708,13 @@ nsBidiPresUtils::InitLogicalArray(nsIFrame* aCurrentFrame)
break;
}
// Create a directional frame before the first frame of an
// element specifying embedding or override
// Add a dummy frame pointer representing a bidi control code before the
// first frame of an element specifying embedding or override
if (ch != 0 && !frame->GetPrevContinuation()) {
nsIFrame* dirFrame = NS_NewDirectionalFrame(shell, styleContext, ch);
if (dirFrame) {
mLogicalFrames.AppendElement(dirFrame);
}
mLogicalFrames.AppendElement(NS_BIDI_CONTROL_FRAME);
mLinePerFrame.AppendElement((nsLineBox*)nsnull);
mBuffer.Append(ch);
mEmbeddingStack.AppendElement(ch);
}
}
@ -713,66 +729,196 @@ nsBidiPresUtils::InitLogicalArray(nsIFrame* aCurrentFrame)
mContentToFrameIndex.Put(content, mLogicalFrames.Length());
}
mLogicalFrames.AppendElement(frame);
AdvanceLineIteratorToFrame(frame, aLineIter, mPrevFrame);
mLinePerFrame.AppendElement(aLineIter->GetLine().get());
// Append the content of the frame to the paragraph buffer
nsIAtom* frameType = frame->GetType();
if (nsGkAtoms::textFrame == frameType) {
if (content != mPrevContent) {
mPrevContent = content;
if (!frame->GetStyleContext()->GetStyleText()->NewlineIsSignificant()) {
content->AppendTextTo(mBuffer);
} else {
/*
* For preformatted text we have to do bidi resolution on each line
* separately.
*/
nsAutoString text;
content->AppendTextTo(text);
nsIFrame* next;
do {
next = nsnull;
PRInt32 start, end;
frame->GetOffsets(start, end);
PRInt32 endLine = text.FindCharInSet(NS_LITERAL_STRING("\n\r"),
start);
if (endLine == -1) {
/*
* If there is no newline in the frame, just save the text and
* do bidi resolution later
*/
mBuffer.Append(Substring(text, start));
break;
}
/*
* If there is a newline in the frame, break the frame after the
* newline, do bidi resolution and repeat until the end of the
* element.
*/
++endLine;
/*
* If the frame ends before the new line, save the text and move
* into the next continuation
*/
while (end < endLine) {
mBuffer.Append(Substring(text, start, end - start));
frame = frame->GetNextContinuation();
NS_ASSERTION(frame, "Premature end of continuation chain");
frame->GetOffsets(start, end);
mLogicalFrames.AppendElement(frame);
AdvanceLineIteratorToFrame(frame, aLineIter, mPrevFrame);
mLinePerFrame.AppendElement(aLineIter->GetLine().get());
/*
* If we have already overshot the saved next-sibling while
* scanning the frame's continuations, advance it.
*/
if (frame == nextSibling) {
nextSibling = frame->GetNextSibling();
}
}
mBuffer.Append(Substring(text, start, endLine - start));
PRBool createdContinuation = PR_FALSE;
if (PRUint32(endLine) < text.Length()) {
/*
* Timing is everything here: if the frame already has a bidi
* continuation, we need to make the continuation fluid *before*
* resetting the length of the current frame. Otherwise
* nsTextFrame::SetLength won't set the continuation frame's
* text offsets correctly.
*
* On the other hand, if the frame doesn't have a continuation,
* we need to create one *after* resetting the length, or
* CreateContinuingFrame will complain that there is no more
* content for the continuation.
*/
next = frame->GetNextInFlow();
if (!next) {
// If the frame already has a bidi continuation, make it fluid
next = frame->GetNextContinuation();
if (next) {
MakeContinuationFluid(frame, next);
JoinInlineAncestors(frame);
}
}
nsTextFrame* textFrame = static_cast<nsTextFrame*>(frame);
textFrame->SetLength(endLine - start, nsnull);
if (!next) {
// If the frame has no next in flow, create one.
CreateContinuation(frame, &next, PR_TRUE);
createdContinuation = PR_TRUE;
}
}
ResolveParagraphWithinBlock(aBlockFrame);
if (!nextSibling && !createdContinuation) {
break;
} else if (next) {
frame = next;
mLogicalFrames.AppendElement(frame);
AdvanceLineIteratorToFrame(frame, aLineIter, mPrevFrame);
mLinePerFrame.AppendElement(aLineIter->GetLine().get());
}
/*
* If we have already overshot the saved next-sibling while
* scanning the frame's continuations, advance it.
*/
if (frame && frame == nextSibling) {
nextSibling = frame->GetNextSibling();
}
} while (next);
}
}
} else if (nsGkAtoms::brFrame == frameType) {
// break frame -- append line separator
mBuffer.Append(kLineSeparator);
ResolveParagraphWithinBlock(aBlockFrame);
} else {
// other frame type -- see the Unicode Bidi Algorithm:
// "...inline objects (such as graphics) are treated as if they are ...
// U+FFFC"
mBuffer.Append(kObjectSubstitute);
if (!frame->GetStyleContext()->GetStyleDisplay()->IsInlineOutside()) {
// if it is not inline, end the paragraph
ResolveParagraphWithinBlock(aBlockFrame);
}
}
}
else {
// For a non-leaf frame, recurse into TraverseFrames
nsIFrame* kid = frame->GetFirstChild(nsnull);
InitLogicalArray(kid);
TraverseFrames(aBlockFrame, aLineIter, kid);
}
// If the element is attributed by dir, indicate direction pop (add PDF frame)
if (ch != 0 && !frame->GetNextContinuation()) {
// Create a directional frame after the last frame of an
// element specifying embedding or override
nsIFrame* dirFrame = NS_NewDirectionalFrame(shell, styleContext, kPDF);
if (dirFrame) {
mLogicalFrames.AppendElement(dirFrame);
}
if (ch != 0 && isLastFrame) {
// Add a dummy frame pointer representing a bidi control code after the
// last frame of an element specifying embedding or override
mLogicalFrames.AppendElement(NS_BIDI_CONTROL_FRAME);
mLinePerFrame.AppendElement((nsLineBox*)nsnull);
mBuffer.Append(kPDF);
NS_ASSERTION(mEmbeddingStack.Length(), "embedding/override underflow");
mEmbeddingStack.TruncateLength(mEmbeddingStack.Length() - 1);
}
} // for
childFrame = nextSibling;
} while (childFrame);
}
void
nsBidiPresUtils::CreateBlockBuffer()
nsBidiPresUtils::ResolveParagraphWithinBlock(nsBlockFrame* aBlockFrame)
{
mBuffer.SetLength(0);
nsIPresShell* shell;
nsStyleContext* styleContext;
nsIFrame* frame;
nsIContent* prevContent = nsnull;
PRUint32 i;
PRUint32 count = mLogicalFrames.Length();
if (mEmbeddingStack.Length() > 0) {
shell = aBlockFrame->PresContext()->PresShell();
styleContext = aBlockFrame->GetStyleContext();
for (i = 0; i < count; i++) {
frame = mLogicalFrames[i];
nsIAtom* frameType = frame->GetType();
if (nsGkAtoms::textFrame == frameType) {
nsIContent* content = frame->GetContent();
if (!content) {
mSuccess = NS_OK;
break;
}
if (content == prevContent) {
continue;
}
prevContent = content;
content->AppendTextTo(mBuffer);
}
else if (nsGkAtoms::brFrame == frameType) { // break frame
// Append line separator
mBuffer.Append(kLineSeparator);
}
else if (nsGkAtoms::directionalFrame == frameType) {
nsDirectionalFrame* dirFrame = static_cast<nsDirectionalFrame*>(frame);
mBuffer.Append(dirFrame->GetChar());
}
else { // not text frame
// See the Unicode Bidi Algorithm:
// "...inline objects (such as graphics) are treated as if they are ... U+FFFC"
mBuffer.Append(kObjectSubstitute);
// pop all embeddings and overrides
for (PRUint32 i = 0; i < mEmbeddingStack.Length(); ++i) {
mBuffer.Append(kPDF);
mLogicalFrames.AppendElement(NS_BIDI_CONTROL_FRAME);
mLinePerFrame.AppendElement((nsLineBox*)nsnull);
}
}
// XXX: TODO: Handle preformatted text ('\n')
mBuffer.ReplaceChar("\t\r\n", kSpace);
ResolveParagraph(aBlockFrame);
// Clear the frame array and paragraph buffer, and restore the stored
// embeddings and overrides
mLogicalFrames.Clear();
mContentToFrameIndex.Clear();
mLinePerFrame.Clear();
mBuffer.SetLength(0);
mPrevContent = nsnull;
if (mEmbeddingStack.Length() > 0) {
for (PRUint32 i = 0; i < mEmbeddingStack.Length(); ++i) {
mBuffer.Append(mEmbeddingStack[i]);
mLogicalFrames.AppendElement(NS_BIDI_CONTROL_FRAME);
mLinePerFrame.AppendElement((nsLineBox*)nsnull);
}
}
}
void
@ -1219,7 +1365,7 @@ nsBidiPresUtils::EnsureBidiContinuation(nsIFrame* aFrame,
NS_PRECONDITION(aFrame, "aFrame is null");
aFrame->AdjustOffsetsForBidi(aStart, aEnd);
mSuccess = CreateBidiContinuation(aFrame, aNewFrame);
mSuccess = CreateContinuation(aFrame, aNewFrame, PR_FALSE);
}
void
@ -1236,8 +1382,7 @@ nsBidiPresUtils::RemoveBidiContinuation(nsIFrame* aFrame,
for (PRInt32 index = aFirstIndex + 1; index <= aLastIndex; index++) {
nsIFrame* frame = mLogicalFrames[index];
if (nsGkAtoms::directionalFrame == frame->GetType()) {
frame->Destroy();
if (frame == NS_BIDI_CONTROL_FRAME) {
++aOffset;
}
else {
@ -1252,14 +1397,7 @@ nsBidiPresUtils::RemoveBidiContinuation(nsIFrame* aFrame,
while (frame) {
nsIFrame* prev = frame->GetPrevContinuation();
if (prev) {
NS_ASSERTION (!frame->GetPrevInFlow() || frame->GetPrevInFlow() == prev,
"prev-in-flow is not prev continuation!");
frame->SetPrevInFlow(prev);
NS_ASSERTION (!prev->GetNextInFlow() || prev->GetNextInFlow() == frame,
"next-in-flow is not next continuation!");
prev->SetNextInFlow(frame);
MakeContinuationFluid(prev, frame);
frame = frame->GetParent();
} else {
break;

View File

@ -175,6 +175,8 @@ public:
* @lina 06/18/2000
*/
nsresult Resolve(nsBlockFrame* aBlockFrame);
void ResolveParagraph(nsBlockFrame* aBlockFrame);
void ResolveParagraphWithinBlock(nsBlockFrame* aBlockFrame);
/**
* Reorder this line using Bidi engine.
@ -362,18 +364,16 @@ private:
nscoord* aWidth /* may be null */);
/**
* Create a string containing entire text content of this block.
*
* @lina 05/02/2000
* Traverse the child frames of the block element and:
* Set up an array of the frames in logical order
* Create a string containing the text content of all the frames
* If we encounter content that requires us to split the element into more
* than one paragraph for bidi resolution, resolve the paragraph up to that
* point.
*/
void CreateBlockBuffer();
/**
* Set up an array of the frames after splitting frames so that each frame has
* consistent directionality. At this point the frames are still in logical
* order
*/
void InitLogicalArray(nsIFrame* aCurrentFrame);
void TraverseFrames(nsBlockFrame* aBlockFrame,
nsBlockInFlowLineIterator* aLineIter,
nsIFrame* aCurrentFrame);
/**
* Initialize the logically-ordered array of frames
@ -513,14 +513,20 @@ private:
PRUint32 aSrcLength,
PRUnichar* aDest);
nsAutoString mBuffer;
nsString mBuffer;
nsTArray<PRUnichar> mEmbeddingStack;
nsTArray<nsIFrame*> mLogicalFrames;
nsTArray<nsLineBox*> mLinePerFrame;
nsTArray<nsIFrame*> mVisualFrames;
nsDataHashtable<nsISupportsHashKey, PRInt32> mContentToFrameIndex;
PRInt32 mArraySize;
PRInt32* mIndexMap;
PRUint8* mLevels;
nsresult mSuccess;
PRPackedBool mIsVisual;
nsBidiLevel mParaLevel;
nsIFrame* mPrevFrame;
nsIContent* mPrevContent;
nsBidi* mBidiEngine;
};

View File

@ -772,8 +772,10 @@ nsPresContext::GetUserPreferences()
}
void
nsPresContext::AppUnitsPerDevPixelChanged()
nsPresContext::InvalidateThebesLayers()
{
if (!mShell)
return;
nsIFrame* rootFrame = mShell->FrameManager()->GetRootFrame();
if (rootFrame) {
// FrameLayerBuilder caches invalidation-related values that depend on the
@ -781,6 +783,12 @@ nsPresContext::AppUnitsPerDevPixelChanged()
// is completely flushed.
FrameLayerBuilder::InvalidateThebesLayersInSubtree(rootFrame);
}
}
void
nsPresContext::AppUnitsPerDevPixelChanged()
{
InvalidateThebesLayers();
mDeviceContext->FlushFontCache();
@ -868,6 +876,7 @@ nsPresContext::UpdateAfterPreferencesChanged()
mShell->SetPreferenceStyleRules(PR_TRUE);
}
InvalidateThebesLayers();
mDeviceContext->FlushFontCache();
nsChangeHint hint = nsChangeHint(0);

View File

@ -1049,6 +1049,7 @@ protected:
NS_HIDDEN_(void) UpdateCharSet(const nsAFlatCString& aCharSet);
void InvalidateThebesLayers();
void AppUnitsPerDevPixelChanged();
PRBool MayHavePaintEventListener();

View File

@ -332,6 +332,7 @@ _TEST_FILES += \
test_bug588174.html \
test_bug607529.html \
file_bug607529.html \
test_bug644768.html \
$(NULL)
endif

View File

@ -0,0 +1,59 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=644768
-->
<head>
<title>Test for Bug 644768</title>
<script type="text/javascript" src="/MochiKit/packed.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/WindowSnapshot.js"></script>
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body onload="test()">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=644768">Mozilla Bug 644768</a>
<p id="display"></p>
<div id="content">
<!-- test text is
== زادروزها ==
* [[۱۳۰۷]]
-->
<textarea id="testInput" dir="rtl" cols="80" rows="25">
== &#x0632;&#x0627;&#x062F;&#x0631;&#x0648;&#x0632;&#x0647;&#x0627; ==
* [[&#x06F1;&#x06F3;&#x06F0;&#x06F7;]]</textarea>
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
/** Test for Bug 644768 **/
SimpleTest.waitForExplicitFinish();
function test() {
var textInput = $("testInput");
var s1, s2, equal, str1, str2;
textInput.focus();
s1 = snapshotWindow(window);
synthesizeKey("VK_UP", { });
synthesizeKey("VK_UP", { });
synthesizeKey("VK_UP", { });
synthesizeKey("VK_DELETE", { });
synthesizeKey("VK_ENTER", { });
s2 = snapshotWindow(window);
[equal, str1, str2] = compareSnapshots(s1, s2, true);
ok(equal, "newline before bidi text shouldn't change direction: expected " +
str1 + " but got " + str2);
SimpleTest.finish();
}
</script>
</pre>
</body>
</html>

View File

@ -121,7 +121,6 @@
#include "nsContentSink.h"
#include "nsFrameMessageManager.h"
#include "nsRefreshDriver.h"
#include "CanvasImageCache.h"
#include "nsHyphenationManager.h"
@ -281,7 +280,6 @@ nsLayoutStatics::Initialize()
void
nsLayoutStatics::Shutdown()
{
CanvasImageCache::Shutdown();
nsFrameScriptExecutor::Shutdown();
nsFocusManager::Shutdown();
#ifdef MOZ_XUL

View File

@ -71,13 +71,6 @@ EXPORTS = \
nsObjectFrame.h \
$(NULL)
ifdef IBMBIDI
EXPORTS += \
nsBidiFrames.h \
$(NULL)
endif
CPPSRCS = \
nsAbsoluteContainingBlock.cpp \
nsBRFrame.cpp \
@ -126,12 +119,6 @@ CPPSRCS += \
$(NULL)
endif
ifdef IBMBIDI
CPPSRCS += \
nsBidiFrames.cpp \
$(NULL)
endif
ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
CMMSRCS += \
nsPluginUtilsOSX.mm \

View File

@ -1,76 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* ***** 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.org code.
*
* The Initial Developer of the Original Code is
* IBM Corporation.
* Portions created by the Initial Developer are Copyright (C) 2000
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of 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 ***** */
#ifdef IBMBIDI
#include "nsBidiFrames.h"
#include "nsGkAtoms.h"
nsDirectionalFrame::nsDirectionalFrame(nsStyleContext* aContext, PRUnichar aChar)
: nsFrame(aContext), mChar(aChar)
{
}
nsDirectionalFrame::~nsDirectionalFrame()
{
}
nsIAtom*
nsDirectionalFrame::GetType() const
{
return nsGkAtoms::directionalFrame;
}
#ifdef NS_DEBUG
NS_IMETHODIMP
nsDirectionalFrame::GetFrameName(nsAString& aResult) const
{
return MakeFrameName(NS_LITERAL_STRING("Directional"), aResult);
}
#endif
nsIFrame*
NS_NewDirectionalFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, PRUnichar aChar)
{
return new (aPresShell) nsDirectionalFrame(aContext, aChar);
}
NS_IMPL_FRAMEARENA_HELPERS(nsDirectionalFrame)
#endif /* IBMBIDI */

View File

@ -1,76 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* ***** 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.org code.
*
* The Initial Developer of the Original Code is
* IBM Corporation.
* Portions created by the Initial Developer are Copyright (C) 2000
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of 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 ***** */
#ifdef IBMBIDI
#ifndef nsBidiFrames_h___
#define nsBidiFrames_h___
#include "nsFrame.h"
class nsDirectionalFrame : public nsFrame
{
protected:
virtual ~nsDirectionalFrame();
public:
NS_DECL_FRAMEARENA_HELPERS
nsDirectionalFrame(nsStyleContext* aContext, PRUnichar aChar);
/**
* Get the "type" of the frame
*
* @see nsGkAtoms::directionalFrame
*/
virtual nsIAtom* GetType() const;
PRUnichar GetChar() const { return mChar; }
#ifdef NS_DEBUG
NS_IMETHOD GetFrameName(nsAString& aResult) const;
#endif
private:
PRUnichar mChar;
};
#endif /* nsBidiFrames_h___ */
#endif /* IBMBIDI */

View File

@ -88,7 +88,6 @@ public:
nsContainerFrame_id,
nsContinuingTextFrame_id,
nsDeckFrame_id,
nsDirectionalFrame_id,
nsDocElementBoxFrame_id,
nsFieldSetFrame_id,
nsFileControlFrame_id,

View File

@ -106,7 +106,6 @@
#endif
#include "nsAutoPtr.h"
#include "nsBidiFrames.h"
#include "nsBidiPresUtils.h"
#include "nsBidiUtils.h"

View File

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<title>br-as-bidi-paragraph-break</title>
<meta charset="UTF-8">
</head>
<body>
<p>&#x05D0; --&gt;&lrm;<br>--&gt; &#x05D1;</p>
</body>
</html>

View File

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<title>br-as-bidi-paragraph-break</title>
<meta charset="UTF-8">
</head>
<body>
<p>&#x05D0; --&gt;<br>--&gt; &#x05D1;</p>
</body>
</html>

View File

@ -0,0 +1,43 @@
<DOCTYPE html>
<html DIR=RTL>
<head>
<meta charset=UTF-8>
<title>BIDI Layout Testing</title>
</head>
<body>
<h2>This is a testing for BiDi layout issues.</h2>
<br>
1 - No tag<br>
2 - SPAN<br>
3 - P<br>
4 - DIV<br>
<br>
<b>Test1: No space</b><br>
This is a testing for BiDi layout issues.&rlm;<br>
<span>This is a testing for BiDi layout issues.&rlm;<br></span>
<p>This is a testing for BiDi layout issues.&rlm;<br></p>
<div>This is a testing for BiDi layout issues.&rlm;<br></div>
<br><br>
<b>Test2: 3 spaces at the end</b><br>
This is a testing for BiDi layout issues.&rlm;&nbsp;&nbsp;&nbsp;<br>
<span>This is a testing for BiDi layout issues.&rlm;&nbsp;&nbsp;&nbsp;<br></span>
<p>This is a testing for BiDi layout issues.&rlm;&nbsp;&nbsp;&nbsp;<br></p>
<div>This is a testing for BiDi layout issues.&rlm;&nbsp;&nbsp;&nbsp;<br></div>
<br><br>
<b>Test3: 3 spaces at the beginning</b><br>
&nbsp;&nbsp;&nbsp;This is a testing for BiDi layout issues.&rlm;<br>
<span>&nbsp;&nbsp;&nbsp;This is a testing for BiDi layout issues.&rlm;<br></span>
<p>&nbsp;&nbsp;&nbsp;This is a testing for BiDi layout issues.&rlm;<br></p>
<div>&nbsp;&nbsp;&nbsp;This is a testing for BiDi layout issues.&rlm;<br></div>
<br><br>
<b>Test4: 3 spaces at the end and the beginning</b><br>
&nbsp;&nbsp;&nbsp;This is a testing for BiDi layout issues.&rlm;&nbsp;&nbsp;&nbsp;<br>
<span>&nbsp;&nbsp;&nbsp;This is a testing for BiDi layout issues.&rlm;&nbsp;&nbsp;&nbsp;<br></span>
<p>&nbsp;&nbsp;&nbsp;This is a testing for BiDi layout issues.&rlm;&nbsp;&nbsp;&nbsp;<br></p>
<div>&nbsp;&nbsp;&nbsp;This is a testing for BiDi layout issues.&rlm;&nbsp;&nbsp;&nbsp;<br></div>
</body>
</html>

View File

@ -0,0 +1,43 @@
<DOCTYPE html>
<html DIR=RTL>
<head>
<meta charset=UTF-8>
<title>BIDI Layout Testing</title>
</head>
<body>
<h2>This is a testing for BiDi layout issues.</h2>
<br>
1 - No tag<br>
2 - SPAN<br>
3 - P<br>
4 - DIV<br>
<br>
<b>Test1: No space</b><br>
This is a testing for BiDi layout issues.<br>
<span>This is a testing for BiDi layout issues.<br></span>
<p>This is a testing for BiDi layout issues.<br></p>
<div>This is a testing for BiDi layout issues.<br></div>
<br><br>
<b>Test2: 3 spaces at the end</b><br>
This is a testing for BiDi layout issues.&nbsp;&nbsp;&nbsp;<br>
<span>This is a testing for BiDi layout issues.&nbsp;&nbsp;&nbsp;<br></span>
<p>This is a testing for BiDi layout issues.&nbsp;&nbsp;&nbsp;<br></p>
<div>This is a testing for BiDi layout issues.&nbsp;&nbsp;&nbsp;<br></div>
<br><br>
<b>Test3: 3 spaces at the beginning</b><br>
&nbsp;&nbsp;&nbsp;This is a testing for BiDi layout issues.<br>
<span>&nbsp;&nbsp;&nbsp;This is a testing for BiDi layout issues.<br></span>
<p>&nbsp;&nbsp;&nbsp;This is a testing for BiDi layout issues.<br></p>
<div>&nbsp;&nbsp;&nbsp;This is a testing for BiDi layout issues.<br></div>
<br><br>
<b>Test4: 3 spaces at the end and the beginning</b><br>
&nbsp;&nbsp;&nbsp;This is a testing for BiDi layout issues.&nbsp;&nbsp;&nbsp;<br>
<span>&nbsp;&nbsp;&nbsp;This is a testing for BiDi layout issues.&nbsp;&nbsp;&nbsp;<br></span>
<p>&nbsp;&nbsp;&nbsp;This is a testing for BiDi layout issues.&nbsp;&nbsp;&nbsp;<br></p>
<div>&nbsp;&nbsp;&nbsp;This is a testing for BiDi layout issues.&nbsp;&nbsp;&nbsp;<br></div>
</body>
</html>

View File

@ -0,0 +1,35 @@
<DOCTYPE html>
<!-- This tests that embeddings and overrides are preserved after <br> -->
<html>
<head>
<meta charset=UTF-8>
<title>Bug 229367</title>
<style type="text/css">
p { margin: 0; text-align: left; }
p.er { unicode-bidi: embed; direction: rtl; }
p.ol { unicode-bidi: bidi-override; direction: ltr; }
p.or { unicode-bidi: bidi-override; direction: rtl; }
</style>
</head>
<body>
<p>במה מדליקין,</p>
<p>ובמה אין מדליקין?</p>
<p class="er">אין מדליקין לא בלכש, </p>
<p class="er">ולא בחוסן, </p>
<p class="er">ולא בכלך, </p>
<p class="er">ולא בפתילת האידן, </p>
<p class="ol">ולא בפתילת המדבר, </p>
<p class="ol">ולא בירוקה שעל פני המים. </p>
<p class="ol">לא בזפת, </p>
<p class="or">ולא בשעווה, </p>
<p class="or">ולא בשמן קיק, </p>
<p class="or">ולא בשמן שריפה, </p>
<p class="or">ולא באליה, </p>
<p class="ol">ולא בחלב. </p>
<p class="ol">נחום המדי אומר, </p>
<p class="er">מדליקין בחלב מבושל;</p>
<p class="er">וחכמים אומרים, </p>
<p>אחד מבושל ואחד שאינו מבושל,</p>
<p>אין מדליקין בו.</p>
</body>
</html>

View File

@ -0,0 +1,30 @@
<DOCTYPE html>
<!-- This tests that embeddings and overrides are preserved after <br> -->
<html>
<head>
<meta charset=UTF-8>
<title>Bug 229367</title>
</head>
<body>
<div>במה מדליקין,<br>
ובמה אין מדליקין?<br>
<span style="unicode-bidi: embed; direction: rtl">אין מדליקין לא בלכש, <br>
ולא בחוסן, <br>
ולא בכלך, <br>
ולא בפתילת האידן, <br>
<span style="unicode-bidi: bidi-override; direction: ltr">ולא בפתילת המדבר, <br>
ולא בירוקה שעל פני המים. <br>
לא בזפת, <br>
<span style="unicode-bidi: bidi-override; direction: rtl">ולא בשעווה, <br>
ולא בשמן קיק, <br>
ולא בשמן שריפה, <br>
ולא באליה, <br></span>
ולא בחלב. <br>
נחום המדי אומר, <br></span>
מדליקין בחלב מבושל; <br>
וחכמים אומרים, <br></span>
אחד מבושל ואחד שאינו מבושל,<br>
אין מדליקין בו.
</div>
</body>
</html>

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<title>preformatted-paragraph-break-as-bidi-paragraph-break</title>
<meta charset="UTF-8">
</head>
<body>
<pre>&#x05D0; --&gt;&lrm;
--&gt; &#x05D1;</pre>
</body>
</html>

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<title>preformatted-paragraph-break-as-bidi-paragraph-break</title>
<meta charset="UTF-8">
</head>
<body>
<pre>&#x05D0; --&gt;
--&gt; &#x05D1;</pre>
</body>
</html>

View File

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<head>
<title>preformatted-paragraph-break-as-bidi-paragraph-break</title>
<meta charset="UTF-8">
<script type="text/javascript">
function boom()
{
document.getElementById("w").style.whiteSpace="pre";
}
</script>
</head>
<body onload="boom();">
<pre id="w" style="white-space: normal">&#x05D0; --&gt;
--&gt; &#x05D1;</pre>
</body>
</html>

View File

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<head>
<title>preformatted-paragraph-break-as-bidi-paragraph-break</title>
<meta charset="UTF-8">
<script type="text/javascript">
function boom()
{
document.getElementById("w").style.whiteSpace="normal";
}
</script>
</head>
<body onload="boom();">
<pre id="w">&#x05D0; --&gt;
--&gt; &#x05D1;</pre>
</body>
</html>

View File

@ -0,0 +1,47 @@
<DOCTYPE html>
<html DIR=RTL>
<head>
<meta charset=UTF-8>
<title>BIDI Layout Testing</title>
</head>
<body>
<div style="white-space: pre">
<b>Test1: No space</b>
This is a testing for BiDi layout issues. &rlm;
<span>This is a testing for BiDi layout issues.&rlm;
</span>
<p>This is a testing for BiDi layout issues.&rlm;
</p>
<div>This is a testing for BiDi layout issues.&rlm;
</div>
<b>Test2: 3 spaces at the end</b>
This is a testing for BiDi layout issues.&rlm;&nbsp;&nbsp;&nbsp;
<span>This is a testing for BiDi layout issues.&rlm;&nbsp;&nbsp;&nbsp;
</span>
<p>This is a testing for BiDi layout issues.&rlm;&nbsp;&nbsp;&nbsp;
</p>
<div>This is a testing for BiDi layout issues.&rlm;&nbsp;&nbsp;&nbsp;
</div>
<b>Test3: 3 spaces at the beginning</b>
&nbsp;&nbsp;&nbsp;This is a testing for BiDi layout issues.&rlm;
<span>&nbsp;&nbsp;&nbsp;This is a testing for BiDi layout issues.&rlm;
</span>
<p>&nbsp;&nbsp;&nbsp;This is a testing for BiDi layout issues.&rlm;
</p>
<div>&nbsp;&nbsp;&nbsp;This is a testing for BiDi layout issues.&rlm;
</div>
<b>Test4: 3 spaces at the end and the beginning</b>
&nbsp;&nbsp;&nbsp;This is a testing for BiDi layout issues.&rlm;&nbsp;&nbsp;&nbsp;
<span>&nbsp;&nbsp;&nbsp;This is a testing for BiDi layout issues.&rlm;&nbsp;&nbsp;&nbsp;
</span>
<p>&nbsp;&nbsp;&nbsp;This is a testing for BiDi layout issues.&rlm;&nbsp;&nbsp;&nbsp;
</p>
<div>&nbsp;&nbsp;&nbsp;This is a testing for BiDi layout issues.&rlm;&nbsp;&nbsp;&nbsp;
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,46 @@
<DOCTYPE html>
<html DIR=RTL>
<head>
<meta charset=UTF-8>
<title>BIDI Layout Testing</title>
</head>
<body>
<div style="white-space: pre">
<b>Test1: No space</b>
This is a testing for BiDi layout issues.
<span>This is a testing for BiDi layout issues.
</span>
<p>This is a testing for BiDi layout issues.
</p>
<div>This is a testing for BiDi layout issues.</div>
<b>Test2: 3 spaces at the end</b>
This is a testing for BiDi layout issues.&nbsp;&nbsp;&nbsp;
<span>This is a testing for BiDi layout issues.&nbsp;&nbsp;&nbsp;
</span>
<p>This is a testing for BiDi layout issues.&nbsp;&nbsp;&nbsp;
</p>
<div>This is a testing for BiDi layout issues.&nbsp;&nbsp;&nbsp;
</div>
<b>Test3: 3 spaces at the beginning</b>
&nbsp;&nbsp;&nbsp;This is a testing for BiDi layout issues.
<span>&nbsp;&nbsp;&nbsp;This is a testing for BiDi layout issues.
</span>
<p>&nbsp;&nbsp;&nbsp;This is a testing for BiDi layout issues.
</p>
<div>&nbsp;&nbsp;&nbsp;This is a testing for BiDi layout issues.
</div>
<b>Test4: 3 spaces at the end and the beginning</b>
&nbsp;&nbsp;&nbsp;This is a testing for BiDi layout issues.&nbsp;&nbsp;&nbsp;
<span>&nbsp;&nbsp;&nbsp;This is a testing for BiDi layout issues.&nbsp;&nbsp;&nbsp;
</span>
<p>&nbsp;&nbsp;&nbsp;This is a testing for BiDi layout issues.&nbsp;&nbsp;&nbsp;
</p>
<div>&nbsp;&nbsp;&nbsp;This is a testing for BiDi layout issues.&nbsp;&nbsp;&nbsp;
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,35 @@
<DOCTYPE html>
<!-- This tests that embeddings and overrides are preserved after <br> -->
<html>
<head>
<meta charset=UTF-8>
<title>Bug 263359</title>
<style type="text/css">
p { margin: 0; text-align: left; white-space: pre }
p.er { direction: rtl; }
p.ol { unicode-bidi: bidi-override; direction: ltr; }
p.or { unicode-bidi: bidi-override; direction: rtl; }
</style>
</head>
<body>
<p>במה מדליקין,</p>
<p>ובמה אין מדליקין?</p>
<p class="er">אין מדליקין לא בלכש,</p>
<p class="er">ולא בחוסן,</p>
<p class="er">ולא בכלך,</p>
<p class="er">ולא בפתילת האידן,</p>
<p class="ol">ולא בפתילת המדבר,</p>
<p class="ol">ולא בירוקה שעל פני המים.</p>
<p class="ol">לא בזפת,</p>
<p class="or">ולא בשעווה,</p>
<p class="or">ולא בשמן קיק,</p>
<p class="or">ולא בשמן שריפה,</p>
<p class="or">ולא באליה,</p>
<p class="ol">ולא בחלב.</p>
<p class="ol">נחום המדי אומר,</p>
<p class="er">מדליקין בחלב מבושל;</p>
<p class="er">וחכמים אומרים,</p>
<p>אחד מבושל ואחד שאינו מבושל,</p>
<p>אין מדליקין בו.</p>
</body>
</html>

View File

@ -0,0 +1,36 @@
<DOCTYPE html>
<!-- This tests that embeddings and overrides are preserved in <pre> -->
<html>
<head>
<meta charset=UTF-8>
<title>Bug 263359</title>
<style type="text/css">
p {
white-space: pre;
margin: 0;
}
</style>
</head>
<body>
<p style="">במה מדליקין,
ובמה אין מדליקין?
<span dir="rtl">אין מדליקין לא בלכש,
ולא בחוסן,
ולא בכלך,
ולא בפתילת האידן,
<span style="unicode-bidi: bidi-override; direction: ltr">ולא בפתילת המדבר,
ולא בירוקה שעל פני המים.
לא בזפת,
<span style="unicode-bidi: bidi-override; direction: rtl">ולא בשעווה,
ולא בשמן קיק,
ולא בשמן שריפה,
ולא באליה, </span>
ולא בחלב.
נחום המדי אומר, </span>
מדליקין בחלב מבושל;
וחכמים אומרים, </span>
אחד מבושל ואחד שאינו מבושל,
אין מדליקין בו.
</pre>
</body>
</html>

View File

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html>
<head>
<title>change direction of pre with bidi text</title>
<meta charset="UTF-8">
</head>
<body>
<pre dir="rtl"> can_be_executable=TRUE
[he]description=סוג לא ידוע
description=Unknown type
[ar]description=نوع غير معروف
[az]description=Namə'lum növ
</pre>
</body>
</html>

View File

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html>
<head>
<title>change direction of pre with bidi text</title>
<meta charset="UTF-8">
<script type="text/javascript">
function boom()
{
document.getElementById("w").style.direction="rtl";
}
</script>
</head>
<body onload="boom();">
<pre id="w"> can_be_executable=TRUE
[he]description=סוג לא ידוע
description=Unknown type
[ar]description=نوع غير معروف
[az]description=Namə'lum növ
</pre>
</body>
</html>

View File

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<title>block-element-as-bidi-paragraph-break</title>
<meta charset="UTF-8">
</head>
<body>
<div>&#x05D0; --&gt;&lrm;<hr>--&gt; &#x05D1;</div>
</body>
</html>

View File

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<title>block-element-as-bidi-paragraph-break</title>
<meta charset="UTF-8">
</head>
<body>
<div>&#x05D0; --&gt;<hr>--&gt; &#x05D1;</div>
</body>
</html>

View File

@ -0,0 +1,10 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Inline blocks shouldn't end the paragraph</title>
</head>
<body>
<p>&#x202e;אני אוהב--&gt; 4 xoferiF--&gt;8 ימים בשבוע</p>
</body>
</html>

View File

@ -0,0 +1,11 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Inline blocks shouldn't end the paragraph</title>
</head>
<body>
<p><span dir="rtl">אני אוהב</span>--&gt;<span style="display: inline-block">Firefox 4&nbsp;</span>--&gt;8 ימים בשבוע
</p>
</body>
</html>

View File

@ -43,7 +43,16 @@ random-if(cocoaWidget) == mirroring-02.html mirroring-02-ref.html
== 83958-2c.html 83958-2-ref.html
== 115921-1.html 115921-1-ref.html
== 115921-2.html 115921-2-ref.html
== 229367-1.html 229367-1-ref.html
== 229367-2.html 229367-2-ref.html
== 229367-3.html 229367-3-ref.html
== 258928-1.html 258928-1-ref.html
== 263359-1.html 263359-1-ref.html
== 263359-1a.html 263359-1-ref.html
!= 263359-1b.html 263359-1-ref.html
== 263359-2.html 263359-2-ref.html
== 263359-3.html 263359-3-ref.html
== 263359-4.html 263359-4-ref.html
random-if(winWidget) == 267459-1.html 267459-1-ref.html # depends on windows version, see bug 590101
fails-if(Android) == 267459-2.html 267459-2-ref.html # bug 650567
== 299065-1.html 299065-1-ref.html
@ -71,3 +80,5 @@ fails-if(Android) == 386339.html 386339-ref.html
== 588739-2.html 588739-ref.html
== 588739-3.html 588739-ref.html
== 612843-1.html 612843-1-ref.html
== 613157-1.html 613157-1-ref.html
== 613157-2.html 613157-2-ref.html

View File

@ -48,6 +48,9 @@ const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
const SIDEBAR_CID = Components.ID("{22117140-9c6e-11d3-aaf1-00805f8a4905}");
const SIDEBAR_CONTRACTID = "@mozilla.org/sidebar;1";
function Sidebar() {
// Depending on if we are in the parent or child, prepare to remote
// certain calls
@ -167,24 +170,19 @@ Sidebar.prototype = {
},
// =========================== nsIClassInfo ===========================
flags: Ci.nsIClassInfo.DOM_OBJECT,
classDescription: "Sidebar",
getInterfaces: function getInterfaces(count) {
var interfaceList = [Ci.nsISidebar, Ci.nsISidebarExternal, Ci.nsIClassInfo];
count.value = interfaceList.length;
return interfaceList;
},
getHelperForLanguage: function getHelperForLanguage(count) {
return null;
},
classInfo: XPCOMUtils.generateCI({classID: SIDEBAR_CID,
contractID: SIDEBAR_CONTRACTID,
interfaces: [Ci.nsISidebar,
Ci.nsISidebarExternal],
flags: Ci.nsIClassInfo.DOM_OBJECT,
classDescription: "Sidebar"}),
// =========================== nsISupports ===========================
QueryInterface: XPCOMUtils.generateQI([Ci.nsISidebar,
Ci.nsISidebarExternal,
Ci.nsIClassInfo]),
Ci.nsISidebarExternal]),
// XPCOMUtils stuff
classID: Components.ID("{22117140-9c6e-11d3-aaf1-00805f8a4905}"),
classID: SIDEBAR_CID,
};
const NSGetFactory = XPCOMUtils.generateNSGetFactory([Sidebar]);

View File

@ -1808,8 +1808,9 @@ pref("gfx.font_rendering.cleartype_params.pixel_structure", -1);
pref("gfx.font_rendering.cleartype_params.rendering_mode", -1);
// A comma-separated list of font family names. Fonts in these families will
// be forced to use "GDI Classic" ClearType mode, ignoring the value
// of gfx.font_rendering.cleartype_params.rendering_mode.
// be forced to use "GDI Classic" ClearType mode, provided the value
// of gfx.font_rendering.cleartype_params.rendering_mode is -1
// (i.e. a specific rendering_mode has not been explicitly set).
// Currently we apply this setting to the sans-serif Microsoft "core Web fonts".
pref("gfx.font_rendering.cleartype_params.force_gdi_classic_for_families",
"Arial,Courier New,Segoe UI,Tahoma,Trebuchet MS,Verdana");

View File

@ -37,6 +37,7 @@
*
* ***** END LICENSE BLOCK ***** */
#include "base/basictypes.h"
#include "nsLoadGroup.h"
#include "nsISupportsArray.h"
#include "nsEnumeratorUtils.h"
@ -50,6 +51,8 @@
#include "nsReadableUtils.h"
#include "nsString.h"
#include "nsTArray.h"
#include "base/histogram.h"
#include "base/logging.h"
#if defined(PR_LOGGING)
//
@ -66,8 +69,15 @@
static PRLogModuleInfo* gLoadGroupLog = nsnull;
#endif
#ifdef LOG
#undef LOG
#endif
#define LOG(args) PR_LOG(gLoadGroupLog, PR_LOG_DEBUG, args)
#define HISTOGRAM_TIME_DELTA(start, end) \
base::TimeDelta::FromMilliseconds( \
(PRUint32)((end - start).ToMilliseconds()))
////////////////////////////////////////////////////////////////////////////////
class RequestMapEntry : public PLDHashEntryHdr
@ -140,6 +150,9 @@ nsLoadGroup::nsLoadGroup(nsISupports* outer)
, mStatus(NS_OK)
, mPriority(PRIORITY_NORMAL)
, mIsCanceling(PR_FALSE)
, mDefaultLoadIsTimed(false)
, mTimedRequests(0)
, mCachedRequests(0)
{
NS_INIT_AGGREGATED(outer);
@ -340,6 +353,8 @@ nsLoadGroup::Cancel(nsresult status)
NS_RELEASE(request);
}
TelemetryReport();
#if defined(DEBUG)
NS_ASSERTION(mRequests.entryCount == 0, "Request list is not empty.");
NS_ASSERTION(mForegroundCount == 0, "Foreground URLs are active.");
@ -507,6 +522,14 @@ nsLoadGroup::SetDefaultLoadRequest(nsIRequest *aRequest)
// in particular, nsIChannel::LOAD_DOCUMENT_URI...
//
mLoadFlags &= 0xFFFF;
nsCOMPtr<nsITimedChannel> timedChannel =
do_QueryInterface(aRequest);
mDefaultLoadIsTimed = timedChannel != nsnull;
if (mDefaultLoadIsTimed) {
timedChannel->GetChannelCreation(&mDefaultRequestCreationTime);
timedChannel->SetTimingEnabled(PR_TRUE);
}
}
// Else, do not change the group's load flags (see bug 95981)
return NS_OK;
@ -577,6 +600,10 @@ nsLoadGroup::AddRequest(nsIRequest *request, nsISupports* ctxt)
if (mPriority != 0)
RescheduleRequest(request, mPriority);
nsCOMPtr<nsITimedChannel> timedChannel = do_QueryInterface(request);
if (timedChannel)
timedChannel->SetTimingEnabled(PR_TRUE);
if (!(flags & nsIRequest::LOAD_BACKGROUND)) {
// Update the count of foreground URIs..
mForegroundCount += 1;
@ -659,6 +686,41 @@ nsLoadGroup::RemoveRequest(nsIRequest *request, nsISupports* ctxt,
PL_DHashTableRawRemove(&mRequests, entry);
// Collect telemetry stats only when default request is a timed channel.
// Don't include failed requests in the timing statistics.
if (mDefaultLoadIsTimed && NS_SUCCEEDED(aStatus)) {
nsCOMPtr<nsITimedChannel> timedChannel =
do_QueryInterface(request);
if (timedChannel) {
// Figure out if this request was served from the cache
++mTimedRequests;
mozilla::TimeStamp timeStamp;
rv = timedChannel->GetCacheReadStart(&timeStamp);
if (NS_SUCCEEDED(rv) && !timeStamp.IsNull())
++mCachedRequests;
rv = timedChannel->GetAsyncOpen(&timeStamp);
if (NS_SUCCEEDED(rv) && !timeStamp.IsNull()) {
UMA_HISTOGRAM_MEDIUM_TIMES(
"HTTP subitem: Page start -> subitem open() (ms)",
HISTOGRAM_TIME_DELTA(mDefaultRequestCreationTime, timeStamp));
}
rv = timedChannel->GetResponseStart(&timeStamp);
if (NS_SUCCEEDED(rv) && !timeStamp.IsNull()) {
UMA_HISTOGRAM_MEDIUM_TIMES(
"HTTP subitem: Page start -> first byte received for subitem reply (ms)",
HISTOGRAM_TIME_DELTA(mDefaultRequestCreationTime, timeStamp));
}
TelemetryReportChannel(timedChannel, false);
}
}
if (mRequests.entryCount == 0) {
TelemetryReport();
}
// Undo any group priority delta...
if (mPriority != 0)
RescheduleRequest(request, -mPriority);
@ -802,6 +864,170 @@ nsLoadGroup::AdjustPriority(PRInt32 aDelta)
////////////////////////////////////////////////////////////////////////////////
void
nsLoadGroup::TelemetryReport()
{
if (mDefaultLoadIsTimed) {
UMA_HISTOGRAM_COUNTS("HTTP: Requests per page (count)",
mTimedRequests);
if (mTimedRequests) {
UMA_HISTOGRAM_ENUMERATION(
"HTTP: Requests serviced from cache (%)",
mCachedRequests * 100 / mTimedRequests,
101);
}
nsCOMPtr<nsITimedChannel> timedChannel =
do_QueryInterface(mDefaultLoadRequest);
if (timedChannel)
TelemetryReportChannel(timedChannel, true);
}
mTimedRequests = 0;
mCachedRequests = 0;
mDefaultLoadIsTimed = false;
}
void
nsLoadGroup::TelemetryReportChannel(nsITimedChannel *aTimedChannel,
bool aDefaultRequest)
{
nsresult rv;
PRBool timingEnabled;
rv = aTimedChannel->GetTimingEnabled(&timingEnabled);
if (NS_FAILED(rv) || !timingEnabled)
return;
mozilla::TimeStamp channelCreation;
rv = aTimedChannel->GetChannelCreation(&channelCreation);
if (NS_FAILED(rv))
return;
mozilla::TimeStamp asyncOpen;
rv = aTimedChannel->GetAsyncOpen(&asyncOpen);
if (NS_FAILED(rv))
return;
mozilla::TimeStamp cacheReadStart;
rv = aTimedChannel->GetCacheReadStart(&cacheReadStart);
if (NS_FAILED(rv))
return;
mozilla::TimeStamp cacheReadEnd;
rv = aTimedChannel->GetCacheReadEnd(&cacheReadEnd);
if (NS_FAILED(rv))
return;
mozilla::TimeStamp domainLookupStart;
rv = aTimedChannel->GetDomainLookupStart(&domainLookupStart);
if (NS_FAILED(rv))
return;
mozilla::TimeStamp domainLookupEnd;
rv = aTimedChannel->GetDomainLookupEnd(&domainLookupEnd);
if (NS_FAILED(rv))
return;
mozilla::TimeStamp connectStart;
rv = aTimedChannel->GetConnectStart(&connectStart);
if (NS_FAILED(rv))
return;
mozilla::TimeStamp connectEnd;
rv = aTimedChannel->GetConnectEnd(&connectEnd);
if (NS_FAILED(rv))
return;
mozilla::TimeStamp requestStart;
rv = aTimedChannel->GetRequestStart(&requestStart);
if (NS_FAILED(rv))
return;
mozilla::TimeStamp responseStart;
rv = aTimedChannel->GetResponseStart(&responseStart);
if (NS_FAILED(rv))
return;
mozilla::TimeStamp responseEnd;
rv = aTimedChannel->GetResponseEnd(&responseEnd);
if (NS_FAILED(rv))
return;
#define _UMA_HTTP_REQUEST_HISTOGRAMS_(prefix) \
if (!domainLookupStart.IsNull()) { \
UMA_HISTOGRAM_TIMES( \
prefix "open() -> DNS request issued (ms)", \
HISTOGRAM_TIME_DELTA(asyncOpen, domainLookupStart)); \
\
UMA_HISTOGRAM_TIMES( \
prefix "DNS lookup time (ms)", \
HISTOGRAM_TIME_DELTA(domainLookupStart, domainLookupEnd)); \
} \
\
if (!connectStart.IsNull()) { \
UMA_HISTOGRAM_TIMES( \
prefix "TCP connection setup (ms)", \
HISTOGRAM_TIME_DELTA(connectStart, connectEnd)); \
} \
\
\
if (!requestStart.IsNull()) { \
UMA_HISTOGRAM_TIMES( \
prefix "Open -> first byte of request sent (ms)", \
HISTOGRAM_TIME_DELTA(asyncOpen, requestStart)); \
\
UMA_HISTOGRAM_TIMES( \
prefix "First byte of request sent -> " \
"last byte of response received (ms)", \
HISTOGRAM_TIME_DELTA(requestStart, responseEnd)); \
\
if (cacheReadStart.IsNull()) { \
UMA_HISTOGRAM_TIMES( \
prefix "Open -> first byte of reply received (ms)", \
HISTOGRAM_TIME_DELTA(asyncOpen, responseStart)); \
} \
} \
\
if (!cacheReadStart.IsNull()) { \
UMA_HISTOGRAM_TIMES( \
prefix "Open -> cache read start (ms)", \
HISTOGRAM_TIME_DELTA(asyncOpen, cacheReadStart)); \
\
UMA_HISTOGRAM_TIMES( \
prefix "Cache read time (ms)", \
HISTOGRAM_TIME_DELTA(cacheReadStart, cacheReadEnd)); \
\
if (!requestStart.IsNull()) { \
UMA_HISTOGRAM_TIMES( \
prefix "Positive cache validation time (ms)", \
HISTOGRAM_TIME_DELTA(requestStart, responseEnd)); \
} \
} \
if (!cacheReadEnd.IsNull()) { \
UMA_HISTOGRAM_TIMES( \
prefix "Overall load time - all (ms)", \
HISTOGRAM_TIME_DELTA(asyncOpen, cacheReadEnd)); \
UMA_HISTOGRAM_TIMES( \
prefix "Overall load time - cache hits (ms)", \
HISTOGRAM_TIME_DELTA(asyncOpen, cacheReadEnd)); \
} \
else if (!responseEnd.IsNull()) { \
UMA_HISTOGRAM_TIMES( \
prefix "Overall load time - all (ms)", \
HISTOGRAM_TIME_DELTA(asyncOpen, responseEnd)); \
UMA_HISTOGRAM_TIMES( \
prefix "Overall load time: network (ms)", \
HISTOGRAM_TIME_DELTA(asyncOpen, responseEnd)); \
}
if (aDefaultRequest) {
_UMA_HTTP_REQUEST_HISTOGRAMS_("HTTP page: ")
} else {
_UMA_HTTP_REQUEST_HISTOGRAMS_("HTTP subitem: ")
}
#undef _UMA_HTTP_REQUEST_HISTOGRAMS_
}
nsresult nsLoadGroup::MergeLoadFlags(nsIRequest *aRequest, nsLoadFlags& outFlags)
{
nsresult rv;

View File

@ -48,7 +48,9 @@
#include "nsIInterfaceRequestor.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsISupportsPriority.h"
#include "nsITimedChannel.h"
#include "pldhash.h"
#include "mozilla/TimeStamp.h"
class nsISupportsArray;
@ -83,6 +85,11 @@ protected:
nsresult MergeLoadFlags(nsIRequest *aRequest, nsLoadFlags& flags);
private:
void TelemetryReport();
void TelemetryReportChannel(nsITimedChannel *timedChannel,
bool defaultRequest);
protected:
PRUint32 mForegroundCount;
PRUint32 mLoadFlags;
@ -98,6 +105,13 @@ protected:
nsresult mStatus;
PRInt32 mPriority;
PRBool mIsCanceling;
/* Telemetry */
mozilla::TimeStamp mPageLoadStartTime;
mozilla::TimeStamp mDefaultRequestCreationTime;
bool mDefaultLoadIsTimed;
PRUint32 mTimedRequests;
PRUint32 mCachedRequests;
};
#endif // nsLoadGroup_h__

View File

@ -419,14 +419,8 @@ HistoryTracker.prototype = {
}
},
_GUIDForUri: function _GUIDForUri(uri, create) {
// Isn't indirection fun...
return Engines.get("history")._store.GUIDForUri(uri, create);
},
QueryInterface: XPCOMUtils.generateQI([
Ci.nsINavHistoryObserver,
Ci.nsINavHistoryObserver_MOZILLA_1_9_1_ADDITIONS,
Ci.nsISupportsWeakReference
]),
@ -442,31 +436,25 @@ HistoryTracker.prototype = {
this.score += 1;
},
onVisit: function HT_onVisit(uri, vid, time, session, referrer, trans) {
onVisit: function HT_onVisit(uri, vid, time, session, referrer, trans, guid) {
if (this.ignoreAll)
return;
this._log.trace("onVisit: " + uri.spec);
let self = this;
Utils.delay(function() {
if (self.addChangedID(self._GUIDForUri(uri, true))) {
self._upScore();
}
}, 0);
},
onDeleteVisits: function onDeleteVisits() {
},
onPageExpired: function HT_onPageExpired(uri, time, entry) {
},
onBeforeDeleteURI: function onBeforeDeleteURI(uri) {
if (this.ignoreAll)
return;
this._log.trace("onBeforeDeleteURI: " + uri.spec);
let self = this;
if (this.addChangedID(this._GUIDForUri(uri, true))) {
if (this.addChangedID(guid)) {
this._upScore();
}
},
onDeleteURI: function HT_onDeleteURI(uri) {
onDeleteVisits: function onDeleteVisits() {
},
onBeforeDeleteURI: function onBeforeDeleteURI(uri, guid) {
if (this.ignoreAll)
return;
this._log.trace("onBeforeDeleteURI: " + uri.spec);
if (this.addChangedID(guid)) {
this._upScore();
}
},
onDeleteURI: function HT_onDeleteURI(uri, guid) {
},
onClearHistory: function HT_onClearHistory() {
this._log.trace("onClearHistory");

View File

@ -1851,7 +1851,8 @@ nsDownloadManager::OnEndUpdateBatch()
NS_IMETHODIMP
nsDownloadManager::OnVisit(nsIURI *aURI, PRInt64 aVisitID, PRTime aTime,
PRInt64 aSessionID, PRInt64 aReferringID,
PRUint32 aTransitionType, PRUint32 *aAdded)
PRUint32 aTransitionType, const nsACString& aGUID,
PRUint32 *aAdded)
{
return NS_OK;
}
@ -1863,13 +1864,13 @@ nsDownloadManager::OnTitleChanged(nsIURI *aURI, const nsAString &aPageTitle)
}
NS_IMETHODIMP
nsDownloadManager::OnBeforeDeleteURI(nsIURI *aURI)
nsDownloadManager::OnBeforeDeleteURI(nsIURI *aURI, const nsACString& aGUID)
{
return NS_OK;
}
NS_IMETHODIMP
nsDownloadManager::OnDeleteURI(nsIURI *aURI)
nsDownloadManager::OnDeleteURI(nsIURI *aURI, const nsACString& aGUID)
{
return RemoveDownloadsForURI(aURI);
}
@ -1888,7 +1889,8 @@ nsDownloadManager::OnPageChanged(nsIURI *aURI, PRUint32 aWhat,
}
NS_IMETHODIMP
nsDownloadManager::OnDeleteVisits(nsIURI *aURI, PRTime aVisitTime)
nsDownloadManager::OnDeleteVisits(nsIURI *aURI, PRTime aVisitTime,
const nsACString& aGUID)
{
// Don't bother removing downloads until the page is removed.
return NS_OK;

View File

@ -556,19 +556,9 @@ extApplication.prototype = {
this._registered = {"unload": true};
},
// for nsIClassInfo
flags : Ci.nsIClassInfo.SINGLETON,
implementationLanguage : Ci.nsIProgrammingLanguage.JAVASCRIPT,
getInterfaces : function app_gi(aCount) {
var interfaces = [Ci.extIApplication, Ci.nsIObserver, Ci.nsIClassInfo];
aCount.value = interfaces.length;
return interfaces;
},
getHelperForLanguage : function app_ghfl(aCount) {
return null;
},
classInfo: XPCOMUtils.generateCI({interfaces: [Ci.extIApplication,
Ci.nsIObserver],
flags: Ci.nsIClassInfo.SINGLETON}),
// extIApplication
get id() {

View File

@ -36,9 +36,6 @@
*
* ***** END LICENSE BLOCK ***** */
const Cc = Components.classes;
const Ci = Components.interfaces;
function test() {
waitForExplicitFinish();

View File

@ -35,9 +35,6 @@
*
* ***** END LICENSE BLOCK ***** */
const Cc = Components.classes;
const Ci = Components.interfaces;
function test() {
waitForExplicitFinish();

View File

@ -35,9 +35,6 @@
*
* ***** END LICENSE BLOCK ***** */
const Cc = Components.classes;
const Ci = Components.interfaces;
function test() {
waitForExplicitFinish();

View File

@ -464,7 +464,7 @@ public:
mPlace.transitionType != nsINavHistoryService::TRANSITION_FRAMED_LINK) {
navHistory->NotifyOnVisit(uri, mPlace.visitId, mPlace.visitTime,
mPlace.sessionId, mReferrer.visitId,
mPlace.transitionType);
mPlace.transitionType, mPlace.guid);
}
nsCOMPtr<nsIObserverService> obsService =
@ -801,8 +801,9 @@ private:
NS_ENSURE_SUCCESS(rv, rv);
// We need the place id and guid of the page we just inserted when we
// have a callback. No point in doing the disk I/O if we do not need it.
if (mCallback) {
// have a callback or when the GUID isn't known. No point in doing the
// disk I/O if we do not need it.
if (mCallback || aPlace.guid.IsEmpty()) {
bool exists = mHistory->FetchPageInfo(aPlace);
if (!exists) {
NS_NOTREACHED("should have an entry in moz_places");

View File

@ -25,6 +25,7 @@
* Marco Bonardo <mak77@bonardo.net>
* Asaf Romano <mano@mozilla.com>
* Drew Willcoxon <adw@mozilla.com>
* Philipp von Weitershausen <philipp@weitershausen.de>
*
* 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
@ -808,7 +809,7 @@ interface nsINavHistoryResult : nsISupports
* DANGER! If you are in the middle of a batch transaction, there may be a
* database transaction active. You can still access the DB, but be careful.
*/
[scriptable, uuid(0a5ce210-c803-11de-8a39-0800200c9a66)]
[scriptable, uuid(06602bb6-0774-4576-8855-ea930bb85bbe)]
interface nsINavHistoryObserver : nsISupports
{
/**
@ -837,14 +838,20 @@ interface nsINavHistoryObserver : nsISupports
* @param aSessionID The ID of one connected sequence of visits.
* @param aReferringID The ID of the visit the user came from. 0 if empty.
* @param aTransitionType One of nsINavHistory.TRANSITION_*
* @param aGUID The unique ID associated with the page.
* @param aAdded Incremented by query nodes when the visited uri
* belongs to them. If no such query exists, the
* history result creates a new query node dynamically.
* It is used in places views only and can be ignored.
*/
void onVisit(in nsIURI aURI, in long long aVisitID, in PRTime aTime,
in long long aSessionID, in long long aReferringID,
in unsigned long aTransitionType, out unsigned long aAdded);
void onVisit(in nsIURI aURI,
in long long aVisitID,
in PRTime aTime,
in long long aSessionID,
in long long aReferringID,
in unsigned long aTransitionType,
in ACString aGUID,
out unsigned long aAdded);
/**
* Called whenever either the "real" title or the custom title of the page
@ -859,8 +866,13 @@ interface nsINavHistoryObserver : nsISupports
* to see whether an empty string is "null" or not (it will always be an
* empty string in either case).
*
* @param aURI
* The URI of the page.
* @param aPageTitle
* The new title of the page.
*/
void onTitleChanged(in nsIURI aURI, in AString aPageTitle);
void onTitleChanged(in nsIURI aURI,
in AString aPageTitle);
/**
* This page and all of its visits are about to be deleted. Note: the page
@ -868,8 +880,11 @@ interface nsINavHistoryObserver : nsISupports
*
* @param aURI
* The URI being deleted.
* @param aGUID
* The unique ID associated with the page.
*/
void onBeforeDeleteURI(in nsIURI aURI);
void onBeforeDeleteURI(in nsIURI aURI,
in ACString aGUID);
/**
* This page and all of its visits are being deleted. Note: the page may not
@ -880,8 +895,14 @@ interface nsINavHistoryObserver : nsISupports
* delete. If there is some error in the middle (for example, out of memory)
* then you'll get a notification and it won't get deleted. There's no easy
* way around this.
*
* @param aURI
* The URI that was deleted.
* @param aGUID
* The unique ID associated with the page.
*/
void onDeleteURI(in nsIURI aURI);
void onDeleteURI(in nsIURI aURI,
in ACString aGUID);
/**
* Notification that all of history is being deleted.
@ -891,9 +912,18 @@ interface nsINavHistoryObserver : nsISupports
/**
* A page has had some attribute on it changed. Note that for TYPED and
* HIDDEN, the page may not necessarily have been added yet.
*
* @param aURI
* The URI of the page on which an attribute changed.
* @param aWhat
* The attribute whose value changed.
* @param aValue
* The attribute's new value.
*/
const unsigned long ATTRIBUTE_FAVICON = 3; // favicon updated, aString = favicon annotation URI
void onPageChanged(in nsIURI aURI, in unsigned long aWhat, in AString aValue);
void onPageChanged(in nsIURI aURI,
in unsigned long aWhat,
in AString aValue);
/**
* Called when some visits of an history entry are expired.
@ -903,13 +933,17 @@ interface nsINavHistoryObserver : nsISupports
* @param aVisitTime
* The largest visit time in microseconds that has been expired. We
* guarantee that we don't have any visit older than this date.
* @param aGUID
* The unique ID associated with the page.
*
* @note: when all visits for a page are expired and also the full page entry
* is expired, you will only get an onDeleteURI notification. If a
* page entry is removed, then you can be sure that we don't have
* anymore visits for it.
*/
void onDeleteVisits(in nsIURI aURI, in PRTime aVisitTime);
void onDeleteVisits(in nsIURI aURI,
in PRTime aVisitTime,
in ACString aGUID);
};

View File

@ -3045,7 +3045,8 @@ nsNavBookmarks::OnEndUpdateBatch()
NS_IMETHODIMP
nsNavBookmarks::OnVisit(nsIURI* aURI, PRInt64 aVisitId, PRTime aTime,
PRInt64 aSessionID, PRInt64 aReferringID,
PRUint32 aTransitionType, PRUint32* aAdded)
PRUint32 aTransitionType, const nsACString& aGUID,
PRUint32* aAdded)
{
// If the page is bookmarked, notify observers for each associated bookmark.
ItemVisitData visitData;
@ -3063,14 +3064,14 @@ nsNavBookmarks::OnVisit(nsIURI* aURI, PRInt64 aVisitId, PRTime aTime,
NS_IMETHODIMP
nsNavBookmarks::OnBeforeDeleteURI(nsIURI* aURI)
nsNavBookmarks::OnBeforeDeleteURI(nsIURI* aURI, const nsACString& aGUID)
{
return NS_OK;
}
NS_IMETHODIMP
nsNavBookmarks::OnDeleteURI(nsIURI* aURI)
nsNavBookmarks::OnDeleteURI(nsIURI* aURI, const nsACString& aGUID)
{
#ifdef DEBUG
nsNavHistory* history = nsNavHistory::GetHistoryService();
@ -3148,7 +3149,8 @@ nsNavBookmarks::OnPageChanged(nsIURI* aURI, PRUint32 aWhat,
NS_IMETHODIMP
nsNavBookmarks::OnDeleteVisits(nsIURI* aURI, PRTime aVisitTime)
nsNavBookmarks::OnDeleteVisits(nsIURI* aURI, PRTime aVisitTime,
const nsACString& aGUID)
{
// Notify "cleartime" only if all visits to the page have been removed.
if (!aVisitTime) {

View File

@ -28,6 +28,7 @@
* Michael Ventnor <m.ventnor@gmail.com>
* Ehsan Akhgari <ehsan.akhgari@gmail.com>
* Drew Willcoxon <adw@mozilla.com>
* Philipp von Weitershausen <philipp@weitershausen.de>
*
* 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
@ -1193,8 +1194,10 @@ nsNavHistory::GetStatement(const nsCOMPtr<mozIStorageStatement>& aStmt)
if (!mCanNotify)
return nsnull;
// Note that this query violates the kGetInfoIndex_* convention in
// the last column.
RETURN_IF_STMT(mDBGetURLPageInfo, NS_LITERAL_CSTRING(
"SELECT id, url, title, rev_host, visit_count "
"SELECT id, url, title, rev_host, visit_count, guid "
"FROM moz_places "
"WHERE url = :page_url "
));
@ -1226,7 +1229,7 @@ nsNavHistory::GetStatement(const nsCOMPtr<mozIStorageStatement>& aStmt)
));
RETURN_IF_STMT(mDBGetPageVisitStats, NS_LITERAL_CSTRING(
"SELECT id, visit_count, typed, hidden "
"SELECT id, visit_count, typed, hidden, guid "
"FROM moz_places "
"WHERE url = :page_url "
));
@ -1722,7 +1725,8 @@ nsNavHistory::GetUrlIdFor(nsIURI* aURI, PRInt64* aEntryID,
// create a new hidden, untyped, unvisited entry
nsAutoString voidString;
voidString.SetIsVoid(PR_TRUE);
return InternalAddNewPage(aURI, voidString, PR_TRUE, PR_FALSE, 0, PR_TRUE, aEntryID);
nsCAutoString guid;
return InternalAddNewPage(aURI, voidString, PR_TRUE, PR_FALSE, 0, PR_TRUE, aEntryID, guid);
}
// Doesn't exist: don't do anything, entry ID was already set to 0 above
@ -1748,7 +1752,8 @@ nsNavHistory::InternalAddNewPage(nsIURI* aURI,
PRBool aTyped,
PRInt32 aVisitCount,
PRBool aCalculateFrecency,
PRInt64* aPageID)
PRInt64* aPageID,
nsACString& guid)
{
DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBAddNewPage);
nsresult rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), aURI);
@ -1800,6 +1805,8 @@ nsNavHistory::InternalAddNewPage(nsIURI* aURI,
NS_ENSURE_SUCCESS(rv, rv);
NS_ASSERTION(hasResult, "hasResult is false but the call succeeded?");
pageId = getIdStmt->AsInt64(0);
rv = getIdStmt->GetUTF8String(5, guid);
NS_ENSURE_SUCCESS(rv, rv);
}
if (aCalculateFrecency) {
@ -2024,13 +2031,15 @@ nsNavHistory::NotifyOnVisit(nsIURI* aURI,
PRTime aTime,
PRInt64 aSessionID,
PRInt64 referringVisitID,
PRInt32 aTransitionType)
PRInt32 aTransitionType,
const nsACString& aGUID)
{
PRUint32 added = 0;
MOZ_ASSERT(!aGUID.IsEmpty());
NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
nsINavHistoryObserver,
OnVisit(aURI, aVisitID, aTime, aSessionID,
referringVisitID, aTransitionType, &added));
referringVisitID, aTransitionType, aGUID, &added));
}
void
@ -2606,6 +2615,7 @@ nsNavHistory::AddVisit(nsIURI* aURI, PRTime aTime, nsIURI* aReferringURI,
rv = stmt->ExecuteStep(&alreadyVisited);
NS_ENSURE_SUCCESS(rv, rv);
nsCAutoString guid;
PRInt64 pageID = 0;
PRInt32 hidden;
PRInt32 typed;
@ -2627,6 +2637,9 @@ nsNavHistory::AddVisit(nsIURI* aURI, PRTime aTime, nsIURI* aReferringURI,
rv = stmt->GetInt32(3, &oldHiddenState);
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->GetUTF8String(4, guid);
NS_ENSURE_SUCCESS(rv, rv);
// free the previous statement before we make a new one
stmt->Reset();
scoper.Abandon();
@ -2681,7 +2694,7 @@ nsNavHistory::AddVisit(nsIURI* aURI, PRTime aTime, nsIURI* aReferringURI,
nsString voidString;
voidString.SetIsVoid(PR_TRUE);
rv = InternalAddNewPage(aURI, voidString, hidden == 1, typed == 1, 1,
PR_TRUE, &pageID);
PR_TRUE, &pageID, guid);
NS_ENSURE_SUCCESS(rv, rv);
}
@ -2716,7 +2729,7 @@ nsNavHistory::AddVisit(nsIURI* aURI, PRTime aTime, nsIURI* aReferringURI,
// FIXME bug 325241: make a way to observe hidden URLs
if (!hidden) {
NotifyOnVisit(aURI, *aVisitID, aTime, aSessionID, referringVisitID,
aTransitionType);
aTransitionType, guid);
}
// Normally docshell sends the link visited observer notification for us (this
@ -4169,16 +4182,17 @@ nsNavHistory::CleanupPlacesOnVisitsDelete(const nsCString& aPlaceIdsQueryString)
// Collect about-to-be-deleted URIs to notify onDeleteURI.
nsCOMPtr<mozIStorageStatement> stmt;
mDBConn->CreateStatement(NS_LITERAL_CSTRING(
"SELECT h.id, h.url, (SUBSTR(h.url, 1, 6) <> 'place:' "
"AND NOT EXISTS (SELECT b.id FROM moz_bookmarks b "
"WHERE b.fk = h.id LIMIT 1)"
") as whole_entry "
"SELECT h.id, h.url, h.guid, "
"(SUBSTR(h.url, 1, 6) <> 'place:' "
" AND NOT EXISTS (SELECT b.id FROM moz_bookmarks b "
"WHERE b.fk = h.id LIMIT 1)) as whole_entry "
"FROM moz_places h "
"WHERE h.id IN ( ") + aPlaceIdsQueryString + NS_LITERAL_CSTRING(") "
), getter_AddRefs(stmt));
NS_ENSURE_STATE(stmt);
nsCString filteredPlaceIds;
nsCOMArray<nsIURI> URIs;
nsTArray<nsCString> GUIDs;
PRBool hasMore;
while (NS_SUCCEEDED(stmt->ExecuteStep(&hasMore)) && hasMore) {
PRInt64 placeId;
@ -4186,8 +4200,10 @@ nsNavHistory::CleanupPlacesOnVisitsDelete(const nsCString& aPlaceIdsQueryString)
NS_ENSURE_SUCCESS(rv, rv);
nsCAutoString URLString;
rv = stmt->GetUTF8String(1, URLString);
nsCString guid;
rv = stmt->GetUTF8String(2, guid);
PRInt32 wholeEntry;
rv = stmt->GetInt32(2, &wholeEntry);
rv = stmt->GetInt32(3, &wholeEntry);
nsCOMPtr<nsIURI> uri;
rv = NS_NewURI(getter_AddRefs(uri), URLString);
NS_ENSURE_SUCCESS(rv, rv);
@ -4197,15 +4213,16 @@ nsNavHistory::CleanupPlacesOnVisitsDelete(const nsCString& aPlaceIdsQueryString)
}
filteredPlaceIds.AppendInt(placeId);
URIs.AppendObject(uri);
GUIDs.AppendElement(guid);
// Notify we are about to remove this uri.
NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
nsINavHistoryObserver, OnBeforeDeleteURI(uri));
nsINavHistoryObserver, OnBeforeDeleteURI(uri, guid));
}
else {
// Notify that we will delete all visits for this page, but not the page
// itself, since it's bookmarked or a place: query.
NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
nsINavHistoryObserver, OnDeleteVisits(uri, 0));
nsINavHistoryObserver, OnDeleteVisits(uri, 0, guid));
}
}
@ -4228,7 +4245,7 @@ nsNavHistory::CleanupPlacesOnVisitsDelete(const nsCString& aPlaceIdsQueryString)
// Finally notify about the removed URIs.
for (PRInt32 i = 0; i < URIs.Count(); ++i) {
NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
nsINavHistoryObserver, OnDeleteURI(URIs[i]));
nsINavHistoryObserver, OnDeleteURI(URIs[i], GUIDs[i]));
}
return NS_OK;
@ -5351,20 +5368,21 @@ nsNavHistory::AsyncExecuteLegacyQueries(nsINavHistoryQuery** aQueries,
NS_IMETHODIMP
nsNavHistory::NotifyOnPageExpired(nsIURI *aURI, PRTime aVisitTime,
PRBool aWholeEntry)
PRBool aWholeEntry, const nsACString& aGUID)
{
// Invalidate the cached value for whether there's history or not.
mHasHistoryEntries = -1;
MOZ_ASSERT(!aGUID.IsEmpty());
if (aWholeEntry) {
// Notify our observers that the page has been removed.
NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
nsINavHistoryObserver, OnDeleteURI(aURI));
nsINavHistoryObserver, OnDeleteURI(aURI, aGUID));
}
else {
// Notify our observers that some visits for the page have been removed.
NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
nsINavHistoryObserver, OnDeleteVisits(aURI, aVisitTime));
nsINavHistoryObserver, OnDeleteVisits(aURI, aVisitTime, aGUID));
}
return NS_OK;
@ -6840,6 +6858,7 @@ nsNavHistory::AddPageWithVisits(nsIURI *aURI,
PRInt32 typed = 0;
PRInt32 hidden = 0;
nsCAutoString guid;
if (alreadyVisited) {
// Update the existing entry
rv = stmt->GetInt64(0, &placeId);
@ -6849,6 +6868,8 @@ nsNavHistory::AddPageWithVisits(nsIURI *aURI,
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->GetInt32(3, &hidden);
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->GetUTF8String(4, guid);
NS_ENSURE_SUCCESS(rv, rv);
if (typed == 0 && aTransitionType == TRANSITION_TYPED) {
typed = 1;
@ -6868,7 +6889,7 @@ nsNavHistory::AddPageWithVisits(nsIURI *aURI,
// Insert the new place entry
rv = InternalAddNewPage(aURI, aTitle, hidden == 1,
aTransitionType == TRANSITION_TYPED, 0,
PR_FALSE, &placeId);
PR_FALSE, &placeId, guid);
NS_ENSURE_SUCCESS(rv, rv);
}

View File

@ -595,12 +595,14 @@ public:
PRTime aTime,
PRInt64 aSessionID,
PRInt64 referringVisitID,
PRInt32 aTransitionType);
PRInt32 aTransitionType,
const nsACString& aGUID);
/**
* Fires onTitleChanged event to nsINavHistoryService observers
*/
void NotifyTitleChange(nsIURI* aURI, const nsString& title);
void NotifyTitleChange(nsIURI* aURI,
const nsString& title);
bool isBatching() {
return mBatchLevel > 0;
@ -732,7 +734,7 @@ protected:
nsresult InternalAddNewPage(nsIURI* aURI, const nsAString& aTitle,
PRBool aHidden, PRBool aTyped,
PRInt32 aVisitCount, PRBool aCalculateFrecency,
PRInt64* aPageID);
PRInt64* aPageID, nsACString& guid);
nsresult InternalAddVisit(PRInt64 aPageID, PRInt64 aReferringVisit,
PRInt64 aSessionID, PRTime aTime,
PRInt32 aTransitionType, PRInt64* aVisitID);

View File

@ -2879,6 +2879,7 @@ nsNavHistoryQueryResultNode::OnVisit(nsIURI* aURI, PRInt64 aVisitId,
PRTime aTime, PRInt64 aSessionId,
PRInt64 aReferringId,
PRUint32 aTransitionType,
const nsACString& aGUID,
PRUint32* aAdded)
{
nsNavHistory* history = nsNavHistory::GetHistoryService();
@ -3061,7 +3062,8 @@ nsNavHistoryQueryResultNode::OnTitleChanged(nsIURI* aURI,
NS_IMETHODIMP
nsNavHistoryQueryResultNode::OnBeforeDeleteURI(nsIURI *aURI)
nsNavHistoryQueryResultNode::OnBeforeDeleteURI(nsIURI *aURI,
const nsACString& aGUID)
{
return NS_OK;
}
@ -3071,7 +3073,8 @@ nsNavHistoryQueryResultNode::OnBeforeDeleteURI(nsIURI *aURI)
* the given URI.
*/
NS_IMETHODIMP
nsNavHistoryQueryResultNode::OnDeleteURI(nsIURI *aURI)
nsNavHistoryQueryResultNode::OnDeleteURI(nsIURI *aURI,
const nsACString& aGUID)
{
if (IsContainersQuery()) {
// Incremental updates of query returning queries are pretty much
@ -3165,7 +3168,8 @@ nsNavHistoryQueryResultNode::OnPageChanged(nsIURI *aURI, PRUint32 aWhat,
NS_IMETHODIMP
nsNavHistoryQueryResultNode::OnDeleteVisits(nsIURI* aURI, PRTime aVisitTime)
nsNavHistoryQueryResultNode::OnDeleteVisits(nsIURI* aURI, PRTime aVisitTime,
const nsACString& aGUID)
{
NS_PRECONDITION(mOptions->QueryType() == nsINavHistoryQueryOptions::QUERY_TYPE_HISTORY,
"Bookmarks queries should not get a OnDeleteVisits notification");
@ -3173,7 +3177,7 @@ nsNavHistoryQueryResultNode::OnDeleteVisits(nsIURI* aURI, PRTime aVisitTime)
// All visits for this uri have been removed, but the uri won't be removed
// from the databse, most likely because it's a bookmark. For a history
// query this is equivalent to a onDeleteURI notification.
nsresult rv = OnDeleteURI(aURI);
nsresult rv = OnDeleteURI(aURI, aGUID);
NS_ENSURE_SUCCESS(rv, rv);
}
@ -5064,12 +5068,14 @@ nsNavHistoryResult::OnItemMoved(PRInt64 aItemId,
NS_IMETHODIMP
nsNavHistoryResult::OnVisit(nsIURI* aURI, PRInt64 aVisitId, PRTime aTime,
PRInt64 aSessionId, PRInt64 aReferringId,
PRUint32 aTransitionType, PRUint32* aAdded)
PRUint32 aTransitionType, const nsACString& aGUID,
PRUint32* aAdded)
{
PRUint32 added = 0;
ENUMERATE_HISTORY_OBSERVERS(OnVisit(aURI, aVisitId, aTime, aSessionId,
aReferringId, aTransitionType, &added));
aReferringId, aTransitionType, aGUID,
&added));
if (!mRootNode->mExpanded)
return NS_OK;
@ -5130,16 +5136,16 @@ nsNavHistoryResult::OnTitleChanged(nsIURI* aURI, const nsAString& aPageTitle)
NS_IMETHODIMP
nsNavHistoryResult::OnBeforeDeleteURI(nsIURI *aURI)
nsNavHistoryResult::OnBeforeDeleteURI(nsIURI *aURI, const nsACString& aGUID)
{
return NS_OK;
}
NS_IMETHODIMP
nsNavHistoryResult::OnDeleteURI(nsIURI *aURI)
nsNavHistoryResult::OnDeleteURI(nsIURI *aURI, const nsACString& aGUID)
{
ENUMERATE_HISTORY_OBSERVERS(OnDeleteURI(aURI));
ENUMERATE_HISTORY_OBSERVERS(OnDeleteURI(aURI, aGUID));
return NS_OK;
}
@ -5165,8 +5171,9 @@ nsNavHistoryResult::OnPageChanged(nsIURI *aURI,
* Don't do anything when visits expire.
*/
NS_IMETHODIMP
nsNavHistoryResult::OnDeleteVisits(nsIURI* aURI, PRTime aVisitTime)
nsNavHistoryResult::OnDeleteVisits(nsIURI* aURI, PRTime aVisitTime,
const nsACString& aGUID)
{
ENUMERATE_HISTORY_OBSERVERS(OnDeleteVisits(aURI, aVisitTime));
ENUMERATE_HISTORY_OBSERVERS(OnDeleteVisits(aURI, aVisitTime, aGUID));
return NS_OK;
}

View File

@ -98,14 +98,16 @@ private:
NS_DECL_NSINAVBOOKMARKOBSERVER \
NS_IMETHOD OnVisit(nsIURI* aURI, PRInt64 aVisitId, PRTime aTime, \
PRInt64 aSessionId, PRInt64 aReferringId, \
PRUint32 aTransitionType, PRUint32* aAdded); \
PRUint32 aTransitionType, const nsACString& aGUID, \
PRUint32* aAdded); \
NS_IMETHOD OnTitleChanged(nsIURI* aURI, const nsAString& aPageTitle); \
NS_IMETHOD OnBeforeDeleteURI(nsIURI *aURI); \
NS_IMETHOD OnDeleteURI(nsIURI *aURI); \
NS_IMETHOD OnBeforeDeleteURI(nsIURI *aURI, const nsACString& aGUID); \
NS_IMETHOD OnDeleteURI(nsIURI *aURI, const nsACString& aGUID); \
NS_IMETHOD OnClearHistory(); \
NS_IMETHOD OnPageChanged(nsIURI *aURI, PRUint32 aWhat, \
const nsAString &aValue); \
NS_IMETHOD OnDeleteVisits(nsIURI* aURI, PRTime aVisitTime);
NS_IMETHOD OnDeleteVisits(nsIURI* aURI, PRTime aVisitTime, \
const nsACString& aGUID);
// nsNavHistoryResult
//

View File

@ -22,6 +22,7 @@
*
* Contributor(s):
* Shawn Wilsher <me@shawnwilsher.com> (Original Author)
* Philipp von Weitershausen <philipp@weitershausen.de>
*
* 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
@ -48,7 +49,7 @@ interface nsIURI;
*
* @note See also: nsINavHistoryObserver
*/
[scriptable, uuid(b96adaff-e02c-48da-a379-8af5d10e09af)]
[scriptable, uuid(eb2ec8a9-c764-4abe-b076-b122d7aa8a3b)]
interface nsPIPlacesHistoryListenersNotifier : nsISupports
{
/**
@ -61,7 +62,11 @@ interface nsPIPlacesHistoryListenersNotifier : nsISupports
* The time, in microseconds, that the page being expired was visited.
* @param aWholeEntry
* Indicates if this is the last visit for this URI.
* @param aGUID
* The unique ID associated with the page.
*/
void notifyOnPageExpired(in nsIURI aURI, in PRTime aVisitTime,
in boolean aWholeEntry);
void notifyOnPageExpired(in nsIURI aURI,
in PRTime aVisitTime,
in boolean aWholeEntry,
in ACString aGUID);
};

View File

@ -212,8 +212,8 @@ const EXPIRATION_QUERIES = {
// unique URIs limit.
QUERY_FIND_VISITS_TO_EXPIRE: {
sql: "INSERT INTO expiration_notify "
+ "(v_id, url, visit_date, expected_results) "
+ "SELECT v.id, h.url, v.visit_date, :limit_visits "
+ "(v_id, url, guid, visit_date, expected_results) "
+ "SELECT v.id, h.url, h.guid, v.visit_date, :limit_visits "
+ "FROM moz_historyvisits v "
+ "JOIN moz_places h ON h.id = v.place_id "
+ "WHERE (SELECT COUNT(*) FROM moz_places) > :max_uris "
@ -237,8 +237,8 @@ const EXPIRATION_QUERIES = {
// run this query in such a case, but just delete URIs.
QUERY_FIND_URIS_TO_EXPIRE: {
sql: "INSERT INTO expiration_notify "
+ "(p_id, url, visit_date, expected_results) "
+ "SELECT h.id, h.url, h.last_visit_date, :limit_uris "
+ "(p_id, url, guid, visit_date, expected_results) "
+ "SELECT h.id, h.url, h.guid, h.last_visit_date, :limit_uris "
+ "FROM moz_places h "
+ "LEFT JOIN moz_historyvisits v ON h.id = v.place_id "
+ "LEFT JOIN moz_bookmarks b ON h.id = b.fk "
@ -388,7 +388,7 @@ const EXPIRATION_QUERIES = {
// If p_id is set whole_entry = 1, then we have expired the full page.
// Either p_id or v_id are always set.
QUERY_SELECT_NOTIFICATIONS: {
sql: "SELECT url, MAX(visit_date) AS visit_date, "
sql: "SELECT url, guid, MAX(visit_date) AS visit_date, "
+ "MAX(IFNULL(MIN(p_id, 1), MIN(v_id, 0))) AS whole_entry, "
+ "expected_results "
+ "FROM expiration_notify "
@ -449,6 +449,7 @@ function nsPlacesExpiration()
+ ", v_id INTEGER "
+ ", p_id INTEGER "
+ ", url TEXT NOT NULL "
+ ", guid TEXT NOT NULL "
+ ", visit_date INTEGER "
+ ", expected_results INTEGER NOT NULL "
+ ") ");
@ -632,10 +633,11 @@ nsPlacesExpiration.prototype = {
this._expectedResultsCount--;
let uri = Services.io.newURI(row.getResultByName("url"), null, null);
let guid = row.getResultByName("guid");
let visitDate = row.getResultByName("visit_date");
let wholeEntry = row.getResultByName("whole_entry");
// Dispatch expiration notifications to history.
this._hsn.notifyOnPageExpired(uri, visitDate, wholeEntry);
this._hsn.notifyOnPageExpired(uri, visitDate, wholeEntry, guid);
}
},

View File

@ -297,8 +297,8 @@ nsEscapeHTML(const char* string)
default:
*ptr++ = *string;
}
*ptr = '\0';
}
*ptr = '\0';
}
return escaped;
}
@ -750,8 +750,8 @@ BookmarkContentSink::HandleHeadBegin(const nsIParserNode& node)
// processed.
PRInt32 attrCount = node.GetAttributeCount();
frame.mLastContainerType = BookmarkImportFrame::Container_Normal;
if (!mFolderSpecified) {
for (PRInt32 i = 0; i < attrCount; i ++) {
for (PRInt32 i = 0; i < attrCount; ++i) {
if (!mFolderSpecified) {
if (node.GetKeyAt(i).LowerCaseEqualsLiteral(KEY_TOOLBARFOLDER_LOWER)) {
if (mIsImportDefaults)
frame.mLastContainerType = BookmarkImportFrame::Container_Toolbar;
@ -772,14 +772,15 @@ BookmarkContentSink::HandleHeadBegin(const nsIParserNode& node)
frame.mLastContainerType = BookmarkImportFrame::Container_Places;
break;
}
else if (node.GetKeyAt(i).LowerCaseEqualsLiteral(KEY_DATE_ADDED_LOWER)) {
frame.mPreviousDateAdded =
ConvertImportedDateToInternalDate(NS_ConvertUTF16toUTF8(node.GetValueAt(i)));
}
else if (node.GetKeyAt(i).LowerCaseEqualsLiteral(KEY_LAST_MODIFIED_LOWER)) {
frame.mPreviousLastModifiedDate =
ConvertImportedDateToInternalDate(NS_ConvertUTF16toUTF8(node.GetValueAt(i)));
}
}
if (node.GetKeyAt(i).LowerCaseEqualsLiteral(KEY_DATE_ADDED_LOWER)) {
frame.mPreviousDateAdded =
ConvertImportedDateToInternalDate(NS_ConvertUTF16toUTF8(node.GetValueAt(i)));
}
else if (node.GetKeyAt(i).LowerCaseEqualsLiteral(KEY_LAST_MODIFIED_LOWER)) {
frame.mPreviousLastModifiedDate =
ConvertImportedDateToInternalDate(NS_ConvertUTF16toUTF8(node.GetValueAt(i)));
}
}
CurFrame().mPreviousText.Truncate();

View File

@ -609,6 +609,34 @@ function do_check_valid_places_guid(aGuid,
do_check_true(/^[a-zA-Z0-9\-_]{12}$/.test(aGuid), aStack);
}
/**
* Retrieves the guid for a given uri.
*
* @param aURI
* The uri to check.
* @param [optional] aStack
* The stack frame used to report the error.
* @return the associated the guid.
*/
function do_get_guid_for_uri(aURI,
aStack)
{
if (!aStack) {
aStack = Components.stack.caller;
}
let stmt = DBConn().createStatement(
"SELECT guid "
+ "FROM moz_places "
+ "WHERE url = :url "
);
stmt.params.url = aURI.spec;
do_check_true(stmt.executeStep(), aStack);
let guid = stmt.row.guid;
stmt.finalize();
do_check_valid_places_guid(guid, aStack);
return guid;
}
/**
* Tests that a guid was set in moz_places for a given uri.
*
@ -621,19 +649,11 @@ function do_check_guid_for_uri(aURI,
aGUID)
{
let caller = Components.stack.caller;
let stmt = DBConn().createStatement(
"SELECT guid "
+ "FROM moz_places "
+ "WHERE url = :url "
);
stmt.params.url = aURI.spec;
do_check_true(stmt.executeStep(), caller);
do_check_valid_places_guid(stmt.row.guid, caller);
let guid = do_get_guid_for_uri(aURI, caller);
if (aGUID) {
do_check_valid_places_guid(aGUID, caller);
do_check_eq(stmt.row.guid, aGUID, caller);
do_check_eq(guid, aGUID, caller);
}
stmt.finalize();
}
/**

View File

@ -107,9 +107,11 @@ TitleChangedObserver.prototype = {
* being visited.
*/
function VisitObserver(aURI,
aGUID,
aCallback)
{
this.uri = aURI;
this.guid = aGUID;
this.callback = aCallback;
}
VisitObserver.prototype = {
@ -119,12 +121,13 @@ VisitObserver.prototype = {
aTime,
aSessionId,
aReferringId,
aTransitionType)
aTransitionType,
aGUID)
{
do_log_info("onVisit(" + aURI.spec + ", " + aVisitId + ", " + aTime +
", " + aSessionId + ", " + aReferringId + ", " +
aTransitionType + ")");
if (!this.uri.equals(aURI)) {
aTransitionType + ", " + aGUID + ")");
if (!this.uri.equals(aURI) || this.guid != aGUID) {
return;
}
this.callback(aTime, aTransitionType);
@ -1173,6 +1176,7 @@ function test_visit_notifies()
// There are two observers we need to see for each visit. One is an
// nsINavHistoryObserver and the other is the uri-visit-saved observer topic.
let place = {
guid: "abcdefghijkl",
uri: NetUtil.newURI(TEST_DOMAIN + "test_visit_notifies"),
visits: [
new VisitInfo(),
@ -1186,8 +1190,9 @@ function test_visit_notifies()
waitForAsyncUpdates(run_next_test);
}
}
let visitObserver = new VisitObserver(place.uri, function(aVisitDate,
aTransitionType) {
let visitObserver = new VisitObserver(place.uri, place.guid,
function(aVisitDate,
aTransitionType) {
let visit = place.visits[0];
do_check_eq(visit.visitDate, aVisitDate);
do_check_eq(visit.transitionType, aTransitionType);

View File

@ -0,0 +1,91 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Generic nsINavHistoryObserver that doesn't implement anything, but provides
* dummy methods to prevent errors about an object not having a certain method.
*/
function NavHistoryObserver() {
}
NavHistoryObserver.prototype = {
onBeginUpdateBatch: function() { },
onEndUpdateBatch: function() { },
onVisit: function() { },
onTitleChanged: function() { },
onBeforeDeleteURI: function() { },
onDeleteURI: function() { },
onClearHistory: function() { },
onPageChanged: function() { },
onDeleteVisits: function() { },
QueryInterface: XPCOMUtils.generateQI([Ci.nsINavHistoryObserver])
};
/**
* Registers a one-time history observer for and calls the callback
* when the specified nsINavHistoryObserver method is called.
*/
function onNotify(callback) {
let obs = new NavHistoryObserver();
obs[callback.name] = function () {
PlacesUtils.history.removeObserver(this);
callback.apply(this, arguments);
};
PlacesUtils.history.addObserver(obs, false);
}
/**
* Adds a TRANSITION_TYPED visit to the history database.
*/
function add_visit(uri, timestamp) {
uri = uri || NetUtil.newURI("http://firefox.com/");
timestamp = timestamp || Date.now() * 1000;
PlacesUtils.history.addVisit(
uri, timestamp, null, Ci.nsINavHistoryService.TRANSITION_TYPED, false, 0);
return [uri, timestamp];
}
function run_test() {
run_next_test();
}
add_test(function test_onVisit() {
onNotify(function onVisit(aURI, aVisitID, aTime, aSessionID, aReferringID,
aTransitionType, aGUID) {
do_check_true(aURI.equals(testuri));
do_check_true(aVisitID > 0);
do_check_eq(aTime, testtime);
do_check_eq(aSessionID, 0);
do_check_eq(aReferringID, 0);
do_check_eq(aTransitionType, Ci.nsINavHistoryService.TRANSITION_TYPED);
do_check_guid_for_uri(aURI, aGUID);
run_next_test();
});
let testuri = NetUtil.newURI("http://firefox.com/");
let testtime = Date.now() * 1000;
add_visit(testuri, testtime);
});
add_test(function test_onBeforeDeleteURI() {
onNotify(function onBeforeDeleteURI(aURI, aGUID) {
do_check_true(aURI.equals(testuri));
do_check_guid_for_uri(aURI, aGUID);
run_next_test();
});
let [testuri] = add_visit();
PlacesUtils.bhistory.removePage(testuri);
});
add_test(function test_onDeleteURI() {
onNotify(function onDeleteURI(aURI, aGUID) {
do_check_true(aURI.equals(testuri));
// Can't use do_check_guid_for_uri() here because the visit is already gone.
do_check_eq(aGUID, testguid);
run_next_test();
});
let [testuri] = add_visit();
let testguid = do_get_guid_for_uri(testuri);
PlacesUtils.bhistory.removePage(testuri);
});

View File

@ -68,14 +68,17 @@ Observer.prototype =
onTitleChanged: function(aURI, aPageTable)
{
},
onBeforeDeleteURI: function(aURI)
onBeforeDeleteURI: function(aURI, aGUID)
{
this.removedURI = aURI;
this.removedGUID = aGUID;
do_check_guid_for_uri(aURI, aGUID);
},
onDeleteURI: function(aURI)
onDeleteURI: function(aURI, aGUID)
{
do_check_false(this.checked);
do_check_true(this.removedURI.equals(aURI));
do_check_eq(this.removedGUID, aGUID);
this.checked = true;
},
onPageChanged: function(aURI, aWhat, aValue)

View File

@ -64,6 +64,7 @@ tail =
[test_history_catobs.js]
[test_history_import.js]
[test_history_notifications.js]
[test_history_observer.js]
[test_history_removeAllPages.js]
[test_history_sidebar.js]
[test_isvisited.js]

View File

@ -35,9 +35,6 @@
*
* ***** END LICENSE BLOCK ***** */
const Cc = Components.classes;
const Ci = Components.interfaces;
const PROMPT_URL = "chrome://global/content/commonDialog.xul";
const TEST_URL = "http://example.com/browser/toolkit/components/startup/tests/browser/beforeunload.html";

View File

@ -35,9 +35,6 @@
*
* ***** END LICENSE BLOCK ***** */
const Cc = Components.classes;
const Ci = Components.interfaces;
const PROMPT_URL = "chrome://global/content/commonDialog.xul";
const TEST_URL = "http://example.com/browser/toolkit/components/startup/tests/browser/beforeunload.html";

View File

@ -1,9 +1,6 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const Cc = Components.classes;
const Ci = Components.interfaces;
const URI_BLOCKLIST_DIALOG = "chrome://mozapps/content/extensions/blocklist.xul";
Components.utils.import("resource://gre/modules/Services.jsm");
@ -122,4 +119,4 @@ function bug523784_test2(win) {
args.wrappedJSObject = args;
Services.ww.openWindow(null, URI_BLOCKLIST_DIALOG, "",
"chrome,centerscreen,dialog,titlebar", args);
}
}

View File

@ -51,6 +51,9 @@ const Cc = Components.classes;
const Ci = Components.interfaces;
const Cr = Components.results;
const UPDATESERVICE_CID = Components.ID("{B3C290A6-3943-4B89-8BBE-C01EB7B3B311}");
const UPDATESERVICE_CONTRACTID = "@mozilla.org/updates/update-service;1";
const PREF_APP_UPDATE_ALTWINDOWTYPE = "app.update.altwindowtype";
const PREF_APP_UPDATE_AUTO = "app.update.auto";
const PREF_APP_UPDATE_BACKGROUND_INTERVAL = "app.update.download.backgroundInterval";
@ -1778,19 +1781,14 @@ UpdateService.prototype = {
return this._downloader && this._downloader.isBusy;
},
// nsIClassInfo
flags: Ci.nsIClassInfo.SINGLETON,
implementationLanguage: Ci.nsIProgrammingLanguage.JAVASCRIPT,
getHelperForLanguage: function(language) null,
getInterfaces: function AUS_getInterfaces(count) {
var interfaces = [Ci.nsIApplicationUpdateService,
Ci.nsITimerCallback,
Ci.nsIObserver];
count.value = interfaces.length;
return interfaces;
},
classID: UPDATESERVICE_CID,
classInfo: XPCOMUtils.generateCI({classID: UPDATESERVICE_CID,
contractID: UPDATESERVICE_CONTRACTID,
interfaces: [Ci.nsIApplicationUpdateService,
Ci.nsITimerCallback,
Ci.nsIObserver],
flags: Ci.nsIClassInfo.SINGLETON}),
classID: Components.ID("{B3C290A6-3943-4B89-8BBE-C01EB7B3B311}"),
_xpcom_factory: UpdateServiceFactory,
QueryInterface: XPCOMUtils.generateQI([Ci.nsIApplicationUpdateService,
Ci.nsIAddonUpdateCheckListener,

Some files were not shown because too many files have changed in this diff Show More