Merge inbound to m-c a=merge despite the CLOSED TREE

This commit is contained in:
Wes Kocher 2014-10-01 16:26:44 -07:00
commit 86eb3305b3
512 changed files with 12134 additions and 10231 deletions

View File

@ -55,3 +55,4 @@ skip-if = e10s # Bug 915547 (social providers don't install)
skip-if = e10s # Bug 915547 (social providers don't install)
[browser_social_window.js]
[browser_social_workercrash.js]
skip-if = !crashreporter

View File

@ -8,7 +8,6 @@
# browser_580512.js is disabled for leaking browser windows (bug 752467)
[DEFAULT]
skip-if = e10s
support-files =
head.js
content.js
@ -67,6 +66,7 @@ support-files =
[browser_capabilities.js]
[browser_cleaner.js]
[browser_dying_cache.js]
skip-if = e10s
[browser_dynamic_frames.js]
[browser_form_restore_events.js]
[browser_formdata.js]
@ -83,10 +83,13 @@ skip-if = buildapp == 'mulet'
[browser_privatetabs.js]
[browser_scrollPositions.js]
[browser_sessionHistory.js]
skip-if = e10s
[browser_sessionStorage.js]
skip-if = e10s
[browser_swapDocShells.js]
skip-if = e10s # See bug 918634
[browser_telemetry.js]
skip-if = e10s
[browser_upgrade_backup.js]
[browser_windowRestore_perwindowpb.js]
[browser_248970_b_perwindowpb.js]
@ -104,8 +107,10 @@ skip-if = true
skip-if = true
[browser_394759_behavior.js]
[browser_394759_perwindowpb.js]
skip-if = e10s
[browser_394759_purge.js]
[browser_423132.js]
skip-if = e10s
[browser_447951.js]
[browser_454908.js]
[browser_456342.js]
@ -119,6 +124,7 @@ skip-if = true
[browser_467409-backslashplosion.js]
[browser_477657.js]
[browser_480893.js]
skip-if = e10s
[browser_485482.js]
[browser_485563.js]
[browser_490040.js]

View File

