mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 03:15:11 +00:00
Merge inbound to m-c a=merge despite the CLOSED TREE
This commit is contained in:
commit
86eb3305b3
@ -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
|
||||
|
@ -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]
|
||||
|
@ -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".
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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');
|
||||
|
@ -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);
|
||||
|
@ -8,6 +8,7 @@ DIRS += ['public', 'src']
|
||||
|
||||
MOCHITEST_MANIFESTS += [
|
||||
'test/forms/mochitest.ini',
|
||||
'test/imports/mochitest.ini',
|
||||
'test/mochitest.ini',
|
||||
]
|
||||
|
||||
|
@ -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
|
||||
|
11
content/html/content/test/imports/file_importA1.html
Normal file
11
content/html/content/test/imports/file_importA1.html
Normal 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>
|
10
content/html/content/test/imports/file_importA2.html
Normal file
10
content/html/content/test/imports/file_importA2.html
Normal file
@ -0,0 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
order.push("A2");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
11
content/html/content/test/imports/file_importB1.html
Normal file
11
content/html/content/test/imports/file_importB1.html
Normal 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>
|
10
content/html/content/test/imports/file_importB2.html
Normal file
10
content/html/content/test/imports/file_importB2.html
Normal file
@ -0,0 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
order.push("B2");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
11
content/html/content/test/imports/file_importC1.html
Normal file
11
content/html/content/test/imports/file_importC1.html
Normal 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>
|
11
content/html/content/test/imports/file_importC10.html
Normal file
11
content/html/content/test/imports/file_importC10.html
Normal 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>
|
11
content/html/content/test/imports/file_importC2.html
Normal file
11
content/html/content/test/imports/file_importC2.html
Normal 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>
|
11
content/html/content/test/imports/file_importC3.html
Normal file
11
content/html/content/test/imports/file_importC3.html
Normal 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>
|
11
content/html/content/test/imports/file_importC4.html
Normal file
11
content/html/content/test/imports/file_importC4.html
Normal 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>
|
11
content/html/content/test/imports/file_importC5.html
Normal file
11
content/html/content/test/imports/file_importC5.html
Normal 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>
|
11
content/html/content/test/imports/file_importC6.html
Normal file
11
content/html/content/test/imports/file_importC6.html
Normal 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>
|
11
content/html/content/test/imports/file_importC7.html
Normal file
11
content/html/content/test/imports/file_importC7.html
Normal 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>
|
11
content/html/content/test/imports/file_importC8.html
Normal file
11
content/html/content/test/imports/file_importC8.html
Normal 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>
|
11
content/html/content/test/imports/file_importC9.html
Normal file
11
content/html/content/test/imports/file_importC9.html
Normal 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>
|
8
content/html/content/test/imports/file_importD.html
Normal file
8
content/html/content/test/imports/file_importD.html
Normal file
@ -0,0 +1,8 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-US">
|
||||
<body>
|
||||
<script>
|
||||
order.push("D");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
11
content/html/content/test/imports/file_importE.html
Normal file
11
content/html/content/test/imports/file_importE.html
Normal 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>
|
20
content/html/content/test/imports/mochitest.ini
Normal file
20
content/html/content/test/imports/mochitest.ini
Normal 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
|
||||
|
||||
|
@ -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]
|
||||
|
41
content/html/content/test/test_imports_nested.html
Normal file
41
content/html/content/test/test_imports_nested.html
Normal 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>
|
56
content/html/content/test/test_imports_nested_2.html
Normal file
56
content/html/content/test/test_imports_nested_2.html
Normal 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>
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -648,6 +648,12 @@ AudioContext::MozAudioChannelType() const
|
||||
return mDestination->MozAudioChannelType();
|
||||
}
|
||||
|
||||
void
|
||||
AudioContext::SetMozAudioChannelType(AudioChannel aValue, ErrorResult& aRv)
|
||||
{
|
||||
mDestination->SetMozAudioChannelType(aValue, aRv);
|
||||
}
|
||||
|
||||
AudioChannel
|
||||
AudioContext::TestAudioChannelInAudioNodeStream()
|
||||
{
|
||||
|
@ -222,6 +222,7 @@ public:
|
||||
JSObject* GetGlobalJSObject() const;
|
||||
|
||||
AudioChannel MozAudioChannelType() const;
|
||||
void SetMozAudioChannelType(AudioChannel aValue, ErrorResult& aRv);
|
||||
|
||||
AudioChannel TestAudioChannelInAudioNodeStream();
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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() {
|
||||
|
@ -4,4 +4,4 @@ support-files =
|
||||
process_error_contentscript.js
|
||||
|
||||
[test_process_error.xul]
|
||||
skip-if = buildapp == "mulet"
|
||||
skip-if = buildapp == "mulet" || !crashreporter
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -1,5 +1,6 @@
|
||||
[DEFAULT]
|
||||
|
||||
[test_bug1072116.html]
|
||||
[test_bug319374.xhtml]
|
||||
[test_bug427060.html]
|
||||
[test_bug440974.html]
|
||||
|
37
dom/xslt/tests/mochitest/test_bug1072116.html
Normal file
37
dom/xslt/tests/mochitest/test_bug1072116.html
Normal 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>
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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++) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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|.
|
||||
*/
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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 {
|
||||
|
@ -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&
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -22,6 +22,7 @@ public:
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
bool aVertical,
|
||||
gfxShapedText *aShapedText);
|
||||
|
||||
static void Shutdown();
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -57,6 +57,7 @@ protected:
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
bool aVertical,
|
||||
gfxShapedText *aShapedText);
|
||||
|
||||
void InitMetrics();
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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")
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 &©)
|
||||
@ -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);
|
||||
|
@ -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
@ -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;
|
||||
}
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user