@ -146,6 +146,9 @@ PluginContent.prototype = {
makeNicePluginName : function (aName) {
if (aName == "Shockwave Flash")
return "Adobe Flash";
// Regex checks if aName begins with "Java" + non-letter char
if (/^Java\W/.exec(aName))
return "Java";
// Clean up the plugin name by stripping off parenthetical clauses,
// trailing version numbers or "plugin".

View File

@ -134,8 +134,8 @@ typedef CallbackObjectHolder<NodeFilter, nsIDOMNodeFilter> NodeFilterHolder;
} // namespace mozilla
#define NS_IDOCUMENT_IID \
{ 0x613ea294, 0x0288, 0x48b4, \
{ 0x9e, 0x7b, 0x0f, 0xe9, 0x3f, 0x8c, 0xf8, 0x95 } }
{ 0x42a263db, 0x6ac6, 0x40ff, \
{ 0x89, 0xe2, 0x25, 0x12, 0xe4, 0xbc, 0x2d, 0x2d } }
// Enum for requesting a particular type of document when creating a doc
enum DocumentFlavor {
@ -2362,10 +2362,15 @@ public:
// Each import tree has exactly one master document which is
// the root of the tree, and owns the browser context.
virtual already_AddRefed<nsIDocument> MasterDocument() = 0;
virtual nsIDocument* MasterDocument() = 0;
virtual void SetMasterDocument(nsIDocument* master) = 0;
virtual bool IsMasterDocument() = 0;
virtual already_AddRefed<mozilla::dom::ImportManager> ImportManager() = 0;
virtual mozilla::dom::ImportManager* ImportManager() = 0;
// We keep track of the order of sub imports were added to the document.
virtual bool HasSubImportLink(nsINode* aLink) = 0;
virtual uint32_t IndexOfSubImportLink(nsINode* aLink) = 0;
virtual void AddSubImportLink(nsINode* aLink) = 0;
virtual nsINode* GetSubImportLink(uint32_t aIdx) = 0;
/*
* Given a node, get a weak reference to it and append that reference to

View File

@ -23,6 +23,10 @@
#include "nsScriptLoader.h"
#include "nsNetUtil.h"
//-----------------------------------------------------------------------------
// AutoError
//-----------------------------------------------------------------------------
class AutoError {
public:
explicit AutoError(mozilla::dom::ImportLoader* loader, bool scriptsBlocked = true)
@ -49,6 +53,220 @@ private:
namespace mozilla {
namespace dom {
//-----------------------------------------------------------------------------
// ImportLoader::Updater
//-----------------------------------------------------------------------------
void
ImportLoader::Updater::GetReferrerChain(nsINode* aNode,
nsTArray<nsINode*>& aResult)
{
// We fill up the array backward. First the last link: aNode.
MOZ_ASSERT(mLoader->mLinks.Contains(aNode));
aResult.AppendElement(aNode);
nsINode* node = aNode;
nsRefPtr<ImportManager> manager = mLoader->Manager();
for (ImportLoader* referrersLoader = manager->Find(node->OwnerDoc());
referrersLoader;
referrersLoader = manager->Find(node->OwnerDoc()))
{
// Then walking up the main referrer chain and append each link
// to the array.
node = referrersLoader->GetMainReferrer();
MOZ_ASSERT(node);
aResult.AppendElement(node);
}
// The reversed order is more useful for consumers.
// XXX: This should probably go to nsTArray or some generic utility
// lib for our containers that we don't have... I would really like to
// get rid of this part...
uint32_t l = aResult.Length();
for (uint32_t i = 0; i < l / 2; i++) {
Swap(aResult[i], aResult[l - i - 1]);
}
}
bool
ImportLoader::Updater::ShouldUpdate(nsTArray<nsINode*>& aNewPath)
{
// Let's walk down on the main referrer chains of both the current main and
// the new link, and find the last pair of links that are from the same
// document. This is the junction point between the two referrer chain. Their
// order in the subimport list of that document will determine if we have to
// update the spanning tree or this new edge changes nothing in the script
// execution order.
nsTArray<nsINode*> oldPath;
GetReferrerChain(mLoader->mLinks[mLoader->mMainReferrer], oldPath);
uint32_t max = std::min(oldPath.Length(), aNewPath.Length());
MOZ_ASSERT(max > 0);
uint32_t lastCommonImportAncestor = 0;
for (uint32_t i = 0;
i < max && oldPath[i]->OwnerDoc() == aNewPath[i]->OwnerDoc();
i++)
{
lastCommonImportAncestor = i;
}
MOZ_ASSERT(lastCommonImportAncestor < max);
nsINode* oldLink = oldPath[lastCommonImportAncestor];
nsINode* newLink = aNewPath[lastCommonImportAncestor];
if ((lastCommonImportAncestor == max - 1) &&
newLink == oldLink ) {
// If one chain contains the other entirely, then this is a simple cycle,
// nothing to be done here.
MOZ_ASSERT(oldPath.Length() != aNewPath.Length(),
"This would mean that new link == main referrer link");
return false;
}
MOZ_ASSERT(aNewPath != oldPath,
"How could this happen?");
nsIDocument* doc = oldLink->OwnerDoc();
MOZ_ASSERT(doc->HasSubImportLink(newLink));
MOZ_ASSERT(doc->HasSubImportLink(oldLink));
return doc->IndexOfSubImportLink(newLink) < doc->IndexOfSubImportLink(oldLink);
}
void
ImportLoader::Updater::UpdateMainReferrer(uint32_t aNewIdx)
{
MOZ_ASSERT(aNewIdx < mLoader->mLinks.Length());
nsINode* newMainReferrer = mLoader->mLinks[aNewIdx];
// This new link means we have to execute our scripts sooner...
// Let's make sure that unblocking a loader does not trigger a script execution.
// So we start with placing the new blockers and only then will we remove any
// blockers.
if (mLoader->IsBlocking()) {
// Our import parent is changed, let's block the new one and later unblock
// the old one.
newMainReferrer->OwnerDoc()->ScriptLoader()->AddExecuteBlocker();
}
if (mLoader->mDocument) {
// Our nearest predecessor has changed. So let's add the ScriptLoader to the
// new one if there is any. And remove it from the old one.
nsRefPtr<ImportManager> manager = mLoader->Manager();
nsScriptLoader* loader = mLoader->mDocument->ScriptLoader();
ImportLoader*& pred = mLoader->mBlockingPredecessor;
ImportLoader* newPred = manager->GetNearestPredecessor(newMainReferrer);
if (pred) {
if (newPred) {
newPred->AddBlockedScriptLoader(loader);
}
pred->RemoveBlockedScriptLoader(loader);
}
}
if (mLoader->IsBlocking()) {
mLoader->mImportParent->ScriptLoader()->RemoveExecuteBlocker();
}
// Finally update mMainReferrer to point to the newly added link.
mLoader->mMainReferrer = aNewIdx;
mLoader->mImportParent = newMainReferrer->OwnerDoc();
}
nsINode*
ImportLoader::Updater::NextDependant(nsINode* aCurrentLink,
nsTArray<nsINode*>& aPath,
NodeTable& aVisitedNodes, bool aSkipChildren)
{
// Depth first graph traversal.
if (!aSkipChildren) {
// "first child"
ImportLoader* loader = mLoader->Manager()->Find(aCurrentLink);
if (loader && loader->GetDocument()) {
nsINode* firstSubImport = loader->GetDocument()->GetSubImportLink(0);
if (firstSubImport && !aVisitedNodes.Contains(firstSubImport)) {
aPath.AppendElement(aCurrentLink);
aVisitedNodes.PutEntry(firstSubImport);
return firstSubImport;
}
}
}
aPath.AppendElement(aCurrentLink);
// "(parent's) next sibling"
while(aPath.Length() > 1) {
aCurrentLink = aPath[aPath.Length() - 1];
aPath.RemoveElementAt(aPath.Length() - 1);
// Let's find the next "sibling"
ImportLoader* loader = mLoader->Manager()->Find(aCurrentLink->OwnerDoc());
MOZ_ASSERT(loader && loader->GetDocument(), "How can this happend?");
nsIDocument* doc = loader->GetDocument();
MOZ_ASSERT(doc->HasSubImportLink(aCurrentLink));
uint32_t idx = doc->IndexOfSubImportLink(aCurrentLink);
nsINode* next = doc->GetSubImportLink(idx + 1);
if (next) {
// Note: If we found an already visited link that means the parent links has
// closed the circle it's always the "first child" section that should find
// the first already visited node. Let's just assert that.
MOZ_ASSERT(!aVisitedNodes.Contains(next));
aVisitedNodes.PutEntry(next);
return next;
}
}
return nullptr;
}
void
ImportLoader::Updater::UpdateDependants(nsINode* aNode,
nsTArray<nsINode*>& aPath)
{
NodeTable visitedNodes;
nsINode* current = aNode;
uint32_t initialLength = aPath.Length();
bool neededUpdate = true;
while ((current = NextDependant(current, aPath, visitedNodes, !neededUpdate))) {
if (!current || aPath.Length() <= initialLength) {
break;
}
ImportLoader* loader = mLoader->Manager()->Find(current);
if (!loader) {
continue;
}
Updater& updater = loader->mUpdater;
neededUpdate = updater.ShouldUpdate(aPath);
if (neededUpdate) {
updater.UpdateMainReferrer(loader->mLinks.IndexOf(current));
}
}
}
void
ImportLoader::Updater::UpdateSpanningTree(nsINode* aNode)
{
if (mLoader->mReady || mLoader->mStopped) {
// Scripts already executed, nothing to be done here.
return;
}
if (mLoader->mLinks.Length() == 1) {
// If this is the first referrer, let's mark it.
mLoader->mMainReferrer = 0;
return;
}
nsTArray<nsINode*> newReferrerChain;
GetReferrerChain(aNode, newReferrerChain);
if (ShouldUpdate(newReferrerChain)) {
UpdateMainReferrer(mLoader->mLinks.Length() - 1);
UpdateDependants(aNode, newReferrerChain);
}
}
//-----------------------------------------------------------------------------
// ImportLoader
//-----------------------------------------------------------------------------
NS_INTERFACE_MAP_BEGIN(ImportLoader)
NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
@ -66,10 +284,13 @@ NS_IMPL_CYCLE_COLLECTION(ImportLoader,
ImportLoader::ImportLoader(nsIURI* aURI, nsIDocument* aImportParent)
: mURI(aURI)
, mImportParent(aImportParent)
, mBlockingPredecessor(nullptr)
, mReady(false)
, mStopped(false)
, mBlockingScripts(false)
{}
, mUpdater(MOZ_THIS_IN_INITIALIZER_LIST())
{
}
void
ImportLoader::BlockScripts()
@ -84,9 +305,19 @@ ImportLoader::UnblockScripts()
{
MOZ_ASSERT(mBlockingScripts);
mImportParent->ScriptLoader()->RemoveExecuteBlocker();
for (uint32_t i = 0; i < mBlockedScriptLoaders.Length(); i++) {
mBlockedScriptLoaders[i]->RemoveExecuteBlocker();
}
mBlockedScriptLoaders.Clear();
mBlockingScripts = false;
}
void
ImportLoader::SetBlockingPredecessor(ImportLoader* aLoader)
{
mBlockingPredecessor = aLoader;
}
void
ImportLoader::DispatchEventIfFinished(nsINode* aNode)
{
@ -99,6 +330,26 @@ ImportLoader::DispatchEventIfFinished(nsINode* aNode)
}
}
void
ImportLoader::AddBlockedScriptLoader(nsScriptLoader* aScriptLoader)
{
if (mBlockedScriptLoaders.Contains(aScriptLoader)) {
return;
}
aScriptLoader->AddExecuteBlocker();
// Let's keep track of the pending script loaders.
mBlockedScriptLoaders.AppendElement(aScriptLoader);
}
bool
ImportLoader::RemoveBlockedScriptLoader(nsScriptLoader* aScriptLoader)
{
aScriptLoader->RemoveExecuteBlocker();
return mBlockedScriptLoaders.RemoveElement(aScriptLoader);
}
void
ImportLoader::AddLinkElement(nsINode* aNode)
{
@ -106,14 +357,15 @@ ImportLoader::AddLinkElement(nsINode* aNode)
// refers to an import that is already finished loading or
// stopped trying, we need to fire the corresponding event
// on it.
mLinks.AppendObject(aNode);
mLinks.AppendElement(aNode);
mUpdater.UpdateSpanningTree(aNode);
DispatchEventIfFinished(aNode);
}
void
ImportLoader::RemoveLinkElement(nsINode* aNode)
{
mLinks.RemoveObject(aNode);
mLinks.RemoveElement(aNode);
}
// Events has to be fired with a script runner, so mImport can
@ -159,8 +411,8 @@ void
ImportLoader::Done()
{
mReady = true;
uint32_t count = mLinks.Count();
for (uint32_t i = 0; i < count; i++) {
uint32_t l = mLinks.Length();
for (uint32_t i = 0; i < l; i++) {
DispatchLoadEvent(mLinks[i]);
}
UnblockScripts();
@ -172,8 +424,8 @@ ImportLoader::Error(bool aUnblockScripts)
{
mDocument = nullptr;
mStopped = true;
uint32_t count = mLinks.Count();
for (uint32_t i = 0; i < count; i++) {
uint32_t l = mLinks.Length();
for (uint32_t i = 0; i < l; i++) {
DispatchErrorEvent(mLinks[i]);
}
if (aUnblockScripts) {
@ -391,7 +643,25 @@ ImportLoader::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext)
true);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_ABORT_ERR);
// Let's start parser.
nsCOMPtr<nsIURI> originalURI;
rv = channel->GetOriginalURI(getter_AddRefs(originalURI));
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_ABORT_ERR);
nsCOMPtr<nsIURI> URI;
rv = channel->GetURI(getter_AddRefs(URI));
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_ABORT_ERR);
MOZ_ASSERT(URI, "URI of a channel should never be null");
bool equals;
rv = URI->Equals(originalURI, &equals);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_ABORT_ERR);
if (!equals) {
// In case of a redirection we must add the new URI to the import map.
Manager()->AddLoaderWithNewURI(this, URI);
}
// Let's start the parser.
mParserStreamListener = listener;
rv = listener->OnStartRequest(aRequest, aContext);
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_ABORT_ERR);
@ -400,6 +670,10 @@ ImportLoader::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext)
return NS_OK;
}
//-----------------------------------------------------------------------------
// ImportManager
//-----------------------------------------------------------------------------
NS_IMPL_CYCLE_COLLECTION(ImportManager,
mImports)
@ -417,16 +691,78 @@ ImportManager::Get(nsIURI* aURI, nsINode* aNode, nsIDocument* aOrigDocument)
// and start it up.
nsRefPtr<ImportLoader> loader;
mImports.Get(aURI, getter_AddRefs(loader));
bool needToStart = false;
if (!loader) {
loader = new ImportLoader(aURI, aOrigDocument);
mImports.Put(aURI, loader);
needToStart = true;
}
MOZ_ASSERT(loader);
// Let's keep track of the sub imports links in each document. It will
// be used later for scrip execution order calculation. (see UpdateSpanningTree)
// NOTE: removing and adding back the link to the tree somewhere else will
// NOT have an effect on script execution order.
if (!aOrigDocument->HasSubImportLink(aNode)) {
aOrigDocument->AddSubImportLink(aNode);
}
loader->AddLinkElement(aNode);
if (needToStart) {
loader->Open();
}
loader->AddLinkElement(aNode);
MOZ_ASSERT(loader);
return loader.forget();
}
ImportLoader*
ImportManager::Find(nsIDocument* aImport)
{
return mImports.GetWeak(aImport->GetDocumentURIObject());
}
ImportLoader*
ImportManager::Find(nsINode* aLink)
{
HTMLLinkElement* linkElement = static_cast<HTMLLinkElement*>(aLink);
nsCOMPtr<nsIURI> uri = linkElement->GetHrefURI();
return mImports.GetWeak(uri);
}
void
ImportManager::AddLoaderWithNewURI(ImportLoader* aLoader, nsIURI* aNewURI)
{
mImports.Put(aNewURI, aLoader);
}
nsRefPtr<ImportLoader> ImportManager::GetNearestPredecessor(nsINode* aNode)
{
// Return the previous link if there is any in the same document.
nsIDocument* doc = aNode->OwnerDoc();
int32_t idx = doc->IndexOfSubImportLink(aNode);
MOZ_ASSERT(idx != -1, "aNode must be a sub import link of its owner document");
if (idx == 0) {
if (doc->IsMasterDocument()) {
// If there is no previous one, and it was the master document, then
// there is no predecessor.
return nullptr;
}
// Else we find the main referrer of the import parent of the link's document.
// And do a recursion.
ImportLoader* owner = Find(doc);
MOZ_ASSERT(owner);
nsCOMPtr<nsINode> mainReferrer = owner->GetMainReferrer();
return GetNearestPredecessor(mainReferrer);
}
MOZ_ASSERT(idx > 0);
HTMLLinkElement* link =
static_cast<HTMLLinkElement*>(doc->GetSubImportLink(idx - 1));
nsCOMPtr<nsIURI> uri = link->GetHrefURI();
nsRefPtr<ImportLoader> ret;
mImports.Get(uri, getter_AddRefs(ret));
return ret;
}
} // namespace dom
} // namespace mozilla

View File

@ -39,12 +39,13 @@
#ifndef mozilla_dom_ImportManager_h__
#define mozilla_dom_ImportManager_h__
#include "nsCOMArray.h"
#include "nsTArray.h"
#include "nsCycleCollectionParticipant.h"
#include "nsIDOMEventListener.h"
#include "nsIStreamListener.h"
#include "nsIWeakReferenceUtils.h"
#include "nsRefPtrHashtable.h"
#include "nsScriptLoader.h"
#include "nsURIHashKey.h"
class nsIDocument;
@ -58,11 +59,70 @@ namespace dom {
class ImportManager;
typedef nsTHashtable<nsPtrHashKey<nsINode>> NodeTable;
class ImportLoader MOZ_FINAL : public nsIStreamListener
, public nsIDOMEventListener
{
// A helper inner class to decouple the logic of updating the import graph
// after a new import link has been found by one of the parsers.
class Updater {
public:
Updater(ImportLoader* aLoader) : mLoader(aLoader)
{}
// After a new link is added that refers to this import, we
// have to update the spanning tree, since given this new link the
// priority of this import might be higher in the scripts
// execution order than before. It updates mMainReferrer, mImportParent,
// the corresponding pending ScriptRunners, etc.
// It also handles updating additional dependant loaders via the
// UpdateDependants calls.
// (NOTE: See GetMainReferrer about spanning tree.)
void UpdateSpanningTree(nsINode* aNode);
private:
// Returns an array of links that forms a referring chain from
// the master document to this import. Each link in the array
// is marked as main referrer in the list.
void GetReferrerChain(nsINode* aNode, nsTArray<nsINode*>& aResult);
// Once we find a new referrer path to our import, we have to see if
// it changes the load order hence we have to do an update on the graph.
bool ShouldUpdate(nsTArray<nsINode*>& aNewPath);
void UpdateMainReferrer(uint32_t newIdx);
// It's a depth first graph traversal algorithm, for UpdateDependants. The
// nodes in the graph are the import link elements, and there is a directed
// edge from link1 to link2 if link2 is a subimport in the import document
// of link1.
// If the ImportLoader that aCurrentLink points to didn't need to be updated
// the algorithm skips its "children" (subimports). Note, that this graph can
// also contain cycles, aVisistedLinks is used to track the already visited
// links to avoid an infinite loop.
// aPath - (in/out) the referrer link chain of aCurrentLink when called, and
// of the next link when the function returns
// aVisitedLinks - (in/out) list of links that the traversal already visited
// (to handle cycles in the graph)
// aSkipChildren - when aCurrentLink points to an import that did not need
// to be updated, we can skip its sub-imports ('children')
nsINode* NextDependant(nsINode* aCurrentLink,
nsTArray<nsINode*>& aPath,
NodeTable& aVisitedLinks, bool aSkipChildren);
// When we find a new link that changes the load order of the known imports,
// we also have to check all the subimports of it, to see if they need an
// update too. (see test_imports_nested_2.html)
void UpdateDependants(nsINode* aNode, nsTArray<nsINode*>& aPath);
ImportLoader* mLoader;
};
friend class ::AutoError;
friend class ImportManager;
friend class Updater;
public:
ImportLoader(nsIURI* aURI, nsIDocument* aOriginDocument);
@ -83,11 +143,46 @@ public:
bool IsReady() { return mReady; }
bool IsStopped() { return mStopped; }
bool IsBlocking() { return mBlockingScripts; }
already_AddRefed<nsIDocument> GetImport()
{
return mReady ? nsCOMPtr<nsIDocument>(mDocument).forget() : nullptr;
ImportManager* Manager() {
MOZ_ASSERT(mDocument || mImportParent, "One of them should be always set");
return (mDocument ? mDocument : mImportParent)->ImportManager();
}
// Simply getter for the import document. Can return a partially parsed
// document if called too early.
nsIDocument* GetDocument()
{
return mDocument;
}
// Getter for the import document that is used in the spec. Returns
// nullptr if the import is not yet ready.
nsIDocument* GetImport()
{
return mReady ? mDocument : nullptr;
}
// There is only one referring link that is marked as primary link per
// imports. This is the one that has to be taken into account when
// scrip execution order is determined. Links marked as primary link form
// a spanning tree in the import graph. (Eliminating the cycles and
// multiple parents.) This spanning tree is recalculated every time
// a new import link is added to the manager.
nsINode* GetMainReferrer()
{
return mLinks.IsEmpty() ? nullptr : mLinks[mMainReferrer];
}
// An import is not only blocked by its import children, but also
// by its predecessors. It's enough to find the closest predecessor
// and wait for that to run its scripts. We keep track of all the
// ScriptRunners that are waiting for this import. NOTE: updating
// the main referrer might change this list.
void AddBlockedScriptLoader(nsScriptLoader* aScriptLoader);
bool RemoveBlockedScriptLoader(nsScriptLoader* aScriptLoader);
void SetBlockingPredecessor(ImportLoader* aLoader);
private:
~ImportLoader() {}
@ -122,12 +217,25 @@ private:
nsCOMPtr<nsIURI> mURI;
nsCOMPtr<nsIStreamListener> mParserStreamListener;
nsCOMPtr<nsIDocument> mImportParent;
ImportLoader* mBlockingPredecessor;
// List of the LinkElements that are referring to this import
// we need to keep track of them so we can fire event on them.
nsCOMArray<nsINode> mLinks;
nsTArray<nsCOMPtr<nsINode>> mLinks;
// List of pending ScriptLoaders that are waiting for this import
// to finish.
nsTArray<nsRefPtr<nsScriptLoader>> mBlockedScriptLoaders;
// There is always exactly one referrer link that is flagged as
// the main referrer the primary link. This is the one that is
// used in the script execution order calculation.
// ("Branch" according to the spec.)
uint32_t mMainReferrer;
bool mReady;
bool mStopped;
bool mBlockingScripts;
Updater mUpdater;
};
class ImportManager MOZ_FINAL : public nsISupports
@ -142,9 +250,24 @@ public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(ImportManager)
// Finds the ImportLoader that belongs to aImport in the map.
ImportLoader* Find(nsIDocument* aImport);
// Find the ImportLoader aLink refers to.
ImportLoader* Find(nsINode* aLink);
void AddLoaderWithNewURI(ImportLoader* aLoader, nsIURI* aNewURI);
// When a new import link is added, this getter either creates
// a new ImportLoader for it, or returns an existing one if
// it was already created and in the import map.
already_AddRefed<ImportLoader> Get(nsIURI* aURI, nsINode* aNode,
nsIDocument* aOriginDocument);
// It finds the predecessor for an import link node that runs its
// scripts the latest among its predecessors.
nsRefPtr<ImportLoader> GetNearestPredecessor(nsINode* aNode);
private:
ImportMap mImports;
};

View File

@ -692,6 +692,19 @@ nsCSPContext::SendReports(nsISupports* aBlockedContentSource,
continue; // don't return yet, there may be more URIs
}
// log a warning to console if scheme is not http or https
bool isHttpScheme =
(NS_SUCCEEDED(reportURI->SchemeIs("http", &isHttpScheme)) && isHttpScheme) ||
(NS_SUCCEEDED(reportURI->SchemeIs("https", &isHttpScheme)) && isHttpScheme);
if (!isHttpScheme) {
const char16_t* params[] = { reportURIs[r].get() };
CSP_LogLocalizedStr(NS_LITERAL_STRING("reportURInotHttpsOrHttp2").get(),
params, ArrayLength(params),
aSourceFile, aScriptSample, aLineNum, 0,
nsIScriptError::errorFlag, "CSP", mInnerWindowID);
}
// make sure this is an anonymous request (no cookies) so in case the
// policy URI is injected, it can't be abused for CSRF.
nsLoadFlags flags;

View File

@ -1997,6 +1997,8 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsDocument)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOnDemandBuiltInUASheets)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPreloadingImages)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSubImportLinks)
for (uint32_t i = 0; i < tmp->mFrameRequestCallbacks.Length(); ++i) {
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mFrameRequestCallbacks[i]");
cb.NoteXPCOMChild(tmp->mFrameRequestCallbacks[i].mCallback.GetISupports());
@ -2061,6 +2063,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mRegistry)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mMasterDocument)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mImportManager)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSubImportLinks)
tmp->mParentDocument = nullptr;

View File

@ -1290,10 +1290,10 @@ public:
mozilla::ErrorResult& rv) MOZ_OVERRIDE;
virtual void UseRegistryFromDocument(nsIDocument* aDocument) MOZ_OVERRIDE;
virtual already_AddRefed<nsIDocument> MasterDocument()
virtual nsIDocument* MasterDocument()
{
return mMasterDocument ? (nsCOMPtr<nsIDocument>(mMasterDocument)).forget()
: (nsCOMPtr<nsIDocument>(this)).forget();
return mMasterDocument ? mMasterDocument.get()
: this;
}
virtual void SetMasterDocument(nsIDocument* master)
@ -1306,11 +1306,11 @@ public:
return !mMasterDocument;
}
virtual already_AddRefed<mozilla::dom::ImportManager> ImportManager()
virtual mozilla::dom::ImportManager* ImportManager()
{
if (mImportManager) {
MOZ_ASSERT(!mMasterDocument, "Only the master document has ImportManager set");
return nsRefPtr<mozilla::dom::ImportManager>(mImportManager).forget();
return mImportManager.get();
}
if (mMasterDocument) {
@ -1322,7 +1322,28 @@ public:
// master document and this is the first import in it.
// Let's create a new manager.
mImportManager = new mozilla::dom::ImportManager();
return nsRefPtr<mozilla::dom::ImportManager>(mImportManager).forget();
return mImportManager.get();
}
virtual bool HasSubImportLink(nsINode* aLink)
{
return mSubImportLinks.Contains(aLink);
}
virtual uint32_t IndexOfSubImportLink(nsINode* aLink)
{
return mSubImportLinks.IndexOf(aLink);
}
virtual void AddSubImportLink(nsINode* aLink)
{
mSubImportLinks.AppendElement(aLink);
}
virtual nsINode* GetSubImportLink(uint32_t aIdx)
{
return aIdx < mSubImportLinks.Length() ? mSubImportLinks[aIdx].get()
: nullptr;
}
virtual void UnblockDOMContentLoaded() MOZ_OVERRIDE;
@ -1754,6 +1775,7 @@ private:
nsCOMPtr<nsIDocument> mMasterDocument;
nsRefPtr<mozilla::dom::ImportManager> mImportManager;
nsTArray<nsCOMPtr<nsINode> > mSubImportLinks;
// Set to true when the document is possibly controlled by the ServiceWorker.
// Used to prevent multiple requests to ServiceWorkerManager.

View File

@ -49,6 +49,7 @@
#include "nsSandboxFlags.h"
#include "nsContentTypeParser.h"
#include "nsINetworkPredictor.h"
#include "ImportManager.h"
#include "mozilla/dom/EncodingUtils.h"
#include "mozilla/CORSMode.h"
@ -1236,7 +1237,7 @@ nsScriptLoader::ReadyToExecuteScripts()
if (!SelfReadyToExecuteScripts()) {
return false;
}
for (nsIDocument* doc = mDocument; doc; doc = doc->GetParentDocument()) {
nsScriptLoader* ancestor = doc->ScriptLoader();
if (!ancestor->SelfReadyToExecuteScripts() &&
@ -1246,10 +1247,44 @@ nsScriptLoader::ReadyToExecuteScripts()
}
}
if (!mDocument->IsMasterDocument()) {
nsRefPtr<ImportManager> im = mDocument->ImportManager();
nsRefPtr<ImportLoader> loader = im->Find(mDocument);
MOZ_ASSERT(loader, "How can we have an import document without a loader?");
// The referring link that counts in the execution order calculation
// (in spec: flagged as branch)
nsCOMPtr<nsINode> referrer = loader->GetMainReferrer();
MOZ_ASSERT(referrer, "There has to be a main referring link for each imports");
// Import documents are blocked by their import predecessors. We need to
// wait with script execution until all the predecessors are done.
// Technically it means we have to wait for the last one to finish,
// which is the neares one to us in the order.
nsRefPtr<ImportLoader> lastPred = im->GetNearestPredecessor(referrer);
if (!lastPred) {
// If there is no predecessor we can run.
return true;
}
nsCOMPtr<nsIDocument> doc = lastPred->GetDocument();
if (lastPred->IsBlocking() || !doc || (doc && !doc->ScriptLoader()->SelfReadyToExecuteScripts())) {
// Document has not been created yet or it was created but not ready.
// Either case we are blocked by it. The ImportLoader will take care
// of blocking us, and adding the pending child loader to the blocking
// ScriptLoader when it's possible (at this point the blocking loader
// might not have created the document/ScriptLoader)
lastPred->AddBlockedScriptLoader(this);
// As more imports are parsed, this can change, let's cache what we
// blocked, so it can be later updated if needed (see: ImportLoader::Updater).
loader->SetBlockingPredecessor(lastPred);
return false;
}
}
return true;
}
// This function was copied from nsParser.cpp. It was simplified a bit.
static bool
DetectByteOrderMark(const unsigned char* aBytes, int32_t aLen, nsCString& oCharset)

View File

@ -249,6 +249,10 @@ public:
nsresult ProcessOffThreadRequest(nsScriptLoadRequest *aRequest,
void **aOffThreadToken);
bool AddPendingChildLoader(nsScriptLoader* aChild) {
return mPendingChildLoaders.AppendElement(aChild) != nullptr;
}
private:
virtual ~nsScriptLoader();
@ -302,10 +306,6 @@ private:
return mEnabled && !mBlockerCount;
}
bool AddPendingChildLoader(nsScriptLoader* aChild) {
return mPendingChildLoaders.AppendElement(aChild) != nullptr;
}
nsresult AttemptAsyncScriptParse(nsScriptLoadRequest* aRequest);
nsresult ProcessRequest(nsScriptLoadRequest* aRequest,
void **aOffThreadToken = nullptr);

View File

@ -13,6 +13,7 @@ var is_remote;
dom_test();
xray_test();
compartment_test();
regexp_test();
sync_test();
async_test();
rpc_test();
@ -143,6 +144,11 @@ function compartment_test()
testParentObject: testParentObject });
}
function regexp_test()
{
sendSyncMessage("cpows:regexp_test", {}, { regexp: /myRegExp/g });
}
function sync_test()
{
dump('beginning cpow sync test\n');

View File

@ -233,6 +233,21 @@
results.forEach((x) => is(x.result, "PASS", x.message));
}
function recvRegExpTest(message) {
let regexp = message.objects.regexp;
// These work generically.
is(regexp.toString(), "/myRegExp/g", "toString works right");
ok(regexp.test("I like myRegExp to match"), "No false positives");
ok(!regexp.test("asdfsdf"), "No false positives");
// These go over regexp_toShared.
is("filler myRegExp filler".search(regexp), 7, "String.prototype.match works right");
var shell = /x/;
shell.compile(regexp);
is(regexp.toString(), shell.toString(), ".compile works right");
}
let savedWilldieObj;
let wontDie = {f:2, __exposedProps__: {"f": "r"}};
function recvLifetimeTest1(message) {
@ -286,6 +301,7 @@
mm.addMessageListener("cpows:dom_test_after_gc", recvDomTestAfterGC);
mm.addMessageListener("cpows:xray_test", recvXrayTest);
mm.addMessageListener("cpows:compartment_test", recvCompartmentTest);
mm.addMessageListener("cpows:regexp_test", recvRegExpTest);
mm.addMessageListener("cpows:lifetime_test_1", recvLifetimeTest1);
mm.addMessageListener("cpows:lifetime_test_2", recvLifetimeTest2);
mm.loadFrameScript("chrome://mochitests/content/chrome/content/base/test/chrome/cpows_child.js", true);

View File

@ -8,6 +8,7 @@ DIRS += ['public', 'src']
MOCHITEST_MANIFESTS += [
'test/forms/mochitest.ini',
'test/imports/mochitest.ini',
'test/mochitest.ini',
]

View File

@ -263,15 +263,6 @@ HTMLLinkElement::UpdateImport()
return;
}
// Until the script execution order is not sorted out for nested cases
// let's not allow them.
if (!doc->IsMasterDocument()) {
nsContentUtils::LogSimpleConsoleError(
NS_LITERAL_STRING("Nested imports are not supported yet"),
"Imports");
return;
}
// 2. rel type should be import.
nsAutoString rel;
GetAttr(kNameSpaceID_None, nsGkAtoms::rel, rel);
@ -526,7 +517,7 @@ HTMLLinkElement::WrapNode(JSContext* aCx)
already_AddRefed<nsIDocument>
HTMLLinkElement::GetImport()
{
return mImportLoader ? mImportLoader->GetImport() : nullptr;
return mImportLoader ? nsRefPtr<nsIDocument>(mImportLoader->GetImport()).forget() : nullptr;
}
} // namespace dom

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<link rel="import" href="file_importA2.html" id="A2" onload="loaded()" onerror="failed()"></link>
</head>
<body>
<script>
order.push("A1");
</script>
</body>
</html>

View File

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
</head>
<body>
<script>
order.push("A2");
</script>
</body>
</html>

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<link rel="import" href="file_importB2.html" id="B2" onload="loaded()" onerror="failed()"></link>
</head>
<body>
<script>
order.push("B1");
</script>
</body>
</html>

View File

@ -0,0 +1,10 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
</head>
<body>
<script>
order.push("B2");
</script>
</body>
</html>

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<link rel="import" href="file_importC2.html" onload="loaded()" onerror="failed()"></link>
</head>
<body>
<script>
order.push("C1");
</script>
</body>
</html>

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<link rel="import" href="file_importE.html" onload="loaded()" onerror="failed()"></link>
</head>
<body>
<script>
order.push("C10");
</script>
</body>
</html>

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<link rel="import" href="file_importC3.html" onload="loaded()" onerror="failed()"></link>
</head>
<body>
<script>
order.push("C2");
</script>
</body>
</html>

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<link rel="import" href="file_importC4.html" onload="loaded()" onerror="failed()"></link>
</head>
<body>
<script>
order.push("C3");
</script>
</body>
</html>

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<link rel="import" href="file_importC5.html" onload="loaded()" onerror="failed()"></link>
</head>
<body>
<script>
order.push("C4");
</script>
</body>
</html>

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<link rel="import" href="file_importC6.html" onload="loaded()" onerror="failed()"></link>
</head>
<body>
<script>
order.push("C5");
</script>
</body>
</html>

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<link rel="import" href="file_importC7.html" onload="loaded()" onerror="failed()"></link>
</head>
<body>
<script>
order.push("C6");
</script>
</body>
</html>

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<link rel="import" href="file_importC8.html" onload="loaded()" onerror="failed()"></link>
</head>
<body>
<script>
order.push("C7");
</script>
</body>
</html>

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<link rel="import" href="file_importC9.html" onload="loaded()" onerror="failed()"></link>
</head>
<body>
<script>
order.push("C8");
</script>
</body>
</html>

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<link rel="import" href="file_importC10.html" onload="loaded()" onerror="failed()"></link>
</head>
<body>
<script>
order.push("C9");
</script>
</body>
</html>

View File

@ -0,0 +1,8 @@
<!DOCTYPE html>
<html lang="en-US">
<body>
<script>
order.push("D");
</script>
</body>
</html>

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<link rel="import" href="file_importD.html" onload="loaded()" onerror="failed()"></link>
</head>
<body>
<script>
order.push("E");
</script>
</body>
</html>

View File

@ -0,0 +1,20 @@
[DEFAULT]
support-files =
file_importA1.html
file_importA2.html
file_importB1.html
file_importB2.html
file_importC1.html
file_importC2.html
file_importC3.html
file_importC4.html
file_importC5.html
file_importC6.html
file_importC7.html
file_importC8.html
file_importC9.html
file_importC10.html
file_importD.html
file_importE.html

View File

@ -463,6 +463,10 @@ skip-if = buildapp == 'b2g' || e10s # b2g(multiple concurrent window.open()s fai
[test_imports_basics.html]
[test_imports_redirect.html]
[test_imports_nonhttp.html]
[test_imports_nested.html]
skip-if = toolkit == 'gonk' # nested imports fail on b2g emulator
[test_imports_nested_2.html]
skip-if = toolkit == 'gonk' # nested imports fail on b2g emulator
[test_li_attributes_reflection.html]
[test_link_attributes_reflection.html]
[test_link_sizes.html]

View File

@ -0,0 +1,41 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=877072
-->
<head>
<title>Test for Bug 877072</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=877072">Mozilla Bug 877072</a>
<script type="text/javascript">
SimpleTest.waitForExplicitFinish();
var counter = 0;
var fcounter = 0;
var order = [];
function loaded() {
counter++;
}
function failed() {
fcounter++;
}
</script>
<link rel="import" href="imports/file_importA1.html" id="A1" onload="loaded()" onerror="failed()"></link>
<link rel="import" href="imports/file_importB1.html" id="B1" onload="loaded()" onerror="failed()"></link>
<link rel="import" href="imports/file_importB2.html" id="B2_2" onload="loaded()" onerror="failed()"></link>
<script type="text/javascript">
is(counter, 5, "Imports are loaded");
is(fcounter, 0, "No error in imports");
var expected = ["A2", "A1", "B2", "B1"];
for (i in expected)
is(order[i], expected[i], "import " + i + " should be " + expected[i]);
SimpleTest.finish();
</script>
</body>
</html>

View File

@ -0,0 +1,56 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=877072
-->
<head>
<title>Test for Bug 877072</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=877072">Mozilla Bug 877072</a>
<script type="text/javascript">
SimpleTest.waitForExplicitFinish();
var counter = 0;
var fcounter = 0;
var order = [];
function loaded() {
counter++;
}
function failed() {
fcounter++;
}
</script>
<!--
Master -> c1 -> ... -> C10
| | |
| - - -> D |
| ^ |
| | |
- - - -> E < - - - - - -
This test is for testing ImportLoader::UpdateDependants.Because of the long
chain to C10, it's very likely that C10->E will be the last edge the ImportLoaders
find. At that point it won't only have to update E but also its subimport D.
-->
<link rel="import" href="imports/file_importC1.html" onload="loaded()" onerror="failed()"></link>
<link rel="import" href="imports/file_importD.html" onload="loaded()" onerror="failed()"></link>
<link rel="import" href="imports/file_importE.html" onload="loaded()" onerror="failed()"></link>
<script type="text/javascript">
is(counter, 14, "Imports are loaded"); // 12 imports but 14 link imports...
is(fcounter, 0, "No error in imports");
var expected = ["D", "E", "C10", "C9", "C8", "C7", "C6", "C5", "C4", "C3", "C2", "C1"];
for (i in expected)
is(order[i], expected[i], "import " + i + " should be " + expected[i]);
SimpleTest.finish();
</script>
</body>
</html>

View File

@ -63,7 +63,7 @@ PRLogModuleInfo* gMediaStreamGraphLog;
/**
* The singleton graph instance.
*/
static nsDataHashtable<nsUint32HashKey, MediaStreamGraphImpl*> gGraphs;
static MediaStreamGraphImpl* gGraph;
MediaStreamGraphImpl::~MediaStreamGraphImpl()
{
@ -1633,10 +1633,9 @@ MediaStreamGraphImpl::RunInStableState(bool aSourceIsMSG)
NS_DispatchToMainThread(event);
LIFECYCLE_LOG("Disconnecting MediaStreamGraph %p", this);
MediaStreamGraphImpl* graph;
if (gGraphs.Get(mAudioChannel, &graph) && graph == this) {
if (this == gGraph) {
// null out gGraph if that's the graph being shut down
gGraphs.Remove(mAudioChannel);
gGraph = nullptr;
}
}
} else {
@ -1787,12 +1786,9 @@ MediaStreamGraphImpl::AppendMessage(ControlMessage* aMessage)
delete aMessage;
if (IsEmpty() &&
mLifecycleState >= LIFECYCLE_WAITING_FOR_STREAM_DESTRUCTION) {
MediaStreamGraphImpl* graph;
if (gGraphs.Get(mAudioChannel, &graph) && graph == this) {
gGraphs.Remove(mAudioChannel);
if (gGraph == this) {
gGraph = nullptr;
}
Destroy();
}
return;
@ -2740,7 +2736,6 @@ MediaStreamGraphImpl::MediaStreamGraphImpl(bool aRealtime,
#ifdef DEBUG
, mCanRunMessagesSynchronously(false)
#endif
, mAudioChannel(static_cast<uint32_t>(aChannel))
{
#ifdef PR_LOGGING
if (!gMediaStreamGraphLog) {
@ -2779,26 +2774,15 @@ NS_IMPL_ISUPPORTS(MediaStreamGraphShutdownObserver, nsIObserver)
static bool gShutdownObserverRegistered = false;
namespace {
PLDHashOperator
ForceShutdownEnumerator(const uint32_t& /* aAudioChannel */,
MediaStreamGraphImpl* aGraph,
void* /* aUnused */)
{
aGraph->ForceShutDown();
return PL_DHASH_NEXT;
}
} // anonymous namespace
NS_IMETHODIMP
MediaStreamGraphShutdownObserver::Observe(nsISupports *aSubject,
const char *aTopic,
const char16_t *aData)
{
if (strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0) {
gGraphs.EnumerateRead(ForceShutdownEnumerator, nullptr);
if (gGraph) {
gGraph->ForceShutDown();
}
nsContentUtils::UnregisterShutdownObserver(this);
gShutdownObserverRegistered = false;
}
@ -2810,10 +2794,7 @@ MediaStreamGraph::GetInstance(DOMMediaStream::TrackTypeHints aHint, dom::AudioCh
{
NS_ASSERTION(NS_IsMainThread(), "Main thread only");
uint32_t channel = static_cast<uint32_t>(aChannel);
MediaStreamGraphImpl* graph = nullptr;
if (!gGraphs.Get(channel, &graph)) {
if (!gGraph) {
if (!gShutdownObserverRegistered) {
gShutdownObserverRegistered = true;
nsContentUtils::RegisterShutdownObserver(new MediaStreamGraphShutdownObserver());
@ -2821,13 +2802,12 @@ MediaStreamGraph::GetInstance(DOMMediaStream::TrackTypeHints aHint, dom::AudioCh
CubebUtils::InitPreferredSampleRate();
graph = new MediaStreamGraphImpl(true, CubebUtils::PreferredSampleRate(), aHint, aChannel);
gGraphs.Put(channel, graph);
gGraph = new MediaStreamGraphImpl(true, CubebUtils::PreferredSampleRate(), aHint, aChannel);
STREAM_LOG(PR_LOG_DEBUG, ("Starting up MediaStreamGraph %p", graph));
STREAM_LOG(PR_LOG_DEBUG, ("Starting up MediaStreamGraph %p", gGraph));
}
return graph;
return gGraph;
}
MediaStreamGraph*
@ -2998,10 +2978,7 @@ MediaStreamGraph::CreateAudioNodeStream(AudioNodeEngine* aEngine,
bool
MediaStreamGraph::IsNonRealtime() const
{
const MediaStreamGraphImpl* impl = static_cast<const MediaStreamGraphImpl*>(this);
MediaStreamGraphImpl* graph;
return !gGraphs.Get(impl->AudioChannel(), &graph) || graph != impl;
return this != gGraph;
}
void

View File

@ -654,8 +654,6 @@ public:
nsRefPtr<AudioOutputObserver> mFarendObserverRef;
#endif
uint32_t AudioChannel() const { return mAudioChannel; }
private:
virtual ~MediaStreamGraphImpl();
@ -689,9 +687,6 @@ private:
bool mCanRunMessagesSynchronously;
#endif
// We use uint32_t instead AudioChannel because this is just used as key for
// the hashtable gGraphs.
uint32_t mAudioChannel;
};
}

View File

@ -648,6 +648,12 @@ AudioContext::MozAudioChannelType() const
return mDestination->MozAudioChannelType();
}
void
AudioContext::SetMozAudioChannelType(AudioChannel aValue, ErrorResult& aRv)
{
mDestination->SetMozAudioChannelType(aValue, aRv);
}
AudioChannel
AudioContext::TestAudioChannelInAudioNodeStream()
{

View File

@ -222,6 +222,7 @@ public:
JSObject* GetGlobalJSObject() const;
AudioChannel MozAudioChannelType() const;
void SetMozAudioChannelType(AudioChannel aValue, ErrorResult& aRv);
AudioChannel TestAudioChannelInAudioNodeStream();

View File

@ -18,23 +18,27 @@ function test_basic() {
// Default
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
// random wrong channel
ac.mozAudioChannelType = "foo";
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
// Unpermitted channels
ac = new AudioContext("content");
ac.mozAudioChannelType = "content";
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
ac = new AudioContext("notification");
ac.mozAudioChannelType = "notification";
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
ac = new AudioContext("alarm");
ac.mozAudioChannelType = "alarm";
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
ac = new AudioContext("telephony");
ac.mozAudioChannelType = "telephony";
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
ac = new AudioContext("ringer");
ac.mozAudioChannelType = "ringer";
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
ac = new AudioContext("publicnotification");
ac.mozAudioChannelType = "publicnotification";
is(ac.mozAudioChannelType, "normal", "Default ac channel == 'normal'");
runTest();
@ -52,7 +56,7 @@ function test_permission(aChannel) {
SpecialPowers.pushPermissions(
[{ "type": "audio-channel-" + aChannel, "allow": true, "context": document }],
function() {
var ac = new AudioContext(aChannel);
ac.mozAudioChannelType = aChannel;
is(ac.mozAudioChannelType, aChannel, "Default ac channel == '" + aChannel + "'");
var channel = SpecialPowers.wrap(ac).testAudioChannelInAudioNodeStream();

View File

@ -51,7 +51,7 @@ URLSearchParams::Constructor(const GlobalObject& aGlobal,
ErrorResult& aRv)
{
nsRefPtr<URLSearchParams> sp = new URLSearchParams();
aInit.mSearchParams.EnumerateRead(CopyEnumerator, sp);
sp->mSearchParams = aInit.mSearchParams;
return sp.forget();
}
@ -207,20 +207,6 @@ URLSearchParams::ConvertString(const nsACString& aInput, nsAString& aOutput)
}
}
/* static */ PLDHashOperator
URLSearchParams::CopyEnumerator(const nsAString& aName,
nsTArray<nsString>* aArray,
void *userData)
{
URLSearchParams* aSearchParams = static_cast<URLSearchParams*>(userData);
nsTArray<nsString>* newArray = new nsTArray<nsString>();
newArray->AppendElements(*aArray);
aSearchParams->mSearchParams.Put(aName, newArray);
return PL_DHASH_NEXT;
}
void
URLSearchParams::AddObserver(URLSearchParamsObserver* aObserver)
{
@ -245,38 +231,46 @@ URLSearchParams::RemoveObservers()
void
URLSearchParams::Get(const nsAString& aName, nsString& aRetval)
{
nsTArray<nsString>* array;
if (!mSearchParams.Get(aName, &array)) {
aRetval.Truncate();
return;
}
aRetval.Truncate();
aRetval.Assign(array->ElementAt(0));
for (uint32_t i = 0, len = mSearchParams.Length(); i < len; ++i) {
if (mSearchParams[i].mKey.Equals(aName)) {
aRetval.Assign(mSearchParams[i].mValue);
break;
}
}
}
void
URLSearchParams::GetAll(const nsAString& aName, nsTArray<nsString>& aRetval)
{
nsTArray<nsString>* array;
if (!mSearchParams.Get(aName, &array)) {
return;
}
aRetval.Clear();
aRetval.AppendElements(*array);
for (uint32_t i = 0, len = mSearchParams.Length(); i < len; ++i) {
if (mSearchParams[i].mKey.Equals(aName)) {
aRetval.AppendElement(mSearchParams[i].mValue);
}
}
}
void
URLSearchParams::Set(const nsAString& aName, const nsAString& aValue)
{
nsTArray<nsString>* array;
if (!mSearchParams.Get(aName, &array)) {
array = new nsTArray<nsString>();
array->AppendElement(aValue);
mSearchParams.Put(aName, array);
} else {
array->ElementAt(0) = aValue;
Param* param = nullptr;
for (uint32_t i = 0, len = mSearchParams.Length(); i < len; ++i) {
if (mSearchParams[i].mKey.Equals(aName)) {
param = &mSearchParams[i];
break;
}
}
if (!param) {
param = mSearchParams.AppendElement();
param->mKey = aName;
}
param->mValue = aValue;
NotifyObservers(nullptr);
}
@ -290,32 +284,39 @@ URLSearchParams::Append(const nsAString& aName, const nsAString& aValue)
void
URLSearchParams::AppendInternal(const nsAString& aName, const nsAString& aValue)
{
nsTArray<nsString>* array;
if (!mSearchParams.Get(aName, &array)) {
array = new nsTArray<nsString>();
mSearchParams.Put(aName, array);
}
array->AppendElement(aValue);
Param* param = mSearchParams.AppendElement();
param->mKey = aName;
param->mValue = aValue;
}
bool
URLSearchParams::Has(const nsAString& aName)
{
return mSearchParams.Get(aName, nullptr);
for (uint32_t i = 0, len = mSearchParams.Length(); i < len; ++i) {
if (mSearchParams[i].mKey.Equals(aName)) {
return true;
}
}
return false;
}
void
URLSearchParams::Delete(const nsAString& aName)
{
nsTArray<nsString>* array;
if (!mSearchParams.Get(aName, &array)) {
return;
bool found = false;
for (uint32_t i = 0; i < mSearchParams.Length();) {
if (mSearchParams[i].mKey.Equals(aName)) {
mSearchParams.RemoveElementAt(i);
found = true;
} else {
++i;
}
}
mSearchParams.Remove(aName);
NotifyObservers(nullptr);
if (found) {
NotifyObservers(nullptr);
}
}
void
@ -324,67 +325,49 @@ URLSearchParams::DeleteAll()
mSearchParams.Clear();
}
class MOZ_STACK_CLASS SerializeData
namespace {
void SerializeString(const nsCString& aInput, nsAString& aValue)
{
public:
SerializeData()
: mFirst(true)
{}
const unsigned char* p = (const unsigned char*) aInput.get();
nsAutoString mValue;
bool mFirst;
void Serialize(const nsCString& aInput)
{
const unsigned char* p = (const unsigned char*) aInput.get();
while (p && *p) {
// ' ' to '+'
if (*p == 0x20) {
mValue.Append(0x2B);
// Percent Encode algorithm
} else if (*p == 0x2A || *p == 0x2D || *p == 0x2E ||
(*p >= 0x30 && *p <= 0x39) ||
(*p >= 0x41 && *p <= 0x5A) || *p == 0x5F ||
(*p >= 0x61 && *p <= 0x7A)) {
mValue.Append(*p);
} else {
mValue.AppendPrintf("%%%.2X", *p);
}
++p;
while (p && *p) {
// ' ' to '+'
if (*p == 0x20) {
aValue.Append(0x2B);
// Percent Encode algorithm
} else if (*p == 0x2A || *p == 0x2D || *p == 0x2E ||
(*p >= 0x30 && *p <= 0x39) ||
(*p >= 0x41 && *p <= 0x5A) || *p == 0x5F ||
(*p >= 0x61 && *p <= 0x7A)) {
aValue.Append(*p);
} else {
aValue.AppendPrintf("%%%.2X", *p);
}
++p;
}
};
}
} // anonymous namespace
void
URLSearchParams::Serialize(nsAString& aValue) const
{
SerializeData data;
mSearchParams.EnumerateRead(SerializeEnumerator, &data);
aValue.Assign(data.mValue);
}
aValue.Truncate();
bool first = true;
/* static */ PLDHashOperator
URLSearchParams::SerializeEnumerator(const nsAString& aName,
nsTArray<nsString>* aArray,
void *userData)
{
SerializeData* data = static_cast<SerializeData*>(userData);
for (uint32_t i = 0, len = aArray->Length(); i < len; ++i) {
if (data->mFirst) {
data->mFirst = false;
for (uint32_t i = 0, len = mSearchParams.Length(); i < len; ++i) {
if (first) {
first = false;
} else {
data->mValue.Append('&');
aValue.Append('&');
}
data->Serialize(NS_ConvertUTF16toUTF8(aName));
data->mValue.Append('=');
data->Serialize(NS_ConvertUTF16toUTF8(aArray->ElementAt(i)));
SerializeString(NS_ConvertUTF16toUTF8(mSearchParams[i].mKey), aValue);
aValue.Append('=');
SerializeString(NS_ConvertUTF16toUTF8(mSearchParams[i].mValue), aValue);
}
return PL_DHASH_NEXT;
}
void

View File

@ -10,8 +10,6 @@
#include "mozilla/ErrorResult.h"
#include "nsCycleCollectionParticipant.h"
#include "nsWrapperCache.h"
#include "nsClassHashtable.h"
#include "nsHashKeys.h"
#include "nsISupports.h"
#include "nsIUnicodeDecoder.h"
@ -92,15 +90,13 @@ private:
void NotifyObservers(URLSearchParamsObserver* aExceptObserver);
static PLDHashOperator
CopyEnumerator(const nsAString& aName, nsTArray<nsString>* aArray,
void *userData);
struct Param
{
nsString mKey;
nsString mValue;
};
static PLDHashOperator
SerializeEnumerator(const nsAString& aName, nsTArray<nsString>* aArray,
void *userData);
nsClassHashtable<nsStringHashKey, nsTArray<nsString>> mSearchParams;
nsTArray<Param> mSearchParams;
nsTArray<nsRefPtr<URLSearchParamsObserver>> mObservers;
nsCOMPtr<nsIUnicodeDecoder> mDecoder;

View File

@ -248,6 +248,33 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=887836
runTest();
}
function testOrdering() {
var a = new URLSearchParams("a=1&a=2&b=3&c=4&c=5&a=6");
is(a.toString(), "a=1&a=2&b=3&c=4&c=5&a=6", "Order is correct");
is(a.getAll('a').length, 3, "Correct length of getAll()");
var b = new URLSearchParams();
b.append('a', '1');
b.append('b', '2');
b.append('a', '3');
is(b.toString(), "a=1&b=2&a=3", "Order is correct");
is(b.getAll('a').length, 2, "Correct length of getAll()");
runTest();
}
function testDelete() {
var a = new URLSearchParams("a=1&a=2&b=3&c=4&c=5&a=6");
is(a.toString(), "a=1&a=2&b=3&c=4&c=5&a=6", "Order is correct");
is(a.getAll('a').length, 3, "Correct length of getAll()");
a.delete('a');
is(a.getAll('a').length, 0, "Correct length of getAll()");
is(a.toString(), "b=3&c=4&c=5", "Order is correct");
runTest();
}
var tests = [
testSimpleURLSearchParams,
testCopyURLSearchParams,
@ -256,7 +283,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=887836
function() { testElement(document.getElementById('anchor')) },
function() { testElement(document.getElementById('area')) },
testEncoding,
testMultiURL
testMultiURL,
testOrdering,
testDelete
];
function runTest() {

View File

@ -4,4 +4,4 @@ support-files =
process_error_contentscript.js
[test_process_error.xul]
skip-if = buildapp == "mulet"
skip-if = buildapp == "mulet" || !crashreporter

View File

@ -20,9 +20,6 @@ CSPROViolationWithURI = The page's settings observed the loading of a resource a
# LOCALIZATION NOTE (triedToSendReport):
# %1$S is the URI we attempted to send a report to.
triedToSendReport = Tried to send report to invalid URI: "%1$S"
# LOCALIZATION NOTE (errorWas):
# %1$S is the error resulting from attempting to send the report
errorWas = error was: "%1$S"
# LOCALIZATION NOTE (couldNotParseReportURI):
# %1$S is the report URI that could not be parsed
couldNotParseReportURI = couldn't parse report URI: %1$S
@ -38,21 +35,9 @@ reportURInotHttpsOrHttp2 = The report URI (%1$S) should be an HTTP or HTTPS URI.
# LOCALIZATION NOTE (reportURInotInReportOnlyHeader):
# %1$S is the ETLD of the page with the policy
reportURInotInReportOnlyHeader = This site (%1$S) has a Report-Only policy without a report URI. CSP will not block and cannot report violations of this policy.
# LOCALIZATION NOTE (pageCannotSendReportsTo):
# %1$S is the URI of the page with the policy
# %2$S is the report URI that could not be used
pageCannotSendReportsTo = page on %1$S cannot send reports to %2$S
allowOrDefaultSrcRequired = 'allow' or 'default-src' directive required but not present. Reverting to "default-src 'none'"
# LOCALIZATION NOTE (failedToParseUnrecognizedSource):
# %1$S is the CSP Source that could not be parsed
failedToParseUnrecognizedSource = Failed to parse unrecognized source %1$S
# LOCALIZATION NOTE (reportPostRedirect):
# %1$S is the specified report URI before redirect
reportPostRedirect = Post of violation report to %1$S failed, as a redirect occurred
# LOCALIZATION NOTE (allowDirectiveIsDeprecated):
# Don't translate "allow" and "default-src" as they are keywords and part of
# the CSP protocol syntax.
allowDirectiveIsDeprecated = allow directive is deprecated, use the equivalent default-src directive instead
# LOCALIZATION NOTE (inlineScriptBlocked):
# inline script refers to JavaScript code that is embedded into the HTML document.
inlineScriptBlocked = An attempt to execute inline scripts has been blocked
@ -70,39 +55,9 @@ hostNameMightBeKeyword = Interpreting %1$S as a hostname, not a keyword. If you
notSupportingDirective = Not supporting directive '%1$S'. Directive and values will be ignored.
# CSP Errors:
policyURINotAlone = policy-uri directive can only appear alone
noParentRequest = The policy-uri cannot be fetched without a parent request and a CSP.
# LOCALIZATION NOTE (policyURIParseError):
# %1$S is the URI that could not be parsed
policyURIParseError = could not parse URI in policy URI: %1$S
# LOCALIZATION NOTE (nonMatchingHost):
# %1$S is the URI host that does not match
nonMatchingHost = can't fetch policy uri from non-matching hostname: %1$S
# LOCALIZATION NOTE (nonMatchingPort):
# %1$S is the URI port that does not match
nonMatchingPort = can't fetch policy uri from non-matching port: %1$S
# LOCALIZATION NOTE (nonMatchingScheme):
# %1$S is the URI scheme that does not match
nonMatchingScheme = can't fetch policy uri from non-matching scheme: %1$S
# LOCALIZATION NOTE (errorFetchingPolicy):
# %1$S is the error that caused fetching to fail
errorFetchingPolicy = Error fetching policy-uri: %1$S
cspSourceNotURI = Provided argument is not an nsIURI
argumentIsNotString = Provided argument is not a string
selfDataNotProvided = Can't use 'self' if self data is not provided
# LOCALIZATION NOTE (uriWithoutScheme):
# %1$S is the URI without a scheme
uriWithoutScheme = can't parse a URI without a scheme: %1$S
selfKeywordNoSelfData = self keyword used, but no self data specified
# LOCALIZATION NOTE (couldntParseInvalidSource):
# %1$S is the source that could not be parsed
couldntParseInvalidSource = Couldn't parse invalid source %1$S
# LOCALIZATION NOTE (hostSourceWithoutData):
# %1$S is the source
hostSourceWithoutData = Can't create host-only source %1$S without 'self' data
# LOCALIZATION NOTE (sourceWithoutData):
# %1$S is the source
sourceWithoutData = Can't create source %1$S without 'self' data
# LOCALIZATION NOTE (couldntParseInvalidHost):
# %1$S is the host that's invalid
couldntParseInvalidHost = Couldn't parse invalid host %1$S
@ -112,21 +67,6 @@ couldntParseScheme = Couldn't parse scheme in %1$S
# LOCALIZATION NOTE (couldntParsePort):
# %1$S is the string source
couldntParsePort = Couldn't parse port in %1$S
# LOCALIZATION NOTE (notIntersectPort):
# %1$S is one source we tried to intersect
# %2$S is the other
notIntersectPort = Could not intersect %1$S with %2$S due to port problems.
# LOCALIZATION NOTE (notIntersectScheme):
# %1$S is one source we tried to intersect
# %2$S is the other
notIntersectScheme = Could not intersect %1$S with %2$S due to scheme problems.
# LOCALIZATION NOTE (intersectingSourceWithUndefinedHost):
# %1$S is the source
intersectingSourceWithUndefinedHost = intersecting source with undefined host: %1$S
# LOCALIZATION NOTE (intersectingSourcesWithUndefinedHosts):
# %1$S is the first source
# %2$S is the second source
intersectingSourcesWithUndefinedHosts = intersecting two sources with undefined hosts: %1$S and %2$S
# LOCALIZATION NOTE (duplicateDirective):
# %1$S is the name of the duplicate directive
duplicateDirective = Duplicate %1$S directives detected. All but the first instance will be ignored.

View File

@ -78,8 +78,8 @@ interface AudioContext : EventTarget {
// Mozilla extensions
partial interface AudioContext {
// Read AudioChannel.webidl for more information about this attribute.
[Pref="media.useAudioChannelService"]
readonly attribute AudioChannel mozAudioChannelType;
[Pref="media.useAudioChannelService", SetterThrows]
attribute AudioChannel mozAudioChannelType;
// These 2 events are dispatched when the AudioContext object is muted by
// the AudioChannelService. It's call 'interrupt' because when this event is

View File

@ -1,5 +1,6 @@
[DEFAULT]
[test_bug1072116.html]
[test_bug319374.xhtml]
[test_bug427060.html]
[test_bug440974.html]

View File

@ -0,0 +1,37 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1072116
-->
<head>
<title>Test for Bug 1072116</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1072116">Mozilla Bug 1072116</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 1072116 **/
var attr = document.createAttribute("c");
var xpathExpr = document.createExpression('a', null);
var status = false;
try {
xpathExpr.evaluate(attr, null, null, null, null);
} catch(e) {
status = true;
}
ok(status, "Still alive \\o/");
</script>
</pre>
</body>
</html>

View File

@ -145,6 +145,11 @@ XPathExpression::EvaluateWithContext(nsINode& aContextNode,
}
nsAutoPtr<txXPathNode> contextNode(txXPathNativeNode::createXPathNode(&aContextNode));
if (!contextNode) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
EvalContextImpl eContext(*contextNode, aContextPosition, aContextSize,
mRecycler);
nsRefPtr<txAExprResult> exprResult;

View File

@ -1210,16 +1210,16 @@ DrawTargetD2D1::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha)
}
D2D1_RECT_F samplingBounds;
Matrix mat = pat->mMatrix;
if (!pat->mSamplingRect.IsEmpty()) {
samplingBounds = D2DRect(pat->mSamplingRect);
mat.PreTranslate(pat->mSamplingRect.x, pat->mSamplingRect.y);
} else {
samplingBounds = D2D1::RectF(0, 0,
Float(pat->mSurface->GetSize().width),
Float(pat->mSurface->GetSize().height));
}
Matrix mat = pat->mMatrix;
RefPtr<ID2D1ImageBrush> imageBrush;
RefPtr<ID2D1Image> image = GetImageForSurface(pat->mSurface, mat, pat->mExtendMode);
mDC->CreateImageBrush(image,

View File

@ -11,6 +11,7 @@
#include "Point.h"
#include <math.h>
#include "mozilla/Attributes.h"
#include "mozilla/DebugOnly.h"
namespace mozilla {
namespace gfx {
@ -186,6 +187,14 @@ public:
return true;
}
Matrix Inverse() const
{
Matrix clone = *this;
DebugOnly<bool> inverted = clone.Invert();
MOZ_ASSERT(inverted, "Attempted to get the inverse of a non-invertible matrix");
return clone;
}
Float Determinant() const
{
return _11 * _22 - _12 * _21;
@ -671,6 +680,14 @@ public:
bool Invert();
Matrix4x4 Inverse() const
{
Matrix4x4 clone = *this;
DebugOnly<bool> inverted = clone.Invert();
MOZ_ASSERT(inverted, "Attempted to get the inverse of a non-invertible matrix");
return clone;
}
void Normalize()
{
for (int i = 0; i < 4; i++) {

View File

@ -326,7 +326,7 @@ ScaledFontDWrite::GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget
void
ScaledFontDWrite::CopyGlyphsToBuilder(const GlyphBuffer &aBuffer, PathBuilder *aBuilder, BackendType aBackendType, const Matrix *aTransformHint)
{
if (aBackendType != BackendType::DIRECT2D) {
if (aBackendType != BackendType::DIRECT2D && aBackendType != BackendType::DIRECT2D1_1) {
ScaledFontBase::CopyGlyphsToBuilder(aBuffer, aBuilder, aBackendType, aTransformHint);
return;
}

View File

@ -902,17 +902,13 @@ TransformDisplacement(APZCTreeManager* aTreeManager,
AsyncPanZoomController* aTarget,
ScreenPoint& aStartPoint,
ScreenPoint& aEndPoint) {
Matrix4x4 transformToApzc;
// Convert start and end points to untransformed screen coordinates.
transformToApzc = aTreeManager->GetScreenToApzcTransform(aSource);
Matrix4x4 untransformToApzc = transformToApzc;
untransformToApzc.Invert();
Matrix4x4 untransformToApzc = aTreeManager->GetScreenToApzcTransform(aSource).Inverse();
ApplyTransform(&aStartPoint, untransformToApzc);
ApplyTransform(&aEndPoint, untransformToApzc);
// Convert start and end points to aTarget's transformed screen coordinates.
transformToApzc = aTreeManager->GetScreenToApzcTransform(aTarget);
Matrix4x4 transformToApzc = aTreeManager->GetScreenToApzcTransform(aTarget);
ApplyTransform(&aStartPoint, transformToApzc);
ApplyTransform(&aEndPoint, transformToApzc);
}
@ -1192,8 +1188,7 @@ APZCTreeManager::GetAPZCAtPoint(AsyncPanZoomController* aApzc,
// to aApzc's parent layer's layer coordinates.
// It is PC.Inverse() * OC.Inverse() * NC.Inverse() * MC.Inverse() at recursion level for L,
// and RC.Inverse() * QC.Inverse() at recursion level for P.
Matrix4x4 ancestorUntransform = aApzc->GetAncestorTransform();
ancestorUntransform.Invert();
Matrix4x4 ancestorUntransform = aApzc->GetAncestorTransform().Inverse();
// Hit testing for this layer takes place in our parent layer coordinates,
// since the composition bounds (used to initialize the visible rect against
@ -1207,9 +1202,7 @@ APZCTreeManager::GetAPZCAtPoint(AsyncPanZoomController* aApzc,
// to aApzc's CSS-transformed layer coordinates.
// It is PC.Inverse() * OC.Inverse() * NC.Inverse() * MC.Inverse() * LA.Inverse() at L
// and RC.Inverse() * QC.Inverse() * PA.Inverse() at P.
Matrix4x4 asyncUntransform = aApzc->GetCurrentAsyncTransform();
asyncUntransform.Invert();
Matrix4x4 childUntransform = ancestorUntransform * asyncUntransform;
Matrix4x4 childUntransform = ancestorUntransform * Matrix4x4(aApzc->GetCurrentAsyncTransform()).Inverse();
Point4D hitTestPointForChildLayers = childUntransform.ProjectPoint(aHitTestPoint);
APZCTM_LOG("Untransformed %f %f to layer coordinates %f %f for APZC %p\n",
aHitTestPoint.x, aHitTestPoint.y,
@ -1356,19 +1349,16 @@ APZCTreeManager::GetScreenToApzcTransform(const AsyncPanZoomController *aApzc) c
// leftmost matrix in a multiplication is applied first.
// ancestorUntransform is PC.Inverse() * OC.Inverse() * NC.Inverse() * MC.Inverse()
Matrix4x4 ancestorUntransform = aApzc->GetAncestorTransform();
ancestorUntransform.Invert();
Matrix4x4 ancestorUntransform = aApzc->GetAncestorTransform().Inverse();
// result is initialized to PC.Inverse() * OC.Inverse() * NC.Inverse() * MC.Inverse()
result = ancestorUntransform;
for (AsyncPanZoomController* parent = aApzc->GetParent(); parent; parent = parent->GetParent()) {
// ancestorUntransform is updated to RC.Inverse() * QC.Inverse() when parent == P
ancestorUntransform = parent->GetAncestorTransform();
ancestorUntransform.Invert();
ancestorUntransform = parent->GetAncestorTransform().Inverse();
// asyncUntransform is updated to PA.Inverse() when parent == P
Matrix4x4 asyncUntransform = parent->GetCurrentAsyncTransform();
asyncUntransform.Invert();
Matrix4x4 asyncUntransform = Matrix4x4(parent->GetCurrentAsyncTransform()).Inverse();
// untransformSinceLastApzc is RC.Inverse() * QC.Inverse() * PA.Inverse()
Matrix4x4 untransformSinceLastApzc = ancestorUntransform * asyncUntransform;
@ -1400,8 +1390,7 @@ APZCTreeManager::GetApzcToGeckoTransform(const AsyncPanZoomController *aApzc) co
// leftmost matrix in a multiplication is applied first.
// asyncUntransform is LA.Inverse()
Matrix4x4 asyncUntransform = aApzc->GetCurrentAsyncTransform();
asyncUntransform.Invert();
Matrix4x4 asyncUntransform = Matrix4x4(aApzc->GetCurrentAsyncTransform()).Inverse();
// aTransformToGeckoOut is initialized to LA.Inverse() * LD * MC * NC * OC * PC
result = asyncUntransform * aApzc->GetTransformToLastDispatchedPaint() * aApzc->GetAncestorTransform();

View File

@ -341,8 +341,6 @@ public:
nsRefPtr<const OverscrollHandoffChain> aOverscrollHandoffChain,
bool aHandoff);
void SnapBackOverscrolledApzc(AsyncPanZoomController* aStart);
/*
* Build the chain of APZCs that will handle overscroll for a pan starting at |aInitialTarget|.
*/

View File

@ -520,7 +520,8 @@ public:
// is this one, then the SetState(NOTHING) in UpdateAnimation will
// stomp on the SetState(SNAP_BACK) it does.
mDeferredTasks.append(NewRunnableMethod(mOverscrollHandoffChain.get(),
&OverscrollHandoffChain::SnapBackOverscrolledApzc));
&OverscrollHandoffChain::SnapBackOverscrolledApzc,
&mApzc));
return false;
}
@ -1742,9 +1743,8 @@ static void TransformVector(const Matrix4x4& aTransform,
void AsyncPanZoomController::ToGlobalScreenCoordinates(ScreenPoint* aVector,
const ScreenPoint& aAnchor) const {
if (APZCTreeManager* treeManagerLocal = GetApzcTreeManager()) {
Matrix4x4 transform = treeManagerLocal->GetScreenToApzcTransform(this);
transform.Invert();
TransformVector(transform, aVector, aAnchor);
Matrix4x4 apzcToScreen = treeManagerLocal->GetScreenToApzcTransform(this).Inverse();
TransformVector(apzcToScreen, aVector, aAnchor);
}
}

View File

@ -88,18 +88,19 @@ OverscrollHandoffChain::ClearOverscroll() const
}
void
OverscrollHandoffChain::SnapBackOverscrolledApzc() const
OverscrollHandoffChain::SnapBackOverscrolledApzc(const AsyncPanZoomController* aStart) const
{
uint32_t i = 0;
for (i = 0; i < Length(); ++i) {
uint32_t i = IndexOf(aStart);
for (; i < Length(); ++i) {
AsyncPanZoomController* apzc = mChain[i];
if (!apzc->IsDestroyed() && apzc->SnapBackIfOverscrolled()) {
// At most one APZC along the hand-off chain can be overscrolled.
// At most one APZC from |aStart| onwards can be overscrolled.
break;
}
}
// In debug builds, verify our assumption that only one APZC is overscrolled.
// In debug builds, verify our assumption that only one APZC from |aStart|
// onwards is overscrolled.
#ifdef DEBUG
++i;
for (; i < Length(); ++i) {

View File

@ -98,8 +98,9 @@ public:
// Clear overscroll all the way up the chain.
void ClearOverscroll() const;
// Snap back the APZC that is overscrolled, if any.
void SnapBackOverscrolledApzc() const;
// Snap back the APZC that is overscrolled on the subset of the chain from
// |aStart| onwards, if any.
void SnapBackOverscrolledApzc(const AsyncPanZoomController* aStart) const;
// Determine whether the given APZC, or any APZC further in the chain,
// has room to be panned.

View File

@ -512,7 +512,7 @@ TileClient::TileClient(const TileClient& o)
mFrontBufferOnWhite = o.mFrontBufferOnWhite;
mBackLock = o.mBackLock;
mFrontLock = o.mFrontLock;
mCompositableClient = nullptr;
mCompositableClient = o.mCompositableClient;
#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
mLastUpdate = o.mLastUpdate;
#endif
@ -531,7 +531,7 @@ TileClient::operator=(const TileClient& o)
mFrontBufferOnWhite = o.mFrontBufferOnWhite;
mBackLock = o.mBackLock;
mFrontLock = o.mFrontLock;
mCompositableClient = nullptr;
mCompositableClient = o.mCompositableClient;
#ifdef GFX_TILEDLAYER_DEBUG_OVERLAY
mLastUpdate = o.mLastUpdate;
#endif

View File

@ -308,8 +308,7 @@ AsyncCompositionManager::AlignFixedAndStickyLayers(Layer* aLayer,
if (newCumulativeTransform.IsSingular()) {
return;
}
Matrix newCumulativeTransformInverse = newCumulativeTransform;
newCumulativeTransformInverse.Invert();
Matrix newCumulativeTransformInverse = newCumulativeTransform.Inverse();
// Now work out the translation necessary to make sure the layer doesn't
// move given the new sub-tree root transform.
@ -699,9 +698,7 @@ ApplyAsyncTransformToScrollbarForContent(Layer* aScrollbar,
Matrix4x4 asyncTransform = apzc->GetCurrentAsyncTransform();
Matrix4x4 nontransientTransform = apzc->GetNontransientAsyncTransform();
Matrix4x4 nontransientUntransform = nontransientTransform;
nontransientUntransform.Invert();
Matrix4x4 transientTransform = asyncTransform * nontransientUntransform;
Matrix4x4 transientTransform = asyncTransform * nontransientTransform.Inverse();
// |transientTransform| represents the amount by which we have scrolled and
// zoomed since the last paint. Because the scrollbar was sized and positioned based
@ -736,15 +733,15 @@ ApplyAsyncTransformToScrollbarForContent(Layer* aScrollbar,
// the content. This is needed because otherwise that transient async transform is
// part of the effective transform of this scrollbar, and the scrollbar will jitter
// as the content scrolls.
transientTransform.Invert();
transform = transform * transientTransform;
Matrix4x4 transientUntransform = transientTransform.Inverse();
transform = transform * transientUntransform;
// We also need to make a corresponding change on the clip rect of all the
// layers on the ancestor chain from the scrollbar layer up to but not
// including the layer with the async transform. Otherwise the scrollbar
// shifts but gets clipped and so appears to flicker.
for (Layer* ancestor = aScrollbar; ancestor != aContent.GetLayer(); ancestor = ancestor->GetParent()) {
TransformClipRect(ancestor, transientTransform);
TransformClipRect(ancestor, transientUntransform);
}
}

View File

@ -52,6 +52,7 @@ gfxCoreTextShaper::ShapeText(gfxContext *aContext,
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
bool aVertical,
gfxShapedText *aShapedText)
{
// Create a CFAttributedString with text and style info, so we can use CoreText to lay it out.

View File

@ -23,6 +23,7 @@ public:
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
bool aVertical,
gfxShapedText *aShapedText);
// clean up static objects that may have been cached

View File

@ -219,9 +219,10 @@ gfxDWriteFont::ComputeMetrics(AntialiasOption anAAOption)
TRUETYPE_TAG('h','h','e','a'));
if (hheaTable) {
uint32_t len;
const HheaTable* hhea =
reinterpret_cast<const HheaTable*>(hb_blob_get_data(hheaTable, &len));
if (len >= sizeof(HheaTable)) {
const MetricsHeader* hhea =
reinterpret_cast<const MetricsHeader*>
(hb_blob_get_data(hheaTable, &len));
if (len >= sizeof(MetricsHeader)) {
mMetrics->maxAdvance =
uint16_t(hhea->advanceWidthMax) * mFUnitsConvFactor;
}

View File

@ -48,10 +48,11 @@ gfxFT2Font::ShapeText(gfxContext *aContext,
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
bool aVertical,
gfxShapedText *aShapedText)
{
if (!gfxFont::ShapeText(aContext, aText, aOffset, aLength, aScript,
aShapedText)) {
aVertical, aShapedText)) {
// harfbuzz must have failed(?!), just render raw glyphs
AddRange(aText, aOffset, aLength, aShapedText);
PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText);

View File

@ -77,6 +77,7 @@ protected:
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
bool aVertical,
gfxShapedText *aShapedText);
void FillGlyphDataForChar(uint32_t ch, CachedGlyphData *gd);

View File

@ -1692,16 +1692,28 @@ gfxFont::DrawOneGlyph(uint32_t aGlyphID, double aAdvance, gfxPoint *aPt,
const TextRunDrawParams& runParams(aBuffer.mRunParams);
const FontDrawParams& fontParams(aBuffer.mFontParams);
double glyphX;
if (runParams.isRTL) {
aPt->x -= aAdvance;
double glyphX, glyphY;
if (fontParams.isVerticalFont) {
glyphX = aPt->x;
if (runParams.isRTL) {
aPt->y -= aAdvance;
glyphY = aPt->y;
} else {
glyphY = aPt->y;
aPt->y += aAdvance;
}
} else {
glyphX = aPt->x;
aPt->x += aAdvance;
glyphY = aPt->y;
if (runParams.isRTL) {
aPt->x -= aAdvance;
glyphX = aPt->x;
} else {
glyphX = aPt->x;
aPt->x += aAdvance;
}
}
gfxPoint devPt(ToDeviceUnits(glyphX, runParams.devPerApp),
ToDeviceUnits(aPt->y, runParams.devPerApp));
ToDeviceUnits(glyphY, runParams.devPerApp));
if (fontParams.haveSVGGlyphs) {
if (!runParams.paintSVGGlyphs) {
@ -1727,7 +1739,11 @@ gfxFont::DrawOneGlyph(uint32_t aGlyphID, double aAdvance, gfxPoint *aPt,
// Synthetic bolding (if required) by multi-striking.
for (int32_t i = 0; i < fontParams.extraStrikes; ++i) {
devPt.x += fontParams.synBoldOnePixelOffset;
if (fontParams.isVerticalFont) {
devPt.y += fontParams.synBoldOnePixelOffset;
} else {
devPt.x += fontParams.synBoldOnePixelOffset;
}
aBuffer.OutputGlyph(aGlyphID, devPt);
}
@ -1747,8 +1763,10 @@ gfxFont::DrawGlyphs(gfxShapedText *aShapedText,
bool emittedGlyphs = false;
GlyphBufferAzure buffer(aRunParams, aFontParams);
gfxFloat& inlineCoord = aFontParams.isVerticalFont ? aPt->y : aPt->x;
if (aRunParams.spacing) {
aPt->x += aRunParams.direction * aRunParams.spacing[0].mBefore;
inlineCoord += aRunParams.direction * aRunParams.spacing[0].mBefore;
}
const gfxShapedText::CompressedGlyph *glyphData =
@ -1767,22 +1785,31 @@ gfxFont::DrawGlyphs(gfxShapedText *aShapedText,
NS_ASSERTION(details, "detailedGlyph should not be missing!");
for (uint32_t j = 0; j < glyphCount; ++j, ++details) {
double advance = details->mAdvance;
if (glyphData->IsMissing()) {
// Default-ignorable chars will have zero advance width;
// we don't have to draw the hexbox for them.
if (aRunParams.drawMode != DrawMode::GLYPH_PATH &&
advance > 0) {
double glyphX = aPt->x;
double glyphY = aPt->y;
if (aRunParams.isRTL) {
glyphX -= advance;
if (aFontParams.isVerticalFont) {
glyphY -= advance;
} else {
glyphX -= advance;
}
}
gfxPoint pt(ToDeviceUnits(glyphX, aRunParams.devPerApp),
ToDeviceUnits(aPt->y, aRunParams.devPerApp));
ToDeviceUnits(glyphY, aRunParams.devPerApp));
gfxFloat advanceDevUnits =
ToDeviceUnits(advance, aRunParams.devPerApp);
gfxFloat height = GetMetrics(eHorizontal).maxAscent;
gfxRect glyphRect(pt.x, pt.y - height,
advanceDevUnits, height);
gfxRect glyphRect = aFontParams.isVerticalFont ?
gfxRect(pt.x - height / 2, pt.y,
height, advanceDevUnits) :
gfxRect(pt.x, pt.y - height,
advanceDevUnits, height);
// If there's a fake-italic skew in effect as part
// of the drawTarget's transform, we need to remove
@ -1806,12 +1833,18 @@ gfxFont::DrawGlyphs(gfxShapedText *aShapedText,
}
} else {
gfxPoint glyphXY(*aPt);
glyphXY.x += details->mXOffset;
glyphXY.y += details->mYOffset;
if (aFontParams.isVerticalFont) {
glyphXY.x += details->mYOffset;
glyphXY.y += details->mXOffset;
} else {
glyphXY.x += details->mXOffset;
glyphXY.y += details->mYOffset;
}
DrawOneGlyph(details->mGlyphID, advance, &glyphXY,
buffer, &emittedGlyphs);
}
aPt->x += aRunParams.direction * advance;
inlineCoord += aRunParams.direction * advance;
}
}
}
@ -1821,7 +1854,7 @@ gfxFont::DrawGlyphs(gfxShapedText *aShapedText,
if (i + 1 < aCount) {
space += aRunParams.spacing[i + 1].mBefore;
}
aPt->x += aRunParams.direction * space;
inlineCoord += aRunParams.direction * space;
}
}
@ -1830,7 +1863,8 @@ gfxFont::DrawGlyphs(gfxShapedText *aShapedText,
void
gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
gfxPoint *aPt, const TextRunDrawParams& aRunParams)
gfxPoint *aPt, const TextRunDrawParams& aRunParams,
uint16_t aOrientation)
{
NS_ASSERTION(aRunParams.drawMode == DrawMode::GLYPH_PATH ||
!(int(aRunParams.drawMode) & int(DrawMode::GLYPH_PATH)),
@ -1850,6 +1884,34 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
fontParams.haveSVGGlyphs = GetFontEntry()->TryGetSVGData(this);
fontParams.haveColorGlyphs = GetFontEntry()->TryGetColorGlyphs();
fontParams.contextPaint = aRunParams.runContextPaint;
fontParams.isVerticalFont =
aOrientation == gfxTextRunFactory::TEXT_ORIENT_VERTICAL_UPRIGHT;
bool sideways = false;
gfxPoint origPt = *aPt;
if (aRunParams.isVerticalRun && !fontParams.isVerticalFont) {
sideways = true;
aRunParams.context->Save();
gfxPoint p(aPt->x * aRunParams.devPerApp,
aPt->y * aRunParams.devPerApp);
const Metrics& metrics = GetMetrics(eHorizontal);
// Adjust the matrix to draw the (horizontally-shaped) textrun with
// 90-degree CW rotation, and adjust position so that the rotated
// horizontal text (which uses a standard alphabetic baseline) will
// look OK when juxtaposed with upright glyphs (rendered on a centered
// vertical baseline). The adjustment here is somewhat ad hoc; we
// should eventually look for baseline tables[1] in the fonts and use
// those if available.
// [1] http://www.microsoft.com/typography/otspec/base.htm
aRunParams.context->SetMatrix(aRunParams.context->CurrentMatrix().
Translate(p). // translate origin for rotation
Rotate(M_PI / 2.0). // turn 90deg clockwise
Translate(-p). // undo the translation
Translate(gfxPoint(0, metrics.emAscent - metrics.emDescent) / 2));
// and offset the (alphabetic) baseline of the
// horizontally-shaped text from the (centered)
// default baseline used for vertical
}
nsAutoPtr<gfxTextContextPaint> contextPaint;
if (fontParams.haveSVGGlyphs && !fontParams.contextPaint) {
@ -1920,16 +1982,18 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
}
}
double origY = aPt->y;
gfxFloat& baseline = fontParams.isVerticalFont ? aPt->x : aPt->y;
gfxFloat origBaseline = baseline;
if (mStyle.baselineOffset != 0.0) {
aPt->y += mStyle.baselineOffset * aTextRun->GetAppUnitsPerDevUnit();
baseline +=
mStyle.baselineOffset * aTextRun->GetAppUnitsPerDevUnit();
}
bool emittedGlyphs =
DrawGlyphs(aTextRun, aStart, aEnd - aStart, aPt,
aRunParams, fontParams);
aPt->y = origY;
baseline = origBaseline;
if (aRunParams.callbacks && emittedGlyphs) {
aRunParams.callbacks->NotifyGlyphPathEmitted();
@ -1937,6 +2001,11 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
aRunParams.dt->SetTransform(oldMat);
aRunParams.dt->SetPermitSubpixelAA(oldSubpixelAA);
if (sideways) {
aRunParams.context->Restore();
*aPt = gfxPoint(origPt.x, origPt.y + (aPt->x - origPt.x));
}
}
bool
@ -2214,6 +2283,7 @@ gfxFont::GetShapedWord(gfxContext *aContext,
uint32_t aLength,
uint32_t aHash,
int32_t aRunScript,
bool aVertical,
int32_t aAppUnitsPerDevUnit,
uint32_t aFlags,
gfxTextPerfMetrics *aTextPerf GFX_MAYBE_UNUSED)
@ -2273,7 +2343,7 @@ gfxFont::GetShapedWord(gfxContext *aContext,
}
DebugOnly<bool> ok =
ShapeText(aContext, aText, 0, aLength, aRunScript, sw);
ShapeText(aContext, aText, 0, aLength, aRunScript, aVertical, sw);
NS_WARN_IF_FALSE(ok, "failed to shape word - expect garbled text");
@ -2323,6 +2393,7 @@ gfxFont::ShapeText(gfxContext *aContext,
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
bool aVertical,
gfxShapedText *aShapedText)
{
nsDependentCSubstring ascii((const char*)aText, aLength);
@ -2332,7 +2403,7 @@ gfxFont::ShapeText(gfxContext *aContext,
return false;
}
return ShapeText(aContext, utf16.BeginReading(), aOffset, aLength,
aScript, aShapedText);
aScript, aVertical, aShapedText);
}
bool
@ -2341,17 +2412,20 @@ gfxFont::ShapeText(gfxContext *aContext,
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
bool aVertical,
gfxShapedText *aShapedText)
{
bool ok = false;
if (FontCanSupportGraphite()) {
// XXX Currently, we do all vertical shaping through harfbuzz.
// Vertical graphite support may be wanted as a future enhancement.
if (FontCanSupportGraphite() && !aVertical) {
if (gfxPlatform::GetPlatform()->UseGraphiteShaping()) {
if (!mGraphiteShaper) {
mGraphiteShaper = new gfxGraphiteShaper(this);
}
ok = mGraphiteShaper->ShapeText(aContext, aText, aOffset, aLength,
aScript, aShapedText);
aScript, aVertical, aShapedText);
}
}
@ -2360,7 +2434,7 @@ gfxFont::ShapeText(gfxContext *aContext,
mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
}
ok = mHarfBuzzShaper->ShapeText(aContext, aText, aOffset, aLength,
aScript, aShapedText);
aScript, aVertical, aShapedText);
}
NS_WARN_IF_FALSE(ok, "shaper failed, expect scrambled or missing text");
@ -2397,6 +2471,7 @@ gfxFont::ShapeFragmentWithoutWordCache(gfxContext *aContext,
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
bool aVertical,
gfxTextRun *aTextRun)
{
aTextRun->SetupClusterBoundaries(aOffset, aText, aLength);
@ -2432,7 +2507,8 @@ gfxFont::ShapeFragmentWithoutWordCache(gfxContext *aContext,
}
}
ok = ShapeText(aContext, aText, aOffset, fragLen, aScript, aTextRun);
ok = ShapeText(aContext, aText, aOffset, fragLen, aScript, aVertical,
aTextRun);
aText += fragLen;
aOffset += fragLen;
@ -2460,6 +2536,7 @@ gfxFont::ShapeTextWithoutWordCache(gfxContext *aContext,
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
bool aVertical,
gfxTextRun *aTextRun)
{
uint32_t fragStart = 0;
@ -2478,7 +2555,7 @@ gfxFont::ShapeTextWithoutWordCache(gfxContext *aContext,
if (length > 0) {
ok = ShapeFragmentWithoutWordCache(aContext, aText + fragStart,
aOffset + fragStart, length,
aScript, aTextRun);
aScript, aVertical, aTextRun);
}
if (i == aLength) {
@ -2534,7 +2611,8 @@ gfxFont::SplitAndInitTextRun(gfxContext *aContext,
const T *aString, // text for this font run
uint32_t aRunStart, // position in the textrun
uint32_t aRunLength,
int32_t aRunScript)
int32_t aRunScript,
bool aVertical)
{
if (aRunLength == 0) {
return true;
@ -2569,7 +2647,8 @@ gfxFont::SplitAndInitTextRun(gfxContext *aContext,
HasSpaces(aString, aRunLength)) {
TEXT_PERF_INCR(tp, wordCacheSpaceRules);
return ShapeTextWithoutWordCache(aContext, aString,
aRunStart, aRunLength, aRunScript,
aRunStart, aRunLength,
aRunScript, aVertical,
aTextRun);
}
}
@ -2622,6 +2701,7 @@ gfxFont::SplitAndInitTextRun(gfxContext *aContext,
aRunStart + wordStart,
length,
aRunScript,
aVertical,
aTextRun);
if (!ok) {
return false;
@ -2638,7 +2718,7 @@ gfxFont::SplitAndInitTextRun(gfxContext *aContext,
}
gfxShapedWord *sw = GetShapedWord(aContext,
aString + wordStart, length,
hash, aRunScript,
hash, aRunScript, aVertical,
appUnitsPerDevUnit,
wordFlags, tp);
if (sw) {
@ -2652,7 +2732,9 @@ gfxFont::SplitAndInitTextRun(gfxContext *aContext,
// word was terminated by a space: add that to the textrun
uint16_t orientation = flags & gfxTextRunFactory::TEXT_ORIENT_MASK;
if (orientation == gfxTextRunFactory::TEXT_ORIENT_VERTICAL_MIXED) {
orientation = gfxTextRunFactory::TEXT_ORIENT_VERTICAL_UPRIGHT;
orientation = aVertical ?
gfxTextRunFactory::TEXT_ORIENT_VERTICAL_UPRIGHT :
gfxTextRunFactory::TEXT_ORIENT_VERTICAL_SIDEWAYS_RIGHT;
}
if (!aTextRun->SetSpaceGlyphIfSimple(this, aContext,
aRunStart + i, ch,
@ -2662,7 +2744,7 @@ gfxFont::SplitAndInitTextRun(gfxContext *aContext,
gfxShapedWord *sw =
GetShapedWord(aContext,
&space, 1,
gfxShapedWord::HashMix(0, ' '), aRunScript,
gfxShapedWord::HashMix(0, ' '), aRunScript, aVertical,
appUnitsPerDevUnit,
flags | gfxTextRunFactory::TEXT_IS_8BIT, tp);
if (sw) {
@ -2711,15 +2793,17 @@ gfxFont::SplitAndInitTextRun(gfxContext *aContext,
const uint8_t *aString,
uint32_t aRunStart,
uint32_t aRunLength,
int32_t aRunScript);
int32_t aRunScript,
bool aVertical);
template bool
gfxFont::SplitAndInitTextRun(gfxContext *aContext,
gfxTextRun *aTextRun,
const char16_t *aString,
uint32_t aRunStart,
uint32_t aRunLength,
int32_t aRunScript);
int32_t aRunScript,
bool aVertical);
template<>
bool
gfxFont::InitFakeSmallCapsRun(gfxContext *aContext,
@ -2745,6 +2829,8 @@ gfxFont::InitFakeSmallCapsRun(gfxContext *aContext,
RunCaseAction runAction = kNoChange;
uint32_t runStart = 0;
bool vertical =
aOrientation == gfxTextRunFactory::TEXT_ORIENT_VERTICAL_UPRIGHT;
for (uint32_t i = 0; i <= aLength; ++i) {
uint32_t extraCodeUnits = 0; // Will be set to 1 if we need to consume
@ -2803,7 +2889,7 @@ gfxFont::InitFakeSmallCapsRun(gfxContext *aContext,
if (!f->SplitAndInitTextRun(aContext, aTextRun,
aText + runStart,
aOffset + runStart, runLength,
aScript)) {
aScript, vertical)) {
ok = false;
}
break;
@ -2844,7 +2930,7 @@ gfxFont::InitFakeSmallCapsRun(gfxContext *aContext,
if (!f->SplitAndInitTextRun(aContext, tempRun,
convertedString.BeginReading(),
0, convertedString.Length(),
aScript)) {
aScript, vertical)) {
ok = false;
} else {
nsAutoPtr<gfxTextRun> mergedRun;
@ -2863,7 +2949,7 @@ gfxFont::InitFakeSmallCapsRun(gfxContext *aContext,
if (!f->SplitAndInitTextRun(aContext, aTextRun,
convertedString.BeginReading(),
aOffset + runStart, runLength,
aScript)) {
aScript, vertical)) {
ok = false;
}
}
@ -2897,7 +2983,7 @@ gfxFont::InitFakeSmallCapsRun(gfxContext *aContext,
{
NS_ConvertASCIItoUTF16 unicodeString(reinterpret_cast<const char*>(aText),
aLength);
return InitFakeSmallCapsRun(aContext, aTextRun, unicodeString.get(),
return InitFakeSmallCapsRun(aContext, aTextRun, static_cast<const char16_t*>(unicodeString.get()),
aOffset, aLength, aMatchType, aOrientation,
aScript, aSyntheticLower, aSyntheticUpper);
}
@ -3024,9 +3110,10 @@ gfxFont::InitMetricsFromSfntTables(Metrics& aMetrics)
if (!hheaTable) {
return false; // no 'hhea' table -> not an sfnt
}
const HheaTable* hhea =
reinterpret_cast<const HheaTable*>(hb_blob_get_data(hheaTable, &len));
if (len < sizeof(HheaTable)) {
const MetricsHeader* hhea =
reinterpret_cast<const MetricsHeader*>
(hb_blob_get_data(hheaTable, &len));
if (len < sizeof(MetricsHeader)) {
return false;
}
@ -3272,10 +3359,10 @@ gfxFont::CreateVerticalMetrics()
if (!metrics->aveCharWidth) {
gfxFontEntry::AutoTable hheaTable(mFontEntry, kHheaTableTag);
if (hheaTable) {
const HheaTable* hhea =
reinterpret_cast<const HheaTable*>(hb_blob_get_data(hheaTable,
&len));
if (len >= sizeof(HheaTable)) {
const MetricsHeader* hhea =
reinterpret_cast<const MetricsHeader*>
(hb_blob_get_data(hheaTable, &len));
if (len >= sizeof(MetricsHeader)) {
SET_SIGNED(aveCharWidth, int16_t(hhea->ascender) -
int16_t(hhea->descender));
metrics->maxAscent = metrics->aveCharWidth / 2;
@ -3288,10 +3375,10 @@ gfxFont::CreateVerticalMetrics()
// Read real vertical metrics if available.
gfxFontEntry::AutoTable vheaTable(mFontEntry, kVheaTableTag);
if (vheaTable) {
const HheaTable* vhea =
reinterpret_cast<const HheaTable*>(hb_blob_get_data(vheaTable,
&len));
if (len >= sizeof(HheaTable)) {
const MetricsHeader* vhea =
reinterpret_cast<const MetricsHeader*>
(hb_blob_get_data(vheaTable, &len));
if (len >= sizeof(MetricsHeader)) {
SET_UNSIGNED(maxAdvance, vhea->advanceWidthMax);
SET_SIGNED(maxAscent, vhea->ascender);
SET_SIGNED(maxDescent, -int16_t(vhea->descender));

View File

@ -610,6 +610,7 @@ public:
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
bool aVertical,
gfxShapedText *aShapedText) = 0;
gfxFont *GetFont() const { return mFont; }
@ -1527,7 +1528,8 @@ public:
* -- all glyphs use this font
*/
void Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
gfxPoint *aPt, const TextRunDrawParams& aRunParams);
gfxPoint *aPt, const TextRunDrawParams& aRunParams,
uint16_t aOrientation);
/**
* Measure a run of characters. See gfxTextRun::Metrics.
@ -1630,7 +1632,8 @@ public:
const T *aString,
uint32_t aRunStart,
uint32_t aRunLength,
int32_t aRunScript);
int32_t aRunScript,
bool aVertical);
// Get a ShapedWord representing the given text (either 8- or 16-bit)
// for use in setting up a gfxTextRun.
@ -1640,6 +1643,7 @@ public:
uint32_t aLength,
uint32_t aHash,
int32_t aRunScript,
bool aVertical,
int32_t aAppUnitsPerDevUnit,
uint32_t aFlags,
gfxTextPerfMetrics *aTextPerf);
@ -1816,6 +1820,7 @@ protected:
uint32_t aOffset, // dest offset in gfxShapedText
uint32_t aLength,
int32_t aScript,
bool aVertical,
gfxShapedText *aShapedText); // where to store the result
// Call the appropriate shaper to generate glyphs for aText and store
@ -1825,6 +1830,7 @@ protected:
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
bool aVertical,
gfxShapedText *aShapedText);
// Helper to adjust for synthetic bold and set character-type flags
@ -1849,6 +1855,7 @@ protected:
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
bool aVertical,
gfxTextRun *aTextRun);
// Shape a fragment of text (a run that is known to contain only
@ -1862,6 +1869,7 @@ protected:
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
bool aVertical,
gfxTextRun *aTextRun);
void CheckForFeaturesInvolvingSpace();
@ -2053,6 +2061,7 @@ struct TextRunDrawParams {
gfxFloat direction;
double devPerApp;
DrawMode drawMode;
bool isVerticalRun;
bool isRTL;
bool paintSVGGlyphs;
};
@ -2066,6 +2075,7 @@ struct FontDrawParams {
double synBoldOnePixelOffset;
int32_t extraStrikes;
mozilla::gfx::DrawOptions drawOptions;
bool isVerticalFont;
bool haveSVGGlyphs;
bool haveColorGlyphs;
};

View File

@ -553,7 +553,10 @@ struct PostTable {
AutoSwap_PRUint32 maxMemType1;
};
struct HheaTable {
// This structure is used for both 'hhea' and 'vhea' tables.
// The field names here are those of the horizontal version; the
// vertical table just exchanges vertical and horizontal coordinates.
struct MetricsHeader {
AutoSwap_PRUint32 version;
AutoSwap_PRInt16 ascender;
AutoSwap_PRInt16 descender;
@ -570,7 +573,7 @@ struct HheaTable {
AutoSwap_PRInt16 reserved3;
AutoSwap_PRInt16 reserved4;
AutoSwap_PRInt16 metricDataFormat;
AutoSwap_PRUint16 numOfLongHorMetrics;
AutoSwap_PRUint16 numOfLongMetrics;
};
struct MaxpTableHeader {

View File

@ -83,6 +83,7 @@ gfxGDIFont::ShapeText(gfxContext *aContext,
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
bool aVertical,
gfxShapedText *aShapedText)
{
if (!mMetrics) {
@ -102,7 +103,7 @@ gfxGDIFont::ShapeText(gfxContext *aContext,
}
return gfxFont::ShapeText(aContext, aText, aOffset, aLength, aScript,
aShapedText);
aVertical, aShapedText);
}
const gfxFont::Metrics&

View File

@ -77,6 +77,7 @@ protected:
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
bool aVertical,
gfxShapedText *aShapedText);
void Initialize(); // creates metrics and Cairo fonts

View File

@ -89,6 +89,7 @@ gfxGraphiteShaper::ShapeText(gfxContext *aContext,
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
bool aVertical,
gfxShapedText *aShapedText)
{
// some font back-ends require this in order to get proper hinted metrics

View File

@ -22,6 +22,7 @@ public:
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
bool aVertical,
gfxShapedText *aShapedText);
static void Shutdown();

View File

@ -39,14 +39,18 @@ gfxHarfBuzzShaper::gfxHarfBuzzShaper(gfxFont *aFont)
mHBFont(nullptr),
mKernTable(nullptr),
mHmtxTable(nullptr),
mNumLongMetrics(0),
mVmtxTable(nullptr),
mVORGTable(nullptr),
mCmapTable(nullptr),
mCmapFormat(-1),
mSubtableOffset(0),
mUVSTableOffset(0),
mNumLongHMetrics(0),
mNumLongVMetrics(0),
mUseFontGetGlyph(aFont->ProvidesGetGlyph()),
mUseFontGlyphWidths(false),
mInitialized(false)
mInitialized(false),
mVerticalInitialized(false)
{
}
@ -166,30 +170,15 @@ HBGetGlyph(hb_font_t *font, void *font_data,
return *glyph != 0;
}
struct HMetricsHeader {
AutoSwap_PRUint32 tableVersionNumber;
AutoSwap_PRInt16 ascender;
AutoSwap_PRInt16 descender;
AutoSwap_PRInt16 lineGap;
AutoSwap_PRUint16 advanceWidthMax;
AutoSwap_PRInt16 minLeftSideBearing;
AutoSwap_PRInt16 minRightSideBearing;
AutoSwap_PRInt16 xMaxExtent;
AutoSwap_PRInt16 caretSlopeRise;
AutoSwap_PRInt16 caretSlopeRun;
AutoSwap_PRInt16 caretOffset;
AutoSwap_PRInt16 reserved[4];
AutoSwap_PRInt16 metricDataFormat;
AutoSwap_PRUint16 numberOfHMetrics;
// Glyph metrics structures, shared (with appropriate reinterpretation of
// field names) by horizontal and vertical metrics tables.
struct LongMetric {
AutoSwap_PRUint16 advanceWidth; // or advanceHeight, when vertical
AutoSwap_PRInt16 lsb; // or tsb, when vertical
};
struct HLongMetric {
AutoSwap_PRUint16 advanceWidth;
AutoSwap_PRInt16 lsb;
};
struct HMetrics {
HLongMetric metrics[1]; // actually numberOfHMetrics
struct GlyphMetrics {
LongMetric metrics[1]; // actually numberOfLongMetrics
// the variable-length metrics[] array is immediately followed by:
// AutoSwap_PRUint16 leftSideBearing[];
};
@ -198,23 +187,51 @@ hb_position_t
gfxHarfBuzzShaper::GetGlyphHAdvance(gfxContext *aContext,
hb_codepoint_t glyph) const
{
// font did not implement GetHintedGlyphWidth, so get an unhinted value
// font did not implement GetGlyphWidth, so get an unhinted value
// directly from the font tables
NS_ASSERTION((mNumLongMetrics > 0) && mHmtxTable != nullptr,
NS_ASSERTION((mNumLongHMetrics > 0) && mHmtxTable != nullptr,
"font is lacking metrics, we shouldn't be here");
if (glyph >= uint32_t(mNumLongMetrics)) {
glyph = mNumLongMetrics - 1;
if (glyph >= uint32_t(mNumLongHMetrics)) {
glyph = mNumLongHMetrics - 1;
}
// glyph must be valid now, because we checked during initialization
// that mNumLongMetrics is > 0, and that the hmtx table is large enough
// to contain mNumLongMetrics records
const HMetrics* hmtx =
reinterpret_cast<const HMetrics*>(hb_blob_get_data(mHmtxTable, nullptr));
// that mNumLongHMetrics is > 0, and that the metrics table is large enough
// to contain mNumLongHMetrics records
const GlyphMetrics* metrics =
reinterpret_cast<const GlyphMetrics*>(hb_blob_get_data(mHmtxTable,
nullptr));
return FloatToFixed(mFont->FUnitsToDevUnitsFactor() *
uint16_t(hmtx->metrics[glyph].advanceWidth));
uint16_t(metrics->metrics[glyph].advanceWidth));
}
hb_position_t
gfxHarfBuzzShaper::GetGlyphVAdvance(gfxContext *aContext,
hb_codepoint_t glyph) const
{
if (!mVmtxTable) {
// Must be a "vertical" font that doesn't actually have vertical metrics;
// use a fixed advance.
return FloatToFixed(mFont->GetMetrics(gfxFont::eVertical).aveCharWidth);
}
NS_ASSERTION(mNumLongVMetrics > 0,
"font is lacking metrics, we shouldn't be here");
if (glyph >= uint32_t(mNumLongVMetrics)) {
glyph = mNumLongVMetrics - 1;
}
// glyph must be valid now, because we checked during initialization
// that mNumLongVMetrics is > 0, and that the metrics table is large enough
// to contain mNumLongVMetrics records
const GlyphMetrics* metrics =
reinterpret_cast<const GlyphMetrics*>(hb_blob_get_data(mVmtxTable,
nullptr));
return FloatToFixed(mFont->FUnitsToDevUnitsFactor() *
uint16_t(metrics->metrics[glyph].advanceWidth));
}
/* static */
@ -232,6 +249,111 @@ gfxHarfBuzzShaper::HBGetGlyphHAdvance(hb_font_t *font, void *font_data,
}
}
/* static */
hb_position_t
gfxHarfBuzzShaper::HBGetGlyphVAdvance(hb_font_t *font, void *font_data,
hb_codepoint_t glyph, void *user_data)
{
const gfxHarfBuzzShaper::FontCallbackData *fcd =
static_cast<const gfxHarfBuzzShaper::FontCallbackData*>(font_data);
gfxFont *gfxfont = fcd->mShaper->GetFont();
if (gfxfont->ProvidesGlyphWidths()) {
return gfxfont->GetGlyphWidth(fcd->mContext, glyph);
} else {
return fcd->mShaper->GetGlyphVAdvance(fcd->mContext, glyph);
}
}
/* static */
hb_bool_t
gfxHarfBuzzShaper::HBGetGlyphHOrigin(hb_font_t *font, void *font_data,
hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y,
void *user_data)
{
// We work in horizontal coordinates, so no origin adjustment needed here.
return true;
}
struct VORG {
AutoSwap_PRUint16 majorVersion;
AutoSwap_PRUint16 minorVersion;
AutoSwap_PRInt16 defaultVertOriginY;
AutoSwap_PRUint16 numVertOriginYMetrics;
};
struct VORGrec {
AutoSwap_PRUint16 glyphIndex;
AutoSwap_PRInt16 vertOriginY;
};
/* static */
hb_bool_t
gfxHarfBuzzShaper::HBGetGlyphVOrigin(hb_font_t *font, void *font_data,
hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y,
void *user_data)
{
const gfxHarfBuzzShaper::FontCallbackData *fcd =
static_cast<const gfxHarfBuzzShaper::FontCallbackData*>(font_data);
fcd->mShaper->GetGlyphVOrigin(fcd->mContext, glyph, x, y);
return true;
}
void
gfxHarfBuzzShaper::GetGlyphVOrigin(gfxContext *aContext, hb_codepoint_t aGlyph,
hb_position_t *aX, hb_position_t *aY) const
{
*aX = -0.5 * GetGlyphHAdvance(aContext, aGlyph);
if (mVORGTable) {
// We checked in Initialize() that the VORG table is safely readable,
// so no length/bounds-check needed here.
const VORG* vorg =
reinterpret_cast<const VORG*>(hb_blob_get_data(mVORGTable, nullptr));
const VORGrec *lo = reinterpret_cast<const VORGrec*>(vorg + 1);
const VORGrec *hi = lo + uint16_t(vorg->numVertOriginYMetrics);
const VORGrec *limit = hi;
while (lo < hi) {
const VORGrec *mid = lo + (hi - lo) / 2;
if (uint16_t(mid->glyphIndex) < aGlyph) {
lo = mid + 1;
} else {
hi = mid;
}
}
if (lo < limit && uint16_t(lo->glyphIndex) == aGlyph) {
*aY = -FloatToFixed(GetFont()->FUnitsToDevUnitsFactor() *
int16_t(lo->vertOriginY));
} else {
*aY = -FloatToFixed(GetFont()->FUnitsToDevUnitsFactor() *
int16_t(vorg->defaultVertOriginY));
}
return;
}
// XXX should we consider using OS/2 sTypo* metrics if available?
gfxFontEntry::AutoTable hheaTable(GetFont()->GetFontEntry(),
TRUETYPE_TAG('h','h','e','a'));
if (hheaTable) {
uint32_t len;
const MetricsHeader* hhea =
reinterpret_cast<const MetricsHeader*>(hb_blob_get_data(hheaTable,
&len));
if (len >= sizeof(MetricsHeader)) {
*aY = -FloatToFixed(GetFont()->FUnitsToDevUnitsFactor() *
int16_t(hhea->ascender));
return;
}
}
NS_NOTREACHED("we shouldn't be here!");
*aY = -FloatToFixed(GetFont()->GetAdjustedSize() / 2);
}
static hb_bool_t
HBGetContourPoint(hb_font_t *font, void *font_data,
unsigned int point_index, hb_codepoint_t glyph,
@ -858,6 +980,15 @@ gfxHarfBuzzShaper::Initialize()
hb_font_funcs_set_glyph_h_advance_func(sHBFontFuncs,
HBGetGlyphHAdvance,
nullptr, nullptr);
hb_font_funcs_set_glyph_v_advance_func(sHBFontFuncs,
HBGetGlyphVAdvance,
nullptr, nullptr);
hb_font_funcs_set_glyph_h_origin_func(sHBFontFuncs,
HBGetGlyphHOrigin,
nullptr, nullptr);
hb_font_funcs_set_glyph_v_origin_func(sHBFontFuncs,
HBGetGlyphVOrigin,
nullptr, nullptr);
hb_font_funcs_set_glyph_contour_point_func(sHBFontFuncs,
HBGetContourPoint,
nullptr, nullptr);
@ -910,36 +1041,9 @@ gfxHarfBuzzShaper::Initialize()
}
if (!mUseFontGlyphWidths) {
// if font doesn't implement GetGlyphWidth, we will be reading
// the hmtx table directly;
// read mNumLongMetrics from hhea table without caching its blob,
// and preload/cache the hmtx table
gfxFontEntry::AutoTable hheaTable(entry, TRUETYPE_TAG('h','h','e','a'));
if (hheaTable) {
uint32_t len;
const HMetricsHeader* hhea =
reinterpret_cast<const HMetricsHeader*>
(hb_blob_get_data(hheaTable, &len));
if (len >= sizeof(HMetricsHeader)) {
mNumLongMetrics = hhea->numberOfHMetrics;
if (mNumLongMetrics > 0 &&
int16_t(hhea->metricDataFormat) == 0) {
// no point reading hmtx if number of entries is zero!
// in that case, we won't be able to use this font
// (this method will return FALSE below if mHmtx is null)
mHmtxTable =
entry->GetFontTable(TRUETYPE_TAG('h','m','t','x'));
if (hb_blob_get_length(mHmtxTable) <
mNumLongMetrics * sizeof(HLongMetric)) {
// hmtx table is not large enough for the claimed
// number of entries: invalid, do not use.
hb_blob_destroy(mHmtxTable);
mHmtxTable = nullptr;
}
}
}
}
if (!mHmtxTable) {
// If font doesn't implement GetGlyphWidth, we will be reading
// the metrics table directly, so make sure we can load it.
if (!LoadHmtxTable()) {
return false;
}
}
@ -953,12 +1057,109 @@ gfxHarfBuzzShaper::Initialize()
return true;
}
bool
gfxHarfBuzzShaper::LoadHmtxTable()
{
// Read mNumLongHMetrics from metrics-head table without caching its
// blob, and preload/cache the metrics table.
gfxFontEntry *entry = mFont->GetFontEntry();
gfxFontEntry::AutoTable hheaTable(entry, TRUETYPE_TAG('h','h','e','a'));
if (hheaTable) {
uint32_t len;
const MetricsHeader* hhea =
reinterpret_cast<const MetricsHeader*>
(hb_blob_get_data(hheaTable, &len));
if (len >= sizeof(MetricsHeader)) {
mNumLongHMetrics = hhea->numOfLongMetrics;
if (mNumLongHMetrics > 0 &&
int16_t(hhea->metricDataFormat) == 0) {
// no point reading metrics if number of entries is zero!
// in that case, we won't be able to use this font
// (this method will return FALSE below if mHmtxTable
// is null)
mHmtxTable = entry->GetFontTable(TRUETYPE_TAG('h','m','t','x'));
if (hb_blob_get_length(mHmtxTable) <
mNumLongHMetrics * sizeof(LongMetric)) {
// metrics table is not large enough for the claimed
// number of entries: invalid, do not use.
hb_blob_destroy(mHmtxTable);
mHmtxTable = nullptr;
}
}
}
}
if (!mHmtxTable) {
return false;
}
return true;
}
bool
gfxHarfBuzzShaper::InitializeVertical()
{
if (!mHmtxTable) {
if (!LoadHmtxTable()) {
return false;
}
}
// Load vertical metrics if present in the font; if not, we'll synthesize
// vertical glyph advances based on (horizontal) ascent/descent metrics.
gfxFontEntry *entry = mFont->GetFontEntry();
gfxFontEntry::AutoTable vheaTable(entry, TRUETYPE_TAG('v','h','e','a'));
if (vheaTable) {
uint32_t len;
const MetricsHeader* vhea =
reinterpret_cast<const MetricsHeader*>
(hb_blob_get_data(vheaTable, &len));
if (len >= sizeof(MetricsHeader)) {
mNumLongVMetrics = vhea->numOfLongMetrics;
if (mNumLongVMetrics > 0 &&
int16_t(vhea->metricDataFormat) == 0) {
mVmtxTable = entry->GetFontTable(TRUETYPE_TAG('v','m','t','x'));
if (hb_blob_get_length(mVmtxTable) <
mNumLongVMetrics * sizeof(LongMetric)) {
// metrics table is not large enough for the claimed
// number of entries: invalid, do not use.
hb_blob_destroy(mVmtxTable);
mVmtxTable = nullptr;
}
}
}
}
// For CFF fonts only, load a VORG table if present.
if (entry->HasFontTable(TRUETYPE_TAG('C','F','F',' '))) {
mVORGTable = entry->GetFontTable(TRUETYPE_TAG('V','O','R','G'));
if (mVORGTable) {
uint32_t len;
const VORG* vorg =
reinterpret_cast<const VORG*>(hb_blob_get_data(mVORGTable,
&len));
if (len < sizeof(VORG) ||
uint16_t(vorg->majorVersion) != 1 ||
uint16_t(vorg->minorVersion) != 0 ||
len < sizeof(VORG) + uint16_t(vorg->numVertOriginYMetrics) *
sizeof(VORGrec)) {
// VORG table is an unknown version, or not large enough
// to be valid -- discard it.
NS_WARNING("discarding invalid VORG table");
hb_blob_destroy(mVORGTable);
mVORGTable = nullptr;
}
}
}
return true;
}
bool
gfxHarfBuzzShaper::ShapeText(gfxContext *aContext,
const char16_t *aText,
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
bool aVertical,
gfxShapedText *aShapedText)
{
// some font back-ends require this in order to get proper hinted metrics
@ -972,6 +1173,12 @@ gfxHarfBuzzShaper::ShapeText(gfxContext *aContext,
return false;
}
if (aVertical) {
if (!InitializeVertical()) {
return false;
}
}
const gfxFontStyle *style = mFont->GetStyle();
nsAutoTArray<hb_feature_t,20> features;
@ -1007,8 +1214,11 @@ gfxHarfBuzzShaper::ShapeText(gfxContext *aContext,
bool isRightToLeft = aShapedText->IsRightToLeft();
hb_buffer_t *buffer = hb_buffer_create();
hb_buffer_set_unicode_funcs(buffer, sHBUnicodeFuncs);
hb_buffer_set_direction(buffer, isRightToLeft ? HB_DIRECTION_RTL :
HB_DIRECTION_LTR);
hb_buffer_set_direction(buffer,
aVertical ? HB_DIRECTION_TTB :
(isRightToLeft ? HB_DIRECTION_RTL :
HB_DIRECTION_LTR));
hb_script_t scriptTag;
if (aShapedText->GetFlags() & gfxTextRunFactory::TEXT_USE_MATH_SCRIPT) {
scriptTag = sMathScript;
@ -1042,7 +1252,7 @@ gfxHarfBuzzShaper::ShapeText(gfxContext *aContext,
}
nsresult rv = SetGlyphsFromRun(aContext, aShapedText, aOffset, aLength,
aText, buffer);
aText, buffer, aVertical);
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "failed to store glyphs into gfxShapedWord");
hb_buffer_destroy(buffer);
@ -1055,12 +1265,13 @@ gfxHarfBuzzShaper::ShapeText(gfxContext *aContext,
// for charToGlyphArray
nsresult
gfxHarfBuzzShaper::SetGlyphsFromRun(gfxContext *aContext,
gfxShapedText *aShapedText,
uint32_t aOffset,
uint32_t aLength,
gfxHarfBuzzShaper::SetGlyphsFromRun(gfxContext *aContext,
gfxShapedText *aShapedText,
uint32_t aOffset,
uint32_t aLength,
const char16_t *aText,
hb_buffer_t *aBuffer)
hb_buffer_t *aBuffer,
bool aVertical)
{
uint32_t numGlyphs;
const hb_glyph_info_t *ginfo = hb_buffer_get_glyph_infos(aBuffer, &numGlyphs);
@ -1092,9 +1303,13 @@ gfxHarfBuzzShaper::SetGlyphsFromRun(gfxContext *aContext,
int32_t glyphStart = 0; // looking for a clump that starts at this glyph
int32_t charStart = 0; // and this char index within the range of the run
bool roundX;
bool roundY;
aContext->GetRoundOffsetsToPixels(&roundX, &roundY);
bool roundI;
bool roundB;
if (aVertical) {
aContext->GetRoundOffsetsToPixels(&roundB, &roundI);
} else {
aContext->GetRoundOffsetsToPixels(&roundI, &roundB);
}
int32_t appUnitsPerDevUnit = aShapedText->GetAppUnitsPerDevUnit();
gfxShapedText::CompressedGlyph *charGlyphs =
@ -1114,10 +1329,10 @@ gfxHarfBuzzShaper::SetGlyphsFromRun(gfxContext *aContext,
//
// The value of the residual is the part of the desired distance that has
// not been included in integer offsets.
hb_position_t x_residual = 0;
hb_position_t residual = 0;
// keep track of y-position to set glyph offsets if needed
nscoord yPos = 0;
nscoord bPos = 0;
const hb_glyph_position_t *posInfo =
hb_buffer_get_glyph_positions(aBuffer, nullptr);
@ -1212,28 +1427,43 @@ gfxHarfBuzzShaper::SetGlyphsFromRun(gfxContext *aContext,
continue;
}
hb_position_t x_offset = posInfo[glyphStart].x_offset;
hb_position_t x_advance = posInfo[glyphStart].x_advance;
nscoord xOffset, advance;
if (roundX) {
xOffset =
appUnitsPerDevUnit * FixedToIntRound(x_offset + x_residual);
// Desired distance from the base glyph to the next reference point.
hb_position_t width = x_advance - x_offset;
int intWidth = FixedToIntRound(width);
x_residual = width - FloatToFixed(intWidth);
advance = appUnitsPerDevUnit * intWidth + xOffset;
// HarfBuzz gives us physical x- and y-coordinates, but we will store
// them as logical inline- and block-direction values in the textrun.
hb_position_t i_offset, i_advance; // inline-direction offset/advance
hb_position_t b_offset, b_advance; // block-direction offset/advance
if (aVertical) {
i_offset = posInfo[glyphStart].y_offset;
i_advance = posInfo[glyphStart].y_advance;
b_offset = posInfo[glyphStart].x_offset;
b_advance = posInfo[glyphStart].x_advance;
} else {
xOffset = floor(hb2appUnits * x_offset + 0.5);
advance = floor(hb2appUnits * x_advance + 0.5);
i_offset = posInfo[glyphStart].x_offset;
i_advance = posInfo[glyphStart].x_advance;
b_offset = posInfo[glyphStart].y_offset;
b_advance = posInfo[glyphStart].y_advance;
}
nscoord iOffset, advance;
if (roundI) {
iOffset =
appUnitsPerDevUnit * FixedToIntRound(i_offset + residual);
// Desired distance from the base glyph to the next reference point.
hb_position_t width = i_advance - i_offset;
int intWidth = FixedToIntRound(width);
residual = width - FloatToFixed(intWidth);
advance = appUnitsPerDevUnit * intWidth + iOffset;
} else {
iOffset = floor(hb2appUnits * i_offset + 0.5);
advance = floor(hb2appUnits * i_advance + 0.5);
}
// Check if it's a simple one-to-one mapping
if (glyphsInClump == 1 &&
gfxTextRun::CompressedGlyph::IsSimpleGlyphID(ginfo[glyphStart].codepoint) &&
gfxTextRun::CompressedGlyph::IsSimpleAdvance(advance) &&
charGlyphs[baseCharIndex].IsClusterStart() &&
xOffset == 0 &&
posInfo[glyphStart].y_offset == 0 && yPos == 0)
iOffset == 0 && b_offset == 0 &&
b_advance == 0 && bPos == 0)
{
charGlyphs[baseCharIndex].SetSimpleGlyph(advance,
ginfo[glyphStart].codepoint);
@ -1247,41 +1477,49 @@ gfxHarfBuzzShaper::SetGlyphsFromRun(gfxContext *aContext,
detailedGlyphs.AppendElement();
details->mGlyphID = ginfo[glyphStart].codepoint;
details->mXOffset = xOffset;
details->mXOffset = iOffset;
details->mAdvance = advance;
hb_position_t y_offset = posInfo[glyphStart].y_offset;
details->mYOffset = yPos -
(roundY ? appUnitsPerDevUnit * FixedToIntRound(y_offset)
: floor(hb2appUnits * y_offset + 0.5));
details->mYOffset = bPos -
(roundB ? appUnitsPerDevUnit * FixedToIntRound(b_offset)
: floor(hb2appUnits * b_offset + 0.5));
hb_position_t y_advance = posInfo[glyphStart].y_advance;
if (y_advance != 0) {
yPos -=
roundY ? appUnitsPerDevUnit * FixedToIntRound(y_advance)
: floor(hb2appUnits * y_advance + 0.5);
if (b_advance != 0) {
bPos -=
roundB ? appUnitsPerDevUnit * FixedToIntRound(b_advance)
: floor(hb2appUnits * b_advance + 0.5);
}
if (++glyphStart >= glyphEnd) {
break;
}
x_offset = posInfo[glyphStart].x_offset;
x_advance = posInfo[glyphStart].x_advance;
if (roundX) {
xOffset = appUnitsPerDevUnit *
FixedToIntRound(x_offset + x_residual);
if (aVertical) {
i_offset = posInfo[glyphStart].y_offset;
i_advance = posInfo[glyphStart].y_advance;
b_offset = posInfo[glyphStart].x_offset;
b_advance = posInfo[glyphStart].x_advance;
} else {
i_offset = posInfo[glyphStart].x_offset;
i_advance = posInfo[glyphStart].x_advance;
b_offset = posInfo[glyphStart].y_offset;
b_advance = posInfo[glyphStart].y_advance;
}
if (roundI) {
iOffset = appUnitsPerDevUnit *
FixedToIntRound(i_offset + residual);
// Desired distance to the next reference point. The
// residual is considered here, and includes the residual
// from the base glyph offset and subsequent advances, so
// that the distance from the base glyph is optimized
// rather than the distance from combining marks.
x_advance += x_residual;
int intAdvance = FixedToIntRound(x_advance);
x_residual = x_advance - FloatToFixed(intAdvance);
i_advance += residual;
int intAdvance = FixedToIntRound(i_advance);
residual = i_advance - FloatToFixed(intAdvance);
advance = appUnitsPerDevUnit * intAdvance;
} else {
xOffset = floor(hb2appUnits * x_offset + 0.5);
advance = floor(hb2appUnits * x_advance + 0.5);
iOffset = floor(hb2appUnits * i_offset + 0.5);
advance = floor(hb2appUnits * i_advance + 0.5);
}
}

View File

@ -31,6 +31,7 @@ public:
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
bool aVertical,
gfxShapedText *aShapedText);
// get a given font table in harfbuzz blob form
@ -44,11 +45,33 @@ public:
hb_position_t GetGlyphHAdvance(gfxContext *aContext,
hb_codepoint_t glyph) const;
hb_position_t GetGlyphVAdvance(gfxContext *aContext,
hb_codepoint_t glyph) const;
void GetGlyphVOrigin(gfxContext *aContext, hb_codepoint_t aGlyph,
hb_position_t *aX, hb_position_t *aY) const;
// get harfbuzz horizontal advance in 16.16 fixed point format.
static hb_position_t
HBGetGlyphHAdvance(hb_font_t *font, void *font_data,
hb_codepoint_t glyph, void *user_data);
// get harfbuzz vertical advance in 16.16 fixed point format.
static hb_position_t
HBGetGlyphVAdvance(hb_font_t *font, void *font_data,
hb_codepoint_t glyph, void *user_data);
static hb_bool_t
HBGetGlyphHOrigin(hb_font_t *font, void *font_data,
hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y,
void *user_data);
static hb_bool_t
HBGetGlyphVOrigin(hb_font_t *font, void *font_data,
hb_codepoint_t glyph,
hb_position_t *x, hb_position_t *y,
void *user_data);
hb_position_t GetHKerning(uint16_t aFirstGlyph,
uint16_t aSecondGlyph) const;
@ -68,12 +91,13 @@ public:
}
protected:
nsresult SetGlyphsFromRun(gfxContext *aContext,
gfxShapedText *aShapedText,
uint32_t aOffset,
uint32_t aLength,
nsresult SetGlyphsFromRun(gfxContext *aContext,
gfxShapedText *aShapedText,
uint32_t aOffset,
uint32_t aLength,
const char16_t *aText,
hb_buffer_t *aBuffer);
hb_buffer_t *aBuffer,
bool aVertical);
// retrieve glyph positions, applying advance adjustments and attachments
// returns results in appUnits
@ -82,6 +106,9 @@ protected:
nsTArray<nsPoint>& aPositions,
uint32_t aAppUnitsPerDevUnit);
bool InitializeVertical();
bool LoadHmtxTable();
// harfbuzz face object: we acquire a reference from the font entry
// on shaper creation, and release it in our destructor
hb_face_t *mHBFace;
@ -99,13 +126,12 @@ protected:
// Old-style TrueType kern table, if we're not doing GPOS kerning
mutable hb_blob_t *mKernTable;
// Cached copy of the hmtx table and numLongMetrics field from hhea,
// for use when looking up glyph metrics; initialized to 0 by the
// constructor so we can tell it hasn't been set yet.
// This is a signed value so that we can use -1 to indicate
// an error (if the hhea table was not available).
// Cached copy of the hmtx table.
mutable hb_blob_t *mHmtxTable;
mutable int32_t mNumLongMetrics;
// For vertical fonts, cached vmtx and VORG table, if present.
mutable hb_blob_t *mVmtxTable;
mutable hb_blob_t *mVORGTable;
// Cached pointer to cmap subtable to be used for char-to-glyph mapping.
// This comes from GetFontTablePtr; if it is non-null, our destructor
@ -115,6 +141,15 @@ protected:
mutable uint32_t mSubtableOffset;
mutable uint32_t mUVSTableOffset;
// Cached copy of numLongMetrics field from the hhea table,
// for use when looking up glyph metrics; initialized to 0 by the
// constructor so we can tell it hasn't been set yet.
// This is a signed value so that we can use -1 to indicate
// an error (if the hhea table was not available).
mutable int32_t mNumLongHMetrics;
// Similarly for vhea if it's a vertical font.
mutable int32_t mNumLongVMetrics;
// Whether the font implements GetGlyph, or we should read tables
// directly
bool mUseFontGetGlyph;
@ -123,6 +158,7 @@ protected:
bool mUseFontGlyphWidths;
bool mInitialized;
bool mVerticalInitialized;
};
#endif /* GFX_HARFBUZZSHAPER_H */

View File

@ -124,6 +124,7 @@ gfxMacFont::ShapeText(gfxContext *aContext,
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
bool aVertical,
gfxShapedText *aShapedText)
{
if (!mIsValid) {
@ -131,19 +132,22 @@ gfxMacFont::ShapeText(gfxContext *aContext,
return false;
}
if (static_cast<MacOSFontEntry*>(GetFontEntry())->RequiresAATLayout()) {
// Currently, we don't support vertical shaping via CoreText,
// so we ignore RequiresAATLayout if vertical is requested.
if (static_cast<MacOSFontEntry*>(GetFontEntry())->RequiresAATLayout() &&
!aVertical) {
if (!mCoreTextShaper) {
mCoreTextShaper = new gfxCoreTextShaper(this);
}
if (mCoreTextShaper->ShapeText(aContext, aText, aOffset, aLength,
aScript, aShapedText)) {
aScript, aVertical, aShapedText)) {
PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText);
return true;
}
}
return gfxFont::ShapeText(aContext, aText, aOffset, aLength, aScript,
aShapedText);
aVertical, aShapedText);
}
bool

View File

@ -57,6 +57,7 @@ protected:
uint32_t aOffset,
uint32_t aLength,
int32_t aScript,
bool aVertical,
gfxShapedText *aShapedText);
void InitMetrics();

View File

@ -397,32 +397,35 @@ void
gfxTextRun::DrawGlyphs(gfxFont *aFont, uint32_t aStart, uint32_t aEnd,
gfxPoint *aPt, PropertyProvider *aProvider,
uint32_t aSpacingStart, uint32_t aSpacingEnd,
TextRunDrawParams& aParams)
TextRunDrawParams& aParams, uint16_t aOrientation)
{
nsAutoTArray<PropertyProvider::Spacing,200> spacingBuffer;
bool haveSpacing = GetAdjustedSpacingArray(aStart, aEnd, aProvider,
aSpacingStart, aSpacingEnd, &spacingBuffer);
aParams.spacing = haveSpacing ? spacingBuffer.Elements() : nullptr;
aFont->Draw(this, aStart, aEnd, aPt, aParams);
aFont->Draw(this, aStart, aEnd, aPt, aParams, aOrientation);
}
static void
ClipPartialLigature(gfxTextRun *aTextRun, gfxFloat *aLeft, gfxFloat *aRight,
gfxFloat aXOrigin, gfxTextRun::LigatureData *aLigature)
ClipPartialLigature(const gfxTextRun* aTextRun,
gfxFloat *aStart, gfxFloat *aEnd,
gfxFloat aOrigin,
gfxTextRun::LigatureData *aLigature)
{
if (aLigature->mClipBeforePart) {
if (aTextRun->IsRightToLeft()) {
*aRight = std::min(*aRight, aXOrigin);
*aEnd = std::min(*aEnd, aOrigin);
} else {
*aLeft = std::max(*aLeft, aXOrigin);
*aStart = std::max(*aStart, aOrigin);
}
}
if (aLigature->mClipAfterPart) {
gfxFloat endEdge = aXOrigin + aTextRun->GetDirection()*aLigature->mPartWidth;
gfxFloat endEdge =
aOrigin + aTextRun->GetDirection() * aLigature->mPartWidth;
if (aTextRun->IsRightToLeft()) {
*aLeft = std::max(*aLeft, endEdge);
*aStart = std::max(*aStart, endEdge);
} else {
*aRight = std::min(*aRight, endEdge);
*aEnd = std::min(*aEnd, endEdge);
}
}
}
@ -430,17 +433,25 @@ ClipPartialLigature(gfxTextRun *aTextRun, gfxFloat *aLeft, gfxFloat *aRight,
void
gfxTextRun::DrawPartialLigature(gfxFont *aFont, uint32_t aStart, uint32_t aEnd,
gfxPoint *aPt, PropertyProvider *aProvider,
TextRunDrawParams& aParams)
TextRunDrawParams& aParams, uint16_t aOrientation)
{
if (aStart >= aEnd)
if (aStart >= aEnd) {
return;
}
// Draw partial ligature. We hack this by clipping the ligature.
LigatureData data = ComputeLigatureData(aStart, aEnd, aProvider);
gfxRect clipExtents = aParams.context->GetClipExtents();
gfxFloat left = clipExtents.X() * mAppUnitsPerDevUnit;
gfxFloat right = clipExtents.XMost() * mAppUnitsPerDevUnit;
ClipPartialLigature(this, &left, &right, aPt->x, &data);
gfxFloat start, end;
if (aParams.isVerticalRun) {
start = clipExtents.Y() * mAppUnitsPerDevUnit;
end = clipExtents.YMost() * mAppUnitsPerDevUnit;
ClipPartialLigature(this, &start, &end, aPt->y, &data);
} else {
start = clipExtents.X() * mAppUnitsPerDevUnit;
end = clipExtents.XMost() * mAppUnitsPerDevUnit;
ClipPartialLigature(this, &start, &end, aPt->x, &data);
}
{
// Need to preserve the path, otherwise this can break canvas text-on-path;
@ -453,19 +464,38 @@ gfxTextRun::DrawPartialLigature(gfxFont *aFont, uint32_t aStart, uint32_t aEnd,
// Also, make sure we snap the rectangle to device pixels.
aParams.context->Save();
aParams.context->NewPath();
aParams.context->Rectangle(gfxRect(left / mAppUnitsPerDevUnit,
clipExtents.Y(),
(right - left) / mAppUnitsPerDevUnit,
clipExtents.Height()), true);
if (aParams.isVerticalRun) {
aParams.context->Rectangle(gfxRect(clipExtents.X(),
start / mAppUnitsPerDevUnit,
clipExtents.Width(),
(end - start) / mAppUnitsPerDevUnit),
true);
} else {
aParams.context->Rectangle(gfxRect(start / mAppUnitsPerDevUnit,
clipExtents.Y(),
(end - start) / mAppUnitsPerDevUnit,
clipExtents.Height()),
true);
}
aParams.context->Clip();
}
gfxPoint pt(aPt->x - aParams.direction * data.mPartAdvance, aPt->y);
gfxPoint pt;
if (aParams.isVerticalRun) {
pt = gfxPoint(aPt->x, aPt->y - aParams.direction * data.mPartAdvance);
} else {
pt = gfxPoint(aPt->x - aParams.direction * data.mPartAdvance, aPt->y);
}
DrawGlyphs(aFont, data.mLigatureStart, data.mLigatureEnd, &pt,
aProvider, aStart, aEnd, aParams);
aProvider, aStart, aEnd, aParams, aOrientation);
aParams.context->Restore();
aPt->x += aParams.direction * data.mPartWidth;
if (aParams.isVerticalRun) {
aPt->y += aParams.direction * data.mPartWidth;
} else {
aPt->x += aParams.direction * data.mPartWidth;
}
}
// returns true if a glyph run is using a font with synthetic bolding enabled, false otherwise
@ -577,6 +607,7 @@ gfxTextRun::Draw(gfxContext *aContext, gfxPoint aPt, DrawMode aDrawMode,
TextRunDrawParams params;
params.context = aContext;
params.devPerApp = 1.0 / double(GetAppUnitsPerDevUnit());
params.isVerticalRun = IsVertical();
params.isRTL = IsRightToLeft();
params.direction = direction;
params.drawMode = aDrawMode;
@ -585,8 +616,6 @@ gfxTextRun::Draw(gfxContext *aContext, gfxPoint aPt, DrawMode aDrawMode,
params.paintSVGGlyphs = !aCallbacks || aCallbacks->mShouldPaintSVGGlyphs;
params.dt = aContext->GetDrawTarget();
gfxPoint pt = aPt;
// synthetic bolding draws glyphs twice ==> colors with opacity won't draw
// correctly unless first drawn without alpha
BufferAlphaColor syntheticBoldBuffer(aContext);
@ -607,6 +636,8 @@ gfxTextRun::Draw(gfxContext *aContext, gfxPoint aPt, DrawMode aDrawMode,
}
GlyphRunIterator iter(this, aStart, aLength);
gfxFloat advance = 0.0;
while (iter.NextRun()) {
gfxFont *font = iter.GetGlyphRun()->mFont;
uint32_t start = iter.GetStringStart();
@ -617,18 +648,28 @@ gfxTextRun::Draw(gfxContext *aContext, gfxPoint aPt, DrawMode aDrawMode,
bool drawPartial = aDrawMode == DrawMode::GLYPH_FILL ||
(aDrawMode == DrawMode::GLYPH_PATH && aCallbacks);
gfxPoint origPt = aPt;
if (drawPartial) {
DrawPartialLigature(font, start, ligatureRunStart, &pt,
aProvider, params);
DrawPartialLigature(font, start, ligatureRunStart, &aPt,
aProvider, params,
iter.GetGlyphRun()->mOrientation);
}
DrawGlyphs(font, ligatureRunStart, ligatureRunEnd, &pt,
aProvider, ligatureRunStart, ligatureRunEnd, params);
DrawGlyphs(font, ligatureRunStart, ligatureRunEnd, &aPt,
aProvider, ligatureRunStart, ligatureRunEnd, params,
iter.GetGlyphRun()->mOrientation);
if (drawPartial) {
DrawPartialLigature(font, ligatureRunEnd, end, &pt,
aProvider, params);
DrawPartialLigature(font, ligatureRunEnd, end, &aPt,
aProvider, params,
iter.GetGlyphRun()->mOrientation);
}
if (params.isVerticalRun) {
advance += (aPt.y - origPt.y) * params.direction;
} else {
advance += (aPt.x - origPt.x) * params.direction;
}
}
@ -638,7 +679,7 @@ gfxTextRun::Draw(gfxContext *aContext, gfxPoint aPt, DrawMode aDrawMode,
}
if (aAdvanceWidth) {
*aAdvanceWidth = (pt.x - aPt.x)*direction;
*aAdvanceWidth = advance;
}
}
@ -1240,10 +1281,13 @@ gfxTextRun::SetSpaceGlyph(gfxFont *aFont, gfxContext *aContext,
gfxTextRunFactory::TEXT_IS_ASCII |
gfxTextRunFactory::TEXT_IS_PERSISTENT |
aOrientation;
bool vertical =
(GetFlags() & gfxTextRunFactory::TEXT_ORIENT_VERTICAL_UPRIGHT) != 0;
gfxShapedWord *sw = aFont->GetShapedWord(aContext,
&space, 1,
gfxShapedWord::HashMix(0, ' '),
MOZ_SCRIPT_LATIN,
vertical,
mAppUnitsPerDevUnit,
flags,
nullptr);
@ -2224,7 +2268,8 @@ gfxFontGroup::InitScriptRun(gfxContext *aContext,
const gfxTextRange& range = fontRanges[r];
uint32_t matchedLength = range.Length();
gfxFont *matchedFont = range.font;
bool vertical =
range.orientation == gfxTextRunFactory::TEXT_ORIENT_VERTICAL_UPRIGHT;
// create the glyph run for this range
if (matchedFont && mStyle.noFallbackVariantFeatures) {
// common case - just do glyph layout and record the
@ -2236,7 +2281,8 @@ gfxFontGroup::InitScriptRun(gfxContext *aContext,
aString + runStart,
aOffset + runStart,
matchedLength,
aRunScript)) {
aRunScript,
vertical)) {
// glyph layout failed! treat as missing glyphs
matchedFont = nullptr;
}
@ -2275,7 +2321,8 @@ gfxFontGroup::InitScriptRun(gfxContext *aContext,
aString + runStart,
aOffset + runStart,
matchedLength,
aRunScript)) {
aRunScript,
vertical)) {
// glyph layout failed! treat as missing glyphs
matchedFont = nullptr;
}
@ -2319,7 +2366,8 @@ gfxFontGroup::InitScriptRun(gfxContext *aContext,
aString + runStart,
aOffset + runStart,
matchedLength,
aRunScript)) {
aRunScript,
vertical)) {
// glyph layout failed! treat as missing glyphs
matchedFont = nullptr;
}

View File

@ -673,7 +673,7 @@ private:
PropertyProvider *aProvider);
void DrawPartialLigature(gfxFont *aFont, uint32_t aStart, uint32_t aEnd,
gfxPoint *aPt, PropertyProvider *aProvider,
TextRunDrawParams& aParams);
TextRunDrawParams& aParams, uint16_t aOrientation);
// Advance aStart to the start of the nearest ligature; back up aEnd
// to the nearest ligature end; may result in *aStart == *aEnd
void ShrinkToLigatureBoundaries(uint32_t *aStart, uint32_t *aEnd);
@ -698,7 +698,7 @@ private:
void DrawGlyphs(gfxFont *aFont, uint32_t aStart, uint32_t aEnd,
gfxPoint *aPt, PropertyProvider *aProvider,
uint32_t aSpacingStart, uint32_t aSpacingEnd,
TextRunDrawParams& aParams);
TextRunDrawParams& aParams, uint16_t aOrientation);
// XXX this should be changed to a GlyphRun plus a maybe-null GlyphRun*,
// for smaller size especially in the super-common one-glyphrun case

View File

@ -731,11 +731,19 @@ MessageChannel::SendAndWait(Message* aMsg, Message* aReply)
return false;
}
if (mPendingUrgentRequest && !ProcessPendingUrgentRequest())
return false;
// We need to make sure that all messages deposited in mPendingRPCCall
// and mPendingUrgentRequest are dispatched before we leave this
// function. Otherwise, there's nothing to wake us up and force us to
// dispatch them.
while (mPendingUrgentRequest) {
if (!ProcessPendingUrgentRequest())
return false;
}
if (mPendingRPCCall && !ProcessPendingRPCCall())
return false;
while (mPendingRPCCall) {
if (!ProcessPendingRPCCall())
return false;
}
if (mRecvd) {
NS_ABORT_IF_FALSE(mRecvd->is_reply(), "expected reply");

View File

@ -97,6 +97,9 @@ class JavaScriptBase : public WrapperOwner, public WrapperAnswer, public Base
bool AnswerClassName(const uint64_t &objId, nsString *result) {
return Answer::AnswerClassName(ObjectId::deserialize(objId), result);
}
bool AnswerRegExpToShared(const uint64_t &objId, ReturnStatus *rs, nsString *source, uint32_t *flags) {
return Answer::AnswerRegExpToShared(ObjectId::deserialize(objId), rs, source, flags);
}
bool AnswerGetPropertyNames(const uint64_t &objId, const uint32_t &flags,
ReturnStatus *rs, nsTArray<nsString> *names) {
@ -191,6 +194,11 @@ class JavaScriptBase : public WrapperOwner, public WrapperAnswer, public Base
return Base::CallClassName(objId.serialize(), result);
}
bool CallRegExpToShared(const ObjectId &objId, ReturnStatus *rs,
nsString *source, uint32_t *flags) {
return Base::CallRegExpToShared(objId.serialize(), rs, source, flags);
}
bool CallGetPropertyNames(const ObjectId &objId, const uint32_t &flags,
ReturnStatus *rs, nsTArray<nsString> *names) {
return Base::CallGetPropertyNames(objId.serialize(), flags, rs, names);

View File

@ -418,7 +418,7 @@ JavaScriptShared::fromDescriptor(JSContext *cx, Handle<JSPropertyDescriptor> des
if (!toVariant(cx, desc.value(), &out->value()))
return false;
JS_ASSERT(desc.object());
MOZ_ASSERT(desc.object());
if (!toObjectVariant(cx, desc.object(), &out->obj()))
return false;

View File

@ -40,6 +40,7 @@ both:
rpc HasInstance(uint64_t objId, JSVariant v) returns (ReturnStatus rs, bool has);
rpc ObjectClassIs(uint64_t objId, uint32_t classValue) returns (bool result);
rpc ClassName(uint64_t objId) returns (nsString name);
rpc RegExpToShared(uint64_t objId) returns (ReturnStatus rs, nsString source, uint32_t flags);
rpc GetPropertyNames(uint64_t objId, uint32_t flags) returns (ReturnStatus rs, nsString[] names);
rpc InstanceOf(uint64_t objId, JSIID iid) returns (ReturnStatus rs, bool instanceof);

View File

@ -552,6 +552,31 @@ WrapperAnswer::AnswerClassName(const ObjectId &objId, nsString *name)
return true;
}
bool
WrapperAnswer::AnswerRegExpToShared(const ObjectId &objId, ReturnStatus *rs,
nsString *source, uint32_t *flags)
{
AutoSafeJSContext cx;
RootedObject obj(cx, findObjectById(cx, objId));
if (!obj)
return fail(cx, rs);
JSAutoCompartment ac(cx, obj);
MOZ_RELEASE_ASSERT(JS_ObjectIsRegExp(cx, obj));
RootedString sourceJSStr(cx, JS_GetRegExpSource(cx, obj));
if (!sourceJSStr)
return fail(cx, rs);
nsAutoJSString sourceStr;
if (!sourceStr.init(cx, sourceJSStr))
return fail(cx, rs);
source->Assign(sourceStr);
*flags = JS_GetRegExpFlags(cx, obj);
return ok(rs);
}
bool
WrapperAnswer::AnswerGetPropertyNames(const ObjectId &objId, const uint32_t &flags,
ReturnStatus *rs, nsTArray<nsString> *names)

View File

@ -52,6 +52,7 @@ class WrapperAnswer : public virtual JavaScriptShared
bool AnswerObjectClassIs(const ObjectId &objId, const uint32_t &classValue,
bool *result);
bool AnswerClassName(const ObjectId &objId, nsString *result);
bool AnswerRegExpToShared(const ObjectId &objId, ReturnStatus *rs, nsString *source, uint32_t *flags);
bool AnswerGetPropertyNames(const ObjectId &objId, const uint32_t &flags,
ReturnStatus *rs, nsTArray<nsString> *names);

View File

@ -91,6 +91,7 @@ class CPOWProxyHandler : public BaseProxyHandler
virtual bool objectClassIs(HandleObject obj, js::ESClassValue classValue,
JSContext *cx) const MOZ_OVERRIDE;
virtual const char* className(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE;
virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g) const MOZ_OVERRIDE;
virtual void finalize(JSFreeOp *fop, JSObject *proxy) const MOZ_OVERRIDE;
virtual void objectMoved(JSObject *proxy, const JSObject *old) const MOZ_OVERRIDE;
virtual bool isCallable(JSObject *obj) const MOZ_OVERRIDE;
@ -651,6 +652,37 @@ WrapperOwner::className(JSContext *cx, HandleObject proxy)
return ToNewCString(name);
}
bool
CPOWProxyHandler::regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g) const
{
FORWARD(regexp_toShared, (cx, proxy, g));
}
bool
WrapperOwner::regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g)
{
ObjectId objId = idOf(proxy);
ReturnStatus status;
nsString source;
unsigned flags = 0;
if (!CallRegExpToShared(objId, &status, &source, &flags))
return ipcfail(cx);
LOG_STACK();
if (!ok(cx, status))
return false;
RootedObject regexp(cx);
RootedObject global(cx, JS::CurrentGlobalOrNull(cx));
regexp = JS_NewUCRegExpObject(cx, global, source.get(), source.Length(), flags);
if (!regexp)
return false;
return js::RegExpToSharedNonInline(cx, regexp, g);
}
void
CPOWProxyHandler::finalize(JSFreeOp *fop, JSObject *proxy) const
{
@ -865,7 +897,7 @@ bool
WrapperOwner::toObjectVariant(JSContext *cx, JSObject *objArg, ObjectVariant *objVarp)
{
RootedObject obj(cx, objArg);
JS_ASSERT(obj);
MOZ_ASSERT(obj);
// We always save objects unwrapped in the CPOW table. If we stored
// wrappers, then the wrapper might be GCed while the target remained alive.

View File

@ -11,6 +11,7 @@
#include "JavaScriptShared.h"
#include "mozilla/ipc/ProtocolUtils.h"
#include "js/Class.h"
#include "jsproxy.h"
#ifdef XP_WIN
#undef GetClassName
@ -55,6 +56,7 @@ class WrapperOwner : public virtual JavaScriptShared
// SpiderMonkey Extensions.
bool isExtensible(JSContext *cx, JS::HandleObject proxy, bool *extensible);
bool regexp_toShared(JSContext *cx, JS::HandleObject proxy, js::RegExpGuard *g);
bool callOrConstruct(JSContext *cx, JS::HandleObject proxy, const JS::CallArgs &args,
bool construct);
bool hasInstance(JSContext *cx, JS::HandleObject proxy, JS::MutableHandleValue v, bool *bp);
@ -140,6 +142,8 @@ class WrapperOwner : public virtual JavaScriptShared
virtual bool CallObjectClassIs(const ObjectId &objId, const uint32_t &classValue,
bool *result) = 0;
virtual bool CallClassName(const ObjectId &objId, nsString *result) = 0;
virtual bool CallRegExpToShared(const ObjectId &objId, ReturnStatus *rs, nsString *source,
uint32_t *flags) = 0;
virtual bool CallGetPropertyNames(const ObjectId &objId, const uint32_t &flags,
ReturnStatus *rs, nsTArray<nsString> *names) = 0;

View File

@ -959,7 +959,7 @@ class HashTable : private AllocPolicy
// a new key at the new Lookup position. |front()| is invalid after
// this operation until the next call to |popFront()|.
void rekeyFront(const Lookup &l, const Key &k) {
JS_ASSERT(&k != &HashPolicy::getKey(this->cur->get()));
MOZ_ASSERT(&k != &HashPolicy::getKey(this->cur->get()));
Ptr p(*this->cur, table_);
table_.rekeyWithoutRehash(p, l, k);
rekeyed = true;

View File

@ -260,7 +260,7 @@ IsInsideNursery(const js::gc::Cell *cell)
addr &= ~js::gc::ChunkMask;
addr |= js::gc::ChunkLocationOffset;
uint32_t location = *reinterpret_cast<uint32_t *>(addr);
JS_ASSERT(location != 0);
MOZ_ASSERT(location != 0);
return location & ChunkLocationAnyNursery;
#else
return false;
@ -278,7 +278,7 @@ GetTenuredGCThingZone(void *thing)
{
MOZ_ASSERT(thing);
#ifdef JSGC_GENERATIONAL
JS_ASSERT(!js::gc::IsInsideNursery((js::gc::Cell *)thing));
MOZ_ASSERT(!js::gc::IsInsideNursery((js::gc::Cell *)thing));
#endif
return js::gc::GetGCThingArena(thing)->zone;
}

View File

@ -127,8 +127,8 @@ SYMBOL_TO_JSID(JS::Symbol *sym)
jsid id;
MOZ_ASSERT(sym != nullptr);
MOZ_ASSERT((size_t(sym) & JSID_TYPE_MASK) == 0);
JS_ASSERT(!js::gc::IsInsideNursery(JS::AsCell(sym)));
JS_ASSERT(!JS::IsPoisonedPtr(sym));
MOZ_ASSERT(!js::gc::IsInsideNursery(JS::AsCell(sym)));
MOZ_ASSERT(!JS::IsPoisonedPtr(sym));
JSID_BITS(id) = (size_t(sym) | JSID_TYPE_SYMBOL);
return id;
}

View File

@ -34,11 +34,11 @@ class JS_PUBLIC_API(ProfilingFrameIterator)
static const unsigned StorageSpace = 6 * sizeof(void*);
mozilla::AlignedStorage<StorageSpace> storage_;
js::AsmJSProfilingFrameIterator &asmJSIter() {
JS_ASSERT(!done());
MOZ_ASSERT(!done());
return *reinterpret_cast<js::AsmJSProfilingFrameIterator*>(storage_.addr());
}
const js::AsmJSProfilingFrameIterator &asmJSIter() const {
JS_ASSERT(!done());
MOZ_ASSERT(!done());
return *reinterpret_cast<const js::AsmJSProfilingFrameIterator*>(storage_.addr());
}

View File

@ -670,7 +670,7 @@ struct GCMethods<JSObject *>
static gc::Cell *asGCThingOrNull(JSObject *v) {
if (!v)
return nullptr;
JS_ASSERT(uintptr_t(v) > 32);
MOZ_ASSERT(uintptr_t(v) > 32);
return reinterpret_cast<gc::Cell *>(v);
}
static bool needsPostBarrier(JSObject *v) {

View File

@ -51,9 +51,6 @@ namespace js {}
#define JS_SWEPT_FRAME_PATTERN 0x5b
#define JS_POISONED_FORKJOIN_CHUNK 0xBD
#define JS_ASSERT(expr) MOZ_ASSERT(expr)
#define JS_ASSERT_IF(cond, expr) MOZ_ASSERT_IF(cond, expr)
#define JS_STATIC_ASSERT(cond) static_assert(cond, "JS_STATIC_ASSERT")
#define JS_STATIC_ASSERT_IF(cond, expr) MOZ_STATIC_ASSERT_IF(cond, expr, "JS_STATIC_ASSERT_IF")

View File

@ -54,10 +54,10 @@ AsmJSFrameIterator::AsmJSFrameIterator(const AsmJSActivation &activation)
void
AsmJSFrameIterator::operator++()
{
JS_ASSERT(!done());
MOZ_ASSERT(!done());
DebugOnly<uint8_t*> oldfp = fp_;
fp_ += callsite_->stackDepth();
JS_ASSERT_IF(module_->profilingEnabled(), fp_ == CallerFPFromFP(oldfp));
MOZ_ASSERT_IF(module_->profilingEnabled(), fp_ == CallerFPFromFP(oldfp));
settle();
}
@ -67,17 +67,17 @@ AsmJSFrameIterator::settle()
void *returnAddress = ReturnAddressFromFP(fp_);
const AsmJSModule::CodeRange *codeRange = module_->lookupCodeRange(returnAddress);
JS_ASSERT(codeRange);
MOZ_ASSERT(codeRange);
codeRange_ = codeRange;
switch (codeRange->kind()) {
case AsmJSModule::CodeRange::Function:
callsite_ = module_->lookupCallSite(returnAddress);
JS_ASSERT(callsite_);
MOZ_ASSERT(callsite_);
break;
case AsmJSModule::CodeRange::Entry:
fp_ = nullptr;
JS_ASSERT(done());
MOZ_ASSERT(done());
break;
case AsmJSModule::CodeRange::IonFFI:
case AsmJSModule::CodeRange::SlowFFI:
@ -91,14 +91,14 @@ AsmJSFrameIterator::settle()
JSAtom *
AsmJSFrameIterator::functionDisplayAtom() const
{
JS_ASSERT(!done());
MOZ_ASSERT(!done());
return reinterpret_cast<const AsmJSModule::CodeRange*>(codeRange_)->functionName(*module_);
}
unsigned
AsmJSFrameIterator::computeLine(uint32_t *column) const
{
JS_ASSERT(!done());
MOZ_ASSERT(!done());
if (column)
*column = callsite_->column();
return callsite_->line();
@ -176,14 +176,14 @@ GenerateProfilingPrologue(MacroAssembler &masm, unsigned framePushed, AsmJSExit:
masm.bind(begin);
PushRetAddr(masm);
JS_ASSERT(PushedRetAddr == masm.currentOffset() - offsetAtBegin);
MOZ_ASSERT(PushedRetAddr == masm.currentOffset() - offsetAtBegin);
masm.loadAsmJSActivation(scratch);
masm.push(Address(scratch, AsmJSActivation::offsetOfFP()));
JS_ASSERT(PushedFP == masm.currentOffset() - offsetAtBegin);
MOZ_ASSERT(PushedFP == masm.currentOffset() - offsetAtBegin);
masm.storePtr(StackPointer, Address(scratch, AsmJSActivation::offsetOfFP()));
JS_ASSERT(StoredFP == masm.currentOffset() - offsetAtBegin);
MOZ_ASSERT(StoredFP == masm.currentOffset() - offsetAtBegin);
}
if (reason != AsmJSExit::None)
@ -290,7 +290,7 @@ void
js::GenerateAsmJSFunctionEpilogue(MacroAssembler &masm, unsigned framePushed,
AsmJSFunctionLabels *labels)
{
JS_ASSERT(masm.framePushed() == framePushed);
MOZ_ASSERT(masm.framePushed() == framePushed);
#if defined(JS_CODEGEN_ARM)
// Flush pending pools so they do not get dumped between the profilingReturn
@ -379,7 +379,7 @@ js::GenerateAsmJSExitEpilogue(MacroAssembler &masm, unsigned framePushed, AsmJSE
Label *profilingReturn)
{
// Inverse of GenerateAsmJSExitPrologue:
JS_ASSERT(masm.framePushed() == framePushed);
MOZ_ASSERT(masm.framePushed() == framePushed);
GenerateProfilingEpilogue(masm, framePushed, reason, profilingReturn);
masm.setFramePushed(0);
}
@ -404,19 +404,19 @@ AssertMatchesCallSite(const AsmJSModule &module, const AsmJSModule::CodeRange *c
{
#ifdef DEBUG
const AsmJSModule::CodeRange *callerCodeRange = module.lookupCodeRange(callerPC);
JS_ASSERT(callerCodeRange);
MOZ_ASSERT(callerCodeRange);
if (callerCodeRange->isEntry()) {
JS_ASSERT(callerFP == nullptr);
MOZ_ASSERT(callerFP == nullptr);
return;
}
const CallSite *callsite = module.lookupCallSite(callerPC);
if (calleeCodeRange->isThunk()) {
JS_ASSERT(!callsite);
JS_ASSERT(callerCodeRange->isFunction());
MOZ_ASSERT(!callsite);
MOZ_ASSERT(callerCodeRange->isFunction());
} else {
JS_ASSERT(callsite);
JS_ASSERT(callerFP == (uint8_t*)fp + callsite->stackDepth());
MOZ_ASSERT(callsite);
MOZ_ASSERT(callerFP == (uint8_t*)fp + callsite->stackDepth());
}
#endif
}
@ -429,7 +429,7 @@ AsmJSProfilingFrameIterator::initFromFP(const AsmJSActivation &activation)
// If a signal was handled while entering an activation, the frame will
// still be null.
if (!fp) {
JS_ASSERT(done());
MOZ_ASSERT(done());
return;
}
@ -443,7 +443,7 @@ AsmJSProfilingFrameIterator::initFromFP(const AsmJSActivation &activation)
// - for interrupts, we just accept that we'll lose the innermost frame.
void *pc = ReturnAddressFromFP(fp);
const AsmJSModule::CodeRange *codeRange = module_->lookupCodeRange(pc);
JS_ASSERT(codeRange);
MOZ_ASSERT(codeRange);
codeRange_ = codeRange;
stackAddress_ = fp;
@ -477,7 +477,7 @@ AsmJSProfilingFrameIterator::initFromFP(const AsmJSActivation &activation)
if (exitReason_ == AsmJSExit::None)
exitReason_ = AsmJSExit::Interrupt;
JS_ASSERT(!done());
MOZ_ASSERT(!done());
}
typedef JS::ProfilingFrameIterator::RegisterState RegisterState;
@ -496,7 +496,7 @@ AsmJSProfilingFrameIterator::AsmJSProfilingFrameIterator(const AsmJSActivation &
// profiling will be enabled when the module becomes inactive and gets
// called again).
if (!module_->profilingEnabled()) {
JS_ASSERT(done());
MOZ_ASSERT(done());
return;
}
@ -527,9 +527,9 @@ AsmJSProfilingFrameIterator::AsmJSProfilingFrameIterator(const AsmJSActivation &
// prologue/epilogue, as generated by GenerateProfiling(Prologue|Epilogue)
// below.
uint32_t offsetInModule = ((uint8_t*)state.pc) - module_->codeBase();
JS_ASSERT(offsetInModule < module_->codeBytes());
JS_ASSERT(offsetInModule >= codeRange->begin());
JS_ASSERT(offsetInModule < codeRange->end());
MOZ_ASSERT(offsetInModule < module_->codeBytes());
MOZ_ASSERT(offsetInModule >= codeRange->begin());
MOZ_ASSERT(offsetInModule < codeRange->end());
uint32_t offsetInCodeRange = offsetInModule - codeRange->begin();
void **sp = (void**)state.sp;
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_MIPS)
@ -544,7 +544,7 @@ AsmJSProfilingFrameIterator::AsmJSProfilingFrameIterator(const AsmJSActivation &
callerFP_ = fp;
AssertMatchesCallSite(*module_, codeRange, callerPC_, callerFP_, sp - 1);
} else if (offsetInCodeRange < StoredFP) {
JS_ASSERT(fp == CallerFPFromFP(sp));
MOZ_ASSERT(fp == CallerFPFromFP(sp));
callerPC_ = ReturnAddressFromFP(sp);
callerFP_ = CallerFPFromFP(sp);
AssertMatchesCallSite(*module_, codeRange, callerPC_, callerFP_, sp);
@ -559,7 +559,7 @@ AsmJSProfilingFrameIterator::AsmJSProfilingFrameIterator(const AsmJSActivation &
// The entry trampoline is the final frame in an AsmJSActivation. The entry
// trampoline also doesn't GenerateAsmJSPrologue/Epilogue so we can't use
// the general unwinding logic below.
JS_ASSERT(!fp);
MOZ_ASSERT(!fp);
callerPC_ = nullptr;
callerFP_ = nullptr;
break;
@ -567,7 +567,7 @@ AsmJSProfilingFrameIterator::AsmJSProfilingFrameIterator(const AsmJSActivation &
case AsmJSModule::CodeRange::Inline: {
// The throw stub clears AsmJSActivation::fp on it's way out.
if (!fp) {
JS_ASSERT(done());
MOZ_ASSERT(done());
return;
}
@ -583,35 +583,35 @@ AsmJSProfilingFrameIterator::AsmJSProfilingFrameIterator(const AsmJSActivation &
codeRange_ = codeRange;
stackAddress_ = state.sp;
JS_ASSERT(!done());
MOZ_ASSERT(!done());
}
void
AsmJSProfilingFrameIterator::operator++()
{
if (exitReason_ != AsmJSExit::None) {
JS_ASSERT(codeRange_);
MOZ_ASSERT(codeRange_);
exitReason_ = AsmJSExit::None;
JS_ASSERT(!done());
MOZ_ASSERT(!done());
return;
}
if (!callerPC_) {
JS_ASSERT(!callerFP_);
MOZ_ASSERT(!callerFP_);
codeRange_ = nullptr;
JS_ASSERT(done());
MOZ_ASSERT(done());
return;
}
JS_ASSERT(callerPC_);
MOZ_ASSERT(callerPC_);
const AsmJSModule::CodeRange *codeRange = module_->lookupCodeRange(callerPC_);
JS_ASSERT(codeRange);
MOZ_ASSERT(codeRange);
codeRange_ = codeRange;
switch (codeRange->kind()) {
case AsmJSModule::CodeRange::Entry:
JS_ASSERT(callerFP_ == nullptr);
JS_ASSERT(callerPC_ != nullptr);
MOZ_ASSERT(callerFP_ == nullptr);
MOZ_ASSERT(callerPC_ != nullptr);
callerPC_ = nullptr;
break;
case AsmJSModule::CodeRange::Function:
@ -627,7 +627,7 @@ AsmJSProfilingFrameIterator::operator++()
break;
}
JS_ASSERT(!done());
MOZ_ASSERT(!done());
}
static const char *
@ -665,7 +665,7 @@ BuiltinToName(AsmJSExit::BuiltinKind builtin)
const char *
AsmJSProfilingFrameIterator::label() const
{
JS_ASSERT(!done());
MOZ_ASSERT(!done());
// Use the same string for both time inside and under so that the two
// entries will be coalesced by the profiler.

View File

@ -116,7 +116,7 @@ namespace AsmJSExit
return ReasonKind(uint16_t(reason));
}
static inline BuiltinKind ExtractBuiltinKind(Reason reason) {
JS_ASSERT(ExtractReasonKind(reason) == Reason_Builtin);
MOZ_ASSERT(ExtractReasonKind(reason) == Reason_Builtin);
return BuiltinKind(uint16_t(reason >> 16));
}
}
@ -146,7 +146,7 @@ class AsmJSProfilingFrameIterator
void operator++();
bool done() const { return !codeRange_; }
void *stackAddress() const { JS_ASSERT(!done()); return stackAddress_; }
void *stackAddress() const { MOZ_ASSERT(!done()); return stackAddress_; }
const char *label() const;
};

View File

@ -129,7 +129,7 @@ static bool
ValidateGlobalVariable(JSContext *cx, const AsmJSModule &module, AsmJSModule::Global &global,
HandleValue importVal)
{
JS_ASSERT(global.which() == AsmJSModule::Global::Variable);
MOZ_ASSERT(global.which() == AsmJSModule::Global::Variable);
void *datum = module.globalVarToGlobalDatum(global);
@ -435,7 +435,7 @@ LinkModuleToHeap(JSContext *cx, AsmJSModule &module, Handle<ArrayBufferObjectMay
// This check is sufficient without considering the size of the loaded datum because heap
// loads and stores start on an aligned boundary and the heap byteLength has larger alignment.
JS_ASSERT((module.minHeapLength() - 1) <= INT32_MAX);
MOZ_ASSERT((module.minHeapLength() - 1) <= INT32_MAX);
if (heapLength < module.minHeapLength()) {
ScopedJSFreePtr<char> msg(
JS_smprintf("ArrayBuffer byteLength of 0x%x is less than 0x%x (which is the "
@ -777,7 +777,7 @@ SendFunctionsToVTune(JSContext *cx, AsmJSModule &module)
uint8_t *start = base + func.pod.startCodeOffset;
uint8_t *end = base + func.pod.endCodeOffset;
JS_ASSERT(end >= start);
MOZ_ASSERT(end >= start);
unsigned method_id = iJIT_GetNewMethodID();
if (method_id == 0)
@ -820,7 +820,7 @@ SendFunctionsToPerf(JSContext *cx, AsmJSModule &module)
const AsmJSModule::ProfiledFunction &func = module.profiledFunction(i);
uintptr_t start = base + (unsigned long) func.pod.startCodeOffset;
uintptr_t end = base + (unsigned long) func.pod.endCodeOffset;
JS_ASSERT(end >= start);
MOZ_ASSERT(end >= start);
size_t size = end - start;
JSAutoByteString bytes;
@ -908,7 +908,7 @@ CreateExportObject(JSContext *cx, Handle<AsmJSModuleObject*> moduleObj)
if (!fun)
return nullptr;
JS_ASSERT(func.maybeFieldName() != nullptr);
MOZ_ASSERT(func.maybeFieldName() != nullptr);
RootedId id(cx, NameToId(func.maybeFieldName()));
RootedValue val(cx, ObjectValue(*fun));
if (!DefineNativeProperty(cx, obj, id, val, nullptr, nullptr, JSPROP_ENUMERATE))
@ -1174,7 +1174,7 @@ js::AsmJSFunctionToString(JSContext *cx, HandleFunction fun)
// asm.js functions cannot have been created with a Function constructor
// as they belong within a module.
JS_ASSERT(!(begin == 0 && end == source->length() && source->argumentsNotIncluded()));
MOZ_ASSERT(!(begin == 0 && end == source->length() && source->argumentsNotIncluded()));
if (!out.append("function "))
return nullptr;
@ -1185,7 +1185,7 @@ js::AsmJSFunctionToString(JSContext *cx, HandleFunction fun)
// the function name and the rest (arguments + body).
// asm.js functions can't be anonymous
JS_ASSERT(fun->atom());
MOZ_ASSERT(fun->atom());
if (!out.append(fun->atom()))
return nullptr;

View File

@ -59,7 +59,7 @@ using mozilla::Swap;
static uint8_t *
AllocateExecutableMemory(ExclusiveContext *cx, size_t totalBytes)
{
JS_ASSERT(totalBytes % AsmJSPageSize == 0);
MOZ_ASSERT(totalBytes % AsmJSPageSize == 0);
#ifdef XP_WIN
void *p = VirtualAlloc(nullptr, totalBytes, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
@ -204,7 +204,7 @@ struct CallSiteRetAddrOffset
const CallSite *
AsmJSModule::lookupCallSite(void *returnAddress) const
{
JS_ASSERT(isFinished());
MOZ_ASSERT(isFinished());
uint32_t target = ((uint8_t*)returnAddress) - code_;
size_t lowerBound = 0;
@ -243,7 +243,7 @@ operator<(size_t pcOffset, const AsmJSModule::CodeRange &rhs)
const AsmJSModule::CodeRange *
AsmJSModule::lookupCodeRange(void *pc) const
{
JS_ASSERT(isFinished());
MOZ_ASSERT(isFinished());
uint32_t target = ((uint8_t*)pc) - code_;
size_t lowerBound = 0;
@ -268,8 +268,8 @@ struct HeapAccessOffset
const AsmJSHeapAccess *
AsmJSModule::lookupHeapAccess(void *pc) const
{
JS_ASSERT(isFinished());
JS_ASSERT(containsFunctionPC(pc));
MOZ_ASSERT(isFinished());
MOZ_ASSERT(containsFunctionPC(pc));
uint32_t target = ((uint8_t*)pc) - code_;
size_t lowerBound = 0;
@ -286,12 +286,12 @@ bool
AsmJSModule::finish(ExclusiveContext *cx, TokenStream &tokenStream, MacroAssembler &masm,
const Label &interruptLabel)
{
JS_ASSERT(isFinishedWithFunctionBodies() && !isFinished());
MOZ_ASSERT(isFinishedWithFunctionBodies() && !isFinished());
uint32_t endBeforeCurly = tokenStream.currentToken().pos.end;
uint32_t endAfterCurly = tokenStream.peekTokenPos().end;
JS_ASSERT(endBeforeCurly >= srcBodyStart_);
JS_ASSERT(endAfterCurly >= srcBodyStart_);
MOZ_ASSERT(endBeforeCurly >= srcBodyStart_);
MOZ_ASSERT(endAfterCurly >= srcBodyStart_);
pod.srcLength_ = endBeforeCurly - srcStart_;
pod.srcLengthWithRightBrace_ = endAfterCurly - srcStart_;
@ -304,21 +304,21 @@ AsmJSModule::finish(ExclusiveContext *cx, TokenStream &tokenStream, MacroAssembl
// units of pages.
pod.totalBytes_ = AlignBytes(pod.codeBytes_ + globalDataBytes(), AsmJSPageSize);
JS_ASSERT(!code_);
MOZ_ASSERT(!code_);
code_ = AllocateExecutableMemory(cx, pod.totalBytes_);
if (!code_)
return false;
// Copy the code from the MacroAssembler into its final resting place in the
// AsmJSModule.
JS_ASSERT(uintptr_t(code_) % AsmJSPageSize == 0);
MOZ_ASSERT(uintptr_t(code_) % AsmJSPageSize == 0);
masm.executableCopy(code_);
// c.f. JitCode::copyFrom
JS_ASSERT(masm.jumpRelocationTableBytes() == 0);
JS_ASSERT(masm.dataRelocationTableBytes() == 0);
JS_ASSERT(masm.preBarrierTableBytes() == 0);
JS_ASSERT(!masm.hasEnteredExitFrame());
MOZ_ASSERT(masm.jumpRelocationTableBytes() == 0);
MOZ_ASSERT(masm.dataRelocationTableBytes() == 0);
MOZ_ASSERT(masm.preBarrierTableBytes() == 0);
MOZ_ASSERT(!masm.hasEnteredExitFrame());
// Copy over metadata, making sure to update all offsets on ARM.
@ -347,12 +347,12 @@ AsmJSModule::finish(ExclusiveContext *cx, TokenStream &tokenStream, MacroAssembl
}
for (size_t i = 0; i < codeRanges_.length(); i++) {
codeRanges_[i].updateOffsets(masm);
JS_ASSERT_IF(i > 0, codeRanges_[i - 1].end() <= codeRanges_[i].begin());
MOZ_ASSERT_IF(i > 0, codeRanges_[i - 1].end() <= codeRanges_[i].begin());
}
for (size_t i = 0; i < builtinThunkOffsets_.length(); i++)
builtinThunkOffsets_[i] = masm.actualOffset(builtinThunkOffsets_[i]);
#endif
JS_ASSERT(pod.functionBytes_ % AsmJSPageSize == 0);
MOZ_ASSERT(pod.functionBytes_ % AsmJSPageSize == 0);
// Absolute link metadata: absolute addresses that refer to some fixed
// address in the address space.
@ -452,7 +452,7 @@ AsmJSModule::finish(ExclusiveContext *cx, TokenStream &tokenStream, MacroAssembl
void
AsmJSModule::setAutoFlushICacheRange()
{
JS_ASSERT(isFinished());
MOZ_ASSERT(isFinished());
AutoFlushICache::setRange(uintptr_t(code_), pod.codeBytes_);
}
@ -703,8 +703,8 @@ AddressOf(AsmJSImmKind kind, ExclusiveContext *cx)
void
AsmJSModule::staticallyLink(ExclusiveContext *cx)
{
JS_ASSERT(isFinished());
JS_ASSERT(!isStaticallyLinked());
MOZ_ASSERT(isFinished());
MOZ_ASSERT(!isStaticallyLinked());
// Process staticLinkData_
@ -739,15 +739,15 @@ AsmJSModule::staticallyLink(ExclusiveContext *cx)
exitDatum.ionScript = nullptr;
}
JS_ASSERT(isStaticallyLinked());
MOZ_ASSERT(isStaticallyLinked());
}
void
AsmJSModule::initHeap(Handle<ArrayBufferObjectMaybeShared *> heap, JSContext *cx)
{
JS_ASSERT(IsValidAsmJSHeapLength(heap->byteLength()));
JS_ASSERT(dynamicallyLinked_);
JS_ASSERT(!maybeHeap_);
MOZ_ASSERT(IsValidAsmJSHeapLength(heap->byteLength()));
MOZ_ASSERT(dynamicallyLinked_);
MOZ_ASSERT(!maybeHeap_);
maybeHeap_ = heap;
heapDatum() = heap->dataPointer();
@ -761,7 +761,7 @@ AsmJSModule::initHeap(Handle<ArrayBufferObjectMaybeShared *> heap, JSContext *cx
X86Assembler::setPointer(access.patchLengthAt(code_), heapLength);
void *addr = access.patchOffsetAt(code_);
uint32_t disp = reinterpret_cast<uint32_t>(X86Assembler::getPointer(addr));
JS_ASSERT(disp <= INT32_MAX);
MOZ_ASSERT(disp <= INT32_MAX);
X86Assembler::setPointer(addr, (void *)(heapOffset + disp));
}
#elif defined(JS_CODEGEN_X64)
@ -825,7 +825,7 @@ AsmJSModule::restoreToInitialState(uint8_t *prevCode,
const jit::AsmJSHeapAccess &access = heapAccesses_[i];
void *addr = access.patchOffsetAt(code_);
uint8_t *ptr = reinterpret_cast<uint8_t*>(X86Assembler::getPointer(addr));
JS_ASSERT(ptr >= ptrBase);
MOZ_ASSERT(ptr >= ptrBase);
X86Assembler::setPointer(addr, (void *)(ptr - ptrBase));
}
#endif
@ -876,7 +876,7 @@ AsmJSModuleObject::create(ExclusiveContext *cx, ScopedJSDeletePtr<AsmJSModule> *
AsmJSModule &
AsmJSModuleObject::module() const
{
JS_ASSERT(is<AsmJSModuleObject>());
MOZ_ASSERT(is<AsmJSModuleObject>());
return *(AsmJSModule *)getReservedSlot(MODULE_SLOT).toPrivate();
}
@ -928,7 +928,7 @@ AsmJSModule::Name::serializedSize() const
static uint8_t *
SerializeName(uint8_t *cursor, PropertyName *name)
{
JS_ASSERT_IF(name, !name->empty());
MOZ_ASSERT_IF(name, !name->empty());
if (name) {
static_assert(JSString::MAX_LENGTH <= INT32_MAX, "String length must fit in 31 bits");
uint32_t length = name->length();
@ -1207,23 +1207,23 @@ AsmJSModule::CodeRange::CodeRange(uint32_t nameIndex, uint32_t lineNumber,
u.kind_ = Function;
setDeltas(l.entry.offset(), l.profilingJump.offset(), l.profilingEpilogue.offset());
JS_ASSERT(l.begin.offset() < l.entry.offset());
JS_ASSERT(l.entry.offset() < l.profilingJump.offset());
JS_ASSERT(l.profilingJump.offset() < l.profilingEpilogue.offset());
JS_ASSERT(l.profilingEpilogue.offset() < l.profilingReturn.offset());
JS_ASSERT(l.profilingReturn.offset() < l.end.offset());
MOZ_ASSERT(l.begin.offset() < l.entry.offset());
MOZ_ASSERT(l.entry.offset() < l.profilingJump.offset());
MOZ_ASSERT(l.profilingJump.offset() < l.profilingEpilogue.offset());
MOZ_ASSERT(l.profilingEpilogue.offset() < l.profilingReturn.offset());
MOZ_ASSERT(l.profilingReturn.offset() < l.end.offset());
}
void
AsmJSModule::CodeRange::setDeltas(uint32_t entry, uint32_t profilingJump, uint32_t profilingEpilogue)
{
JS_ASSERT(entry - begin_ <= UINT8_MAX);
MOZ_ASSERT(entry - begin_ <= UINT8_MAX);
u.func.beginToEntry_ = entry - begin_;
JS_ASSERT(profilingReturn_ - profilingJump <= UINT8_MAX);
MOZ_ASSERT(profilingReturn_ - profilingJump <= UINT8_MAX);
u.func.profilingJumpToProfilingReturn_ = profilingReturn_ - profilingJump;
JS_ASSERT(profilingReturn_ - profilingEpilogue <= UINT8_MAX);
MOZ_ASSERT(profilingReturn_ - profilingEpilogue <= UINT8_MAX);
u.func.profilingEpilogueToProfilingReturn_ = profilingReturn_ - profilingEpilogue;
}
@ -1233,8 +1233,8 @@ AsmJSModule::CodeRange::CodeRange(Kind kind, uint32_t begin, uint32_t end)
{
u.kind_ = kind;
JS_ASSERT(begin_ <= end_);
JS_ASSERT(u.kind_ == Entry || u.kind_ == Inline);
MOZ_ASSERT(begin_ <= end_);
MOZ_ASSERT(u.kind_ == Entry || u.kind_ == Inline);
}
AsmJSModule::CodeRange::CodeRange(Kind kind, uint32_t begin, uint32_t profilingReturn, uint32_t end)
@ -1244,9 +1244,9 @@ AsmJSModule::CodeRange::CodeRange(Kind kind, uint32_t begin, uint32_t profilingR
{
u.kind_ = kind;
JS_ASSERT(begin_ < profilingReturn_);
JS_ASSERT(profilingReturn_ < end_);
JS_ASSERT(u.kind_ == IonFFI || u.kind_ == SlowFFI || u.kind_ == Interrupt);
MOZ_ASSERT(begin_ < profilingReturn_);
MOZ_ASSERT(profilingReturn_ < end_);
MOZ_ASSERT(u.kind_ == IonFFI || u.kind_ == SlowFFI || u.kind_ == Interrupt);
}
AsmJSModule::CodeRange::CodeRange(AsmJSExit::BuiltinKind builtin, uint32_t begin,
@ -1258,8 +1258,8 @@ AsmJSModule::CodeRange::CodeRange(AsmJSExit::BuiltinKind builtin, uint32_t begin
u.kind_ = Thunk;
u.thunk.target_ = builtin;
JS_ASSERT(begin_ < profilingReturn_);
JS_ASSERT(profilingReturn_ < end_);
MOZ_ASSERT(begin_ < profilingReturn_);
MOZ_ASSERT(profilingReturn_ < end_);
}
void
@ -1556,7 +1556,7 @@ AsmJSModule::clone(JSContext *cx, ScopedJSDeletePtr<AsmJSModule> *moduleOut) con
void
AsmJSModule::setProfilingEnabled(bool enabled, JSContext *cx)
{
JS_ASSERT(isDynamicallyLinked());
MOZ_ASSERT(isDynamicallyLinked());
if (profilingEnabled_ == enabled)
return;
@ -1623,8 +1623,8 @@ AsmJSModule::setProfilingEnabled(bool enabled, JSContext *cx)
uint8_t *profilingEntry = code_ + codeRange->begin();
uint8_t *entry = code_ + codeRange->entry();
JS_ASSERT_IF(profilingEnabled_, callee == profilingEntry);
JS_ASSERT_IF(!profilingEnabled_, callee == entry);
MOZ_ASSERT_IF(profilingEnabled_, callee == profilingEntry);
MOZ_ASSERT_IF(!profilingEnabled_, callee == entry);
uint8_t *newCallee = enabled ? profilingEntry : entry;
#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
@ -1652,8 +1652,8 @@ AsmJSModule::setProfilingEnabled(bool enabled, JSContext *cx)
const CodeRange *codeRange = lookupCodeRange(callee);
uint8_t *profilingEntry = code_ + codeRange->begin();
uint8_t *entry = code_ + codeRange->entry();
JS_ASSERT_IF(profilingEnabled_, callee == profilingEntry);
JS_ASSERT_IF(!profilingEnabled_, callee == entry);
MOZ_ASSERT_IF(profilingEnabled_, callee == profilingEntry);
MOZ_ASSERT_IF(!profilingEnabled_, callee == entry);
if (enabled)
array[j] = profilingEntry;
else
@ -1674,24 +1674,24 @@ AsmJSModule::setProfilingEnabled(bool enabled, JSContext *cx)
// 0x90. The offset is relative to the address of the instruction after
// the jump. 0x66 0x90 is the canonical two-byte nop.
ptrdiff_t jumpImmediate = profilingEpilogue - jump - 2;
JS_ASSERT(jumpImmediate > 0 && jumpImmediate <= 127);
MOZ_ASSERT(jumpImmediate > 0 && jumpImmediate <= 127);
if (enabled) {
JS_ASSERT(jump[0] == 0x66);
JS_ASSERT(jump[1] == 0x90);
MOZ_ASSERT(jump[0] == 0x66);
MOZ_ASSERT(jump[1] == 0x90);
jump[0] = 0xeb;
jump[1] = jumpImmediate;
} else {
JS_ASSERT(jump[0] == 0xeb);
JS_ASSERT(jump[1] == jumpImmediate);
MOZ_ASSERT(jump[0] == 0xeb);
MOZ_ASSERT(jump[1] == jumpImmediate);
jump[0] = 0x66;
jump[1] = 0x90;
}
#elif defined(JS_CODEGEN_ARM)
if (enabled) {
JS_ASSERT(reinterpret_cast<Instruction*>(jump)->is<InstNOP>());
MOZ_ASSERT(reinterpret_cast<Instruction*>(jump)->is<InstNOP>());
new (jump) InstBImm(BOffImm(profilingEpilogue - jump), Assembler::Always);
} else {
JS_ASSERT(reinterpret_cast<Instruction*>(jump)->is<InstBImm>());
MOZ_ASSERT(reinterpret_cast<Instruction*>(jump)->is<InstBImm>());
new (jump) InstNOP();
}
#elif defined(JS_CODEGEN_MIPS)
@ -1727,7 +1727,7 @@ AsmJSModule::setProfilingEnabled(bool enabled, JSContext *cx)
const AsmJSModule::CodeRange *codeRange = lookupCodeRange(caller);
if (codeRange->isThunk())
continue;
JS_ASSERT(codeRange->isFunction());
MOZ_ASSERT(codeRange->isFunction());
Assembler::PatchDataWithValueCheck(CodeLocationLabel(caller),
PatchedImmPtr(to),
PatchedImmPtr(from));
@ -1740,8 +1740,8 @@ AsmJSModule::setProfilingEnabled(bool enabled, JSContext *cx)
void
AsmJSModule::protectCode(JSRuntime *rt) const
{
JS_ASSERT(isDynamicallyLinked());
JS_ASSERT(rt->currentThreadOwnsInterruptLock());
MOZ_ASSERT(isDynamicallyLinked());
MOZ_ASSERT(rt->currentThreadOwnsInterruptLock());
codeIsProtected_ = true;
@ -1764,8 +1764,8 @@ AsmJSModule::protectCode(JSRuntime *rt) const
void
AsmJSModule::unprotectCode(JSRuntime *rt) const
{
JS_ASSERT(isDynamicallyLinked());
JS_ASSERT(rt->currentThreadOwnsInterruptLock());
MOZ_ASSERT(isDynamicallyLinked());
MOZ_ASSERT(rt->currentThreadOwnsInterruptLock());
codeIsProtected_ = false;
@ -1785,8 +1785,8 @@ AsmJSModule::unprotectCode(JSRuntime *rt) const
bool
AsmJSModule::codeIsProtected(JSRuntime *rt) const
{
JS_ASSERT(isDynamicallyLinked());
JS_ASSERT(rt->currentThreadOwnsInterruptLock());
MOZ_ASSERT(isDynamicallyLinked());
MOZ_ASSERT(rt->currentThreadOwnsInterruptLock());
return codeIsProtected_;
}
@ -1910,7 +1910,7 @@ class ModuleCharsForStore : ModuleChars
public:
bool init(AsmJSParser &parser) {
JS_ASSERT(beginOffset(parser) < endOffset(parser));
MOZ_ASSERT(beginOffset(parser) < endOffset(parser));
uncompressedSize_ = (endOffset(parser) - beginOffset(parser)) * sizeof(char16_t);
size_t maxCompressedSize = LZ4::maxCompressedSize(uncompressedSize_);
@ -2004,7 +2004,7 @@ class ModuleCharsForLookup : ModuleChars
bool match(AsmJSParser &parser) const {
const char16_t *parseBegin = parser.tokenStream.rawBase() + beginOffset(parser);
const char16_t *parseLimit = parser.tokenStream.rawLimit();
JS_ASSERT(parseLimit >= parseBegin);
MOZ_ASSERT(parseLimit >= parseBegin);
if (uint32_t(parseLimit - parseBegin) < chars_.length())
return false;
if (!PodEqual(chars_.begin(), parseBegin, chars_.length()))
@ -2094,7 +2094,7 @@ js::StoreAsmJSModuleInCache(AsmJSParser &parser,
cursor = moduleChars.serialize(cursor);
cursor = module.serialize(cursor);
JS_ASSERT(cursor == entry.memory + serializedSize);
MOZ_ASSERT(cursor == entry.memory + serializedSize);
return true;
}

View File

@ -134,7 +134,7 @@ class AsmJSNumLit
AsmJSNumLit lit;
lit.which_ = w;
lit.value.scalar_ = v;
JS_ASSERT(!lit.isSimd());
MOZ_ASSERT(!lit.isSimd());
return lit;
}
@ -142,7 +142,7 @@ class AsmJSNumLit
AsmJSNumLit lit;
lit.which_ = w;
lit.value.simd_ = c;
JS_ASSERT(lit.isSimd());
MOZ_ASSERT(lit.isSimd());
return lit;
}
@ -151,22 +151,22 @@ class AsmJSNumLit
}
int32_t toInt32() const {
JS_ASSERT(which_ == Fixnum || which_ == NegativeInt || which_ == BigUnsigned);
MOZ_ASSERT(which_ == Fixnum || which_ == NegativeInt || which_ == BigUnsigned);
return value.scalar_.toInt32();
}
double toDouble() const {
JS_ASSERT(which_ == Double);
MOZ_ASSERT(which_ == Double);
return value.scalar_.toDouble();
}
float toFloat() const {
JS_ASSERT(which_ == Float);
MOZ_ASSERT(which_ == Float);
return float(value.scalar_.toDouble());
}
Value scalarValue() const {
JS_ASSERT(which_ != OutOfRangeInt);
MOZ_ASSERT(which_ != OutOfRangeInt);
return value.scalar_;
}
@ -175,7 +175,7 @@ class AsmJSNumLit
}
const jit::SimdConstant &simdValue() const {
JS_ASSERT(isSimd());
MOZ_ASSERT(isSimd());
return value.simd_;
}
@ -238,14 +238,14 @@ class AsmJSModule
Global(Which which, PropertyName *name) {
pod.which_ = which;
name_ = name;
JS_ASSERT_IF(name_, name_->isTenured());
MOZ_ASSERT_IF(name_, name_->isTenured());
}
void trace(JSTracer *trc) {
if (name_)
MarkStringUnbarriered(trc, &name_, "asm.js global name");
JS_ASSERT_IF(pod.which_ == Variable && pod.u.var.initKind_ == InitConstant,
!pod.u.var.u.numLit_.scalarValue().isMarkable());
MOZ_ASSERT_IF(pod.which_ == Variable && pod.u.var.initKind_ == InitConstant,
!pod.u.var.u.numLit_.scalarValue().isMarkable());
}
public:
@ -254,82 +254,82 @@ class AsmJSModule
return pod.which_;
}
uint32_t varIndex() const {
JS_ASSERT(pod.which_ == Variable);
MOZ_ASSERT(pod.which_ == Variable);
return pod.u.var.index_;
}
VarInitKind varInitKind() const {
JS_ASSERT(pod.which_ == Variable);
MOZ_ASSERT(pod.which_ == Variable);
return pod.u.var.initKind_;
}
const AsmJSNumLit &varInitNumLit() const {
JS_ASSERT(pod.which_ == Variable);
JS_ASSERT(pod.u.var.initKind_ == InitConstant);
MOZ_ASSERT(pod.which_ == Variable);
MOZ_ASSERT(pod.u.var.initKind_ == InitConstant);
return pod.u.var.u.numLit_;
}
AsmJSCoercion varInitCoercion() const {
JS_ASSERT(pod.which_ == Variable);
JS_ASSERT(pod.u.var.initKind_ == InitImport);
MOZ_ASSERT(pod.which_ == Variable);
MOZ_ASSERT(pod.u.var.initKind_ == InitImport);
return pod.u.var.u.coercion_;
}
PropertyName *varImportField() const {
JS_ASSERT(pod.which_ == Variable);
JS_ASSERT(pod.u.var.initKind_ == InitImport);
MOZ_ASSERT(pod.which_ == Variable);
MOZ_ASSERT(pod.u.var.initKind_ == InitImport);
return name_;
}
PropertyName *ffiField() const {
JS_ASSERT(pod.which_ == FFI);
MOZ_ASSERT(pod.which_ == FFI);
return name_;
}
uint32_t ffiIndex() const {
JS_ASSERT(pod.which_ == FFI);
MOZ_ASSERT(pod.which_ == FFI);
return pod.u.ffiIndex_;
}
PropertyName *viewName() const {
JS_ASSERT(pod.which_ == ArrayView);
MOZ_ASSERT(pod.which_ == ArrayView);
return name_;
}
Scalar::Type viewType() const {
JS_ASSERT(pod.which_ == ArrayView);
MOZ_ASSERT(pod.which_ == ArrayView);
return pod.u.viewType_;
}
PropertyName *mathName() const {
JS_ASSERT(pod.which_ == MathBuiltinFunction);
MOZ_ASSERT(pod.which_ == MathBuiltinFunction);
return name_;
}
AsmJSMathBuiltinFunction mathBuiltinFunction() const {
JS_ASSERT(pod.which_ == MathBuiltinFunction);
MOZ_ASSERT(pod.which_ == MathBuiltinFunction);
return pod.u.mathBuiltinFunc_;
}
AsmJSSimdType simdCtorType() const {
JS_ASSERT(pod.which_ == SimdCtor);
MOZ_ASSERT(pod.which_ == SimdCtor);
return pod.u.simdCtorType_;
}
PropertyName *simdCtorName() const {
JS_ASSERT(pod.which_ == SimdCtor);
MOZ_ASSERT(pod.which_ == SimdCtor);
return name_;
}
PropertyName *simdOperationName() const {
JS_ASSERT(pod.which_ == SimdOperation);
MOZ_ASSERT(pod.which_ == SimdOperation);
return name_;
}
AsmJSSimdOperation simdOperation() const {
JS_ASSERT(pod.which_ == SimdOperation);
MOZ_ASSERT(pod.which_ == SimdOperation);
return pod.u.simdOp.which_;
}
AsmJSSimdType simdOperationType() const {
JS_ASSERT(pod.which_ == SimdOperation);
MOZ_ASSERT(pod.which_ == SimdOperation);
return pod.u.simdOp.type_;
}
PropertyName *constantName() const {
JS_ASSERT(pod.which_ == Constant);
MOZ_ASSERT(pod.which_ == Constant);
return name_;
}
ConstantKind constantKind() const {
JS_ASSERT(pod.which_ == Constant);
MOZ_ASSERT(pod.which_ == Constant);
return pod.u.constant.kind_;
}
double constantValue() const {
JS_ASSERT(pod.which_ == Constant);
MOZ_ASSERT(pod.which_ == Constant);
return pod.u.constant.value_;
}
@ -361,11 +361,11 @@ class AsmJSModule
return globalDataOffset_;
}
void initInterpOffset(unsigned off) {
JS_ASSERT(!interpCodeOffset_);
MOZ_ASSERT(!interpCodeOffset_);
interpCodeOffset_ = off;
}
void initIonOffset(unsigned off) {
JS_ASSERT(!ionCodeOffset_);
MOZ_ASSERT(!ionCodeOffset_);
ionCodeOffset_ = off;
}
void updateOffsets(jit::MacroAssembler &masm) {
@ -430,7 +430,7 @@ class AsmJSModule
pod.codeOffset_ = UINT32_MAX;
pod.startOffsetInModule_ = startOffsetInModule;
pod.endOffsetInModule_ = endOffsetInModule;
JS_ASSERT_IF(maybeFieldName_, name_->isTenured());
MOZ_ASSERT_IF(maybeFieldName_, name_->isTenured());
}
void trace(JSTracer *trc) {
@ -449,7 +449,7 @@ class AsmJSModule
}
void initCodeOffset(unsigned off) {
JS_ASSERT(pod.codeOffset_ == UINT32_MAX);
MOZ_ASSERT(pod.codeOffset_ == UINT32_MAX);
pod.codeOffset_ = off;
}
void updateCodeOffset(jit::MacroAssembler &masm) {
@ -529,42 +529,42 @@ class AsmJSModule
return begin_;
}
uint32_t entry() const {
JS_ASSERT(isFunction());
MOZ_ASSERT(isFunction());
return begin_ + u.func.beginToEntry_;
}
uint32_t end() const {
return end_;
}
uint32_t profilingJump() const {
JS_ASSERT(isFunction());
MOZ_ASSERT(isFunction());
return profilingReturn_ - u.func.profilingJumpToProfilingReturn_;
}
uint32_t profilingEpilogue() const {
JS_ASSERT(isFunction());
MOZ_ASSERT(isFunction());
return profilingReturn_ - u.func.profilingEpilogueToProfilingReturn_;
}
uint32_t profilingReturn() const {
JS_ASSERT(isFunction() || isFFI() || isInterrupt() || isThunk());
MOZ_ASSERT(isFunction() || isFFI() || isInterrupt() || isThunk());
return profilingReturn_;
}
uint32_t functionNameIndex() const {
JS_ASSERT(isFunction());
MOZ_ASSERT(isFunction());
return nameIndex_;
}
PropertyName *functionName(const AsmJSModule &module) const {
JS_ASSERT(isFunction());
MOZ_ASSERT(isFunction());
return module.names_[nameIndex_].name();
}
const char *functionProfilingLabel(const AsmJSModule &module) const {
JS_ASSERT(isFunction());
MOZ_ASSERT(isFunction());
return module.profilingLabels_[nameIndex_].get();
}
uint32_t functionLineNumber() const {
JS_ASSERT(isFunction());
MOZ_ASSERT(isFunction());
return lineNumber_;
}
AsmJSExit::BuiltinKind thunkTarget() const {
JS_ASSERT(isThunk());
MOZ_ASSERT(isThunk());
return AsmJSExit::BuiltinKind(u.thunk.target_);
}
};
@ -618,7 +618,7 @@ class AsmJSModule
unsigned line = 0, unsigned column = 0)
: name(name)
{
JS_ASSERT(name->isTenured());
MOZ_ASSERT(name->isTenured());
pod.startCodeOffset = start;
pod.endCodeOffset = end;
@ -648,7 +648,7 @@ class AsmJSModule
: ProfiledFunction(name, start, end), endInlineCodeOffset(endInline),
blocks(mozilla::Move(blocksVector))
{
JS_ASSERT(name->isTenured());
MOZ_ASSERT(name->isTenured());
}
ProfiledBlocksFunction(ProfiledBlocksFunction &&copy)
@ -677,7 +677,7 @@ class AsmJSModule
#elif defined(JS_CODEGEN_ARM)
// On ARM, CodeLabels are only used to label raw pointers, so in
// all cases on ARM, a RelativePatch means patching a raw pointer.
JS_ASSERT(kind == CodeLabel || kind == RawPointer);
MOZ_ASSERT(kind == CodeLabel || kind == RawPointer);
#endif
// On X64 and X86, all RelativePatch-es are patched as raw pointers.
}
@ -707,11 +707,11 @@ class AsmJSModule
public:
OffsetVector &operator[](size_t i) {
JS_ASSERT(i < jit::AsmJSImm_Limit);
MOZ_ASSERT(i < jit::AsmJSImm_Limit);
return array_[i];
}
const OffsetVector &operator[](size_t i) const {
JS_ASSERT(i < jit::AsmJSImm_Limit);
MOZ_ASSERT(i < jit::AsmJSImm_Limit);
return array_[i];
}
@ -815,7 +815,7 @@ class AsmJSModule
// These functions may be used as soon as the module is constructed:
ScriptSource *scriptSource() const {
JS_ASSERT(scriptSource_);
MOZ_ASSERT(scriptSource_);
return scriptSource_;
}
bool strict() const {
@ -871,18 +871,18 @@ class AsmJSModule
// module prologue (before the function bodies):
void initGlobalArgumentName(PropertyName *n) {
JS_ASSERT(!isFinishedWithModulePrologue());
JS_ASSERT_IF(n, n->isTenured());
MOZ_ASSERT(!isFinishedWithModulePrologue());
MOZ_ASSERT_IF(n, n->isTenured());
globalArgumentName_ = n;
}
void initImportArgumentName(PropertyName *n) {
JS_ASSERT(!isFinishedWithModulePrologue());
JS_ASSERT_IF(n, n->isTenured());
MOZ_ASSERT(!isFinishedWithModulePrologue());
MOZ_ASSERT_IF(n, n->isTenured());
importArgumentName_ = n;
}
void initBufferArgumentName(PropertyName *n) {
JS_ASSERT(!isFinishedWithModulePrologue());
JS_ASSERT_IF(n, n->isTenured());
MOZ_ASSERT(!isFinishedWithModulePrologue());
MOZ_ASSERT_IF(n, n->isTenured());
bufferArgumentName_ = n;
}
PropertyName *globalArgumentName() const {
@ -895,7 +895,7 @@ class AsmJSModule
return bufferArgumentName_;
}
bool addGlobalVarInit(const AsmJSNumLit &lit, uint32_t *globalIndex) {
JS_ASSERT(!isFinishedWithModulePrologue());
MOZ_ASSERT(!isFinishedWithModulePrologue());
Global g(Global::Variable, nullptr);
g.pod.u.var.initKind_ = Global::InitConstant;
g.pod.u.var.u.numLit_ = lit;
@ -926,7 +926,7 @@ class AsmJSModule
MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("unexpected AsmJSCoercion");
}
bool addGlobalVarImport(PropertyName *name, AsmJSCoercion coercion, uint32_t *globalIndex) {
JS_ASSERT(!isFinishedWithModulePrologue());
MOZ_ASSERT(!isFinishedWithModulePrologue());
Global g(Global::Variable, name);
g.pod.u.var.initKind_ = Global::InitImport;
g.pod.u.var.u.coercion_ = coercion;
@ -936,7 +936,7 @@ class AsmJSModule
return globals_.append(g);
}
bool addFFI(PropertyName *field, uint32_t *ffiIndex) {
JS_ASSERT(!isFinishedWithModulePrologue());
MOZ_ASSERT(!isFinishedWithModulePrologue());
if (pod.numFFIs_ == UINT32_MAX)
return false;
Global g(Global::FFI, field);
@ -944,20 +944,20 @@ class AsmJSModule
return globals_.append(g);
}
bool addArrayView(Scalar::Type vt, PropertyName *field) {
JS_ASSERT(!isFinishedWithModulePrologue());
MOZ_ASSERT(!isFinishedWithModulePrologue());
pod.hasArrayView_ = true;
Global g(Global::ArrayView, field);
g.pod.u.viewType_ = vt;
return globals_.append(g);
}
bool addMathBuiltinFunction(AsmJSMathBuiltinFunction func, PropertyName *field) {
JS_ASSERT(!isFinishedWithModulePrologue());
MOZ_ASSERT(!isFinishedWithModulePrologue());
Global g(Global::MathBuiltinFunction, field);
g.pod.u.mathBuiltinFunc_ = func;
return globals_.append(g);
}
bool addMathBuiltinConstant(double value, PropertyName *field) {
JS_ASSERT(!isFinishedWithModulePrologue());
MOZ_ASSERT(!isFinishedWithModulePrologue());
Global g(Global::Constant, field);
g.pod.u.constant.value_ = value;
g.pod.u.constant.kind_ = Global::MathConstant;
@ -975,7 +975,7 @@ class AsmJSModule
return globals_.append(g);
}
bool addGlobalConstant(double value, PropertyName *name) {
JS_ASSERT(!isFinishedWithModulePrologue());
MOZ_ASSERT(!isFinishedWithModulePrologue());
Global g(Global::Constant, name);
g.pod.u.constant.value_ = value;
g.pod.u.constant.kind_ = Global::GlobalConstant;
@ -991,16 +991,16 @@ class AsmJSModule
/*************************************************************************/
void startFunctionBodies() {
JS_ASSERT(!isFinishedWithModulePrologue());
MOZ_ASSERT(!isFinishedWithModulePrologue());
pod.funcPtrTableAndExitBytes_ = 0;
JS_ASSERT(isFinishedWithModulePrologue());
MOZ_ASSERT(isFinishedWithModulePrologue());
}
/*************************************************************************/
// These functions are called while parsing/compiling function bodies:
void requireHeapLengthToBeAtLeast(uint32_t len) {
JS_ASSERT(isFinishedWithModulePrologue() && !isFinishedWithFunctionBodies());
MOZ_ASSERT(isFinishedWithModulePrologue() && !isFinishedWithFunctionBodies());
len = RoundUpToNextValidAsmJSHeapLength(len);
if (len > pod.minHeapLength_)
pod.minHeapLength_ = len;
@ -1014,8 +1014,8 @@ class AsmJSModule
bool addFunctionCodeRange(PropertyName *name, uint32_t lineNumber,
const AsmJSFunctionLabels &labels)
{
JS_ASSERT(!isFinished());
JS_ASSERT(name->isTenured());
MOZ_ASSERT(!isFinished());
MOZ_ASSERT(name->isTenured());
if (names_.length() >= UINT32_MAX)
return false;
uint32_t nameIndex = names_.length();
@ -1028,7 +1028,7 @@ class AsmJSModule
codeRanges_.append(CodeRange(builtin, begin, profilingReturn, end));
}
bool addExit(unsigned ffiIndex, unsigned *exitIndex) {
JS_ASSERT(isFinishedWithModulePrologue() && !isFinishedWithFunctionBodies());
MOZ_ASSERT(isFinishedWithModulePrologue() && !isFinishedWithFunctionBodies());
if (SIZE_MAX - pod.funcPtrTableAndExitBytes_ < sizeof(ExitDatum))
return false;
uint32_t globalDataOffset = globalDataBytes();
@ -1038,20 +1038,20 @@ class AsmJSModule
return exits_.append(Exit(ffiIndex, globalDataOffset));
}
unsigned numExits() const {
JS_ASSERT(isFinishedWithModulePrologue());
MOZ_ASSERT(isFinishedWithModulePrologue());
return exits_.length();
}
Exit &exit(unsigned i) {
JS_ASSERT(isFinishedWithModulePrologue());
MOZ_ASSERT(isFinishedWithModulePrologue());
return exits_[i];
}
const Exit &exit(unsigned i) const {
JS_ASSERT(isFinishedWithModulePrologue());
MOZ_ASSERT(isFinishedWithModulePrologue());
return exits_[i];
}
bool addFuncPtrTable(unsigned numElems, uint32_t *globalDataOffset) {
JS_ASSERT(isFinishedWithModulePrologue() && !isFinished());
JS_ASSERT(IsPowerOfTwo(numElems));
MOZ_ASSERT(isFinishedWithModulePrologue() && !isFinished());
MOZ_ASSERT(IsPowerOfTwo(numElems));
if (SIZE_MAX - pod.funcPtrTableAndExitBytes_ < numElems * sizeof(void*))
return false;
*globalDataOffset = globalDataBytes();
@ -1061,23 +1061,23 @@ class AsmJSModule
return true;
}
bool addFunctionCounts(jit::IonScriptCounts *counts) {
JS_ASSERT(isFinishedWithModulePrologue() && !isFinishedWithFunctionBodies());
MOZ_ASSERT(isFinishedWithModulePrologue() && !isFinishedWithFunctionBodies());
return functionCounts_.append(counts);
}
#if defined(MOZ_VTUNE) || defined(JS_ION_PERF)
bool addProfiledFunction(PropertyName *name, unsigned codeStart, unsigned codeEnd,
unsigned line, unsigned column)
{
JS_ASSERT(isFinishedWithModulePrologue() && !isFinishedWithFunctionBodies());
MOZ_ASSERT(isFinishedWithModulePrologue() && !isFinishedWithFunctionBodies());
ProfiledFunction func(name, codeStart, codeEnd, line, column);
return profiledFunctions_.append(func);
}
unsigned numProfiledFunctions() const {
JS_ASSERT(isFinishedWithModulePrologue());
MOZ_ASSERT(isFinishedWithModulePrologue());
return profiledFunctions_.length();
}
ProfiledFunction &profiledFunction(unsigned i) {
JS_ASSERT(isFinishedWithModulePrologue());
MOZ_ASSERT(isFinishedWithModulePrologue());
return profiledFunctions_[i];
}
#endif
@ -1085,16 +1085,16 @@ class AsmJSModule
bool addProfiledBlocks(PropertyName *name, unsigned codeBegin, unsigned inlineEnd,
unsigned codeEnd, jit::BasicBlocksVector &basicBlocks)
{
JS_ASSERT(isFinishedWithModulePrologue() && !isFinishedWithFunctionBodies());
MOZ_ASSERT(isFinishedWithModulePrologue() && !isFinishedWithFunctionBodies());
ProfiledBlocksFunction func(name, codeBegin, inlineEnd, codeEnd, basicBlocks);
return perfProfiledBlocksFunctions_.append(mozilla::Move(func));
}
unsigned numPerfBlocksFunctions() const {
JS_ASSERT(isFinishedWithModulePrologue());
MOZ_ASSERT(isFinishedWithModulePrologue());
return perfProfiledBlocksFunctions_.length();
}
ProfiledBlocksFunction &perfProfiledBlocksFunction(unsigned i) {
JS_ASSERT(isFinishedWithModulePrologue());
MOZ_ASSERT(isFinishedWithModulePrologue());
return perfProfiledBlocksFunctions_[i];
}
#endif
@ -1104,9 +1104,9 @@ class AsmJSModule
// This function is called after compiling the function bodies (before
// compiling entries/exits) to record the extent of compiled function code.
void finishFunctionBodies(size_t functionBytes) {
JS_ASSERT(isFinishedWithModulePrologue() && !isFinishedWithFunctionBodies());
MOZ_ASSERT(isFinishedWithModulePrologue() && !isFinishedWithFunctionBodies());
pod.functionBytes_ = functionBytes;
JS_ASSERT(isFinishedWithFunctionBodies());
MOZ_ASSERT(isFinishedWithFunctionBodies());
}
/*************************************************************************/
@ -1124,23 +1124,23 @@ class AsmJSModule
// NB: funcSrcBegin/funcSrcEnd are given relative to the ScriptSource
// (the entire file) and ExportedFunctions store offsets relative to
// the beginning of the module (so that they are caching-invariant).
JS_ASSERT(isFinishedWithFunctionBodies() && !isFinished());
JS_ASSERT(srcStart_ < funcSrcBegin);
JS_ASSERT(funcSrcBegin < funcSrcEnd);
MOZ_ASSERT(isFinishedWithFunctionBodies() && !isFinished());
MOZ_ASSERT(srcStart_ < funcSrcBegin);
MOZ_ASSERT(funcSrcBegin < funcSrcEnd);
ExportedFunction func(name, funcSrcBegin - srcStart_, funcSrcEnd - srcStart_,
maybeFieldName, mozilla::Move(argCoercions), returnType);
return exports_.length() < UINT32_MAX && exports_.append(mozilla::Move(func));
}
unsigned numExportedFunctions() const {
JS_ASSERT(isFinishedWithFunctionBodies());
MOZ_ASSERT(isFinishedWithFunctionBodies());
return exports_.length();
}
const ExportedFunction &exportedFunction(unsigned i) const {
JS_ASSERT(isFinishedWithFunctionBodies());
MOZ_ASSERT(isFinishedWithFunctionBodies());
return exports_[i];
}
ExportedFunction &exportedFunction(unsigned i) {
JS_ASSERT(isFinishedWithFunctionBodies());
MOZ_ASSERT(isFinishedWithFunctionBodies());
return exports_[i];
}
@ -1159,50 +1159,50 @@ class AsmJSModule
// These accessor functions can be used after finish():
bool hasArrayView() const {
JS_ASSERT(isFinished());
MOZ_ASSERT(isFinished());
return pod.hasArrayView_;
}
unsigned numFFIs() const {
JS_ASSERT(isFinished());
MOZ_ASSERT(isFinished());
return pod.numFFIs_;
}
uint32_t srcEndBeforeCurly() const {
JS_ASSERT(isFinished());
MOZ_ASSERT(isFinished());
return srcStart_ + pod.srcLength_;
}
uint32_t srcEndAfterCurly() const {
JS_ASSERT(isFinished());
MOZ_ASSERT(isFinished());
return srcStart_ + pod.srcLengthWithRightBrace_;
}
uint8_t *codeBase() const {
JS_ASSERT(isFinished());
JS_ASSERT(uintptr_t(code_) % AsmJSPageSize == 0);
MOZ_ASSERT(isFinished());
MOZ_ASSERT(uintptr_t(code_) % AsmJSPageSize == 0);
return code_;
}
size_t functionBytes() const {
JS_ASSERT(isFinished());
MOZ_ASSERT(isFinished());
return pod.functionBytes_;
}
size_t codeBytes() const {
JS_ASSERT(isFinished());
MOZ_ASSERT(isFinished());
return pod.codeBytes_;
}
bool containsFunctionPC(void *pc) const {
JS_ASSERT(isFinished());
MOZ_ASSERT(isFinished());
return pc >= code_ && pc < (code_ + functionBytes());
}
bool containsCodePC(void *pc) const {
JS_ASSERT(isFinished());
MOZ_ASSERT(isFinished());
return pc >= code_ && pc < (code_ + codeBytes());
}
uint8_t *interpExitTrampoline(const Exit &exit) const {
JS_ASSERT(isFinished());
JS_ASSERT(exit.interpCodeOffset_);
MOZ_ASSERT(isFinished());
MOZ_ASSERT(exit.interpCodeOffset_);
return code_ + exit.interpCodeOffset_;
}
uint8_t *ionExitTrampoline(const Exit &exit) const {
JS_ASSERT(isFinished());
JS_ASSERT(exit.ionCodeOffset_);
MOZ_ASSERT(isFinished());
MOZ_ASSERT(exit.ionCodeOffset_);
return code_ + exit.ionCodeOffset_;
}
@ -1231,11 +1231,11 @@ class AsmJSModule
// while type checking function bodies (as exits and uses of
// function-pointer tables are encountered).
size_t offsetOfGlobalData() const {
JS_ASSERT(isFinished());
MOZ_ASSERT(isFinished());
return pod.codeBytes_;
}
uint8_t *globalData() const {
JS_ASSERT(isFinished());
MOZ_ASSERT(isFinished());
return code_ + offsetOfGlobalData();
}
size_t globalSimdVarsOffset() const {
@ -1265,7 +1265,7 @@ class AsmJSModule
return sizeof(void*);
}
uint8_t *&heapDatum() const {
JS_ASSERT(isFinished());
MOZ_ASSERT(isFinished());
return *(uint8_t**)(globalData() + heapGlobalDataOffset());
}
static unsigned nan64GlobalDataOffset() {
@ -1285,24 +1285,24 @@ class AsmJSModule
*(float *)(globalData() + nan32GlobalDataOffset()) = GenericNaN();
}
unsigned globalSimdVarIndexToGlobalDataOffset(unsigned i) const {
JS_ASSERT(isFinishedWithModulePrologue());
JS_ASSERT(i < pod.numGlobalSimdVars_);
MOZ_ASSERT(isFinishedWithModulePrologue());
MOZ_ASSERT(i < pod.numGlobalSimdVars_);
return globalSimdVarsOffset() +
i * jit::Simd128DataSize;
}
unsigned globalScalarVarIndexToGlobalDataOffset(unsigned i) const {
JS_ASSERT(isFinishedWithModulePrologue());
JS_ASSERT(i < pod.numGlobalScalarVars_);
MOZ_ASSERT(isFinishedWithModulePrologue());
MOZ_ASSERT(i < pod.numGlobalScalarVars_);
return globalSimdVarsOffset() +
pod.numGlobalSimdVars_ * jit::Simd128DataSize +
i * sizeof(uint64_t);
}
void *globalScalarVarIndexToGlobalDatum(unsigned i) const {
JS_ASSERT(isFinished());
MOZ_ASSERT(isFinished());
return (void *)(globalData() + globalScalarVarIndexToGlobalDataOffset(i));
}
void *globalSimdVarIndexToGlobalDatum(unsigned i) const {
JS_ASSERT(isFinished());
MOZ_ASSERT(isFinished());
return (void *)(globalData() + globalSimdVarIndexToGlobalDataOffset(i));
}
void *globalVarToGlobalDatum(const Global &g) const {
@ -1313,26 +1313,26 @@ class AsmJSModule
: globalScalarVarIndexToGlobalDatum(index);
}
JS_ASSERT(g.varInitKind() == Global::VarInitKind::InitImport);
MOZ_ASSERT(g.varInitKind() == Global::VarInitKind::InitImport);
return IsSimdCoercion(g.varInitCoercion())
? globalSimdVarIndexToGlobalDatum(index)
: globalScalarVarIndexToGlobalDatum(index);
}
uint8_t **globalDataOffsetToFuncPtrTable(unsigned globalDataOffset) const {
JS_ASSERT(isFinished());
JS_ASSERT(globalDataOffset < globalDataBytes());
MOZ_ASSERT(isFinished());
MOZ_ASSERT(globalDataOffset < globalDataBytes());
return (uint8_t **)(globalData() + globalDataOffset);
}
unsigned exitIndexToGlobalDataOffset(unsigned exitIndex) const {
JS_ASSERT(isFinishedWithModulePrologue());
MOZ_ASSERT(isFinishedWithModulePrologue());
return exits_[exitIndex].globalDataOffset();
}
ExitDatum &exitIndexToGlobalDatum(unsigned exitIndex) const {
JS_ASSERT(isFinished());
MOZ_ASSERT(isFinished());
return *(ExitDatum *)(globalData() + exitIndexToGlobalDataOffset(exitIndex));
}
void detachIonCompilation(size_t exitIndex) const {
JS_ASSERT(isFinished());
MOZ_ASSERT(isFinished());
ExitDatum &exitDatum = exitIndexToGlobalDatum(exitIndex);
exitDatum.exit = interpExitTrampoline(exit(exitIndex));
exitDatum.ionScript = nullptr;
@ -1342,7 +1342,7 @@ class AsmJSModule
// These functions are called after finish() but before staticallyLink():
bool addRelativeLink(RelativeLink link) {
JS_ASSERT(isFinished() && !isStaticallyLinked());
MOZ_ASSERT(isFinished() && !isStaticallyLinked());
return staticLinkData_.relativeLinks.append(link);
}
@ -1371,9 +1371,9 @@ class AsmJSModule
// variables. A given asm.js module cannot be dynamically linked more than
// once so, if JS tries, the module is cloned.
void setIsDynamicallyLinked() {
JS_ASSERT(!isDynamicallyLinked());
MOZ_ASSERT(!isDynamicallyLinked());
dynamicallyLinked_ = true;
JS_ASSERT(isDynamicallyLinked());
MOZ_ASSERT(isDynamicallyLinked());
}
void initHeap(Handle<ArrayBufferObjectMaybeShared*> heap, JSContext *cx);
bool clone(JSContext *cx, ScopedJSDeletePtr<AsmJSModule> *moduleOut) const;
@ -1385,27 +1385,27 @@ class AsmJSModule
// Functions that can be called after dynamic linking succeeds:
CodePtr entryTrampoline(const ExportedFunction &func) const {
JS_ASSERT(isDynamicallyLinked());
MOZ_ASSERT(isDynamicallyLinked());
return JS_DATA_TO_FUNC_PTR(CodePtr, code_ + func.pod.codeOffset_);
}
uint8_t *interruptExit() const {
JS_ASSERT(isDynamicallyLinked());
MOZ_ASSERT(isDynamicallyLinked());
return interruptExit_;
}
uint8_t *maybeHeap() const {
JS_ASSERT(isDynamicallyLinked());
MOZ_ASSERT(isDynamicallyLinked());
return heapDatum();
}
ArrayBufferObjectMaybeShared *maybeHeapBufferObject() const {
JS_ASSERT(isDynamicallyLinked());
MOZ_ASSERT(isDynamicallyLinked());
return maybeHeap_;
}
size_t heapLength() const {
JS_ASSERT(isDynamicallyLinked());
MOZ_ASSERT(isDynamicallyLinked());
return maybeHeap_ ? maybeHeap_->byteLength() : 0;
}
bool profilingEnabled() const {
JS_ASSERT(isDynamicallyLinked());
MOZ_ASSERT(isDynamicallyLinked());
return profilingEnabled_;
}
void setProfilingEnabled(bool enabled, JSContext *cx);

View File

@ -185,13 +185,13 @@ class AutoSetHandlingSignal
explicit AutoSetHandlingSignal(JSRuntime *rt)
: rt(rt)
{
JS_ASSERT(!rt->handlingSignal);
MOZ_ASSERT(!rt->handlingSignal);
rt->handlingSignal = true;
}
~AutoSetHandlingSignal()
{
JS_ASSERT(rt->handlingSignal);
MOZ_ASSERT(rt->handlingSignal);
rt->handlingSignal = false;
}
};
@ -439,7 +439,7 @@ HandleException(PEXCEPTION_POINTERS exception)
uint8_t **ppc = ContextToPC(context);
uint8_t *pc = *ppc;
JS_ASSERT(pc == record->ExceptionAddress);
MOZ_ASSERT(pc == record->ExceptionAddress);
if (record->NumberParameters < 2)
return false;
@ -825,7 +825,7 @@ AsmJSMachExceptionHandler::uninstall()
}
if (port_ != MACH_PORT_NULL) {
DebugOnly<kern_return_t> kret = mach_port_destroy(mach_task_self(), port_);
JS_ASSERT(kret == KERN_SUCCESS);
MOZ_ASSERT(kret == KERN_SUCCESS);
port_ = MACH_PORT_NULL;
}
}
@ -833,7 +833,7 @@ AsmJSMachExceptionHandler::uninstall()
bool
AsmJSMachExceptionHandler::install(JSRuntime *rt)
{
JS_ASSERT(!installed());
MOZ_ASSERT(!installed());
kern_return_t kret;
mach_port_t thread;
@ -1056,7 +1056,7 @@ js::RequestInterruptForAsmJSCode(JSRuntime *rt, int interruptModeRaw)
if (!activation)
return;
JS_ASSERT(rt->currentThreadOwnsInterruptLock());
MOZ_ASSERT(rt->currentThreadOwnsInterruptLock());
activation->module().protectCode(rt);
}

File diff suppressed because it is too large Load Diff

View File

@ -75,7 +75,7 @@ RoundUpToNextValidAsmJSHeapLength(uint32_t length)
if (length <= 16 * 1024 * 1024)
return mozilla::RoundUpPow2(length);
JS_ASSERT(length <= 0xff000000);
MOZ_ASSERT(length <= 0xff000000);
return (length + 0x00ffffff) & ~0x00ffffff;
}
@ -86,8 +86,8 @@ IsValidAsmJSHeapLength(uint32_t length)
(IsPowerOfTwo(length) ||
(length & 0x00ffffff) == 0);
JS_ASSERT_IF(valid, length % AsmJSPageSize == 0);
JS_ASSERT_IF(valid, length == RoundUpToNextValidAsmJSHeapLength(length));
MOZ_ASSERT_IF(valid, length % AsmJSPageSize == 0);
MOZ_ASSERT_IF(valid, length == RoundUpToNextValidAsmJSHeapLength(length));
return valid;
}

View File

@ -32,7 +32,7 @@ AssertInnerizedScopeChain(JSContext *cx, JSObject &scopeobj)
#ifdef DEBUG
RootedObject obj(cx);
for (obj = &scopeobj; obj; obj = obj->enclosingScope())
JS_ASSERT(GetInnerObject(obj) == obj);
MOZ_ASSERT(GetInnerObject(obj) == obj);
#endif
}
@ -63,7 +63,7 @@ EvalCacheHashPolicy::match(const EvalCacheEntry &cacheEntry, const EvalCacheLook
{
JSScript *script = cacheEntry.script;
JS_ASSERT(IsEvalCacheCandidate(script));
MOZ_ASSERT(IsEvalCacheCandidate(script));
// Get the source string passed for safekeeping in the atom map
// by the prior eval to frontend::CompileScript.
@ -125,7 +125,7 @@ class EvalScriptGuard
void setNewScript(JSScript *script) {
// JSScript::initFromEmitter has already called js_CallNewScriptHook.
JS_ASSERT(!script_ && script);
MOZ_ASSERT(!script_ && script);
script_ = script;
script_->setActiveEval();
}
@ -135,7 +135,7 @@ class EvalScriptGuard
}
HandleScript script() {
JS_ASSERT(script_);
MOZ_ASSERT(script_);
return script_;
}
};
@ -244,9 +244,9 @@ static bool
EvalKernel(JSContext *cx, const CallArgs &args, EvalType evalType, AbstractFramePtr caller,
HandleObject scopeobj, jsbytecode *pc)
{
JS_ASSERT((evalType == INDIRECT_EVAL) == !caller);
JS_ASSERT((evalType == INDIRECT_EVAL) == !pc);
JS_ASSERT_IF(evalType == INDIRECT_EVAL, scopeobj->is<GlobalObject>());
MOZ_ASSERT((evalType == INDIRECT_EVAL) == !caller);
MOZ_ASSERT((evalType == INDIRECT_EVAL) == !pc);
MOZ_ASSERT_IF(evalType == INDIRECT_EVAL, scopeobj->is<GlobalObject>());
AssertInnerizedScopeChain(cx, *scopeobj);
Rooted<GlobalObject*> scopeObjGlobal(cx, &scopeobj->global());
@ -274,7 +274,7 @@ EvalKernel(JSContext *cx, const CallArgs &args, EvalType evalType, AbstractFrame
unsigned staticLevel;
RootedValue thisv(cx);
if (evalType == DIRECT_EVAL) {
JS_ASSERT_IF(caller.isInterpreterFrame(), !caller.asInterpreterFrame()->runningInJit());
MOZ_ASSERT_IF(caller.isInterpreterFrame(), !caller.asInterpreterFrame()->runningInJit());
staticLevel = caller.script()->staticLevel() + 1;
// Direct calls to eval are supposed to see the caller's |this|. If we
@ -284,7 +284,7 @@ EvalKernel(JSContext *cx, const CallArgs &args, EvalType evalType, AbstractFrame
return false;
thisv = caller.thisValue();
} else {
JS_ASSERT(args.callee().global() == *scopeobj);
MOZ_ASSERT(args.callee().global() == *scopeobj);
staticLevel = 0;
// Use the global as 'this', modulo outerization.
@ -425,7 +425,7 @@ js::DirectEvalStringFromIon(JSContext *cx,
// Primitive 'this' values should have been filtered out by Ion. If boxed,
// the calling frame cannot be updated to store the new object.
JS_ASSERT(thisValue.isObject() || thisValue.isUndefined() || thisValue.isNull());
MOZ_ASSERT(thisValue.isObject() || thisValue.isUndefined() || thisValue.isNull());
return ExecuteKernel(cx, esg.script(), *scopeobj, thisValue, ExecuteType(DIRECT_EVAL),
NullFramePtr() /* evalInFrame */, vp.address());
@ -462,11 +462,11 @@ js::DirectEval(JSContext *cx, const CallArgs &args)
ScriptFrameIter iter(cx);
AbstractFramePtr caller = iter.abstractFramePtr();
JS_ASSERT(caller.scopeChain()->global().valueIsEval(args.calleev()));
JS_ASSERT(JSOp(*iter.pc()) == JSOP_EVAL ||
JSOp(*iter.pc()) == JSOP_SPREADEVAL);
JS_ASSERT_IF(caller.isFunctionFrame(),
caller.compartment() == caller.callee()->compartment());
MOZ_ASSERT(caller.scopeChain()->global().valueIsEval(args.calleev()));
MOZ_ASSERT(JSOp(*iter.pc()) == JSOP_EVAL ||
JSOp(*iter.pc()) == JSOP_SPREADEVAL);
MOZ_ASSERT_IF(caller.isFunctionFrame(),
caller.compartment() == caller.callee()->compartment());
RootedObject scopeChain(cx, caller.scopeChain());
return EvalKernel(cx, args, DIRECT_EVAL, caller, scopeChain, iter.pc());

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