зеркало из https://github.com/mozilla/gecko-dev.git
Merge inbound to m-c a=merge
This commit is contained in:
Коммит
1416242684
|
@ -132,6 +132,7 @@ install-manifests: install-tests
|
|||
install-tests: $(install_manifest_depends)
|
||||
$(call py_action,process_install_manifest,$(if $(NO_REMOVE),--no-remove )_tests _build_manifests/install/tests)
|
||||
|
||||
include $(topsrcdir)/build/moz-automation.mk
|
||||
|
||||
# _tests should be purged during cleaning. However, we don't want it purged
|
||||
# during PGO builds because it contains some auto-generated files.
|
||||
|
@ -168,7 +169,7 @@ endif
|
|||
endif
|
||||
|
||||
default all::
|
||||
$(call BUILDSTATUS,TIERS export $(if $(COMPILE_ENVIRONMENT),$(if $(MOZ_PSEUDO_DERECURSE),compile ))libs tools)
|
||||
$(call BUILDSTATUS,TIERS export $(if $(COMPILE_ENVIRONMENT),$(if $(MOZ_PSEUDO_DERECURSE),compile ))libs tools $(if $(MOZ_AUTOMATION),$(MOZ_AUTOMATION_TIERS)))
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
|
@ -251,6 +252,9 @@ MOZ_SOURCE_STAMP := $(MOZ_SOURCE_STAMP)
|
|||
export MOZ_SOURCE_STAMP
|
||||
endif
|
||||
|
||||
update-packaging:
|
||||
$(MAKE) -C tools/update-packaging
|
||||
|
||||
#XXX: this is a hack, since we don't want to clobber for MSVC
|
||||
# PGO support, but we can't do this test in client.mk
|
||||
ifneq ($(OS_ARCH)_$(GNU_CC), WINNT_)
|
||||
|
|
|
@ -304,10 +304,12 @@ var gAdvancedPane = {
|
|||
|
||||
actualSizeLabel.textContent = prefStrBundle.getString("actualDiskCacheSizeCalculated");
|
||||
|
||||
var cacheService =
|
||||
Components.classes["@mozilla.org/netwerk/cache-storage-service;1"]
|
||||
.getService(Components.interfaces.nsICacheStorageService);
|
||||
cacheService.asyncGetDiskConsumption(this.observer);
|
||||
try {
|
||||
var cacheService =
|
||||
Components.classes["@mozilla.org/netwerk/cache-storage-service;1"]
|
||||
.getService(Components.interfaces.nsICacheStorageService);
|
||||
cacheService.asyncGetDiskConsumption(this.observer);
|
||||
} catch (e) {}
|
||||
},
|
||||
|
||||
// Retrieves the amount of space currently used by offline cache
|
||||
|
@ -324,11 +326,13 @@ var gAdvancedPane = {
|
|||
}
|
||||
};
|
||||
|
||||
var cacheService =
|
||||
Components.classes["@mozilla.org/netwerk/cache-storage-service;1"]
|
||||
.getService(Components.interfaces.nsICacheStorageService);
|
||||
var storage = cacheService.appCacheStorage(LoadContextInfo.default, null);
|
||||
storage.asyncVisitStorage(visitor, false);
|
||||
try {
|
||||
var cacheService =
|
||||
Components.classes["@mozilla.org/netwerk/cache-storage-service;1"]
|
||||
.getService(Components.interfaces.nsICacheStorageService);
|
||||
var storage = cacheService.appCacheStorage(LoadContextInfo.default, null);
|
||||
storage.asyncVisitStorage(visitor, false);
|
||||
} catch (e) {}
|
||||
},
|
||||
|
||||
updateCacheSizeUI: function (smartSizeEnabled)
|
||||
|
@ -372,9 +376,9 @@ var gAdvancedPane = {
|
|||
*/
|
||||
clearCache: function ()
|
||||
{
|
||||
var cache = Components.classes["@mozilla.org/netwerk/cache-storage-service;1"]
|
||||
.getService(Components.interfaces.nsICacheStorageService);
|
||||
try {
|
||||
var cache = Components.classes["@mozilla.org/netwerk/cache-storage-service;1"]
|
||||
.getService(Components.interfaces.nsICacheStorageService);
|
||||
cache.clear();
|
||||
} catch(ex) {}
|
||||
this.updateActualCacheSize();
|
||||
|
|
|
@ -7,11 +7,21 @@ Components.utils.import("resource://gre/modules/NetUtil.jsm");
|
|||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
let prefs = [
|
||||
"browser.cache.offline.enable",
|
||||
"browser.cache.disk.enable",
|
||||
"browser.cache.memory.enable",
|
||||
];
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
Services.prefs.clearUserPref("browser.cache.offline.enable");
|
||||
for (let pref of prefs) {
|
||||
Services.prefs.clearUserPref(pref);
|
||||
}
|
||||
});
|
||||
|
||||
Services.prefs.setBoolPref("browser.cache.offline.enable", false);
|
||||
for (let pref of prefs) {
|
||||
Services.prefs.setBoolPref(pref, false);
|
||||
}
|
||||
|
||||
open_preferences(runTest);
|
||||
}
|
||||
|
|
|
@ -46,23 +46,26 @@ if test -z "$BUILDING_JS" -o -n "$JS_STANDALONE"; then
|
|||
# autotools can't quite handle an MSVC build environment yet.
|
||||
LDFLAGS=
|
||||
CFLAGS=
|
||||
ac_configure_args="$ac_configure_args LD=link CPP=\"cl -nologo -EP\" \
|
||||
CXXCPP=\"cl -nologo -EP\" SHELL=sh.exe"
|
||||
rtl=
|
||||
ac_configure_args="$ac_configure_args LD=link CPP=\"$CC -nologo -EP\" \
|
||||
CXXCPP=\"$CXX -nologo -EP\" SHELL=sh.exe"
|
||||
flags=
|
||||
if test -z "$MOZ_NO_DEBUG_RTL" -a -n "$MOZ_DEBUG"; then
|
||||
rtl=" -DUSE_DEBUG_RTL"
|
||||
flags=" -DUSE_DEBUG_RTL"
|
||||
fi
|
||||
if test -n "$CLANG_CL"; then
|
||||
flags="$flags -clang-cl"
|
||||
fi
|
||||
case "${target_cpu}" in
|
||||
x86_64)
|
||||
# Need target since MSYS tools into mozilla-build may be 32bit
|
||||
ac_configure_args="$ac_configure_args \
|
||||
CC=\"$_topsrcdir/js/src/ctypes/libffi/msvcc.sh -m64$rtl\" \
|
||||
CXX=\"$_topsrcdir/js/src/ctypes/libffi/msvcc.sh -m64$rtl\""
|
||||
CC=\"$_topsrcdir/js/src/ctypes/libffi/msvcc.sh -m64$flags\" \
|
||||
CXX=\"$_topsrcdir/js/src/ctypes/libffi/msvcc.sh -m64$flags\""
|
||||
;;
|
||||
*)
|
||||
ac_configure_args="$ac_configure_args \
|
||||
CC=\"$_topsrcdir/js/src/ctypes/libffi/msvcc.sh$rtl\" \
|
||||
CXX=\"$_topsrcdir/js/src/ctypes/libffi/msvcc.sh$rtl\""
|
||||
CC=\"$_topsrcdir/js/src/ctypes/libffi/msvcc.sh$flags\" \
|
||||
CXX=\"$_topsrcdir/js/src/ctypes/libffi/msvcc.sh$flags\""
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
#!/usr/bin/python
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
import sys, os, sha, json, re
|
||||
from argparse import ArgumentParser
|
||||
|
||||
def getFileHashAndSize(filename):
|
||||
sha1Hash = 'UNKNOWN'
|
||||
size = 'UNKNOWN'
|
||||
|
||||
try:
|
||||
# open in binary mode to make sure we get consistent results
|
||||
# across all platforms
|
||||
f = open(filename, "rb")
|
||||
shaObj = sha.new(f.read())
|
||||
sha1Hash = shaObj.hexdigest()
|
||||
|
||||
size = os.path.getsize(filename)
|
||||
except:
|
||||
pass
|
||||
|
||||
return (sha1Hash, size)
|
||||
|
||||
def getMarProperties(filename):
|
||||
(complete_mar_hash, complete_mar_size) = getFileHashAndSize(filename)
|
||||
return {
|
||||
'completeMarFilename': os.path.basename(filename),
|
||||
'completeMarSize': complete_mar_size,
|
||||
'completeMarHash': complete_mar_hash,
|
||||
}
|
||||
|
||||
def getUrlProperties(filename):
|
||||
# let's create a switch case using name-spaces/dict
|
||||
# rather than a long if/else with duplicate code
|
||||
property_conditions = [
|
||||
# key: property name, value: condition
|
||||
('symbolsUrl', lambda m: m.endswith('crashreporter-symbols.zip') or
|
||||
m.endswith('crashreporter-symbols-full.zip')),
|
||||
('testsUrl', lambda m: m.endswith(('tests.tar.bz2', 'tests.zip'))),
|
||||
('unsignedApkUrl', lambda m: m.endswith('apk') and
|
||||
'unsigned-unaligned' in m),
|
||||
('robocopApkUrl', lambda m: m.endswith('apk') and 'robocop' in m),
|
||||
('jsshellUrl', lambda m: 'jsshell-' in m and m.endswith('.zip')),
|
||||
('completeMarUrl', lambda m: m.endswith('.complete.mar')),
|
||||
# packageUrl must be last!
|
||||
('packageUrl', lambda m: True),
|
||||
]
|
||||
url_re = re.compile(r'''^(https?://.*?\.(?:tar\.bz2|dmg|zip|apk|rpm|mar|tar\.gz))$''')
|
||||
properties = {}
|
||||
|
||||
with open(filename) as f:
|
||||
for line in f:
|
||||
m = url_re.match(line)
|
||||
if m:
|
||||
m = m.group(1)
|
||||
for prop, condition in property_conditions:
|
||||
if condition(m):
|
||||
properties.update({prop: m})
|
||||
break
|
||||
return properties
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = ArgumentParser(description='Generate mach_build_properties.json for automation builds.')
|
||||
parser.add_argument("--complete-mar-file", required=True,
|
||||
action="store", dest="complete_mar_file",
|
||||
help="Path to the complete MAR file, relative to the objdir.")
|
||||
parser.add_argument("--upload-output", required=True,
|
||||
action="store", dest="upload_output",
|
||||
help="Path to the text output of 'make upload'")
|
||||
args = parser.parse_args()
|
||||
|
||||
json_data = getMarProperties(args.complete_mar_file)
|
||||
json_data.update(getUrlProperties(args.upload_output))
|
||||
|
||||
with open('mach_build_properties.json', 'w') as outfile:
|
||||
json.dump(json_data, outfile, indent=4)
|
|
@ -0,0 +1,66 @@
|
|||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
include $(topsrcdir)/toolkit/mozapps/installer/package-name.mk
|
||||
|
||||
# Log file from the 'make upload' step. We need this to parse out the URLs of
|
||||
# the uploaded files.
|
||||
AUTOMATION_UPLOAD_OUTPUT = $(DIST)/automation-upload.txt
|
||||
|
||||
# Automation build steps. Everything in MOZ_AUTOMATION_TIERS also gets used in
|
||||
# TIERS for mach display. As such, the MOZ_AUTOMATION_TIERS are roughly sorted
|
||||
# here in the order that they will be executed (since mach doesn't know of the
|
||||
# dependencies between them).
|
||||
|
||||
MOZ_AUTOMATION_TIERS += package-tests
|
||||
MOZ_AUTOMATION_TIERS += buildsymbols
|
||||
|
||||
ifdef NIGHTLY_BUILD
|
||||
MOZ_AUTOMATION_TIERS += uploadsymbols
|
||||
endif
|
||||
|
||||
ifdef MOZ_UPDATE_PACKAGING
|
||||
MOZ_AUTOMATION_TIERS += update-packaging
|
||||
automation/upload: automation/update-packaging
|
||||
automation/update-packaging: automation/package
|
||||
endif
|
||||
|
||||
MOZ_AUTOMATION_TIERS += package
|
||||
MOZ_AUTOMATION_TIERS += check
|
||||
|
||||
ifndef MOZ_ASAN
|
||||
MOZ_AUTOMATION_TIERS += l10n-check
|
||||
automation/l10n-check: automation/package
|
||||
endif
|
||||
|
||||
MOZ_AUTOMATION_TIERS += upload
|
||||
|
||||
automation/build: $(addprefix automation/,$(MOZ_AUTOMATION_TIERS))
|
||||
$(PYTHON) $(topsrcdir)/build/gen_mach_buildprops.py --complete-mar-file $(DIST)/$(COMPLETE_MAR) --upload-output $(AUTOMATION_UPLOAD_OUTPUT)
|
||||
|
||||
# Dependencies between automation build steps
|
||||
automation/uploadsymbols: automation/buildsymbols
|
||||
|
||||
automation/upload: automation/package
|
||||
automation/upload: automation/package-tests
|
||||
automation/upload: automation/buildsymbols
|
||||
|
||||
# automation/package and automation/check should depend on build (which is
|
||||
# implicit due to the way client.mk invokes automation/build), but buildsymbols
|
||||
# changes the binaries/libs, and that's what we package/test.
|
||||
automation/package: automation/buildsymbols
|
||||
automation/check: automation/buildsymbols
|
||||
|
||||
# make check runs with the keep-going flag so we can see all the failures
|
||||
AUTOMATION_EXTRA_CMDLINE-check = -k
|
||||
|
||||
# We need the log from make upload to grep it for urls in order to set
|
||||
# properties.
|
||||
AUTOMATION_EXTRA_CMDLINE-upload = 2>&1 | tee $(AUTOMATION_UPLOAD_OUTPUT)
|
||||
|
||||
automation/%:
|
||||
$(call BUILDSTATUS,TIER_START $*)
|
||||
@$(MAKE) $* $(AUTOMATION_EXTRA_CMDLINE-$*)
|
||||
$(call BUILDSTATUS,TIER_FINISH $*)
|
|
@ -25,7 +25,6 @@ if test -z "$SCCACHE_DISABLE" -a -z "$no_sccache"; then
|
|||
bucket=mozilla-releng-s3-cache-us-west-2-try
|
||||
;;
|
||||
esac
|
||||
mk_add_options "export SCCACHE_NO_HTTPS=1"
|
||||
;;
|
||||
*use1.mozilla.com*)
|
||||
bucket=mozilla-releng-s3-cache-us-east-1-try
|
||||
|
|
|
@ -176,7 +176,7 @@ CONFIGURES := $(TOPSRCDIR)/configure
|
|||
CONFIGURES += $(TOPSRCDIR)/js/src/configure
|
||||
|
||||
# Make targets that are going to be passed to the real build system
|
||||
OBJDIR_TARGETS = install export libs clean realclean distclean maybe_clobber_profiledbuild upload sdk installer package package-compare stage-package source-package l10n-check
|
||||
OBJDIR_TARGETS = install export libs clean realclean distclean maybe_clobber_profiledbuild upload sdk installer package package-compare stage-package source-package l10n-check automation/build
|
||||
|
||||
#######################################################################
|
||||
# Rules
|
||||
|
|
|
@ -1817,6 +1817,10 @@ GK_ATOM(onuserproximity, "onuserproximity")
|
|||
// light sensor support
|
||||
GK_ATOM(ondevicelight, "ondevicelight")
|
||||
|
||||
// Audio channel events
|
||||
GK_ATOM(onmozinterruptbegin, "onmozinterruptbegin")
|
||||
GK_ATOM(onmozinterruptend, "onmozinterruptbegin")
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Special atoms
|
||||
//---------------------------------------------------------------------------
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "mozilla/dom/OfflineAudioContextBinding.h"
|
||||
#include "mozilla/dom/OwningNonNull.h"
|
||||
#include "MediaStreamGraph.h"
|
||||
#include "AudioChannelService.h"
|
||||
#include "AudioDestinationNode.h"
|
||||
#include "AudioBufferSourceNode.h"
|
||||
#include "AudioBuffer.h"
|
||||
|
@ -131,7 +132,9 @@ AudioContext::Constructor(const GlobalObject& aGlobal,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<AudioContext> object = new AudioContext(window, false);
|
||||
nsRefPtr<AudioContext> object =
|
||||
new AudioContext(window, false,
|
||||
AudioChannelService::GetDefaultAudioChannel());
|
||||
|
||||
RegisterWeakMemoryReporter(object);
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ class AudioContext MOZ_FINAL : public DOMEventTargetHelper,
|
|||
{
|
||||
AudioContext(nsPIDOMWindow* aParentWindow,
|
||||
bool aIsOffline,
|
||||
AudioChannel aChannel = AudioChannel::Normal,
|
||||
AudioChannel aChannel,
|
||||
uint32_t aNumberOfChannels = 0,
|
||||
uint32_t aLength = 0,
|
||||
float aSampleRate = 0.0f);
|
||||
|
@ -231,6 +231,9 @@ public:
|
|||
return aTime - ExtraCurrentTime();
|
||||
}
|
||||
|
||||
IMPL_EVENT_HANDLER(mozinterruptbegin)
|
||||
IMPL_EVENT_HANDLER(mozinterruptend)
|
||||
|
||||
private:
|
||||
/**
|
||||
* Returns the amount of extra time added to the current time of the
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
[DEFAULT]
|
||||
support-files =
|
||||
browser_mozAudioChannel.html
|
||||
|
||||
[browser_mozAudioChannel.js]
|
|
@ -0,0 +1,31 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
|
||||
<meta charset="utf-8">
|
||||
<title>Test for mozinterruptbegin/end in AudioContext</title>
|
||||
|
||||
mozAudioChannelTest = <span id="mozAudioChannelTest">FAIL</span>
|
||||
|
||||
<script type="application/javascript">
|
||||
|
||||
var ac = new AudioContext();
|
||||
|
||||
var buffer = ac.createBuffer(1, 2048, ac.sampleRate);
|
||||
for (var i = 0; i < 2048; ++i) {
|
||||
buffer.getChannelData(0)[i] = Math.sin(440 * 2 * Math.PI * i / ac.sampleRate);
|
||||
}
|
||||
|
||||
var source = ac.createBufferSource();
|
||||
source.buffer = buffer;
|
||||
source.connect(ac.destination);
|
||||
source.start(0);
|
||||
|
||||
ac.onmozinterruptbegin = function(evt) {
|
||||
document.getElementById("mozAudioChannelTest").innerHTML = "mozinterruptbegin";
|
||||
}
|
||||
|
||||
ac.addEventListener('mozinterruptend', function() {
|
||||
document.getElementById("mozAudioChannelTest").innerHTML = "mozinterruptend";
|
||||
}, false);
|
||||
|
||||
document.getElementById("mozAudioChannelTest").innerHTML = "READY";
|
||||
|
||||
</script>
|
|
@ -0,0 +1,71 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
function whenBrowserLoaded(aBrowser, aCallback) {
|
||||
aBrowser.addEventListener("load", function onLoad(event) {
|
||||
if (event.target == aBrowser.contentDocument) {
|
||||
aBrowser.removeEventListener("load", onLoad, true);
|
||||
executeSoon(aCallback);
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
|
||||
function whenTabRestored(aTab, aCallback) {
|
||||
aTab.addEventListener("SSTabRestored", function onRestored(aEvent) {
|
||||
aTab.removeEventListener("SSTabRestored", onRestored, true);
|
||||
executeSoon(function executeWhenTabRestored() {
|
||||
aCallback();
|
||||
});
|
||||
}, true);
|
||||
}
|
||||
|
||||
function whenBrowserUnloaded(aBrowser, aCallback) {
|
||||
aBrowser.addEventListener("unload", function onUnload() {
|
||||
aBrowser.removeEventListener("unload", onUnload, true);
|
||||
executeSoon(aCallback);
|
||||
}, true);
|
||||
}
|
||||
|
||||
function test() {
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
let testURL = "http://mochi.test:8888/browser/" +
|
||||
"content/media/webaudio/test/browser_mozAudioChannel.html";
|
||||
|
||||
SpecialPowers.pushPrefEnv({"set": [["media.defaultAudioChannel", "content" ],
|
||||
["media.useAudioChannelService", true ]]},
|
||||
function() {
|
||||
let tab1 = gBrowser.addTab(testURL);
|
||||
gBrowser.selectedTab = tab1;
|
||||
|
||||
whenBrowserLoaded(tab1.linkedBrowser, function() {
|
||||
let doc = tab1.linkedBrowser.contentDocument;
|
||||
is(doc.getElementById("mozAudioChannelTest").textContent, "READY",
|
||||
"Test is ready to run");
|
||||
|
||||
SpecialPowers.pushPrefEnv({"set": [["media.defaultAudioChannel", "telephony" ]]},
|
||||
function() {
|
||||
let tab2 = gBrowser.duplicateTab(tab1);
|
||||
gBrowser.selectedTab = tab2;
|
||||
whenTabRestored(tab2, function() {
|
||||
is(doc.getElementById("mozAudioChannelTest").textContent, "mozinterruptbegin",
|
||||
"AudioContext has been muted by the second tab.");
|
||||
|
||||
whenBrowserUnloaded(tab2.linkedBrowser, function() {
|
||||
is(doc.getElementById("mozAudioChannelTest").textContent, "mozinterruptend",
|
||||
"AudioContext has been unmuted.");
|
||||
gBrowser.removeTab(tab1);
|
||||
finish();
|
||||
});
|
||||
|
||||
gBrowser.removeTab(tab2);
|
||||
gBrowser.selectedTab = tab1;
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
|
@ -12,3 +12,7 @@ MOCHITEST_MANIFESTS += [
|
|||
MOCHITEST_CHROME_MANIFESTS += [
|
||||
'chrome.ini'
|
||||
]
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += [
|
||||
'browser.ini'
|
||||
]
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "nsGlobalWindow.h"
|
||||
#include "nsJSUtils.h"
|
||||
#include "nsPerformance.h"
|
||||
#include "ScriptSettings.h"
|
||||
#include "WorkerPrivate.h"
|
||||
#include "WorkerRunnable.h"
|
||||
#include "xpcprivate.h"
|
||||
|
@ -323,7 +324,8 @@ private:
|
|||
wp = wp->GetParent();
|
||||
}
|
||||
|
||||
AutoPushJSContext cx(wp->ParentJSContext());
|
||||
AutoJSAPI jsapi;
|
||||
JSContext* cx = jsapi.cx();
|
||||
ClearException ce(cx);
|
||||
|
||||
nsPIDOMWindow* window = wp->GetWindow();
|
||||
|
@ -332,6 +334,8 @@ private:
|
|||
nsRefPtr<nsGlobalWindow> win = static_cast<nsGlobalWindow*>(window);
|
||||
NS_ENSURE_TRUE_VOID(win);
|
||||
|
||||
JSAutoCompartment ac(cx, win->GetWrapperPreserveColor());
|
||||
|
||||
ErrorResult error;
|
||||
nsRefPtr<Console> console = win->GetConsole(error);
|
||||
if (error.Failed()) {
|
||||
|
@ -432,19 +436,18 @@ private:
|
|||
wp = wp->GetParent();
|
||||
}
|
||||
|
||||
AutoPushJSContext cx(wp->ParentJSContext());
|
||||
AutoJSAPI jsapi;
|
||||
JSContext* cx = jsapi.cx();
|
||||
ClearException ce(cx);
|
||||
|
||||
JS::Rooted<JSObject*> global(cx, JS::CurrentGlobalOrNull(cx));
|
||||
NS_ENSURE_TRUE_VOID(global);
|
||||
JSAutoCompartment ac(cx, global);
|
||||
|
||||
nsPIDOMWindow* window = wp->GetWindow();
|
||||
NS_ENSURE_TRUE_VOID(window);
|
||||
|
||||
nsRefPtr<nsGlobalWindow> win = static_cast<nsGlobalWindow*>(window);
|
||||
NS_ENSURE_TRUE_VOID(win);
|
||||
|
||||
JSAutoCompartment ac(cx, win->GetWrapperPreserveColor());
|
||||
|
||||
ErrorResult error;
|
||||
nsRefPtr<Console> console = win->GetConsole(error);
|
||||
if (error.Failed()) {
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "nsContentUtils.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "ScriptSettings.h"
|
||||
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIDOMFile.h"
|
||||
|
@ -271,14 +272,14 @@ PostMessageRunnable::Run()
|
|||
{
|
||||
MOZ_ASSERT(mPort);
|
||||
|
||||
// Get the JSContext for the target window
|
||||
nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(mPort->GetOwner());
|
||||
NS_ENSURE_STATE(sgo);
|
||||
nsCOMPtr<nsIScriptContext> scriptContext = sgo->GetContext();
|
||||
AutoPushJSContext cx(scriptContext ? scriptContext->GetNativeContext()
|
||||
: nsContentUtils::GetSafeJSContext());
|
||||
nsCOMPtr<nsIGlobalObject> globalObject = do_QueryInterface(mPort->GetOwner());
|
||||
if (NS_WARN_IF(!globalObject)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(cx);
|
||||
AutoJSAPI jsapi;
|
||||
JSContext* cx = jsapi.cx();
|
||||
JSAutoCompartment ac(cx, globalObject->GetGlobalJSObject());
|
||||
|
||||
// Deserialize the structured clone data
|
||||
JS::Rooted<JS::Value> messageData(cx);
|
||||
|
|
|
@ -20,65 +20,51 @@
|
|||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class ScriptSettingsStack;
|
||||
static mozilla::ThreadLocal<ScriptSettingsStack*> sScriptSettingsTLS;
|
||||
|
||||
ScriptSettingsStackEntry ScriptSettingsStackEntry::NoJSAPISingleton;
|
||||
static mozilla::ThreadLocal<ScriptSettingsStackEntry*> sScriptSettingsTLS;
|
||||
|
||||
class ScriptSettingsStack {
|
||||
public:
|
||||
static ScriptSettingsStack& Ref() {
|
||||
return *sScriptSettingsTLS.get();
|
||||
}
|
||||
ScriptSettingsStack() {};
|
||||
|
||||
void Push(ScriptSettingsStackEntry* aSettings) {
|
||||
// The bottom-most entry must always be a candidate entry point.
|
||||
MOZ_ASSERT_IF(mStack.Length() == 0 || mStack.LastElement()->NoJSAPI(),
|
||||
aSettings->mIsCandidateEntryPoint);
|
||||
mStack.AppendElement(aSettings);
|
||||
static ScriptSettingsStackEntry* Top() {
|
||||
return sScriptSettingsTLS.get();
|
||||
}
|
||||
|
||||
void PushNoJSAPI() {
|
||||
mStack.AppendElement(&ScriptSettingsStackEntry::NoJSAPISingleton);
|
||||
static void Push(ScriptSettingsStackEntry *aEntry) {
|
||||
MOZ_ASSERT(!aEntry->mOlder);
|
||||
// Whenever JSAPI use is disabled, the next stack entry pushed must
|
||||
// always be a candidate entry point.
|
||||
MOZ_ASSERT_IF(!Top() || Top()->NoJSAPI(), aEntry->mIsCandidateEntryPoint);
|
||||
|
||||
aEntry->mOlder = Top();
|
||||
sScriptSettingsTLS.set(aEntry);
|
||||
}
|
||||
|
||||
void Pop() {
|
||||
MOZ_ASSERT(mStack.Length() > 0);
|
||||
mStack.RemoveElementAt(mStack.Length() - 1);
|
||||
static void Pop(ScriptSettingsStackEntry *aEntry) {
|
||||
MOZ_ASSERT(aEntry == Top());
|
||||
sScriptSettingsTLS.set(aEntry->mOlder);
|
||||
}
|
||||
|
||||
ScriptSettingsStackEntry* Incumbent() {
|
||||
if (!mStack.Length()) {
|
||||
return nullptr;
|
||||
}
|
||||
return mStack.LastElement();
|
||||
}
|
||||
|
||||
nsIGlobalObject* IncumbentGlobal() {
|
||||
ScriptSettingsStackEntry *entry = Incumbent();
|
||||
static nsIGlobalObject* IncumbentGlobal() {
|
||||
ScriptSettingsStackEntry *entry = Top();
|
||||
return entry ? entry->mGlobalObject : nullptr;
|
||||
}
|
||||
|
||||
ScriptSettingsStackEntry* EntryPoint() {
|
||||
if (!mStack.Length())
|
||||
static ScriptSettingsStackEntry* EntryPoint() {
|
||||
ScriptSettingsStackEntry *entry = Top();
|
||||
if (!entry) {
|
||||
return nullptr;
|
||||
for (int i = mStack.Length() - 1; i >= 0; --i) {
|
||||
if (mStack[i]->mIsCandidateEntryPoint) {
|
||||
return mStack[i];
|
||||
}
|
||||
}
|
||||
while (entry) {
|
||||
if (entry->mIsCandidateEntryPoint)
|
||||
return entry;
|
||||
entry = entry->mOlder;
|
||||
}
|
||||
MOZ_CRASH("Non-empty stack should always have an entry point");
|
||||
}
|
||||
|
||||
nsIGlobalObject* EntryGlobal() {
|
||||
static nsIGlobalObject* EntryGlobal() {
|
||||
ScriptSettingsStackEntry *entry = EntryPoint();
|
||||
return entry ? entry->mGlobalObject : nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
// These pointers are caller-owned.
|
||||
nsTArray<ScriptSettingsStackEntry*> mStack;
|
||||
};
|
||||
|
||||
void
|
||||
|
@ -91,16 +77,44 @@ InitScriptSettings()
|
|||
}
|
||||
}
|
||||
|
||||
ScriptSettingsStack* ptr = new ScriptSettingsStack();
|
||||
sScriptSettingsTLS.set(ptr);
|
||||
sScriptSettingsTLS.set(nullptr);
|
||||
}
|
||||
|
||||
void DestroyScriptSettings()
|
||||
{
|
||||
ScriptSettingsStack* ptr = sScriptSettingsTLS.get();
|
||||
MOZ_ASSERT(ptr);
|
||||
sScriptSettingsTLS.set(nullptr);
|
||||
delete ptr;
|
||||
MOZ_ASSERT(sScriptSettingsTLS.get() == nullptr);
|
||||
}
|
||||
|
||||
ScriptSettingsStackEntry::ScriptSettingsStackEntry(nsIGlobalObject *aGlobal,
|
||||
bool aCandidate)
|
||||
: mGlobalObject(aGlobal)
|
||||
, mIsCandidateEntryPoint(aCandidate)
|
||||
, mOlder(nullptr)
|
||||
{
|
||||
MOZ_ASSERT(mGlobalObject);
|
||||
MOZ_ASSERT(mGlobalObject->GetGlobalJSObject(),
|
||||
"Must have an actual JS global for the duration on the stack");
|
||||
MOZ_ASSERT(JS_IsGlobalObject(mGlobalObject->GetGlobalJSObject()),
|
||||
"No outer windows allowed");
|
||||
|
||||
ScriptSettingsStack::Push(this);
|
||||
}
|
||||
|
||||
// This constructor is only for use by AutoNoJSAPI.
|
||||
ScriptSettingsStackEntry::ScriptSettingsStackEntry()
|
||||
: mGlobalObject(nullptr)
|
||||
, mIsCandidateEntryPoint(true)
|
||||
, mOlder(nullptr)
|
||||
{
|
||||
ScriptSettingsStack::Push(this);
|
||||
}
|
||||
|
||||
ScriptSettingsStackEntry::~ScriptSettingsStackEntry()
|
||||
{
|
||||
// We must have an actual JS global for the entire time this is on the stack.
|
||||
MOZ_ASSERT_IF(mGlobalObject, mGlobalObject->GetGlobalJSObject());
|
||||
|
||||
ScriptSettingsStack::Pop(this);
|
||||
}
|
||||
|
||||
// This mostly gets the entry global, but doesn't entirely match the spec in
|
||||
|
@ -115,7 +129,7 @@ BrokenGetEntryGlobal()
|
|||
// must be no entry global on the stack.
|
||||
JSContext *cx = nsContentUtils::GetCurrentJSContextForThread();
|
||||
if (!cx) {
|
||||
MOZ_ASSERT(ScriptSettingsStack::Ref().EntryGlobal() == nullptr);
|
||||
MOZ_ASSERT(ScriptSettingsStack::EntryGlobal() == nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -135,7 +149,7 @@ GetIncumbentGlobal()
|
|||
// global either.
|
||||
JSContext *cx = nsContentUtils::GetCurrentJSContextForThread();
|
||||
if (!cx) {
|
||||
MOZ_ASSERT(ScriptSettingsStack::Ref().EntryGlobal() == nullptr);
|
||||
MOZ_ASSERT(ScriptSettingsStack::EntryGlobal() == nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -149,17 +163,17 @@ GetIncumbentGlobal()
|
|||
|
||||
// Ok, nothing from the JS engine. Let's use whatever's on the
|
||||
// explicit stack.
|
||||
return ScriptSettingsStack::Ref().IncumbentGlobal();
|
||||
return ScriptSettingsStack::IncumbentGlobal();
|
||||
}
|
||||
|
||||
nsIPrincipal*
|
||||
GetWebIDLCallerPrincipal()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
ScriptSettingsStackEntry *entry = ScriptSettingsStack::Ref().EntryPoint();
|
||||
ScriptSettingsStackEntry *entry = ScriptSettingsStack::EntryPoint();
|
||||
|
||||
// If we have an entry point that is not the NoJSAPI singleton, we know it
|
||||
// must be an AutoEntryScript.
|
||||
// If we have an entry point that is not NoJSAPI, we know it must be an
|
||||
// AutoEntryScript.
|
||||
if (!entry || entry->NoJSAPI()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -248,37 +262,21 @@ AutoEntryScript::AutoEntryScript(nsIGlobalObject* aGlobalObject,
|
|||
: AutoJSAPI(aCx ? aCx : FindJSContext(aGlobalObject), aIsMainThread, /* aSkipNullAc = */ true)
|
||||
, ScriptSettingsStackEntry(aGlobalObject, /* aCandidate = */ true)
|
||||
, mAc(cx(), aGlobalObject->GetGlobalJSObject())
|
||||
, mStack(ScriptSettingsStack::Ref())
|
||||
, mWebIDLCallerPrincipal(nullptr)
|
||||
{
|
||||
MOZ_ASSERT(aGlobalObject);
|
||||
MOZ_ASSERT_IF(!aCx, aIsMainThread); // cx is mandatory off-main-thread.
|
||||
MOZ_ASSERT_IF(aCx && aIsMainThread, aCx == FindJSContext(aGlobalObject));
|
||||
mStack.Push(this);
|
||||
}
|
||||
|
||||
AutoEntryScript::~AutoEntryScript()
|
||||
{
|
||||
MOZ_ASSERT(mStack.Incumbent() == this);
|
||||
mStack.Pop();
|
||||
}
|
||||
|
||||
AutoIncumbentScript::AutoIncumbentScript(nsIGlobalObject* aGlobalObject)
|
||||
: ScriptSettingsStackEntry(aGlobalObject, /* aCandidate = */ false)
|
||||
, mStack(ScriptSettingsStack::Ref())
|
||||
, mCallerOverride(nsContentUtils::GetCurrentJSContextForThread())
|
||||
{
|
||||
mStack.Push(this);
|
||||
}
|
||||
|
||||
AutoIncumbentScript::~AutoIncumbentScript()
|
||||
{
|
||||
MOZ_ASSERT(mStack.Incumbent() == this);
|
||||
mStack.Pop();
|
||||
}
|
||||
|
||||
AutoNoJSAPI::AutoNoJSAPI(bool aIsMainThread)
|
||||
: mStack(ScriptSettingsStack::Ref())
|
||||
: ScriptSettingsStackEntry()
|
||||
{
|
||||
MOZ_ASSERT_IF(nsContentUtils::GetCurrentJSContextForThread(),
|
||||
!JS_IsExceptionPending(nsContentUtils::GetCurrentJSContextForThread()));
|
||||
|
@ -286,12 +284,6 @@ AutoNoJSAPI::AutoNoJSAPI(bool aIsMainThread)
|
|||
mCxPusher.construct(static_cast<JSContext*>(nullptr),
|
||||
/* aAllowNull = */ true);
|
||||
}
|
||||
mStack.PushNoJSAPI();
|
||||
}
|
||||
|
||||
AutoNoJSAPI::~AutoNoJSAPI()
|
||||
{
|
||||
mStack.Pop();
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -66,33 +66,25 @@ inline JSObject& IncumbentJSGlobal()
|
|||
}
|
||||
|
||||
class ScriptSettingsStack;
|
||||
struct ScriptSettingsStackEntry {
|
||||
class ScriptSettingsStackEntry {
|
||||
friend class ScriptSettingsStack;
|
||||
|
||||
public:
|
||||
ScriptSettingsStackEntry(nsIGlobalObject *aGlobal, bool aCandidate);
|
||||
~ScriptSettingsStackEntry();
|
||||
|
||||
bool NoJSAPI() { return !mGlobalObject; }
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIGlobalObject> mGlobalObject;
|
||||
bool mIsCandidateEntryPoint;
|
||||
|
||||
ScriptSettingsStackEntry(nsIGlobalObject *aGlobal, bool aCandidate)
|
||||
: mGlobalObject(aGlobal)
|
||||
, mIsCandidateEntryPoint(aCandidate)
|
||||
{
|
||||
MOZ_ASSERT(mGlobalObject);
|
||||
MOZ_ASSERT(mGlobalObject->GetGlobalJSObject(),
|
||||
"Must have an actual JS global for the duration on the stack");
|
||||
MOZ_ASSERT(JS_IsGlobalObject(mGlobalObject->GetGlobalJSObject()),
|
||||
"No outer windows allowed");
|
||||
}
|
||||
|
||||
~ScriptSettingsStackEntry() {
|
||||
// We must have an actual JS global for the entire time this is on the stack.
|
||||
MOZ_ASSERT_IF(mGlobalObject, mGlobalObject->GetGlobalJSObject());
|
||||
}
|
||||
|
||||
bool NoJSAPI() { return this == &NoJSAPISingleton; }
|
||||
static ScriptSettingsStackEntry NoJSAPISingleton;
|
||||
|
||||
private:
|
||||
ScriptSettingsStackEntry() : mGlobalObject(nullptr)
|
||||
, mIsCandidateEntryPoint(true)
|
||||
{}
|
||||
// This constructor is only for use by AutoNoJSAPI.
|
||||
friend class AutoNoJSAPI;
|
||||
ScriptSettingsStackEntry();
|
||||
|
||||
ScriptSettingsStackEntry *mOlder;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -172,7 +164,6 @@ public:
|
|||
bool aIsMainThread = NS_IsMainThread(),
|
||||
// Note: aCx is mandatory off-main-thread.
|
||||
JSContext* aCx = nullptr);
|
||||
~AutoEntryScript();
|
||||
|
||||
void SetWebIDLCallerPrincipal(nsIPrincipal *aPrincipal) {
|
||||
mWebIDLCallerPrincipal = aPrincipal;
|
||||
|
@ -180,7 +171,6 @@ public:
|
|||
|
||||
private:
|
||||
JSAutoCompartment mAc;
|
||||
dom::ScriptSettingsStack& mStack;
|
||||
// It's safe to make this a weak pointer, since it's the subject principal
|
||||
// when we go on the stack, so can't go away until after we're gone. In
|
||||
// particular, this is only used from the CallSetup constructor, and only in
|
||||
|
@ -198,9 +188,7 @@ private:
|
|||
class AutoIncumbentScript : protected ScriptSettingsStackEntry {
|
||||
public:
|
||||
AutoIncumbentScript(nsIGlobalObject* aGlobalObject);
|
||||
~AutoIncumbentScript();
|
||||
private:
|
||||
dom::ScriptSettingsStack& mStack;
|
||||
JS::AutoHideScriptedCaller mCallerOverride;
|
||||
};
|
||||
|
||||
|
@ -212,12 +200,10 @@ private:
|
|||
*
|
||||
* This class may not be instantiated if an exception is pending.
|
||||
*/
|
||||
class AutoNoJSAPI {
|
||||
class AutoNoJSAPI : protected ScriptSettingsStackEntry {
|
||||
public:
|
||||
AutoNoJSAPI(bool aIsMainThread = NS_IsMainThread());
|
||||
~AutoNoJSAPI();
|
||||
private:
|
||||
dom::ScriptSettingsStack& mStack;
|
||||
mozilla::Maybe<AutoCxPusher> mCxPusher;
|
||||
};
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "nsXPCOMCIDInternal.h"
|
||||
#include "nsIXULRuntime.h"
|
||||
#include "nsTextFormatter.h"
|
||||
#include "ScriptSettings.h"
|
||||
|
||||
#include "xpcpublic.h"
|
||||
|
||||
|
@ -1632,7 +1633,9 @@ nsresult
|
|||
nsJSContext::InitClasses(JS::Handle<JSObject*> aGlobalObj)
|
||||
{
|
||||
JSOptionChangedCallback(js_options_dot_str, this);
|
||||
AutoPushJSContext cx(mContext);
|
||||
AutoJSAPI jsapi;
|
||||
JSContext* cx = jsapi.cx();
|
||||
JSAutoCompartment ac(cx, aGlobalObj);
|
||||
|
||||
// Attempt to initialize profiling functions
|
||||
::JS_DefineProfilingFunctions(cx, aGlobalObj);
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "mozilla/dom/PContentPermissionRequestChild.h"
|
||||
#include "mozilla/dom/PermissionMessageUtils.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/EventDispatcher.h"
|
||||
#include "mozilla/EventListenerManager.h"
|
||||
#include "mozilla/LazyIdleThread.h"
|
||||
|
@ -28,6 +29,7 @@
|
|||
#include "mozilla/Services.h"
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsIDirectoryEnumerator.h"
|
||||
|
@ -1695,20 +1697,15 @@ JS::Value StringToJsval(nsPIDOMWindow* aWindow, nsAString& aString)
|
|||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aWindow);
|
||||
|
||||
nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aWindow);
|
||||
if (!sgo) {
|
||||
JSObject* global =
|
||||
static_cast<nsGlobalWindow*>(aWindow)->GetWrapperPreserveColor();
|
||||
if (NS_WARN_IF(!global)) {
|
||||
return JSVAL_NULL;
|
||||
}
|
||||
|
||||
nsIScriptContext *scriptContext = sgo->GetScriptContext();
|
||||
if (!scriptContext) {
|
||||
return JSVAL_NULL;
|
||||
}
|
||||
|
||||
AutoPushJSContext cx(scriptContext->GetNativeContext());
|
||||
if (!cx) {
|
||||
return JSVAL_NULL;
|
||||
}
|
||||
AutoJSAPI jsapi;
|
||||
JSContext* cx = jsapi.cx();
|
||||
JSAutoCompartment ac(cx, global);
|
||||
|
||||
JS::Rooted<JS::Value> result(cx);
|
||||
if (!xpc::StringToJsval(cx, aString, &result)) {
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "mozilla/dom/MozIccBinding.h"
|
||||
#include "mozilla/dom/MozStkCommandEvent.h"
|
||||
#include "mozilla/dom/DOMRequest.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "nsIDOMIccInfo.h"
|
||||
#include "nsJSON.h"
|
||||
#include "nsRadioInterfaceLayer.h"
|
||||
|
@ -51,7 +52,9 @@ Icc::NotifyStkEvent(const nsAString& aName, const nsAString& aMessage)
|
|||
nsIScriptContext* sc = GetContextForEventHandlers(&rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
AutoPushJSContext cx(sc->GetNativeContext());
|
||||
AutoJSAPIWithErrorsReportedToWindow jsapi(sc);
|
||||
JSContext* cx = jsapi.cx();
|
||||
JSAutoCompartment ac(cx, sc->GetWindowProxyPreserveColor());
|
||||
JS::Rooted<JS::Value> value(cx);
|
||||
|
||||
if (!aMessage.IsEmpty()) {
|
||||
|
|
|
@ -81,3 +81,14 @@ partial interface AudioContext {
|
|||
[Pref="media.useAudioChannelService", SetterThrows]
|
||||
attribute AudioChannel mozAudioChannelType;
|
||||
};
|
||||
|
||||
partial interface AudioContext {
|
||||
// These 2 events are dispatched when the AudioContext object is muted by
|
||||
// the AudioChannelService. It's call 'interrupt' because when this event is
|
||||
// dispatched on a HTMLMediaElement, the audio stream is paused.
|
||||
[Pref="media.useAudioChannelService"]
|
||||
attribute EventHandler onmozinterruptbegin;
|
||||
|
||||
[Pref="media.useAudioChannelService"]
|
||||
attribute EventHandler onmozinterruptend;
|
||||
};
|
||||
|
|
|
@ -5034,6 +5034,7 @@ nsEditor::DetermineCurrentDirection()
|
|||
{
|
||||
// Get the current root direction from its frame
|
||||
nsIContent* rootElement = GetExposedRoot();
|
||||
NS_ENSURE_TRUE(rootElement, NS_ERROR_FAILURE);
|
||||
|
||||
// If we don't have an explicit direction, determine our direction
|
||||
// from the content's direction
|
||||
|
|
|
@ -12,13 +12,7 @@ namespace gfx {
|
|||
TemporaryRef<DataSourceSurface>
|
||||
DataSourceSurface::GetDataSurface()
|
||||
{
|
||||
RefPtr<DataSourceSurface> temp;
|
||||
if (GetType() == SurfaceType::DATA) {
|
||||
temp = this;
|
||||
} else {
|
||||
temp = new DataSourceSurfaceWrapper(this);
|
||||
}
|
||||
return temp;
|
||||
return (GetType() == SurfaceType::DATA) ? this : new DataSourceSurfaceWrapper(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -170,9 +170,8 @@ DrawTargetCG::Snapshot()
|
|||
if (!mSnapshot) {
|
||||
if (GetContextType(mCg) == CG_CONTEXT_TYPE_IOSURFACE) {
|
||||
return new SourceSurfaceCGIOSurfaceContext(this);
|
||||
} else {
|
||||
mSnapshot = new SourceSurfaceCGBitmapContext(this);
|
||||
}
|
||||
mSnapshot = new SourceSurfaceCGBitmapContext(this);
|
||||
}
|
||||
|
||||
return mSnapshot;
|
||||
|
@ -185,10 +184,9 @@ DrawTargetCG::CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aForma
|
|||
// to add that in somehow, but at a higher level
|
||||
RefPtr<DrawTargetCG> newTarget = new DrawTargetCG();
|
||||
if (newTarget->Init(GetType(), aSize, aFormat)) {
|
||||
return newTarget;
|
||||
} else {
|
||||
return nullptr;
|
||||
return newTarget.forget();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TemporaryRef<SourceSurface>
|
||||
|
@ -199,11 +197,11 @@ DrawTargetCG::CreateSourceSurfaceFromData(unsigned char *aData,
|
|||
{
|
||||
RefPtr<SourceSurfaceCG> newSurf = new SourceSurfaceCG();
|
||||
|
||||
if (!newSurf->InitFromData(aData, aSize, aStride, aFormat)) {
|
||||
if (!newSurf->InitFromData(aData, aSize, aStride, aFormat)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return newSurf;
|
||||
return newSurf.forget();
|
||||
}
|
||||
|
||||
// This function returns a retained CGImage that needs to be released after
|
||||
|
@ -1447,8 +1445,7 @@ DrawTargetCG::Init(BackendType aType, const IntSize &aSize, SurfaceFormat &aForm
|
|||
TemporaryRef<PathBuilder>
|
||||
DrawTargetCG::CreatePathBuilder(FillRule aFillRule) const
|
||||
{
|
||||
RefPtr<PathBuilderCG> pb = new PathBuilderCG(aFillRule);
|
||||
return pb;
|
||||
return new PathBuilderCG(aFillRule);
|
||||
}
|
||||
|
||||
void*
|
||||
|
|
|
@ -976,9 +976,7 @@ DrawTargetCairo::PopClip()
|
|||
TemporaryRef<PathBuilder>
|
||||
DrawTargetCairo::CreatePathBuilder(FillRule aFillRule /* = FillRule::FILL_WINDING */) const
|
||||
{
|
||||
RefPtr<PathBuilderCairo> builder = new PathBuilderCairo(aFillRule);
|
||||
|
||||
return builder;
|
||||
return new PathBuilderCairo(aFillRule);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -998,9 +996,7 @@ TemporaryRef<GradientStops>
|
|||
DrawTargetCairo::CreateGradientStops(GradientStop *aStops, uint32_t aNumStops,
|
||||
ExtendMode aExtendMode) const
|
||||
{
|
||||
RefPtr<GradientStopsCairo> stops = new GradientStopsCairo(aStops, aNumStops,
|
||||
aExtendMode);
|
||||
return stops;
|
||||
return new GradientStopsCairo(aStops, aNumStops, aExtendMode);
|
||||
}
|
||||
|
||||
TemporaryRef<FilterNode>
|
||||
|
@ -1059,7 +1055,7 @@ DrawTargetCairo::CreateSourceSurfaceFromData(unsigned char *aData,
|
|||
RefPtr<SourceSurfaceCairo> source_surf = new SourceSurfaceCairo(surf, aSize, aFormat);
|
||||
cairo_surface_destroy(surf);
|
||||
|
||||
return source_surf;
|
||||
return source_surf.forget();
|
||||
}
|
||||
|
||||
#ifdef CAIRO_HAS_XLIB_SURFACE
|
||||
|
@ -1156,10 +1152,7 @@ DrawTargetCairo::OptimizeSourceSurface(SourceSurface *aSurface) const
|
|||
IntPoint(0, 0));
|
||||
dt->Flush();
|
||||
|
||||
RefPtr<SourceSurface> surf =
|
||||
new SourceSurfaceCairo(csurf, size, format);
|
||||
|
||||
return surf;
|
||||
return new SourceSurfaceCairo(csurf, size, format);
|
||||
#endif
|
||||
|
||||
return aSurface;
|
||||
|
@ -1175,9 +1168,7 @@ DrawTargetCairo::CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurf
|
|||
return nullptr;
|
||||
}
|
||||
cairo_surface_t* surf = static_cast<cairo_surface_t*>(aSurface.mSurface);
|
||||
RefPtr<SourceSurfaceCairo> source =
|
||||
new SourceSurfaceCairo(surf, aSurface.mSize, aSurface.mFormat);
|
||||
return source;
|
||||
return new SourceSurfaceCairo(surf, aSurface.mSize, aSurface.mFormat);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
@ -1193,7 +1184,7 @@ DrawTargetCairo::CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFo
|
|||
if (!cairo_surface_status(similar)) {
|
||||
RefPtr<DrawTargetCairo> target = new DrawTargetCairo();
|
||||
target->InitAlreadyReferenced(similar, aSize);
|
||||
return target;
|
||||
return target.forget();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
@ -1234,7 +1225,7 @@ DrawTargetCairo::CreateShadowDrawTarget(const IntSize &aSize, SurfaceFormat aFor
|
|||
if (aSigma == 0.0F) {
|
||||
RefPtr<DrawTargetCairo> target = new DrawTargetCairo();
|
||||
target->InitAlreadyReferenced(similar, aSize);
|
||||
return target;
|
||||
return target.forget();
|
||||
}
|
||||
|
||||
cairo_surface_t* blursurf = cairo_image_surface_create(CAIRO_FORMAT_A8,
|
||||
|
@ -1257,7 +1248,7 @@ DrawTargetCairo::CreateShadowDrawTarget(const IntSize &aSize, SurfaceFormat aFor
|
|||
|
||||
RefPtr<DrawTargetCairo> target = new DrawTargetCairo();
|
||||
target->InitAlreadyReferenced(tee, aSize);
|
||||
return target;
|
||||
return target.forget();
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -1198,7 +1198,7 @@ DrawTargetD2D::CreateSourceSurfaceFromData(unsigned char *aData,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
return newSurf;
|
||||
return newSurf.forget();
|
||||
}
|
||||
|
||||
TemporaryRef<SourceSurface>
|
||||
|
@ -1222,9 +1222,9 @@ DrawTargetD2D::OptimizeSourceSurface(SourceSurface *aSurface) const
|
|||
data->Unmap();
|
||||
|
||||
if (!success) {
|
||||
return data;
|
||||
return data.forget();
|
||||
}
|
||||
return newSurf;
|
||||
return newSurf.forget();
|
||||
}
|
||||
|
||||
TemporaryRef<SourceSurface>
|
||||
|
@ -1244,7 +1244,7 @@ DrawTargetD2D::CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurfac
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
return newSurf;
|
||||
return newSurf.forget();
|
||||
}
|
||||
|
||||
TemporaryRef<DrawTarget>
|
||||
|
@ -1258,7 +1258,7 @@ DrawTargetD2D::CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aForm
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
return newTarget;
|
||||
return newTarget.forget();
|
||||
}
|
||||
|
||||
TemporaryRef<PathBuilder>
|
||||
|
@ -1498,7 +1498,7 @@ DrawTargetD2D::GetCachedLayer()
|
|||
}
|
||||
|
||||
mCurrentCachedLayer++;
|
||||
return layer;
|
||||
return layer.forget();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1982,7 +1982,7 @@ DrawTargetD2D::CreateRTForTexture(ID3D10Texture2D *aTexture, SurfaceFormat aForm
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
return rt;
|
||||
return rt.forget();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2282,7 +2282,7 @@ DrawTargetD2D::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha)
|
|||
if (!IsPatternSupportedByD2D(aPattern)) {
|
||||
RefPtr<ID2D1SolidColorBrush> colBrush;
|
||||
mRT->CreateSolidColorBrush(D2D1::ColorF(1.0f, 1.0f, 1.0f, 1.0f), byRef(colBrush));
|
||||
return colBrush;
|
||||
return colBrush.forget();
|
||||
}
|
||||
|
||||
if (aPattern.GetType() == PatternType::COLOR) {
|
||||
|
@ -2292,8 +2292,9 @@ DrawTargetD2D::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha)
|
|||
color.b, color.a),
|
||||
D2D1::BrushProperties(aAlpha),
|
||||
byRef(colBrush));
|
||||
return colBrush;
|
||||
} else if (aPattern.GetType() == PatternType::LINEAR_GRADIENT) {
|
||||
return colBrush.forget();
|
||||
}
|
||||
if (aPattern.GetType() == PatternType::LINEAR_GRADIENT) {
|
||||
RefPtr<ID2D1LinearGradientBrush> gradBrush;
|
||||
const LinearGradientPattern *pat =
|
||||
static_cast<const LinearGradientPattern*>(&aPattern);
|
||||
|
@ -2313,7 +2314,7 @@ DrawTargetD2D::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha)
|
|||
mRT->CreateSolidColorBrush(d2dStops.back().color,
|
||||
D2D1::BrushProperties(aAlpha),
|
||||
byRef(colBrush));
|
||||
return colBrush;
|
||||
return colBrush.forget();
|
||||
}
|
||||
|
||||
mRT->CreateLinearGradientBrush(D2D1::LinearGradientBrushProperties(D2DPoint(pat->mBegin),
|
||||
|
@ -2321,8 +2322,9 @@ DrawTargetD2D::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha)
|
|||
D2D1::BrushProperties(aAlpha, D2DMatrix(pat->mMatrix)),
|
||||
stops->mStopCollection,
|
||||
byRef(gradBrush));
|
||||
return gradBrush;
|
||||
} else if (aPattern.GetType() == PatternType::RADIAL_GRADIENT) {
|
||||
return gradBrush.forget();
|
||||
}
|
||||
if (aPattern.GetType() == PatternType::RADIAL_GRADIENT) {
|
||||
RefPtr<ID2D1RadialGradientBrush> gradBrush;
|
||||
const RadialGradientPattern *pat =
|
||||
static_cast<const RadialGradientPattern*>(&aPattern);
|
||||
|
@ -2343,8 +2345,9 @@ DrawTargetD2D::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha)
|
|||
stops->mStopCollection,
|
||||
byRef(gradBrush));
|
||||
|
||||
return gradBrush;
|
||||
} else if (aPattern.GetType() == PatternType::SURFACE) {
|
||||
return gradBrush.forget();
|
||||
}
|
||||
if (aPattern.GetType() == PatternType::SURFACE) {
|
||||
RefPtr<ID2D1BitmapBrush> bmBrush;
|
||||
const SurfacePattern *pat =
|
||||
static_cast<const SurfacePattern*>(&aPattern);
|
||||
|
@ -2401,7 +2404,7 @@ DrawTargetD2D::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha)
|
|||
D2D1::BrushProperties(aAlpha, D2DMatrix(mat)),
|
||||
byRef(bmBrush));
|
||||
|
||||
return bmBrush;
|
||||
return bmBrush.forget();
|
||||
}
|
||||
|
||||
gfxWarning() << "Invalid pattern type detected.";
|
||||
|
@ -2477,7 +2480,7 @@ DrawTargetD2D::CreateGradientTexture(const GradientStopsD2D *aStops)
|
|||
RefPtr<ID3D10Texture2D> tex;
|
||||
mDevice->CreateTexture2D(&desc, &data, byRef(tex));
|
||||
|
||||
return tex;
|
||||
return tex.forget();
|
||||
}
|
||||
|
||||
TemporaryRef<ID3D10Texture2D>
|
||||
|
@ -2542,7 +2545,7 @@ DrawTargetD2D::CreateTextureForAnalysis(IDWriteGlyphRunAnalysis *aAnalysis, cons
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
return tex;
|
||||
return tex.forget();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -533,7 +533,7 @@ DrawTargetD2D1::CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFor
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
return dt;
|
||||
return dt.forget();
|
||||
}
|
||||
|
||||
TemporaryRef<PathBuilder>
|
||||
|
@ -797,7 +797,7 @@ DrawTargetD2D1::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha)
|
|||
if (!IsPatternSupportedByD2D(aPattern)) {
|
||||
RefPtr<ID2D1SolidColorBrush> colBrush;
|
||||
mDC->CreateSolidColorBrush(D2D1::ColorF(1.0f, 1.0f, 1.0f, 1.0f), byRef(colBrush));
|
||||
return colBrush;
|
||||
return colBrush.forget();
|
||||
}
|
||||
|
||||
if (aPattern.GetType() == PatternType::COLOR) {
|
||||
|
@ -807,8 +807,9 @@ DrawTargetD2D1::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha)
|
|||
color.b, color.a),
|
||||
D2D1::BrushProperties(aAlpha),
|
||||
byRef(colBrush));
|
||||
return colBrush;
|
||||
} else if (aPattern.GetType() == PatternType::LINEAR_GRADIENT) {
|
||||
return colBrush.forget();
|
||||
}
|
||||
if (aPattern.GetType() == PatternType::LINEAR_GRADIENT) {
|
||||
RefPtr<ID2D1LinearGradientBrush> gradBrush;
|
||||
const LinearGradientPattern *pat =
|
||||
static_cast<const LinearGradientPattern*>(&aPattern);
|
||||
|
@ -828,7 +829,7 @@ DrawTargetD2D1::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha)
|
|||
mDC->CreateSolidColorBrush(d2dStops.back().color,
|
||||
D2D1::BrushProperties(aAlpha),
|
||||
byRef(colBrush));
|
||||
return colBrush;
|
||||
return colBrush.forget();
|
||||
}
|
||||
|
||||
mDC->CreateLinearGradientBrush(D2D1::LinearGradientBrushProperties(D2DPoint(pat->mBegin),
|
||||
|
@ -836,8 +837,9 @@ DrawTargetD2D1::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha)
|
|||
D2D1::BrushProperties(aAlpha, D2DMatrix(pat->mMatrix)),
|
||||
stops->mStopCollection,
|
||||
byRef(gradBrush));
|
||||
return gradBrush;
|
||||
} else if (aPattern.GetType() == PatternType::RADIAL_GRADIENT) {
|
||||
return gradBrush.forget();
|
||||
}
|
||||
if (aPattern.GetType() == PatternType::RADIAL_GRADIENT) {
|
||||
RefPtr<ID2D1RadialGradientBrush> gradBrush;
|
||||
const RadialGradientPattern *pat =
|
||||
static_cast<const RadialGradientPattern*>(&aPattern);
|
||||
|
@ -855,11 +857,12 @@ DrawTargetD2D1::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha)
|
|||
D2DPoint(pat->mCenter1 - pat->mCenter2),
|
||||
pat->mRadius2, pat->mRadius2),
|
||||
D2D1::BrushProperties(aAlpha, D2DMatrix(pat->mMatrix)),
|
||||
stops->mStopCollection,
|
||||
byRef(gradBrush));
|
||||
stops->mStopCollection,
|
||||
byRef(gradBrush));
|
||||
|
||||
return gradBrush;
|
||||
} else if (aPattern.GetType() == PatternType::SURFACE) {
|
||||
return gradBrush.forget();
|
||||
}
|
||||
if (aPattern.GetType() == PatternType::SURFACE) {
|
||||
const SurfacePattern *pat =
|
||||
static_cast<const SurfacePattern*>(&aPattern);
|
||||
|
||||
|
@ -881,7 +884,7 @@ DrawTargetD2D1::CreateBrushForPattern(const Pattern &aPattern, Float aAlpha)
|
|||
D2DInterpolationMode(pat->mFilter)),
|
||||
D2D1::BrushProperties(aAlpha, D2DMatrix(mat)),
|
||||
byRef(imageBrush));
|
||||
return imageBrush;
|
||||
return imageBrush.forget();
|
||||
}
|
||||
|
||||
gfxWarning() << "Invalid pattern type detected.";
|
||||
|
@ -909,16 +912,13 @@ DrawTargetD2D1::GetImageForSurface(SourceSurface *aSurface, Matrix &aSourceTrans
|
|||
gfxWarning() << "Invalid surface type.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
image = CreatePartialBitmapForSurface(dataSurf, mTransform, mSize, aExtendMode,
|
||||
aSourceTransform, mDC);
|
||||
|
||||
return image;
|
||||
return CreatePartialBitmapForSurface(dataSurf, mTransform, mSize, aExtendMode,
|
||||
aSourceTransform, mDC);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return image;
|
||||
return image.forget();
|
||||
}
|
||||
|
||||
TemporaryRef<SourceSurface>
|
||||
|
@ -943,7 +943,7 @@ DrawTargetD2D1::OptimizeSourceSurface(SourceSurface* aSurface) const
|
|||
data->Unmap();
|
||||
|
||||
if (!bitmap) {
|
||||
return data;
|
||||
return data.forget();
|
||||
}
|
||||
|
||||
return new SourceSurfaceD2D1(bitmap.get(), mDC, data->GetFormat(), data->GetSize());
|
||||
|
|
|
@ -371,7 +371,7 @@ DrawTargetRecording::Snapshot()
|
|||
|
||||
mRecorder->RecordEvent(RecordedSnapshot(retSurf, this));
|
||||
|
||||
return retSurf;
|
||||
return retSurf.forget();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -416,7 +416,7 @@ DrawTargetRecording::CreateFilter(FilterType aType)
|
|||
|
||||
mRecorder->RecordEvent(RecordedFilterNodeCreation(retNode, aType));
|
||||
|
||||
return retNode;
|
||||
return retNode.forget();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -470,7 +470,7 @@ DrawTargetRecording::CreateSourceSurfaceFromData(unsigned char *aData,
|
|||
|
||||
mRecorder->RecordEvent(RecordedSourceSurfaceCreation(retSurf, aData, aStride, aSize, aFormat));
|
||||
|
||||
return retSurf;
|
||||
return retSurf.forget();
|
||||
}
|
||||
|
||||
TemporaryRef<SourceSurface>
|
||||
|
@ -503,7 +503,7 @@ DrawTargetRecording::OptimizeSourceSurface(SourceSurface *aSurface) const
|
|||
dataSurf->GetSize(), dataSurf->GetFormat()));
|
||||
}
|
||||
|
||||
return retSurf;
|
||||
return retSurf.forget();
|
||||
}
|
||||
|
||||
TemporaryRef<SourceSurface>
|
||||
|
@ -531,17 +531,14 @@ DrawTargetRecording::CreateSourceSurfaceFromNativeSurface(const NativeSurface &a
|
|||
dataSurf->GetSize(), dataSurf->GetFormat()));
|
||||
}
|
||||
|
||||
return retSurf;
|
||||
return retSurf.forget();
|
||||
}
|
||||
|
||||
TemporaryRef<DrawTarget>
|
||||
DrawTargetRecording::CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const
|
||||
{
|
||||
RefPtr<DrawTarget> dt = mFinalDT->CreateSimilarDrawTarget(aSize, aFormat);
|
||||
|
||||
RefPtr<DrawTarget> retDT = new DrawTargetRecording(mRecorder.get(), dt);
|
||||
|
||||
return retDT;
|
||||
return new DrawTargetRecording(mRecorder.get(), dt);
|
||||
}
|
||||
|
||||
TemporaryRef<PathBuilder>
|
||||
|
@ -562,7 +559,7 @@ DrawTargetRecording::CreateGradientStops(GradientStop *aStops,
|
|||
|
||||
mRecorder->RecordEvent(RecordedGradientStopsCreation(retStops, aStops, aNumStops, aExtendMode));
|
||||
|
||||
return retStops;
|
||||
return retStops.forget();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -135,7 +135,7 @@ DrawTargetSkia::Snapshot()
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
return snapshot;
|
||||
return snapshot.forget();
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -587,7 +587,7 @@ DrawTargetSkia::CreateSourceSurfaceFromData(unsigned char *aData,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
return newSurf;
|
||||
return newSurf.forget();
|
||||
}
|
||||
|
||||
TemporaryRef<DrawTarget>
|
||||
|
@ -597,7 +597,7 @@ DrawTargetSkia::CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFor
|
|||
if (!target->Init(aSize, aFormat)) {
|
||||
return nullptr;
|
||||
}
|
||||
return target;
|
||||
return target.forget();
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -638,7 +638,7 @@ DrawTargetSkia::OptimizeSourceSurface(SourceSurface *aSurface) const
|
|||
map.mStride,
|
||||
dataSurf->GetFormat());
|
||||
dataSurf->Unmap();
|
||||
return result;
|
||||
return result.forget();
|
||||
}
|
||||
|
||||
TemporaryRef<SourceSurface>
|
||||
|
@ -808,8 +808,7 @@ DrawTargetSkia::GetNativeSurface(NativeSurfaceType aType)
|
|||
TemporaryRef<PathBuilder>
|
||||
DrawTargetSkia::CreatePathBuilder(FillRule aFillRule) const
|
||||
{
|
||||
RefPtr<PathBuilderSkia> pb = new PathBuilderSkia(aFillRule);
|
||||
return pb;
|
||||
return new PathBuilderSkia(aFillRule);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -76,7 +76,7 @@ public:
|
|||
}
|
||||
surf->Unmap();
|
||||
|
||||
return surf;
|
||||
return surf.forget();
|
||||
}
|
||||
private:
|
||||
vector<RefPtr<SourceSurface>> mSnapshots;
|
||||
|
|
|
@ -299,9 +299,7 @@ Factory::CreateDrawTarget(BackendType aBackend, const IntSize &aSize, SurfaceFor
|
|||
}
|
||||
|
||||
if (mRecorder && retVal) {
|
||||
RefPtr<DrawTarget> recordDT;
|
||||
recordDT = new DrawTargetRecording(mRecorder, retVal);
|
||||
return recordDT;
|
||||
return new DrawTargetRecording(mRecorder, retVal);
|
||||
}
|
||||
|
||||
if (!retVal) {
|
||||
|
@ -309,7 +307,7 @@ Factory::CreateDrawTarget(BackendType aBackend, const IntSize &aSize, SurfaceFor
|
|||
gfxDebug() << "Failed to create DrawTarget, Type: " << int(aBackend) << " Size: " << aSize;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
return retVal.forget();
|
||||
}
|
||||
|
||||
TemporaryRef<DrawTarget>
|
||||
|
@ -347,7 +345,7 @@ Factory::CreateDrawTargetForData(BackendType aBackend,
|
|||
{
|
||||
RefPtr<DrawTargetCG> newTarget = new DrawTargetCG();
|
||||
if (newTarget->Init(aBackend, aData, aSize, aStride, aFormat))
|
||||
return newTarget;
|
||||
return newTarget.forget();
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
@ -357,7 +355,7 @@ Factory::CreateDrawTargetForData(BackendType aBackend,
|
|||
RefPtr<DrawTargetCairo> newTarget;
|
||||
newTarget = new DrawTargetCairo();
|
||||
if (newTarget->Init(aData, aSize, aStride, aFormat)) {
|
||||
retVal = newTarget;
|
||||
retVal = newTarget.forget();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -368,15 +366,14 @@ Factory::CreateDrawTargetForData(BackendType aBackend,
|
|||
}
|
||||
|
||||
if (mRecorder && retVal) {
|
||||
RefPtr<DrawTarget> recordDT = new DrawTargetRecording(mRecorder, retVal, true);
|
||||
return recordDT;
|
||||
return new DrawTargetRecording(mRecorder, retVal, true);
|
||||
}
|
||||
|
||||
if (!retVal) {
|
||||
gfxDebug() << "Failed to create DrawTarget, Type: " << int(aBackend) << " Size: " << aSize;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
return retVal.forget();
|
||||
}
|
||||
|
||||
TemporaryRef<DrawTarget>
|
||||
|
@ -388,7 +385,7 @@ Factory::CreateTiledDrawTarget(const TileSet& aTileSet)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
return dt;
|
||||
return dt.forget();
|
||||
}
|
||||
|
||||
TemporaryRef<ScaledFont>
|
||||
|
@ -453,7 +450,7 @@ Factory::CreateScaledFontWithCairo(const NativeFont& aNativeFont, Float aSize, c
|
|||
// Therefore, we just reuse CreateScaledFontForNativeFont's implementation.
|
||||
RefPtr<ScaledFont> font = CreateScaledFontForNativeFont(aNativeFont, aSize);
|
||||
static_cast<ScaledFontBase*>(font.get())->SetCairoScaledFont(aScaledFont);
|
||||
return font;
|
||||
return font.forget();
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
|
@ -471,7 +468,7 @@ Factory::CreateDualDrawTarget(DrawTarget *targetA, DrawTarget *targetB)
|
|||
retVal = new DrawTargetRecording(mRecorder, retVal);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
return retVal.forget();
|
||||
}
|
||||
|
||||
|
||||
|
@ -489,7 +486,7 @@ Factory::CreateDrawTargetForD3D10Texture(ID3D10Texture2D *aTexture, SurfaceForma
|
|||
retVal = new DrawTargetRecording(mRecorder, retVal, true);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
return retVal.forget();
|
||||
}
|
||||
|
||||
gfxWarning() << "Failed to create draw target for D3D10 texture.";
|
||||
|
@ -527,7 +524,7 @@ Factory::CreateDualDrawTargetForD3D10Textures(ID3D10Texture2D *aTextureA,
|
|||
retVal = new DrawTargetRecording(mRecorder, retVal);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
return retVal.forget();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -571,10 +568,7 @@ Factory::GetD2D1Device()
|
|||
TemporaryRef<GlyphRenderingOptions>
|
||||
Factory::CreateDWriteGlyphRenderingOptions(IDWriteRenderingParams *aParams)
|
||||
{
|
||||
RefPtr<GlyphRenderingOptions> options =
|
||||
new GlyphRenderingOptionsDWrite(aParams);
|
||||
|
||||
return options;
|
||||
return new GlyphRenderingOptionsDWrite(aParams);
|
||||
}
|
||||
|
||||
uint64_t
|
||||
|
@ -607,7 +601,7 @@ Factory::CreateDrawTargetSkiaWithGrContext(GrContext* aGrContext,
|
|||
if (!newTarget->InitWithGrContext(aGrContext, aSize, aFormat)) {
|
||||
return nullptr;
|
||||
}
|
||||
return newTarget;
|
||||
return newTarget.forget();
|
||||
}
|
||||
|
||||
#endif // USE_SKIA_GPU
|
||||
|
@ -626,7 +620,7 @@ Factory::CreateCairoGlyphRenderingOptions(FontHinting aHinting, bool aAutoHintin
|
|||
|
||||
options->SetHinting(aHinting);
|
||||
options->SetAutoHinting(aAutoHinting);
|
||||
return options;
|
||||
return options.forget();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -644,10 +638,10 @@ Factory::CreateDrawTargetForCairoSurface(cairo_surface_t* aSurface, const IntSiz
|
|||
|
||||
if (mRecorder && retVal) {
|
||||
RefPtr<DrawTarget> recordDT = new DrawTargetRecording(mRecorder, retVal, true);
|
||||
return recordDT;
|
||||
return recordDT.forget();
|
||||
}
|
||||
#endif
|
||||
return retVal;
|
||||
return retVal.forget();
|
||||
}
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
|
@ -663,10 +657,9 @@ Factory::CreateDrawTargetForCairoCGContext(CGContextRef cg, const IntSize& aSize
|
|||
}
|
||||
|
||||
if (mRecorder && retVal) {
|
||||
RefPtr<DrawTarget> recordDT = new DrawTargetRecording(mRecorder, retVal);
|
||||
return recordDT;
|
||||
return new DrawTargetRecording(mRecorder, retVal);
|
||||
}
|
||||
return retVal;
|
||||
return retVal.forget();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -682,7 +675,7 @@ Factory::CreateWrappingDataSourceSurface(uint8_t *aData, int32_t aStride,
|
|||
RefPtr<SourceSurfaceRawData> newSurf = new SourceSurfaceRawData();
|
||||
|
||||
if (newSurf->InitWrappingData(aData, aSize, aStride, aFormat, false)) {
|
||||
return newSurf;
|
||||
return newSurf.forget();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
@ -698,7 +691,7 @@ Factory::CreateDataSourceSurface(const IntSize &aSize,
|
|||
|
||||
RefPtr<SourceSurfaceAlignedRawData> newSurf = new SourceSurfaceAlignedRawData();
|
||||
if (newSurf->Init(aSize, aFormat)) {
|
||||
return newSurf;
|
||||
return newSurf.forget();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
@ -715,7 +708,7 @@ Factory::CreateDataSourceSurfaceWithStride(const IntSize &aSize,
|
|||
|
||||
RefPtr<SourceSurfaceAlignedRawData> newSurf = new SourceSurfaceAlignedRawData();
|
||||
if (newSurf->InitWithStride(aSize, aFormat, aStride)) {
|
||||
return newSurf;
|
||||
return newSurf.forget();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
|
|
@ -282,7 +282,7 @@ CloneAligned(DataSourceSurface* aSource)
|
|||
if (copy) {
|
||||
CopyRect(aSource, copy, IntRect(IntPoint(), aSource->GetSize()), IntPoint());
|
||||
}
|
||||
return copy;
|
||||
return copy.forget();
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -518,7 +518,7 @@ GetDataSurfaceInRect(SourceSurface *aSurface,
|
|||
}
|
||||
|
||||
if (!aSurface) {
|
||||
return target;
|
||||
return target.forget();
|
||||
}
|
||||
|
||||
RefPtr<DataSourceSurface> dataSource = aSurface->GetDataSurface();
|
||||
|
@ -526,7 +526,7 @@ GetDataSurfaceInRect(SourceSurface *aSurface,
|
|||
|
||||
if (aEdgeMode == EDGE_MODE_WRAP) {
|
||||
TileSurface(dataSource, target, intersectInDestSpace.TopLeft());
|
||||
return target;
|
||||
return target.forget();
|
||||
}
|
||||
|
||||
CopyRect(dataSource, target, intersectInSourceSpace,
|
||||
|
@ -536,7 +536,7 @@ GetDataSurfaceInRect(SourceSurface *aSurface,
|
|||
DuplicateEdges(target, intersectInDestSpace);
|
||||
}
|
||||
|
||||
return target;
|
||||
return target.forget();
|
||||
}
|
||||
|
||||
/* static */ TemporaryRef<FilterNode>
|
||||
|
@ -623,7 +623,7 @@ FilterNodeSoftware::Create(FilterType aType)
|
|||
filter = new FilterNodeLightingSoftware<DistantLightSoftware, SpecularLightingSoftware>("FilterNodeLightingSoftware<DistantLight, SpecularLighting>");
|
||||
break;
|
||||
}
|
||||
return filter;
|
||||
return filter.forget();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -857,7 +857,7 @@ FilterNodeSoftware::GetInputDataSourceSurface(uint32_t aInputEnumIndex,
|
|||
|
||||
MOZ_ASSERT(!result || result->GetSize() == aRect.Size(), "wrong surface size");
|
||||
|
||||
return result;
|
||||
return result.forget();
|
||||
}
|
||||
|
||||
IntRect
|
||||
|
@ -1022,7 +1022,7 @@ FilterNodeBlendSoftware::Render(const IntRect& aRect)
|
|||
}
|
||||
|
||||
// Third case: one of them is transparent. Return the non-transparent one.
|
||||
return input1 ? input1 : input2;
|
||||
return input1 ? input1.forget() : input2.forget();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1104,7 +1104,7 @@ FilterNodeTransformSoftware::Render(const IntRect& aRect)
|
|||
Matrix transform = Matrix::Translation(srcRect.x, srcRect.y) * mMatrix *
|
||||
Matrix::Translation(-aRect.x, -aRect.y);
|
||||
if (transform.IsIdentity() && srcRect.Size() == aRect.Size()) {
|
||||
return input;
|
||||
return input.forget();
|
||||
}
|
||||
|
||||
RefPtr<DrawTarget> dt =
|
||||
|
@ -1119,7 +1119,7 @@ FilterNodeTransformSoftware::Render(const IntRect& aRect)
|
|||
|
||||
RefPtr<SourceSurface> result = dt->Snapshot();
|
||||
RefPtr<DataSourceSurface> resultData = result->GetDataSurface();
|
||||
return resultData;
|
||||
return resultData.forget();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1229,7 +1229,7 @@ ApplyMorphology(const IntRect& aSourceRect, DataSourceSurface* aInput,
|
|||
tmpData, tmpStride, destData, destStride, destRect, ry, aOperator);
|
||||
}
|
||||
|
||||
return dest;
|
||||
return dest.forget();
|
||||
}
|
||||
|
||||
TemporaryRef<DataSourceSurface>
|
||||
|
@ -1248,7 +1248,7 @@ FilterNodeMorphologySoftware::Render(const IntRect& aRect)
|
|||
int32_t ry = mRadii.height;
|
||||
|
||||
if (rx == 0 && ry == 0) {
|
||||
return input;
|
||||
return input.forget();
|
||||
}
|
||||
|
||||
return ApplyMorphology(srcRect, input, aRect, rx, ry, mOperator);
|
||||
|
@ -1325,7 +1325,7 @@ Premultiply(DataSourceSurface* aSurface)
|
|||
FilterProcessing::DoPremultiplicationCalculation(
|
||||
size, targetData, targetStride, inputData, inputStride);
|
||||
|
||||
return target;
|
||||
return target.forget();
|
||||
}
|
||||
|
||||
static TemporaryRef<DataSourceSurface>
|
||||
|
@ -1350,7 +1350,7 @@ Unpremultiply(DataSourceSurface* aSurface)
|
|||
FilterProcessing::DoUnpremultiplicationCalculation(
|
||||
size, targetData, targetStride, inputData, inputStride);
|
||||
|
||||
return target;
|
||||
return target.forget();
|
||||
}
|
||||
|
||||
TemporaryRef<DataSourceSurface>
|
||||
|
@ -1373,7 +1373,7 @@ FilterNodeColorMatrixSoftware::Render(const IntRect& aRect)
|
|||
result = Premultiply(result);
|
||||
}
|
||||
|
||||
return result;
|
||||
return result.forget();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1452,7 +1452,7 @@ FilterNodeFloodSoftware::Render(const IntRect& aRect)
|
|||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
return target;
|
||||
return target.forget();
|
||||
}
|
||||
|
||||
// Override GetOutput to get around caching. Rendering simple floods is
|
||||
|
@ -1564,7 +1564,7 @@ FilterNodeTileSoftware::Render(const IntRect& aRect)
|
|||
}
|
||||
}
|
||||
|
||||
return target;
|
||||
return target.forget();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1706,7 +1706,7 @@ FilterNodeComponentTransferSoftware::Render(const IntRect& aRect)
|
|||
|
||||
SurfaceFormat format = input->GetFormat();
|
||||
if (format == SurfaceFormat::A8 && mDisableA) {
|
||||
return input;
|
||||
return input.forget();
|
||||
}
|
||||
|
||||
RefPtr<DataSourceSurface> target =
|
||||
|
@ -1721,7 +1721,7 @@ FilterNodeComponentTransferSoftware::Render(const IntRect& aRect)
|
|||
TransferComponents<4>(input, target, lookupTables);
|
||||
}
|
||||
|
||||
return target;
|
||||
return target.forget();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2426,7 +2426,7 @@ FilterNodeConvolveMatrixSoftware::DoRender(const IntRect& aRect,
|
|||
}
|
||||
delete[] intKernel;
|
||||
|
||||
return target;
|
||||
return target.forget();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2567,7 +2567,7 @@ FilterNodeDisplacementMapSoftware::Render(const IntRect& aRect)
|
|||
}
|
||||
}
|
||||
|
||||
return target;
|
||||
return target.forget();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2824,7 +2824,7 @@ FilterNodeCompositeSoftware::Render(const IntRect& aRect)
|
|||
}
|
||||
}
|
||||
}
|
||||
return dest;
|
||||
return dest.forget();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -3429,7 +3429,7 @@ FilterNodeLightingSoftware<LightType, LightingType>::DoRender(const IntRect& aRe
|
|||
}
|
||||
}
|
||||
|
||||
return target;
|
||||
return target.forget();
|
||||
}
|
||||
|
||||
DiffuseLightingSoftware::DiffuseLightingSoftware()
|
||||
|
|
|
@ -26,7 +26,7 @@ FilterProcessing::ExtractAlpha(DataSourceSurface* aSource)
|
|||
ExtractAlpha_Scalar(size, sourceData, sourceStride, alphaData, alphaStride);
|
||||
}
|
||||
|
||||
return alpha;
|
||||
return alpha.forget();
|
||||
}
|
||||
|
||||
TemporaryRef<DataSourceSurface>
|
||||
|
@ -162,7 +162,7 @@ FilterProcessing::CombineColorChannels(DataSourceSurface* aChannel0, DataSourceS
|
|||
CombineColorChannels_Scalar(size, resultStride, resultData, channelStride, channel0Data, channel1Data, channel2Data, channel3Data);
|
||||
}
|
||||
|
||||
return result;
|
||||
return result.forget();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -85,7 +85,7 @@ ApplyBlending_Scalar(DataSourceSurface* aInput1, DataSourceSurface* aInput2)
|
|||
}
|
||||
}
|
||||
|
||||
return target;
|
||||
return target.forget();
|
||||
}
|
||||
|
||||
TemporaryRef<DataSourceSurface>
|
||||
|
|
|
@ -355,7 +355,7 @@ GetTransformedGeometry(ID2D1Geometry *aGeometry, const D2D1_MATRIX_3X2_F &aTrans
|
|||
aGeometry->Simplify(D2D1_GEOMETRY_SIMPLIFICATION_OPTION_CUBICS_AND_LINES,
|
||||
aTransform, currentSink);
|
||||
currentSink->Close();
|
||||
return tmpGeometry;
|
||||
return tmpGeometry.forget();
|
||||
}
|
||||
|
||||
static TemporaryRef<ID2D1Geometry>
|
||||
|
@ -368,7 +368,7 @@ IntersectGeometry(ID2D1Geometry *aGeometryA, ID2D1Geometry *aGeometryB)
|
|||
aGeometryA->CombineWithGeometry(aGeometryB, D2D1_COMBINE_MODE_INTERSECT, nullptr, sink);
|
||||
sink->Close();
|
||||
|
||||
return pathGeom;
|
||||
return pathGeom.forget();
|
||||
}
|
||||
|
||||
static TemporaryRef<ID2D1StrokeStyle>
|
||||
|
@ -442,7 +442,7 @@ CreateStrokeStyleForOptions(const StrokeOptions &aStrokeOptions)
|
|||
gfxWarning() << "Failed to create Direct2D stroke style.";
|
||||
}
|
||||
|
||||
return style;
|
||||
return style.forget();
|
||||
}
|
||||
|
||||
// This creates a (partially) uploaded bitmap for a DataSourceSurface. It
|
||||
|
@ -525,7 +525,7 @@ CreatePartialBitmapForSurface(DataSourceSurface *aSurface, const Matrix &aDestin
|
|||
|
||||
aSourceTransform.Translate(uploadRect.x, uploadRect.y);
|
||||
|
||||
return bitmap;
|
||||
return bitmap.forget();
|
||||
} else {
|
||||
int Bpp = BytesPerPixel(aSurface->GetFormat());
|
||||
|
||||
|
@ -571,7 +571,7 @@ CreatePartialBitmapForSurface(DataSourceSurface *aSurface, const Matrix &aDestin
|
|||
|
||||
aSourceTransform.Scale(Float(size.width / newSize.width),
|
||||
Float(size.height / newSize.height));
|
||||
return bitmap;
|
||||
return bitmap.forget();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -100,16 +100,14 @@ PathBuilderCG::EnsureActive(const Point &aPoint)
|
|||
TemporaryRef<Path>
|
||||
PathBuilderCG::Finish()
|
||||
{
|
||||
RefPtr<PathCG> path = new PathCG(mCGPath, mFillRule);
|
||||
return path;
|
||||
return new PathCG(mCGPath, mFillRule);
|
||||
}
|
||||
|
||||
TemporaryRef<PathBuilder>
|
||||
PathCG::CopyToBuilder(FillRule aFillRule) const
|
||||
{
|
||||
CGMutablePathRef path = CGPathCreateMutableCopy(mPath);
|
||||
RefPtr<PathBuilderCG> builder = new PathBuilderCG(path, aFillRule);
|
||||
return builder;
|
||||
return new PathBuilderCG(path, aFillRule);
|
||||
}
|
||||
|
||||
|
||||
|
@ -169,8 +167,7 @@ PathCG::TransformedCopyToBuilder(const Matrix &aTransform, FillRule aFillRule) c
|
|||
ta.transform = GfxMatrixToCGAffineTransform(aTransform);
|
||||
|
||||
CGPathApply(mPath, &ta, TransformApplier::TranformCGPathApplierFunc);
|
||||
RefPtr<PathBuilderCG> builder = new PathBuilderCG(ta.path, aFillRule);
|
||||
return builder;
|
||||
return new PathBuilderCG(ta.path, aFillRule);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -167,7 +167,7 @@ PathCairo::CopyToBuilder(FillRule aFillRule) const
|
|||
builder->mPathData = mPathData;
|
||||
builder->mCurrentPoint = mCurrentPoint;
|
||||
|
||||
return builder;
|
||||
return builder.forget();
|
||||
}
|
||||
|
||||
TemporaryRef<PathBuilder>
|
||||
|
@ -178,7 +178,7 @@ PathCairo::TransformedCopyToBuilder(const Matrix &aTransform, FillRule aFillRule
|
|||
AppendPathToBuilder(builder, &aTransform);
|
||||
builder->mCurrentPoint = aTransform * mCurrentPoint;
|
||||
|
||||
return builder;
|
||||
return builder.forget();
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -353,7 +353,7 @@ PathD2D::TransformedCopyToBuilder(const Matrix &aTransform, FillRule aFillRule)
|
|||
pathBuilder->mFigureActive = true;
|
||||
}
|
||||
|
||||
return pathBuilder;
|
||||
return pathBuilder.forget();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -90,7 +90,7 @@ PathRecording::CopyToBuilder(FillRule aFillRule) const
|
|||
RefPtr<PathBuilder> pathBuilder = mPath->CopyToBuilder(aFillRule);
|
||||
RefPtr<PathBuilderRecording> recording = new PathBuilderRecording(pathBuilder, aFillRule);
|
||||
recording->mPathOps = mPathOps;
|
||||
return recording;
|
||||
return recording.forget();
|
||||
}
|
||||
|
||||
TemporaryRef<PathBuilder>
|
||||
|
@ -113,7 +113,7 @@ PathRecording::TransformedCopyToBuilder(const Matrix &aTransform, FillRule aFill
|
|||
}
|
||||
recording->mPathOps.push_back(newPathOp);
|
||||
}
|
||||
return recording;
|
||||
return recording.forget();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -105,8 +105,7 @@ PathBuilderSkia::CurrentPoint() const
|
|||
TemporaryRef<Path>
|
||||
PathBuilderSkia::Finish()
|
||||
{
|
||||
RefPtr<PathSkia> path = new PathSkia(mPath, mFillRule);
|
||||
return path;
|
||||
return new PathSkia(mPath, mFillRule);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -124,8 +123,7 @@ PathSkia::CopyToBuilder(FillRule aFillRule) const
|
|||
TemporaryRef<PathBuilder>
|
||||
PathSkia::TransformedCopyToBuilder(const Matrix &aTransform, FillRule aFillRule) const
|
||||
{
|
||||
RefPtr<PathBuilderSkia> builder = new PathBuilderSkia(aTransform, mPath, aFillRule);
|
||||
return builder;
|
||||
return new PathBuilderSkia(aTransform, mPath, aFillRule);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -379,7 +379,7 @@ RadialGradientEffectD2D1::CreateGradientTexture()
|
|||
gfxWarning() << "Failed to create resource texture: " << hr;
|
||||
}
|
||||
|
||||
return tex;
|
||||
return tex.forget();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -118,7 +118,7 @@ ScaledFontBase::GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *a
|
|||
cairo_destroy(ctx);
|
||||
}
|
||||
|
||||
return newPath;
|
||||
return newPath.forget();
|
||||
}
|
||||
#endif
|
||||
return nullptr;
|
||||
|
|
|
@ -96,9 +96,8 @@ ScaledFontMac::GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aT
|
|||
TemporaryRef<Path> ret = new PathCG(path, FillRule::FILL_WINDING);
|
||||
CGPathRelease(path);
|
||||
return ret;
|
||||
} else {
|
||||
return ScaledFontBase::GetPathForGlyphs(aBuffer, aTarget);
|
||||
}
|
||||
return ScaledFontBase::GetPathForGlyphs(aBuffer, aTarget);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -43,9 +43,7 @@ SourceSurfaceCG::GetDataSurface()
|
|||
|
||||
// We also need to make sure that the returned surface has
|
||||
// surface->GetType() == SurfaceType::DATA.
|
||||
dataSurf = new DataSourceSurfaceWrapper(dataSurf);
|
||||
|
||||
return dataSurf;
|
||||
return new DataSourceSurfaceWrapper(dataSurf);
|
||||
}
|
||||
|
||||
static void releaseCallback(void *info, const void *data, size_t size) {
|
||||
|
|
|
@ -81,9 +81,7 @@ SourceSurfaceCairo::GetDataSurface()
|
|||
|
||||
// We also need to make sure that the returned surface has
|
||||
// surface->GetType() == SurfaceType::DATA.
|
||||
dataSurf = new DataSourceSurfaceWrapper(dataSurf);
|
||||
|
||||
return dataSurf;
|
||||
return new DataSourceSurfaceWrapper(dataSurf);
|
||||
}
|
||||
|
||||
cairo_surface_t*
|
||||
|
|
|
@ -45,7 +45,7 @@ SourceSurfaceD2D::GetDataSurface()
|
|||
{
|
||||
RefPtr<DataSourceSurfaceD2D> result = new DataSourceSurfaceD2D(this);
|
||||
if (result->IsValid()) {
|
||||
return result;
|
||||
return result.forget();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ SourceSurfaceD2DTarget::GetDataSurface()
|
|||
}
|
||||
Factory::GetDirect3D10Device()->CopyResource(dataSurf->mTexture, mTexture);
|
||||
|
||||
return dataSurf;
|
||||
return dataSurf.forget();
|
||||
}
|
||||
|
||||
void*
|
||||
|
|
|
@ -197,7 +197,11 @@
|
|||
#define unlikely(expr) (expr)
|
||||
#endif
|
||||
|
||||
#ifndef __GNUC__
|
||||
/*
|
||||
* clang-cl supports __attribute__, but MSVC doesn't, so we need to make sure
|
||||
* we do this if not GNUC but also if not clang either.
|
||||
*/
|
||||
#if !defined(__GNUC__) && !defined(__clang__)
|
||||
#undef __attribute__
|
||||
#define __attribute__(x)
|
||||
#endif
|
||||
|
|
|
@ -330,8 +330,11 @@ preprocess_text_thai (const hb_ot_shape_plan_t *plan,
|
|||
if (unlikely (buffer->in_error))
|
||||
return;
|
||||
|
||||
/* Ok, let's see... */
|
||||
/* Make Nikhahit be recognized as a mark when zeroing widths. */
|
||||
unsigned int end = buffer->out_len;
|
||||
_hb_glyph_info_set_general_category (&buffer->out_info[end - 2], HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK);
|
||||
|
||||
/* Ok, let's see... */
|
||||
unsigned int start = end - 2;
|
||||
while (start > 0 && IS_TONE_MARK (buffer->out_info[start - 1].codepoint))
|
||||
start--;
|
||||
|
|
|
@ -452,26 +452,42 @@ hb_ot_substitute (hb_ot_shape_context_t *c)
|
|||
/* Position */
|
||||
|
||||
static inline void
|
||||
zero_mark_widths_by_unicode (hb_buffer_t *buffer)
|
||||
adjust_mark_offsets (hb_glyph_position_t *pos)
|
||||
{
|
||||
pos->x_offset -= pos->x_advance;
|
||||
pos->y_offset -= pos->y_advance;
|
||||
}
|
||||
|
||||
static inline void
|
||||
zero_mark_width (hb_glyph_position_t *pos)
|
||||
{
|
||||
pos->x_advance = 0;
|
||||
pos->y_advance = 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
zero_mark_widths_by_unicode (hb_buffer_t *buffer, bool adjust_offsets)
|
||||
{
|
||||
unsigned int count = buffer->len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (_hb_glyph_info_get_general_category (&buffer->info[i]) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
|
||||
{
|
||||
buffer->pos[i].x_advance = 0;
|
||||
buffer->pos[i].y_advance = 0;
|
||||
if (adjust_offsets)
|
||||
adjust_mark_offsets (&buffer->pos[i]);
|
||||
zero_mark_width (&buffer->pos[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
zero_mark_widths_by_gdef (hb_buffer_t *buffer)
|
||||
zero_mark_widths_by_gdef (hb_buffer_t *buffer, bool adjust_offsets)
|
||||
{
|
||||
unsigned int count = buffer->len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (_hb_glyph_info_is_mark (&buffer->info[i]))
|
||||
{
|
||||
buffer->pos[i].x_advance = 0;
|
||||
buffer->pos[i].y_advance = 0;
|
||||
if (adjust_offsets)
|
||||
adjust_mark_offsets (&buffer->pos[i]);
|
||||
zero_mark_width (&buffer->pos[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -501,16 +517,19 @@ hb_ot_position_complex (hb_ot_shape_context_t *c)
|
|||
{
|
||||
bool ret = false;
|
||||
unsigned int count = c->buffer->len;
|
||||
bool has_positioning = hb_ot_layout_has_positioning (c->face);
|
||||
bool adjust_offsets_when_zeroing = !(has_positioning || c->plan->shaper->fallback_position ||
|
||||
HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction));
|
||||
|
||||
switch (c->plan->shaper->zero_width_marks)
|
||||
{
|
||||
case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY:
|
||||
zero_mark_widths_by_gdef (c->buffer);
|
||||
zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing);
|
||||
break;
|
||||
|
||||
/* Not currently used for any shaper:
|
||||
case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_EARLY:
|
||||
zero_mark_widths_by_unicode (c->buffer);
|
||||
zero_mark_widths_by_unicode (c->buffer, adjust_offsets_when_zeroing);
|
||||
break;
|
||||
*/
|
||||
|
||||
|
@ -521,7 +540,7 @@ hb_ot_position_complex (hb_ot_shape_context_t *c)
|
|||
break;
|
||||
}
|
||||
|
||||
if (hb_ot_layout_has_positioning (c->face))
|
||||
if (has_positioning)
|
||||
{
|
||||
hb_glyph_info_t *info = c->buffer->info;
|
||||
hb_glyph_position_t *pos = c->buffer->pos;
|
||||
|
@ -550,11 +569,11 @@ hb_ot_position_complex (hb_ot_shape_context_t *c)
|
|||
switch (c->plan->shaper->zero_width_marks)
|
||||
{
|
||||
case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_UNICODE_LATE:
|
||||
zero_mark_widths_by_unicode (c->buffer);
|
||||
zero_mark_widths_by_unicode (c->buffer, adjust_offsets_when_zeroing);
|
||||
break;
|
||||
|
||||
case HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE:
|
||||
zero_mark_widths_by_gdef (c->buffer);
|
||||
zero_mark_widths_by_gdef (c->buffer, adjust_offsets_when_zeroing);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -357,6 +357,13 @@ public:
|
|||
NONE, SCROLLABLE
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if aLayer is optimized for the given ThebesLayerCreationHint.
|
||||
*/
|
||||
virtual bool IsOptimizedFor(ThebesLayer* aLayer,
|
||||
ThebesLayerCreationHint aCreationHint)
|
||||
{ return true; }
|
||||
|
||||
/**
|
||||
* CONSTRUCTION PHASE ONLY
|
||||
* Create a ThebesLayer for this manager's layer tree.
|
||||
|
@ -1549,6 +1556,8 @@ public:
|
|||
ComputeEffectiveTransformForMaskLayer(aTransformToSurface);
|
||||
}
|
||||
|
||||
LayerManager::ThebesLayerCreationHint GetCreationHint() const { return mCreationHint; }
|
||||
|
||||
bool UsedForReadback() { return mUsedForReadback; }
|
||||
void SetUsedForReadback(bool aUsed) { mUsedForReadback = aUsed; }
|
||||
/**
|
||||
|
@ -1562,9 +1571,11 @@ public:
|
|||
gfxPoint GetResidualTranslation() const { return mResidualTranslation; }
|
||||
|
||||
protected:
|
||||
ThebesLayer(LayerManager* aManager, void* aImplData)
|
||||
ThebesLayer(LayerManager* aManager, void* aImplData,
|
||||
LayerManager::ThebesLayerCreationHint aCreationHint = LayerManager::NONE)
|
||||
: Layer(aManager, aImplData)
|
||||
, mValidRegion()
|
||||
, mCreationHint(aCreationHint)
|
||||
, mUsedForReadback(false)
|
||||
, mAllowResidualTranslation(false)
|
||||
{
|
||||
|
@ -1580,6 +1591,10 @@ protected:
|
|||
*/
|
||||
gfxPoint mResidualTranslation;
|
||||
nsIntRegion mValidRegion;
|
||||
/**
|
||||
* The creation hint that was used when constructing this layer.
|
||||
*/
|
||||
const LayerManager::ThebesLayerCreationHint mCreationHint;
|
||||
/**
|
||||
* Set when this ThebesLayer is participating in readback, i.e. some
|
||||
* ReadbackLayer (may) be getting its background from this layer.
|
||||
|
|
|
@ -73,6 +73,8 @@ public:
|
|||
|
||||
virtual void Mutated(Layer* aLayer);
|
||||
|
||||
virtual bool IsOptimizedFor(ThebesLayer* aLayer, ThebesLayerCreationHint aHint);
|
||||
|
||||
virtual already_AddRefed<ThebesLayer> CreateThebesLayer();
|
||||
virtual already_AddRefed<ThebesLayer> CreateThebesLayerWithHint(ThebesLayerCreationHint aHint);
|
||||
virtual already_AddRefed<ContainerLayer> CreateContainerLayer();
|
||||
|
|
|
@ -127,6 +127,22 @@ ClientThebesLayer::RenderLayer()
|
|||
mContentClient->EndPaint();
|
||||
}
|
||||
|
||||
bool
|
||||
ClientLayerManager::IsOptimizedFor(ThebesLayer* aLayer, ThebesLayerCreationHint aHint)
|
||||
{
|
||||
#ifdef MOZ_B2G
|
||||
// The only creation hint is whether the layer is scrollable or not, and this
|
||||
// is only respected on B2G, where it's used to determine whether to use
|
||||
// tiled layers or not.
|
||||
// There are pretty nasty performance consequences for not using tiles on
|
||||
// large, scrollable layers, so we want the layer to be recreated in this
|
||||
// situation.
|
||||
return aHint == aLayer->GetCreationHint();
|
||||
#else
|
||||
return LayerManager::IsOptimizedFor(aLayer, aHint);
|
||||
#endif
|
||||
}
|
||||
|
||||
already_AddRefed<ThebesLayer>
|
||||
ClientLayerManager::CreateThebesLayer()
|
||||
{
|
||||
|
@ -150,19 +166,19 @@ ClientLayerManager::CreateThebesLayerWithHint(ThebesLayerCreationHint aHint)
|
|||
}
|
||||
if (gfxPrefs::LayersUseSimpleTiles()) {
|
||||
nsRefPtr<SimpleClientTiledThebesLayer> layer =
|
||||
new SimpleClientTiledThebesLayer(this);
|
||||
new SimpleClientTiledThebesLayer(this, aHint);
|
||||
CREATE_SHADOW(Thebes);
|
||||
return layer.forget();
|
||||
} else {
|
||||
nsRefPtr<ClientTiledThebesLayer> layer =
|
||||
new ClientTiledThebesLayer(this);
|
||||
new ClientTiledThebesLayer(this, aHint);
|
||||
CREATE_SHADOW(Thebes);
|
||||
return layer.forget();
|
||||
}
|
||||
} else
|
||||
{
|
||||
nsRefPtr<ClientThebesLayer> layer =
|
||||
new ClientThebesLayer(this);
|
||||
new ClientThebesLayer(this, aHint);
|
||||
CREATE_SHADOW(Thebes);
|
||||
return layer.forget();
|
||||
}
|
||||
|
|
|
@ -27,15 +27,17 @@ class CompositableClient;
|
|||
class ShadowableLayer;
|
||||
class SpecificLayerAttributes;
|
||||
|
||||
class ClientThebesLayer : public ThebesLayer,
|
||||
class ClientThebesLayer : public ThebesLayer,
|
||||
public ClientLayer {
|
||||
public:
|
||||
typedef RotatedContentBuffer::PaintState PaintState;
|
||||
typedef RotatedContentBuffer::ContentType ContentType;
|
||||
|
||||
ClientThebesLayer(ClientLayerManager* aLayerManager) :
|
||||
ClientThebesLayer(ClientLayerManager* aLayerManager,
|
||||
LayerManager::ThebesLayerCreationHint aCreationHint = LayerManager::NONE) :
|
||||
ThebesLayer(aLayerManager,
|
||||
static_cast<ClientLayer*>(MOZ_THIS_IN_INITIALIZER_LIST())),
|
||||
static_cast<ClientLayer*>(MOZ_THIS_IN_INITIALIZER_LIST()),
|
||||
aCreationHint),
|
||||
mContentClient(nullptr)
|
||||
{
|
||||
MOZ_COUNT_CTOR(ClientThebesLayer);
|
||||
|
|
|
@ -29,9 +29,11 @@ namespace mozilla {
|
|||
namespace layers {
|
||||
|
||||
|
||||
ClientTiledThebesLayer::ClientTiledThebesLayer(ClientLayerManager* const aManager)
|
||||
ClientTiledThebesLayer::ClientTiledThebesLayer(ClientLayerManager* const aManager,
|
||||
ClientLayerManager::ThebesLayerCreationHint aCreationHint)
|
||||
: ThebesLayer(aManager,
|
||||
static_cast<ClientLayer*>(MOZ_THIS_IN_INITIALIZER_LIST()))
|
||||
static_cast<ClientLayer*>(MOZ_THIS_IN_INITIALIZER_LIST()),
|
||||
aCreationHint)
|
||||
, mContentClient()
|
||||
{
|
||||
MOZ_COUNT_CTOR(ClientTiledThebesLayer);
|
||||
|
|
|
@ -41,7 +41,8 @@ class ClientTiledThebesLayer : public ThebesLayer,
|
|||
typedef ThebesLayer Base;
|
||||
|
||||
public:
|
||||
ClientTiledThebesLayer(ClientLayerManager* const aManager);
|
||||
ClientTiledThebesLayer(ClientLayerManager* const aManager,
|
||||
ClientLayerManager::ThebesLayerCreationHint aCreationHint = LayerManager::NONE);
|
||||
~ClientTiledThebesLayer();
|
||||
|
||||
// Override name to distinguish it from ClientThebesLayer in layer dumps
|
||||
|
|
|
@ -247,9 +247,11 @@ SimpleTiledContentClient::UseTiledLayerBuffer()
|
|||
mTiledBuffer.ClearPaintedRegion();
|
||||
}
|
||||
|
||||
SimpleClientTiledThebesLayer::SimpleClientTiledThebesLayer(ClientLayerManager* aManager)
|
||||
SimpleClientTiledThebesLayer::SimpleClientTiledThebesLayer(ClientLayerManager* aManager,
|
||||
ClientLayerManager::ThebesLayerCreationHint aCreationHint)
|
||||
: ThebesLayer(aManager,
|
||||
static_cast<ClientLayer*>(MOZ_THIS_IN_INITIALIZER_LIST()))
|
||||
static_cast<ClientLayer*>(MOZ_THIS_IN_INITIALIZER_LIST()),
|
||||
aCreationHint)
|
||||
, mContentClient()
|
||||
{
|
||||
MOZ_COUNT_CTOR(SimpleClientTiledThebesLayer);
|
||||
|
|
|
@ -159,7 +159,8 @@ class SimpleClientTiledThebesLayer : public ThebesLayer,
|
|||
typedef ThebesLayer Base;
|
||||
|
||||
public:
|
||||
SimpleClientTiledThebesLayer(ClientLayerManager* const aManager);
|
||||
SimpleClientTiledThebesLayer(ClientLayerManager* const aManager,
|
||||
ClientLayerManager::ThebesLayerCreationHint aCreationHint = LayerManager::NONE);
|
||||
~SimpleClientTiledThebesLayer();
|
||||
|
||||
// Thebes Layer
|
||||
|
|
|
@ -144,6 +144,13 @@ GrallocTextureSourceOGL::BindTexture(GLenum aTextureUnit, gfx::Filter aFilter)
|
|||
}
|
||||
|
||||
ApplyFilterToBoundTexture(gl(), aFilter, textureTarget);
|
||||
|
||||
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
|
||||
if (mTextureHost) {
|
||||
// Wait until it's ready.
|
||||
mTextureHost->WaitAcquireFenceSyncComplete();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void GrallocTextureSourceOGL::Lock()
|
||||
|
@ -443,12 +450,6 @@ GrallocTextureSourceOGL::GetGLTexture()
|
|||
void
|
||||
GrallocTextureSourceOGL::BindEGLImage()
|
||||
{
|
||||
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
|
||||
if (mTextureHost) {
|
||||
mTextureHost->WaitAcquireFenceSyncComplete();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mCompositableBackendData) {
|
||||
CompositableDataGonkOGL* backend = static_cast<CompositableDataGonkOGL*>(mCompositableBackendData.get());
|
||||
backend->BindEGLImage(GetTextureTarget(), mEGLImage);
|
||||
|
|
|
@ -229,9 +229,12 @@ TextureHostOGL::SetAcquireFence(const android::sp<android::Fence>& aAcquireFence
|
|||
}
|
||||
|
||||
android::sp<android::Fence>
|
||||
TextureHostOGL::GetAcquireFence()
|
||||
TextureHostOGL::GetAndResetAcquireFence()
|
||||
{
|
||||
return mAcquireFence;
|
||||
android::sp<android::Fence> fence = mAcquireFence;
|
||||
// Reset current AcquireFence.
|
||||
mAcquireFence = android::Fence::NO_FENCE;
|
||||
return fence;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -174,7 +174,10 @@ public:
|
|||
|
||||
virtual void SetAcquireFence(const android::sp<android::Fence>& aAcquireFence);
|
||||
|
||||
virtual android::sp<android::Fence> GetAcquireFence();
|
||||
/**
|
||||
* Return a acquireFence's Fence and clear a reference to the Fence.
|
||||
*/
|
||||
virtual android::sp<android::Fence> GetAndResetAcquireFence();
|
||||
|
||||
virtual void WaitAcquireFenceSyncComplete();
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
|
||||
#include "gfxDWriteShaper.h"
|
||||
#include "gfxHarfBuzzShaper.h"
|
||||
#include <algorithm>
|
||||
#include "gfxGraphiteShaper.h"
|
||||
|
@ -15,8 +14,6 @@
|
|||
#include "gfxContext.h"
|
||||
#include <dwrite.h>
|
||||
|
||||
#include "gfxDWriteTextAnalysis.h"
|
||||
|
||||
#include "harfbuzz/hb.h"
|
||||
|
||||
// Chosen this as to resemble DWrite's own oblique face style.
|
||||
|
@ -137,10 +134,30 @@ gfxDWriteFont::CopyWithAntialiasOption(AntialiasOption anAAOption)
|
|||
&mStyle, mNeedsBold, anAAOption);
|
||||
}
|
||||
|
||||
void
|
||||
gfxDWriteFont::CreatePlatformShaper()
|
||||
bool
|
||||
gfxDWriteFont::ShapeText(gfxContext *aContext,
|
||||
const char16_t *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText,
|
||||
bool aPreferPlatformShaping)
|
||||
{
|
||||
mPlatformShaper = new gfxDWriteShaper(this);
|
||||
bool ok = false;
|
||||
|
||||
if (mGraphiteShaper && gfxPlatform::GetPlatform()->UseGraphiteShaping()) {
|
||||
ok = mGraphiteShaper->ShapeText(aContext, aText, aOffset, aLength,
|
||||
aScript, aShapedText);
|
||||
}
|
||||
|
||||
if (!ok && mHarfBuzzShaper) {
|
||||
ok = mHarfBuzzShaper->ShapeText(aContext, aText, aOffset, aLength,
|
||||
aScript, aShapedText);
|
||||
}
|
||||
|
||||
PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
const gfxFont::Metrics&
|
||||
|
@ -595,7 +612,7 @@ gfxDWriteFont::Measure(gfxTextRun *aTextRun,
|
|||
}
|
||||
|
||||
bool
|
||||
gfxDWriteFont::ProvidesGlyphWidths()
|
||||
gfxDWriteFont::ProvidesGlyphWidths() const
|
||||
{
|
||||
return !mUseSubpixelPositions ||
|
||||
(mFontFace->GetSimulations() & DWRITE_FONT_SIMULATIONS_BOLD);
|
||||
|
|
|
@ -53,7 +53,7 @@ public:
|
|||
gfxContext *aContextForTightBoundingBox,
|
||||
Spacing *aSpacing);
|
||||
|
||||
virtual bool ProvidesGlyphWidths();
|
||||
virtual bool ProvidesGlyphWidths() const;
|
||||
|
||||
virtual int32_t GetGlyphWidth(gfxContext *aCtx, uint16_t aGID);
|
||||
|
||||
|
@ -71,9 +71,13 @@ public:
|
|||
virtual cairo_scaled_font_t *GetCairoScaledFont();
|
||||
|
||||
protected:
|
||||
friend class gfxDWriteShaper;
|
||||
|
||||
virtual void CreatePlatformShaper();
|
||||
virtual bool ShapeText(gfxContext *aContext,
|
||||
const char16_t *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText,
|
||||
bool aPreferPlatformShaping = false);
|
||||
|
||||
bool GetFakeMetricsForArialBlack(DWRITE_FONT_METRICS *aFontMetrics);
|
||||
|
||||
|
|
|
@ -1,230 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "gfxDWriteShaper.h"
|
||||
#include "gfxWindowsPlatform.h"
|
||||
|
||||
#include <dwrite.h>
|
||||
|
||||
#include "gfxDWriteTextAnalysis.h"
|
||||
|
||||
#include "nsCRT.h"
|
||||
|
||||
bool
|
||||
gfxDWriteShaper::ShapeText(gfxContext *aContext,
|
||||
const char16_t *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText)
|
||||
{
|
||||
HRESULT hr;
|
||||
// TODO: Handle TEXT_DISABLE_OPTIONAL_LIGATURES
|
||||
|
||||
DWRITE_READING_DIRECTION readingDirection =
|
||||
aShapedText->IsRightToLeft()
|
||||
? DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
|
||||
: DWRITE_READING_DIRECTION_LEFT_TO_RIGHT;
|
||||
|
||||
gfxDWriteFont *font = static_cast<gfxDWriteFont*>(mFont);
|
||||
|
||||
gfxShapedText::CompressedGlyph g;
|
||||
|
||||
IDWriteTextAnalyzer *analyzer =
|
||||
gfxWindowsPlatform::GetPlatform()->GetDWriteAnalyzer();
|
||||
if (!analyzer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* There's an internal 16-bit limit on some things inside the analyzer,
|
||||
* but we never attempt to shape a word longer than 32K characters
|
||||
* in a single call, so we cannot exceed that limit.
|
||||
*/
|
||||
UINT32 length = aLength;
|
||||
char16ptr_t text = aText;
|
||||
|
||||
TextAnalysis analysis(text, length, nullptr, readingDirection);
|
||||
TextAnalysis::Run *runHead;
|
||||
hr = analysis.GenerateResults(analyzer, &runHead);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
NS_WARNING("Analyzer failed to generate results.");
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t appUnitsPerDevPixel = aShapedText->GetAppUnitsPerDevUnit();
|
||||
|
||||
UINT32 maxGlyphs = 0;
|
||||
trymoreglyphs:
|
||||
if ((UINT32_MAX - 3 * length / 2 + 16) < maxGlyphs) {
|
||||
// This isn't going to work, we're going to cross the UINT32 upper
|
||||
// limit. Give up.
|
||||
NS_WARNING("Shaper needs to generate more than 2^32 glyphs?!");
|
||||
return false;
|
||||
}
|
||||
maxGlyphs += 3 * length / 2 + 16;
|
||||
|
||||
AutoFallibleTArray<UINT16, 400> clusters;
|
||||
AutoFallibleTArray<UINT16, 400> indices;
|
||||
AutoFallibleTArray<DWRITE_SHAPING_TEXT_PROPERTIES, 400> textProperties;
|
||||
AutoFallibleTArray<DWRITE_SHAPING_GLYPH_PROPERTIES, 400> glyphProperties;
|
||||
if (!clusters.SetLength(length) ||
|
||||
!indices.SetLength(maxGlyphs) ||
|
||||
!textProperties.SetLength(maxGlyphs) ||
|
||||
!glyphProperties.SetLength(maxGlyphs)) {
|
||||
NS_WARNING("Shaper failed to allocate memory.");
|
||||
return false;
|
||||
}
|
||||
|
||||
UINT32 actualGlyphs;
|
||||
|
||||
hr = analyzer->GetGlyphs(text, length,
|
||||
font->GetFontFace(), FALSE,
|
||||
readingDirection == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT,
|
||||
&runHead->mScript, nullptr, nullptr, nullptr, nullptr, 0,
|
||||
maxGlyphs, clusters.Elements(), textProperties.Elements(),
|
||||
indices.Elements(), glyphProperties.Elements(), &actualGlyphs);
|
||||
|
||||
if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) {
|
||||
// We increase the amount of glyphs and try again.
|
||||
goto trymoreglyphs;
|
||||
}
|
||||
if (FAILED(hr)) {
|
||||
NS_WARNING("Analyzer failed to get glyphs.");
|
||||
return false;
|
||||
}
|
||||
|
||||
WORD gID = indices[0];
|
||||
AutoFallibleTArray<FLOAT, 400> advances;
|
||||
AutoFallibleTArray<DWRITE_GLYPH_OFFSET, 400> glyphOffsets;
|
||||
if (!advances.SetLength(actualGlyphs) ||
|
||||
!glyphOffsets.SetLength(actualGlyphs)) {
|
||||
NS_WARNING("Shaper failed to allocate memory.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!static_cast<gfxDWriteFont*>(mFont)->mUseSubpixelPositions) {
|
||||
hr = analyzer->GetGdiCompatibleGlyphPlacements(
|
||||
text,
|
||||
clusters.Elements(),
|
||||
textProperties.Elements(),
|
||||
length,
|
||||
indices.Elements(),
|
||||
glyphProperties.Elements(),
|
||||
actualGlyphs,
|
||||
font->GetFontFace(),
|
||||
font->GetAdjustedSize(),
|
||||
1.0,
|
||||
nullptr,
|
||||
FALSE,
|
||||
FALSE,
|
||||
FALSE,
|
||||
&runHead->mScript,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
0,
|
||||
advances.Elements(),
|
||||
glyphOffsets.Elements());
|
||||
} else {
|
||||
hr = analyzer->GetGlyphPlacements(text,
|
||||
clusters.Elements(),
|
||||
textProperties.Elements(),
|
||||
length,
|
||||
indices.Elements(),
|
||||
glyphProperties.Elements(),
|
||||
actualGlyphs,
|
||||
font->GetFontFace(),
|
||||
font->GetAdjustedSize(),
|
||||
FALSE,
|
||||
FALSE,
|
||||
&runHead->mScript,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
0,
|
||||
advances.Elements(),
|
||||
glyphOffsets.Elements());
|
||||
}
|
||||
if (FAILED(hr)) {
|
||||
NS_WARNING("Analyzer failed to get glyph placements.");
|
||||
return false;
|
||||
}
|
||||
|
||||
nsAutoTArray<gfxShapedText::DetailedGlyph,1> detailedGlyphs;
|
||||
gfxShapedText::CompressedGlyph *charGlyphs =
|
||||
aShapedText->GetCharacterGlyphs();
|
||||
|
||||
for (unsigned int c = 0; c < length; c++) {
|
||||
uint32_t k = clusters[c];
|
||||
uint32_t absC = aOffset + c;
|
||||
|
||||
if (c > 0 && k == clusters[c - 1]) {
|
||||
// This is a cluster continuation. No glyph here.
|
||||
gfxShapedText::CompressedGlyph &g = charGlyphs[absC];
|
||||
NS_ASSERTION(!g.IsSimpleGlyph(), "overwriting a simple glyph");
|
||||
g.SetComplex(g.IsClusterStart(), false, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Count glyphs for this character
|
||||
uint32_t glyphCount = actualGlyphs - k;
|
||||
uint32_t nextClusterOffset;
|
||||
for (nextClusterOffset = c + 1;
|
||||
nextClusterOffset < length; ++nextClusterOffset) {
|
||||
if (clusters[nextClusterOffset] > k) {
|
||||
glyphCount = clusters[nextClusterOffset] - k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int32_t advance = (int32_t)(advances[k] * appUnitsPerDevPixel);
|
||||
if (glyphCount == 1 && advance >= 0 &&
|
||||
glyphOffsets[k].advanceOffset == 0 &&
|
||||
glyphOffsets[k].ascenderOffset == 0 &&
|
||||
charGlyphs[absC].IsClusterStart() &&
|
||||
gfxShapedText::CompressedGlyph::IsSimpleAdvance(advance) &&
|
||||
gfxShapedText::CompressedGlyph::IsSimpleGlyphID(indices[k])) {
|
||||
charGlyphs[absC].SetSimpleGlyph(advance, indices[k]);
|
||||
} else {
|
||||
if (detailedGlyphs.Length() < glyphCount) {
|
||||
if (!detailedGlyphs.AppendElements(
|
||||
glyphCount - detailedGlyphs.Length())) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
float totalAdvance = 0;
|
||||
for (unsigned int z = 0; z < glyphCount; z++) {
|
||||
detailedGlyphs[z].mGlyphID = indices[k + z];
|
||||
detailedGlyphs[z].mAdvance =
|
||||
(int32_t)(advances[k + z]
|
||||
* appUnitsPerDevPixel);
|
||||
if (readingDirection ==
|
||||
DWRITE_READING_DIRECTION_RIGHT_TO_LEFT) {
|
||||
detailedGlyphs[z].mXOffset =
|
||||
(totalAdvance +
|
||||
glyphOffsets[k + z].advanceOffset)
|
||||
* appUnitsPerDevPixel;
|
||||
} else {
|
||||
detailedGlyphs[z].mXOffset =
|
||||
glyphOffsets[k + z].advanceOffset *
|
||||
appUnitsPerDevPixel;
|
||||
}
|
||||
detailedGlyphs[z].mYOffset =
|
||||
-glyphOffsets[k + z].ascenderOffset *
|
||||
appUnitsPerDevPixel;
|
||||
totalAdvance += advances[k + z];
|
||||
}
|
||||
aShapedText->SetGlyphs(
|
||||
absC,
|
||||
g.SetComplex(charGlyphs[absC].IsClusterStart(),
|
||||
true,
|
||||
glyphCount),
|
||||
detailedGlyphs.Elements());
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef GFX_DWRITESHAPER_H
|
||||
#define GFX_DWRITESHAPER_H
|
||||
|
||||
#include "gfxDWriteFonts.h"
|
||||
|
||||
/**
|
||||
* \brief Class representing a DWrite font shaper.
|
||||
*/
|
||||
class gfxDWriteShaper : public gfxFontShaper
|
||||
{
|
||||
public:
|
||||
gfxDWriteShaper(gfxDWriteFont *aFont)
|
||||
: gfxFontShaper(aFont)
|
||||
{
|
||||
MOZ_COUNT_CTOR(gfxDWriteShaper);
|
||||
}
|
||||
|
||||
virtual ~gfxDWriteShaper()
|
||||
{
|
||||
MOZ_COUNT_DTOR(gfxDWriteShaper);
|
||||
}
|
||||
|
||||
virtual bool ShapeText(gfxContext *aContext,
|
||||
const char16_t *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText);
|
||||
};
|
||||
|
||||
#endif /* GFX_DWRITESHAPER_H */
|
|
@ -1,257 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "gfxDWriteTextAnalysis.h"
|
||||
|
||||
TextAnalysis::TextAnalysis(const wchar_t* text,
|
||||
UINT32 textLength,
|
||||
const wchar_t* localeName,
|
||||
DWRITE_READING_DIRECTION readingDirection)
|
||||
: mText(text)
|
||||
, mTextLength(textLength)
|
||||
, mLocaleName(localeName)
|
||||
, mReadingDirection(readingDirection)
|
||||
, mCurrentRun(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
TextAnalysis::~TextAnalysis()
|
||||
{
|
||||
// delete runs, except mRunHead which is part of the TextAnalysis object
|
||||
for (Run *run = mRunHead.nextRun; run;) {
|
||||
Run *origRun = run;
|
||||
run = run->nextRun;
|
||||
delete origRun;
|
||||
}
|
||||
}
|
||||
|
||||
STDMETHODIMP
|
||||
TextAnalysis::GenerateResults(IDWriteTextAnalyzer* textAnalyzer,
|
||||
OUT Run **runHead)
|
||||
{
|
||||
// Analyzes the text using the script analyzer and returns
|
||||
// the result as a series of runs.
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
// Initially start out with one result that covers the entire range.
|
||||
// This result will be subdivided by the analysis processes.
|
||||
mRunHead.mTextStart = 0;
|
||||
mRunHead.mTextLength = mTextLength;
|
||||
mRunHead.mBidiLevel =
|
||||
(mReadingDirection == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
|
||||
mRunHead.nextRun = nullptr;
|
||||
mCurrentRun = &mRunHead;
|
||||
|
||||
// Call each of the analyzers in sequence, recording their results.
|
||||
if (SUCCEEDED(hr = textAnalyzer->AnalyzeScript(this,
|
||||
0,
|
||||
mTextLength,
|
||||
this))) {
|
||||
*runHead = &mRunHead;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// IDWriteTextAnalysisSource source implementation
|
||||
|
||||
IFACEMETHODIMP
|
||||
TextAnalysis::GetTextAtPosition(UINT32 textPosition,
|
||||
OUT WCHAR const** textString,
|
||||
OUT UINT32* textLength)
|
||||
{
|
||||
if (textPosition >= mTextLength) {
|
||||
// No text at this position, valid query though.
|
||||
*textString = nullptr;
|
||||
*textLength = 0;
|
||||
} else {
|
||||
*textString = mText + textPosition;
|
||||
*textLength = mTextLength - textPosition;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
IFACEMETHODIMP
|
||||
TextAnalysis::GetTextBeforePosition(UINT32 textPosition,
|
||||
OUT WCHAR const** textString,
|
||||
OUT UINT32* textLength)
|
||||
{
|
||||
if (textPosition == 0 || textPosition > mTextLength) {
|
||||
// Either there is no text before here (== 0), or this
|
||||
// is an invalid position. The query is considered valid thouh.
|
||||
*textString = nullptr;
|
||||
*textLength = 0;
|
||||
} else {
|
||||
*textString = mText;
|
||||
*textLength = textPosition;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
DWRITE_READING_DIRECTION STDMETHODCALLTYPE
|
||||
TextAnalysis::GetParagraphReadingDirection()
|
||||
{
|
||||
// We support only a single reading direction.
|
||||
return mReadingDirection;
|
||||
}
|
||||
|
||||
|
||||
IFACEMETHODIMP
|
||||
TextAnalysis::GetLocaleName(UINT32 textPosition,
|
||||
OUT UINT32* textLength,
|
||||
OUT WCHAR const** localeName)
|
||||
{
|
||||
// Single locale name is used, valid until the end of the string.
|
||||
*localeName = mLocaleName;
|
||||
*textLength = mTextLength - textPosition;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
IFACEMETHODIMP
|
||||
TextAnalysis::GetNumberSubstitution(UINT32 textPosition,
|
||||
OUT UINT32* textLength,
|
||||
OUT IDWriteNumberSubstitution** numberSubstitution)
|
||||
{
|
||||
// We do not support number substitution.
|
||||
*numberSubstitution = nullptr;
|
||||
*textLength = mTextLength - textPosition;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// IDWriteTextAnalysisSink implementation
|
||||
|
||||
IFACEMETHODIMP
|
||||
TextAnalysis::SetLineBreakpoints(UINT32 textPosition,
|
||||
UINT32 textLength,
|
||||
DWRITE_LINE_BREAKPOINT const* lineBreakpoints)
|
||||
{
|
||||
// We don't use this for now.
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
IFACEMETHODIMP
|
||||
TextAnalysis::SetScriptAnalysis(UINT32 textPosition,
|
||||
UINT32 textLength,
|
||||
DWRITE_SCRIPT_ANALYSIS const* scriptAnalysis)
|
||||
{
|
||||
SetCurrentRun(textPosition);
|
||||
SplitCurrentRun(textPosition);
|
||||
while (textLength > 0) {
|
||||
Run *run = FetchNextRun(&textLength);
|
||||
run->mScript = *scriptAnalysis;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
IFACEMETHODIMP
|
||||
TextAnalysis::SetBidiLevel(UINT32 textPosition,
|
||||
UINT32 textLength,
|
||||
UINT8 explicitLevel,
|
||||
UINT8 resolvedLevel)
|
||||
{
|
||||
// We don't use this for now.
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
IFACEMETHODIMP
|
||||
TextAnalysis::SetNumberSubstitution(UINT32 textPosition,
|
||||
UINT32 textLength,
|
||||
IDWriteNumberSubstitution* numberSubstitution)
|
||||
{
|
||||
// We don't use this for now.
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Run modification.
|
||||
|
||||
TextAnalysis::Run *
|
||||
TextAnalysis::FetchNextRun(IN OUT UINT32* textLength)
|
||||
{
|
||||
// Used by the sink setters, this returns a reference to the next run.
|
||||
// Position and length are adjusted to now point after the current run
|
||||
// being returned.
|
||||
|
||||
Run *origRun = mCurrentRun;
|
||||
// Split the tail if needed (the length remaining is less than the
|
||||
// current run's size).
|
||||
if (*textLength < mCurrentRun->mTextLength) {
|
||||
SplitCurrentRun(mCurrentRun->mTextStart + *textLength);
|
||||
} else {
|
||||
// Just advance the current run.
|
||||
mCurrentRun = mCurrentRun->nextRun;
|
||||
}
|
||||
*textLength -= origRun->mTextLength;
|
||||
|
||||
// Return a reference to the run that was just current.
|
||||
return origRun;
|
||||
}
|
||||
|
||||
|
||||
void TextAnalysis::SetCurrentRun(UINT32 textPosition)
|
||||
{
|
||||
// Move the current run to the given position.
|
||||
// Since the analyzers generally return results in a forward manner,
|
||||
// this will usually just return early. If not, find the
|
||||
// corresponding run for the text position.
|
||||
|
||||
if (mCurrentRun && mCurrentRun->ContainsTextPosition(textPosition)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Run *run = &mRunHead; run; run = run->nextRun) {
|
||||
if (run->ContainsTextPosition(textPosition)) {
|
||||
mCurrentRun = run;
|
||||
return;
|
||||
}
|
||||
}
|
||||
NS_NOTREACHED("We should always be able to find the text position in one \
|
||||
of our runs");
|
||||
}
|
||||
|
||||
|
||||
void TextAnalysis::SplitCurrentRun(UINT32 splitPosition)
|
||||
{
|
||||
if (!mCurrentRun) {
|
||||
NS_ASSERTION(false, "SplitCurrentRun called without current run.");
|
||||
// Shouldn't be calling this when no current run is set!
|
||||
return;
|
||||
}
|
||||
// Split the current run.
|
||||
if (splitPosition <= mCurrentRun->mTextStart) {
|
||||
// No need to split, already the start of a run
|
||||
// or before it. Usually the first.
|
||||
return;
|
||||
}
|
||||
Run *newRun = new Run;
|
||||
|
||||
*newRun = *mCurrentRun;
|
||||
|
||||
// Insert the new run in our linked list.
|
||||
newRun->nextRun = mCurrentRun->nextRun;
|
||||
mCurrentRun->nextRun = newRun;
|
||||
|
||||
// Adjust runs' text positions and lengths.
|
||||
UINT32 splitPoint = splitPosition - mCurrentRun->mTextStart;
|
||||
newRun->mTextStart += splitPoint;
|
||||
newRun->mTextLength -= splitPoint;
|
||||
mCurrentRun->mTextLength = splitPoint;
|
||||
mCurrentRun = newRun;
|
||||
}
|
|
@ -1,146 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef GFX_DWRITETEXTANALYSIS_H
|
||||
#define GFX_DWRITETEXTANALYSIS_H
|
||||
|
||||
#include "gfxDWriteCommon.h"
|
||||
|
||||
// Helper source/sink class for text analysis.
|
||||
class TextAnalysis
|
||||
: public IDWriteTextAnalysisSource,
|
||||
public IDWriteTextAnalysisSink
|
||||
{
|
||||
public:
|
||||
|
||||
// IUnknown interface
|
||||
IFACEMETHOD(QueryInterface)(IID const& iid, OUT void** ppObject)
|
||||
{
|
||||
if (iid == __uuidof(IDWriteTextAnalysisSource)) {
|
||||
*ppObject = static_cast<IDWriteTextAnalysisSource*>(this);
|
||||
return S_OK;
|
||||
} else if (iid == __uuidof(IDWriteTextAnalysisSink)) {
|
||||
*ppObject = static_cast<IDWriteTextAnalysisSink*>(this);
|
||||
return S_OK;
|
||||
} else if (iid == __uuidof(IUnknown)) {
|
||||
*ppObject =
|
||||
static_cast<IUnknown*>(static_cast<IDWriteTextAnalysisSource*>(this));
|
||||
return S_OK;
|
||||
} else {
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
}
|
||||
|
||||
IFACEMETHOD_(ULONG, AddRef)()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
IFACEMETHOD_(ULONG, Release)()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
// A single contiguous run of characters containing the same analysis
|
||||
// results.
|
||||
struct Run
|
||||
{
|
||||
UINT32 mTextStart; // starting text position of this run
|
||||
UINT32 mTextLength; // number of contiguous code units covered
|
||||
UINT32 mGlyphStart; // starting glyph in the glyphs array
|
||||
UINT32 mGlyphCount; // number of glyphs associated with this run of
|
||||
// text
|
||||
DWRITE_SCRIPT_ANALYSIS mScript;
|
||||
UINT8 mBidiLevel;
|
||||
bool mIsSideways;
|
||||
|
||||
inline bool ContainsTextPosition(UINT32 aTextPosition) const
|
||||
{
|
||||
return aTextPosition >= mTextStart
|
||||
&& aTextPosition < mTextStart + mTextLength;
|
||||
}
|
||||
|
||||
Run *nextRun;
|
||||
};
|
||||
|
||||
public:
|
||||
TextAnalysis(const wchar_t* text,
|
||||
UINT32 textLength,
|
||||
const wchar_t* localeName,
|
||||
DWRITE_READING_DIRECTION readingDirection);
|
||||
|
||||
~TextAnalysis();
|
||||
|
||||
STDMETHODIMP GenerateResults(IDWriteTextAnalyzer* textAnalyzer,
|
||||
Run **runHead);
|
||||
|
||||
// IDWriteTextAnalysisSource implementation
|
||||
|
||||
IFACEMETHODIMP GetTextAtPosition(UINT32 textPosition,
|
||||
OUT WCHAR const** textString,
|
||||
OUT UINT32* textLength);
|
||||
|
||||
IFACEMETHODIMP GetTextBeforePosition(UINT32 textPosition,
|
||||
OUT WCHAR const** textString,
|
||||
OUT UINT32* textLength);
|
||||
|
||||
IFACEMETHODIMP_(DWRITE_READING_DIRECTION)
|
||||
GetParagraphReadingDirection() throw();
|
||||
|
||||
IFACEMETHODIMP GetLocaleName(UINT32 textPosition,
|
||||
OUT UINT32* textLength,
|
||||
OUT WCHAR const** localeName);
|
||||
|
||||
IFACEMETHODIMP
|
||||
GetNumberSubstitution(UINT32 textPosition,
|
||||
OUT UINT32* textLength,
|
||||
OUT IDWriteNumberSubstitution** numberSubstitution);
|
||||
|
||||
// IDWriteTextAnalysisSink implementation
|
||||
|
||||
IFACEMETHODIMP
|
||||
SetScriptAnalysis(UINT32 textPosition,
|
||||
UINT32 textLength,
|
||||
DWRITE_SCRIPT_ANALYSIS const* scriptAnalysis);
|
||||
|
||||
IFACEMETHODIMP
|
||||
SetLineBreakpoints(UINT32 textPosition,
|
||||
UINT32 textLength,
|
||||
const DWRITE_LINE_BREAKPOINT* lineBreakpoints);
|
||||
|
||||
IFACEMETHODIMP SetBidiLevel(UINT32 textPosition,
|
||||
UINT32 textLength,
|
||||
UINT8 explicitLevel,
|
||||
UINT8 resolvedLevel);
|
||||
|
||||
IFACEMETHODIMP
|
||||
SetNumberSubstitution(UINT32 textPosition,
|
||||
UINT32 textLength,
|
||||
IDWriteNumberSubstitution* numberSubstitution);
|
||||
|
||||
protected:
|
||||
Run *FetchNextRun(IN OUT UINT32* textLength);
|
||||
|
||||
void SetCurrentRun(UINT32 textPosition);
|
||||
|
||||
void SplitCurrentRun(UINT32 splitPosition);
|
||||
|
||||
protected:
|
||||
// Input
|
||||
// (weak references are fine here, since this class is a transient
|
||||
// stack-based helper that doesn't need to copy data)
|
||||
UINT32 mTextLength;
|
||||
const wchar_t* mText;
|
||||
const wchar_t* mLocaleName;
|
||||
DWRITE_READING_DIRECTION mReadingDirection;
|
||||
|
||||
// Current processing state.
|
||||
Run *mCurrentRun;
|
||||
|
||||
// Output is a list of runs starting here
|
||||
Run mRunHead;
|
||||
};
|
||||
|
||||
#endif /* GFX_DWRITETEXTANALYSIS_H */
|
|
@ -25,7 +25,7 @@ public:
|
|||
virtual uint32_t GetSpaceGlyph();
|
||||
virtual bool ProvidesGetGlyph() const { return true; }
|
||||
virtual uint32_t GetGlyph(uint32_t unicode, uint32_t variation_selector);
|
||||
virtual bool ProvidesGlyphWidths() { return true; }
|
||||
virtual bool ProvidesGlyphWidths() const { return true; }
|
||||
virtual int32_t GetGlyphWidth(gfxContext *aCtx, uint16_t aGID);
|
||||
|
||||
cairo_scaled_font_t *CairoScaledFont() { return mScaledFont; };
|
||||
|
|
|
@ -3983,7 +3983,6 @@ gfxFont::ShapeText(gfxContext *aContext,
|
|||
if (!ok) {
|
||||
if (!mPlatformShaper) {
|
||||
CreatePlatformShaper();
|
||||
NS_ASSERTION(mPlatformShaper, "no platform shaper available!");
|
||||
}
|
||||
if (mPlatformShaper) {
|
||||
ok = mPlatformShaper->ShapeText(aContext, aText, aOffset, aLength,
|
||||
|
|
|
@ -1952,7 +1952,7 @@ protected:
|
|||
// subclasses may provide (possibly hinted) glyph widths (in font units);
|
||||
// if they do not override this, harfbuzz will use unhinted widths
|
||||
// derived from the font tables
|
||||
virtual bool ProvidesGlyphWidths() {
|
||||
virtual bool ProvidesGlyphWidths() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
|
||||
#include "gfxGDIShaper.h"
|
||||
#include "gfxUniscribeShaper.h"
|
||||
#include "gfxHarfBuzzShaper.h"
|
||||
#include <algorithm>
|
||||
#include "gfxGraphiteShaper.h"
|
||||
|
@ -51,14 +49,13 @@ gfxGDIFont::gfxGDIFont(GDIFontEntry *aFontEntry,
|
|||
mFontFace(nullptr),
|
||||
mMetrics(nullptr),
|
||||
mSpaceGlyph(0),
|
||||
mNeedsBold(aNeedsBold)
|
||||
mNeedsBold(aNeedsBold),
|
||||
mScriptCache(nullptr)
|
||||
{
|
||||
if (FontCanSupportGraphite()) {
|
||||
mGraphiteShaper = new gfxGraphiteShaper(this);
|
||||
}
|
||||
if (FontCanSupportHarfBuzz()) {
|
||||
mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
|
||||
}
|
||||
mHarfBuzzShaper = new gfxHarfBuzzShaper(this);
|
||||
}
|
||||
|
||||
gfxGDIFont::~gfxGDIFont()
|
||||
|
@ -72,15 +69,12 @@ gfxGDIFont::~gfxGDIFont()
|
|||
if (mFont) {
|
||||
::DeleteObject(mFont);
|
||||
}
|
||||
if (mScriptCache) {
|
||||
ScriptFreeCache(&mScriptCache);
|
||||
}
|
||||
delete mMetrics;
|
||||
}
|
||||
|
||||
void
|
||||
gfxGDIFont::CreatePlatformShaper()
|
||||
{
|
||||
mPlatformShaper = new gfxGDIShaper(this);
|
||||
}
|
||||
|
||||
gfxFont*
|
||||
gfxGDIFont::CopyWithAntialiasOption(AntialiasOption anAAOption)
|
||||
{
|
||||
|
@ -88,29 +82,6 @@ gfxGDIFont::CopyWithAntialiasOption(AntialiasOption anAAOption)
|
|||
&mStyle, mNeedsBold, anAAOption);
|
||||
}
|
||||
|
||||
static bool
|
||||
UseUniscribe(gfxShapedText *aShapedText,
|
||||
char16ptr_t aText,
|
||||
uint32_t aLength)
|
||||
{
|
||||
uint32_t flags = aShapedText->Flags();
|
||||
bool useGDI;
|
||||
|
||||
bool isXP = !IsVistaOrLater();
|
||||
|
||||
// bug 561304 - Uniscribe bug produces bad positioning at certain
|
||||
// font sizes on XP, so default to GDI on XP using logic of 3.6
|
||||
|
||||
useGDI = isXP &&
|
||||
(flags &
|
||||
(gfxTextRunFactory::TEXT_OPTIMIZE_SPEED |
|
||||
gfxTextRunFactory::TEXT_IS_RTL)
|
||||
) == gfxTextRunFactory::TEXT_OPTIMIZE_SPEED;
|
||||
|
||||
return !useGDI ||
|
||||
ScriptIsComplex(aText, aLength, SIC_COMPLEX) == S_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
gfxGDIFont::ShapeText(gfxContext *aContext,
|
||||
const char16_t *aText,
|
||||
|
@ -128,8 +99,6 @@ gfxGDIFont::ShapeText(gfxContext *aContext,
|
|||
return false;
|
||||
}
|
||||
|
||||
bool ok = false;
|
||||
|
||||
// Ensure the cairo font is set up, so there's no risk it'll fall back to
|
||||
// creating a "toy" font internally (see bug 544617).
|
||||
// We must check that this succeeded, otherwise we risk cairo creating the
|
||||
|
@ -138,83 +107,8 @@ gfxGDIFont::ShapeText(gfxContext *aContext,
|
|||
return false;
|
||||
}
|
||||
|
||||
if (mGraphiteShaper && gfxPlatform::GetPlatform()->UseGraphiteShaping()) {
|
||||
ok = mGraphiteShaper->ShapeText(aContext, aText,
|
||||
aOffset, aLength,
|
||||
aScript, aShapedText);
|
||||
}
|
||||
|
||||
if (!ok && mHarfBuzzShaper) {
|
||||
if (gfxPlatform::GetPlatform()->UseHarfBuzzForScript(aScript) ||
|
||||
(!IsVistaOrLater() &&
|
||||
ScriptShapingType(aScript) == SHAPING_INDIC &&
|
||||
!Preferences::GetBool("gfx.font_rendering.winxp-indic-uniscribe",
|
||||
false))) {
|
||||
ok = mHarfBuzzShaper->ShapeText(aContext, aText, aOffset, aLength,
|
||||
aScript, aShapedText);
|
||||
}
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
GDIFontEntry *fe = static_cast<GDIFontEntry*>(GetFontEntry());
|
||||
bool preferUniscribe =
|
||||
(!fe->IsTrueType() || fe->IsSymbolFont()) && !fe->mForceGDI;
|
||||
|
||||
if (preferUniscribe || UseUniscribe(aShapedText, aText, aLength)) {
|
||||
// first try Uniscribe
|
||||
if (!mUniscribeShaper) {
|
||||
mUniscribeShaper = new gfxUniscribeShaper(this);
|
||||
}
|
||||
|
||||
ok = mUniscribeShaper->ShapeText(aContext, aText, aOffset, aLength,
|
||||
aScript, aShapedText);
|
||||
if (!ok) {
|
||||
// fallback to GDI shaping
|
||||
if (!mPlatformShaper) {
|
||||
CreatePlatformShaper();
|
||||
}
|
||||
|
||||
ok = mPlatformShaper->ShapeText(aContext, aText, aOffset,
|
||||
aLength, aScript, aShapedText);
|
||||
}
|
||||
} else {
|
||||
// first use GDI
|
||||
if (!mPlatformShaper) {
|
||||
CreatePlatformShaper();
|
||||
}
|
||||
|
||||
ok = mPlatformShaper->ShapeText(aContext, aText, aOffset, aLength,
|
||||
aScript, aShapedText);
|
||||
if (!ok) {
|
||||
// try Uniscribe if GDI failed
|
||||
if (!mUniscribeShaper) {
|
||||
mUniscribeShaper = new gfxUniscribeShaper(this);
|
||||
}
|
||||
|
||||
// use Uniscribe shaping
|
||||
ok = mUniscribeShaper->ShapeText(aContext, aText,
|
||||
aOffset, aLength,
|
||||
aScript, aShapedText);
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
if (!ok) {
|
||||
NS_ConvertUTF16toUTF8 name(GetName());
|
||||
char msg[256];
|
||||
|
||||
sprintf(msg,
|
||||
"text shaping with both uniscribe and GDI failed for"
|
||||
" font: %s",
|
||||
name.get());
|
||||
NS_WARNING(msg);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
PostShapingFixup(aContext, aText, aOffset, aLength, aShapedText);
|
||||
|
||||
return ok;
|
||||
return gfxFont::ShapeText(aContext, aText, aOffset, aLength, aScript,
|
||||
aShapedText, aPreferPlatformShaping);
|
||||
}
|
||||
|
||||
const gfxFont::Metrics&
|
||||
|
@ -537,6 +431,43 @@ gfxGDIFont::FillLogFont(LOGFONTW& aLogFont, gfxFloat aSize,
|
|||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
gfxGDIFont::GetGlyph(uint32_t aUnicode, uint32_t aVarSelector)
|
||||
{
|
||||
// Callback used only for fonts that lack a 'cmap' table.
|
||||
|
||||
// We don't support variation selector sequences or non-BMP characters
|
||||
// in the legacy bitmap, vector or postscript fonts that might use
|
||||
// this code path.
|
||||
if (aUnicode > 0xffff || aVarSelector) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!mGlyphIDs) {
|
||||
mGlyphIDs = new nsDataHashtable<nsUint32HashKey,uint32_t>(128);
|
||||
}
|
||||
|
||||
uint32_t gid;
|
||||
if (mGlyphIDs->Get(aUnicode, &gid)) {
|
||||
return gid;
|
||||
}
|
||||
|
||||
wchar_t ch = aUnicode;
|
||||
WORD glyph;
|
||||
DWORD ret = ScriptGetCMap(nullptr, &mScriptCache, &ch, 1, 0, &glyph);
|
||||
if (ret == E_PENDING) {
|
||||
AutoDC dc;
|
||||
AutoSelectFont fs(dc.GetDC(), GetHFONT());
|
||||
ret = ScriptGetCMap(dc.GetDC(), &mScriptCache, &ch, 1, 0, &glyph);
|
||||
}
|
||||
if (ret != S_OK) {
|
||||
glyph = 0;
|
||||
}
|
||||
|
||||
mGlyphIDs->Put(aUnicode, glyph);
|
||||
return glyph;
|
||||
}
|
||||
|
||||
int32_t
|
||||
gfxGDIFont::GetGlyphWidth(gfxContext *aCtx, uint16_t aGID)
|
||||
{
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "nsHashKeys.h"
|
||||
|
||||
#include "cairo.h"
|
||||
#include "usp10.h"
|
||||
|
||||
class gfxGDIFont : public gfxFont
|
||||
{
|
||||
|
@ -49,7 +50,15 @@ public:
|
|||
/* required for MathML to suppress effects of ClearType "padding" */
|
||||
virtual gfxFont* CopyWithAntialiasOption(AntialiasOption anAAOption);
|
||||
|
||||
virtual bool ProvidesGlyphWidths() { return true; }
|
||||
// If the font has a cmap table, we handle it purely with harfbuzz;
|
||||
// but if not (e.g. .fon fonts), we'll use a GDI callback to get glyphs.
|
||||
virtual bool ProvidesGetGlyph() const {
|
||||
return !mFontEntry->HasCmapTable();
|
||||
}
|
||||
|
||||
virtual uint32_t GetGlyph(uint32_t aUnicode, uint32_t aVarSelector);
|
||||
|
||||
virtual bool ProvidesGlyphWidths() const { return true; }
|
||||
|
||||
// get hinted glyph width in pixels as 16.16 fixed-point value
|
||||
virtual int32_t GetGlyphWidth(gfxContext *aCtx, uint16_t aGID);
|
||||
|
@ -62,9 +71,7 @@ public:
|
|||
virtual FontType GetType() const { return FONT_TYPE_GDI; }
|
||||
|
||||
protected:
|
||||
virtual void CreatePlatformShaper();
|
||||
|
||||
/* override to check for uniscribe failure and fall back to GDI */
|
||||
/* override to ensure the cairo font is set up properly */
|
||||
virtual bool ShapeText(gfxContext *aContext,
|
||||
const char16_t *aText,
|
||||
uint32_t aOffset,
|
||||
|
@ -80,10 +87,6 @@ protected:
|
|||
// italics.
|
||||
void FillLogFont(LOGFONTW& aLogFont, gfxFloat aSize, bool aUseGDIFakeItalic);
|
||||
|
||||
// mPlatformShaper is used for the GDI shaper, mUniscribeShaper
|
||||
// for the Uniscribe version if needed
|
||||
nsAutoPtr<gfxFontShaper> mUniscribeShaper;
|
||||
|
||||
HFONT mFont;
|
||||
cairo_font_face_t *mFontFace;
|
||||
|
||||
|
@ -92,6 +95,10 @@ protected:
|
|||
|
||||
bool mNeedsBold;
|
||||
|
||||
// cache of glyph IDs (used for non-sfnt fonts only)
|
||||
nsAutoPtr<nsDataHashtable<nsUint32HashKey,uint32_t> > mGlyphIDs;
|
||||
SCRIPT_CACHE mScriptCache;
|
||||
|
||||
// cache of glyph widths in 16.16 fixed-point pixels
|
||||
nsAutoPtr<nsDataHashtable<nsUint32HashKey,int32_t> > mGlyphWidths;
|
||||
};
|
||||
|
|
|
@ -1,96 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
//#define FORCE_PR_LOG
|
||||
|
||||
#include "gfxGDIShaper.h"
|
||||
|
||||
/**********************************************************************
|
||||
*
|
||||
* class gfxGDIShaper
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
bool
|
||||
gfxGDIShaper::ShapeText(gfxContext *aContext,
|
||||
const char16_t *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText)
|
||||
{
|
||||
DCFromContext dc(aContext);
|
||||
AutoSelectFont selectFont(dc, static_cast<gfxGDIFont*>(mFont)->GetHFONT());
|
||||
|
||||
uint32_t length = aLength;
|
||||
AutoFallibleTArray<WORD,500> glyphArray;
|
||||
if (!glyphArray.SetLength(length)) {
|
||||
return false;
|
||||
}
|
||||
WORD *glyphs = glyphArray.Elements();
|
||||
|
||||
DWORD ret = ::GetGlyphIndicesW(dc, char16ptr_t(aText), length,
|
||||
glyphs, GGI_MARK_NONEXISTING_GLYPHS);
|
||||
if (ret == GDI_ERROR) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int k = 0; k < length; k++) {
|
||||
if (glyphs[k] == 0xFFFF)
|
||||
return false;
|
||||
}
|
||||
|
||||
SIZE size;
|
||||
AutoFallibleTArray<int,500> partialWidthArray;
|
||||
if (!partialWidthArray.SetLength(length)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BOOL success = ::GetTextExtentExPointI(dc,
|
||||
glyphs,
|
||||
length,
|
||||
INT_MAX,
|
||||
nullptr,
|
||||
partialWidthArray.Elements(),
|
||||
&size);
|
||||
if (!success) {
|
||||
return false;
|
||||
}
|
||||
|
||||
gfxTextRun::CompressedGlyph g;
|
||||
gfxTextRun::CompressedGlyph *charGlyphs =
|
||||
aShapedText->GetCharacterGlyphs();
|
||||
uint32_t i;
|
||||
int32_t lastWidth = 0;
|
||||
int32_t appUnitsPerDevPixel = aShapedText->GetAppUnitsPerDevUnit();
|
||||
for (i = 0; i < length; ++i) {
|
||||
uint32_t offset = aOffset + i;
|
||||
int32_t advancePixels = partialWidthArray[i] - lastWidth;
|
||||
lastWidth = partialWidthArray[i];
|
||||
int32_t advanceAppUnits = advancePixels * appUnitsPerDevPixel;
|
||||
WCHAR glyph = glyphs[i];
|
||||
NS_ASSERTION(!gfxFontGroup::IsInvalidChar(aText[i]),
|
||||
"Invalid character detected!");
|
||||
bool atClusterStart = charGlyphs[offset].IsClusterStart();
|
||||
if (advanceAppUnits >= 0 &&
|
||||
gfxShapedWord::CompressedGlyph::IsSimpleAdvance(advanceAppUnits) &&
|
||||
gfxShapedWord::CompressedGlyph::IsSimpleGlyphID(glyph) &&
|
||||
atClusterStart)
|
||||
{
|
||||
charGlyphs[offset].SetSimpleGlyph(advanceAppUnits, glyph);
|
||||
} else {
|
||||
gfxShapedText::DetailedGlyph details;
|
||||
details.mGlyphID = glyph;
|
||||
details.mAdvance = advanceAppUnits;
|
||||
details.mXOffset = 0;
|
||||
details.mYOffset = 0;
|
||||
aShapedText->SetGlyphs(offset,
|
||||
g.SetComplex(atClusterStart, true, 1),
|
||||
&details);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef GFX_GDISHAPER_H
|
||||
#define GFX_GDISHAPER_H
|
||||
|
||||
#include "gfxGDIFont.h"
|
||||
|
||||
class gfxGDIShaper : public gfxFontShaper
|
||||
{
|
||||
public:
|
||||
gfxGDIShaper(gfxGDIFont *aFont)
|
||||
: gfxFontShaper(aFont)
|
||||
{
|
||||
MOZ_COUNT_CTOR(gfxGDIShaper);
|
||||
}
|
||||
|
||||
virtual ~gfxGDIShaper()
|
||||
{
|
||||
MOZ_COUNT_DTOR(gfxGDIShaper);
|
||||
}
|
||||
|
||||
virtual bool ShapeText(gfxContext *aContext,
|
||||
const char16_t *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText);
|
||||
};
|
||||
|
||||
#endif /* GFX_GDISHAPER_H */
|
|
@ -1,527 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "gfxTypes.h"
|
||||
|
||||
#include "gfxContext.h"
|
||||
#include "gfxUniscribeShaper.h"
|
||||
#include "gfxWindowsPlatform.h"
|
||||
|
||||
#include "gfxFontTest.h"
|
||||
|
||||
#include "cairo.h"
|
||||
#include "cairo-win32.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "nsTArray.h"
|
||||
|
||||
#include "prinit.h"
|
||||
|
||||
/**********************************************************************
|
||||
*
|
||||
* class gfxUniscribeShaper
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
#define ESTIMATE_MAX_GLYPHS(L) (((3 * (L)) >> 1) + 16)
|
||||
|
||||
class UniscribeItem
|
||||
{
|
||||
public:
|
||||
UniscribeItem(gfxContext *aContext, HDC aDC,
|
||||
gfxUniscribeShaper *aShaper,
|
||||
const char16_t *aString, uint32_t aLength,
|
||||
SCRIPT_ITEM *aItem, uint32_t aIVS) :
|
||||
mContext(aContext), mDC(aDC),
|
||||
mShaper(aShaper),
|
||||
mItemString(aString), mItemLength(aLength),
|
||||
mAlternativeString(nullptr), mScriptItem(aItem),
|
||||
mScript(aItem->a.eScript),
|
||||
mNumGlyphs(0), mMaxGlyphs(ESTIMATE_MAX_GLYPHS(aLength)),
|
||||
mFontSelected(false), mIVS(aIVS)
|
||||
{
|
||||
// See bug 394751 for details.
|
||||
NS_ASSERTION(mMaxGlyphs < 65535,
|
||||
"UniscribeItem is too big, ScriptShape() will fail!");
|
||||
}
|
||||
|
||||
~UniscribeItem() {
|
||||
free(mAlternativeString);
|
||||
}
|
||||
|
||||
bool AllocateBuffers() {
|
||||
return (mGlyphs.SetLength(mMaxGlyphs) &&
|
||||
mClusters.SetLength(mItemLength + 1) &&
|
||||
mAttr.SetLength(mMaxGlyphs));
|
||||
}
|
||||
|
||||
/* possible return values:
|
||||
* S_OK - things succeeded
|
||||
* GDI_ERROR - things failed to shape. Might want to try again after calling DisableShaping()
|
||||
*/
|
||||
|
||||
HRESULT Shape() {
|
||||
HRESULT rv;
|
||||
HDC shapeDC = nullptr;
|
||||
|
||||
char16ptr_t str = mAlternativeString ? mAlternativeString : mItemString;
|
||||
|
||||
mScriptItem->a.fLogicalOrder = true;
|
||||
SCRIPT_ANALYSIS sa = mScriptItem->a;
|
||||
|
||||
while (true) {
|
||||
|
||||
rv = ScriptShape(shapeDC, mShaper->ScriptCache(),
|
||||
str, mItemLength,
|
||||
mMaxGlyphs, &sa,
|
||||
mGlyphs.Elements(), mClusters.Elements(),
|
||||
mAttr.Elements(), &mNumGlyphs);
|
||||
|
||||
if (rv == E_OUTOFMEMORY) {
|
||||
mMaxGlyphs *= 2;
|
||||
if (!mGlyphs.SetLength(mMaxGlyphs) ||
|
||||
!mAttr.SetLength(mMaxGlyphs)) {
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Uniscribe can't do shaping with some fonts, so it sets the
|
||||
// fNoGlyphIndex flag in the SCRIPT_ANALYSIS structure to indicate
|
||||
// this. This occurs with CFF fonts loaded with
|
||||
// AddFontMemResourceEx but it's not clear what the other cases
|
||||
// are. We return an error so our caller can try fallback shaping.
|
||||
// see http://msdn.microsoft.com/en-us/library/ms776520(VS.85).aspx
|
||||
|
||||
if (sa.fNoGlyphIndex) {
|
||||
return GDI_ERROR;
|
||||
}
|
||||
|
||||
if (rv == E_PENDING) {
|
||||
if (shapeDC == mDC) {
|
||||
// we already tried this once, something failed, give up
|
||||
return E_PENDING;
|
||||
}
|
||||
|
||||
SelectFont();
|
||||
|
||||
shapeDC = mDC;
|
||||
continue;
|
||||
}
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/dd368564(VS.85).aspx:
|
||||
// Uniscribe will return this if "the font corresponding to the
|
||||
// DC does not support the script required by the run...".
|
||||
// In this case, we'll set the script code to SCRIPT_UNDEFINED
|
||||
// and try again, so that we'll at least get glyphs even though
|
||||
// they won't necessarily have proper shaping.
|
||||
// (We probably shouldn't have selected this font at all,
|
||||
// but it's too late to fix that here.)
|
||||
if (rv == USP_E_SCRIPT_NOT_IN_FONT) {
|
||||
sa.eScript = SCRIPT_UNDEFINED;
|
||||
NS_WARNING("Uniscribe says font does not support script needed");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Prior to Windows 7, Uniscribe didn't support Ideographic Variation
|
||||
// Selectors. Replace the UVS glyph manually.
|
||||
if (mIVS) {
|
||||
uint32_t lastChar = str[mItemLength - 1];
|
||||
if (NS_IS_LOW_SURROGATE(lastChar)
|
||||
&& NS_IS_HIGH_SURROGATE(str[mItemLength - 2])) {
|
||||
lastChar = SURROGATE_TO_UCS4(str[mItemLength - 2], lastChar);
|
||||
}
|
||||
uint16_t glyphId = mShaper->GetFont()->GetUVSGlyph(lastChar, mIVS);
|
||||
if (glyphId) {
|
||||
mGlyphs[mNumGlyphs - 1] = glyphId;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
bool ShapingEnabled() {
|
||||
return (mScriptItem->a.eScript != SCRIPT_UNDEFINED);
|
||||
}
|
||||
void DisableShaping() {
|
||||
mScriptItem->a.eScript = SCRIPT_UNDEFINED;
|
||||
// Note: If we disable the shaping by using SCRIPT_UNDEFINED and
|
||||
// the string has the surrogate pair, ScriptShape API is
|
||||
// *sometimes* crashed. Therefore, we should replace the surrogate
|
||||
// pair to U+FFFD. See bug 341500.
|
||||
GenerateAlternativeString();
|
||||
}
|
||||
void EnableShaping() {
|
||||
mScriptItem->a.eScript = mScript;
|
||||
if (mAlternativeString) {
|
||||
free(mAlternativeString);
|
||||
mAlternativeString = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsGlyphMissing(SCRIPT_FONTPROPERTIES *aSFP, uint32_t aGlyphIndex) {
|
||||
return (mGlyphs[aGlyphIndex] == aSFP->wgDefault);
|
||||
}
|
||||
|
||||
|
||||
HRESULT Place() {
|
||||
HRESULT rv;
|
||||
HDC placeDC = nullptr;
|
||||
|
||||
if (!mOffsets.SetLength(mNumGlyphs) ||
|
||||
!mAdvances.SetLength(mNumGlyphs)) {
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
SCRIPT_ANALYSIS sa = mScriptItem->a;
|
||||
|
||||
while (true) {
|
||||
rv = ScriptPlace(placeDC, mShaper->ScriptCache(),
|
||||
mGlyphs.Elements(), mNumGlyphs,
|
||||
mAttr.Elements(), &sa,
|
||||
mAdvances.Elements(), mOffsets.Elements(), nullptr);
|
||||
|
||||
if (rv == E_PENDING) {
|
||||
SelectFont();
|
||||
placeDC = mDC;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rv == USP_E_SCRIPT_NOT_IN_FONT) {
|
||||
sa.eScript = SCRIPT_UNDEFINED;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
void ScriptFontProperties(SCRIPT_FONTPROPERTIES *sfp) {
|
||||
HRESULT rv;
|
||||
|
||||
memset(sfp, 0, sizeof(SCRIPT_FONTPROPERTIES));
|
||||
sfp->cBytes = sizeof(SCRIPT_FONTPROPERTIES);
|
||||
rv = ScriptGetFontProperties(nullptr, mShaper->ScriptCache(),
|
||||
sfp);
|
||||
if (rv == E_PENDING) {
|
||||
SelectFont();
|
||||
rv = ScriptGetFontProperties(mDC, mShaper->ScriptCache(),
|
||||
sfp);
|
||||
}
|
||||
}
|
||||
|
||||
void SaveGlyphs(gfxShapedText *aShapedText, uint32_t aOffset) {
|
||||
uint32_t offsetInRun = mScriptItem->iCharPos;
|
||||
|
||||
// XXX We should store this in the item and only fetch it once
|
||||
SCRIPT_FONTPROPERTIES sfp;
|
||||
ScriptFontProperties(&sfp);
|
||||
|
||||
uint32_t offset = 0;
|
||||
nsAutoTArray<gfxShapedText::DetailedGlyph,1> detailedGlyphs;
|
||||
gfxShapedText::CompressedGlyph g;
|
||||
gfxShapedText::CompressedGlyph *charGlyphs =
|
||||
aShapedText->GetCharacterGlyphs();
|
||||
const uint32_t appUnitsPerDevUnit = aShapedText->GetAppUnitsPerDevUnit();
|
||||
while (offset < mItemLength) {
|
||||
uint32_t runOffset = aOffset + offsetInRun + offset;
|
||||
bool atClusterStart = charGlyphs[runOffset].IsClusterStart();
|
||||
if (offset > 0 && mClusters[offset] == mClusters[offset - 1]) {
|
||||
gfxShapedText::CompressedGlyph &g = charGlyphs[runOffset];
|
||||
NS_ASSERTION(!g.IsSimpleGlyph(), "overwriting a simple glyph");
|
||||
g.SetComplex(atClusterStart, false, 0);
|
||||
} else {
|
||||
// Count glyphs for this character
|
||||
uint32_t k = mClusters[offset];
|
||||
uint32_t glyphCount = mNumGlyphs - k;
|
||||
uint32_t nextClusterOffset;
|
||||
bool missing = IsGlyphMissing(&sfp, k);
|
||||
for (nextClusterOffset = offset + 1; nextClusterOffset < mItemLength; ++nextClusterOffset) {
|
||||
if (mClusters[nextClusterOffset] > k) {
|
||||
glyphCount = mClusters[nextClusterOffset] - k;
|
||||
break;
|
||||
}
|
||||
}
|
||||
uint32_t j;
|
||||
for (j = 1; j < glyphCount; ++j) {
|
||||
if (IsGlyphMissing(&sfp, k + j)) {
|
||||
missing = true;
|
||||
}
|
||||
}
|
||||
int32_t advance = mAdvances[k]*appUnitsPerDevUnit;
|
||||
WORD glyph = mGlyphs[k];
|
||||
NS_ASSERTION(!gfxFontGroup::IsInvalidChar(mItemString[offset]),
|
||||
"invalid character detected");
|
||||
if (missing) {
|
||||
if (NS_IS_HIGH_SURROGATE(mItemString[offset]) &&
|
||||
offset + 1 < mItemLength &&
|
||||
NS_IS_LOW_SURROGATE(mItemString[offset + 1])) {
|
||||
aShapedText->SetMissingGlyph(runOffset,
|
||||
SURROGATE_TO_UCS4(mItemString[offset],
|
||||
mItemString[offset + 1]),
|
||||
mShaper->GetFont());
|
||||
} else {
|
||||
aShapedText->SetMissingGlyph(runOffset, mItemString[offset],
|
||||
mShaper->GetFont());
|
||||
}
|
||||
} else if (glyphCount == 1 && advance >= 0 &&
|
||||
mOffsets[k].dv == 0 && mOffsets[k].du == 0 &&
|
||||
gfxShapedText::CompressedGlyph::IsSimpleAdvance(advance) &&
|
||||
gfxShapedText::CompressedGlyph::IsSimpleGlyphID(glyph) &&
|
||||
atClusterStart)
|
||||
{
|
||||
charGlyphs[runOffset].SetSimpleGlyph(advance, glyph);
|
||||
} else {
|
||||
if (detailedGlyphs.Length() < glyphCount) {
|
||||
if (!detailedGlyphs.AppendElements(glyphCount - detailedGlyphs.Length()))
|
||||
return;
|
||||
}
|
||||
uint32_t i;
|
||||
for (i = 0; i < glyphCount; ++i) {
|
||||
gfxTextRun::DetailedGlyph *details = &detailedGlyphs[i];
|
||||
details->mGlyphID = mGlyphs[k + i];
|
||||
details->mAdvance = mAdvances[k + i] * appUnitsPerDevUnit;
|
||||
details->mXOffset = float(mOffsets[k + i].du) * appUnitsPerDevUnit *
|
||||
aShapedText->GetDirection();
|
||||
details->mYOffset = - float(mOffsets[k + i].dv) * appUnitsPerDevUnit;
|
||||
}
|
||||
aShapedText->SetGlyphs(runOffset,
|
||||
g.SetComplex(atClusterStart, true,
|
||||
glyphCount),
|
||||
detailedGlyphs.Elements());
|
||||
}
|
||||
}
|
||||
++offset;
|
||||
}
|
||||
}
|
||||
|
||||
void SelectFont() {
|
||||
if (mFontSelected)
|
||||
return;
|
||||
|
||||
cairo_t *cr = mContext->GetCairo();
|
||||
|
||||
cairo_set_font_face(cr, mShaper->GetFont()->CairoFontFace());
|
||||
cairo_set_font_size(cr, mShaper->GetFont()->GetAdjustedSize());
|
||||
cairo_scaled_font_t *scaledFont = mShaper->GetFont()->CairoScaledFont();
|
||||
cairo_win32_scaled_font_select_font(scaledFont, mDC);
|
||||
|
||||
mFontSelected = true;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void GenerateAlternativeString() {
|
||||
if (mAlternativeString)
|
||||
free(mAlternativeString);
|
||||
mAlternativeString = (char16_t *)malloc(mItemLength * sizeof(char16_t));
|
||||
if (!mAlternativeString)
|
||||
return;
|
||||
memcpy((void *)mAlternativeString, (const void *)mItemString,
|
||||
mItemLength * sizeof(char16_t));
|
||||
for (uint32_t i = 0; i < mItemLength; i++) {
|
||||
if (NS_IS_HIGH_SURROGATE(mItemString[i]) || NS_IS_LOW_SURROGATE(mItemString[i]))
|
||||
mAlternativeString[i] = char16_t(0xFFFD);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<gfxContext> mContext;
|
||||
HDC mDC;
|
||||
gfxUniscribeShaper *mShaper;
|
||||
|
||||
SCRIPT_ITEM *mScriptItem;
|
||||
WORD mScript;
|
||||
|
||||
public:
|
||||
// these point to the full string/length of the item
|
||||
const char16_t *mItemString;
|
||||
const uint32_t mItemLength;
|
||||
|
||||
private:
|
||||
char16_t *mAlternativeString;
|
||||
|
||||
#define AVERAGE_ITEM_LENGTH 40
|
||||
|
||||
AutoFallibleTArray<WORD, uint32_t(ESTIMATE_MAX_GLYPHS(AVERAGE_ITEM_LENGTH))> mGlyphs;
|
||||
AutoFallibleTArray<WORD, AVERAGE_ITEM_LENGTH + 1> mClusters;
|
||||
AutoFallibleTArray<SCRIPT_VISATTR, uint32_t(ESTIMATE_MAX_GLYPHS(AVERAGE_ITEM_LENGTH))> mAttr;
|
||||
|
||||
AutoFallibleTArray<GOFFSET, 2 * AVERAGE_ITEM_LENGTH> mOffsets;
|
||||
AutoFallibleTArray<int, 2 * AVERAGE_ITEM_LENGTH> mAdvances;
|
||||
|
||||
#undef AVERAGE_ITEM_LENGTH
|
||||
|
||||
int mMaxGlyphs;
|
||||
int mNumGlyphs;
|
||||
uint32_t mIVS;
|
||||
|
||||
bool mFontSelected;
|
||||
};
|
||||
|
||||
class Uniscribe
|
||||
{
|
||||
public:
|
||||
Uniscribe(const char16_t *aString,
|
||||
gfxShapedText *aShapedText,
|
||||
uint32_t aOffset, uint32_t aLength):
|
||||
mString(aString), mShapedText(aShapedText),
|
||||
mOffset(aOffset), mLength(aLength)
|
||||
{
|
||||
}
|
||||
|
||||
void Init() {
|
||||
memset(&mControl, 0, sizeof(SCRIPT_CONTROL));
|
||||
memset(&mState, 0, sizeof(SCRIPT_STATE));
|
||||
// Lock the direction. Don't allow the itemizer to change directions
|
||||
// based on character type.
|
||||
mState.uBidiLevel = mShapedText->IsRightToLeft() ? 1 : 0;
|
||||
mState.fOverrideDirection = true;
|
||||
}
|
||||
|
||||
public:
|
||||
int Itemize() {
|
||||
HRESULT rv;
|
||||
|
||||
int maxItems = 5;
|
||||
|
||||
Init();
|
||||
|
||||
// Allocate space for one more item than expected, to handle a rare
|
||||
// overflow in ScriptItemize (pre XP SP2). See bug 366643.
|
||||
if (!mItems.SetLength(maxItems + 1)) {
|
||||
return 0;
|
||||
}
|
||||
while ((rv = ScriptItemize(mString, mLength,
|
||||
maxItems, &mControl, &mState,
|
||||
mItems.Elements(), &mNumItems)) == E_OUTOFMEMORY) {
|
||||
maxItems *= 2;
|
||||
if (!mItems.SetLength(maxItems + 1)) {
|
||||
return 0;
|
||||
}
|
||||
Init();
|
||||
}
|
||||
|
||||
return mNumItems;
|
||||
}
|
||||
|
||||
SCRIPT_ITEM *ScriptItem(uint32_t i) {
|
||||
NS_ASSERTION(i <= (uint32_t)mNumItems, "Trying to get out of bounds item");
|
||||
return &mItems[i];
|
||||
}
|
||||
|
||||
private:
|
||||
char16ptr_t mString;
|
||||
gfxShapedText *mShapedText;
|
||||
uint32_t mOffset;
|
||||
uint32_t mLength;
|
||||
|
||||
SCRIPT_CONTROL mControl;
|
||||
SCRIPT_STATE mState;
|
||||
FallibleTArray<SCRIPT_ITEM> mItems;
|
||||
int mNumItems;
|
||||
};
|
||||
|
||||
|
||||
bool
|
||||
gfxUniscribeShaper::ShapeText(gfxContext *aContext,
|
||||
const char16_t *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText)
|
||||
{
|
||||
DCFromContext aDC(aContext);
|
||||
|
||||
bool result = true;
|
||||
HRESULT rv;
|
||||
|
||||
Uniscribe us(aText, aShapedText, aOffset, aLength);
|
||||
|
||||
/* itemize the string */
|
||||
int numItems = us.Itemize();
|
||||
|
||||
uint32_t length = aLength;
|
||||
SaveDC(aDC);
|
||||
uint32_t ivs = 0;
|
||||
for (int i = 0; i < numItems; ++i) {
|
||||
int iCharPos = us.ScriptItem(i)->iCharPos;
|
||||
int iCharPosNext = us.ScriptItem(i+1)->iCharPos;
|
||||
|
||||
if (ivs) {
|
||||
iCharPos += 2;
|
||||
if (iCharPos >= iCharPosNext) {
|
||||
ivs = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (i+1 < numItems && iCharPosNext <= length - 2
|
||||
&& aText[iCharPosNext] == H_SURROGATE(kUnicodeVS17)
|
||||
&& uint32_t(aText[iCharPosNext + 1]) - L_SURROGATE(kUnicodeVS17)
|
||||
<= L_SURROGATE(kUnicodeVS256) - L_SURROGATE(kUnicodeVS17)) {
|
||||
|
||||
ivs = SURROGATE_TO_UCS4(aText[iCharPosNext],
|
||||
aText[iCharPosNext + 1]);
|
||||
} else {
|
||||
ivs = 0;
|
||||
}
|
||||
|
||||
UniscribeItem item(aContext, aDC, this,
|
||||
aText + iCharPos,
|
||||
iCharPosNext - iCharPos,
|
||||
us.ScriptItem(i), ivs);
|
||||
if (!item.AllocateBuffers()) {
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!item.ShapingEnabled()) {
|
||||
item.EnableShaping();
|
||||
}
|
||||
|
||||
rv = item.Shape();
|
||||
if (FAILED(rv)) {
|
||||
// we know we have the glyphs to display this font already
|
||||
// so Uniscribe just doesn't know how to shape the script.
|
||||
// Render the glyphs without shaping.
|
||||
item.DisableShaping();
|
||||
rv = item.Shape();
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (FAILED(rv)) {
|
||||
NS_WARNING("Uniscribe failed to shape with font");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (SUCCEEDED(rv)) {
|
||||
rv = item.Place();
|
||||
#ifdef DEBUG
|
||||
if (FAILED(rv)) {
|
||||
// crap fonts may fail when placing (e.g. funky free fonts)
|
||||
NS_WARNING("Uniscribe failed to place with font");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (FAILED(rv)) {
|
||||
// Uniscribe doesn't like this font for some reason.
|
||||
// Returning FALSE will make the gfxGDIFont retry with the
|
||||
// "dumb" GDI shaper, unless useUniscribeOnly was set.
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
|
||||
item.SaveGlyphs(aShapedText, aOffset);
|
||||
}
|
||||
|
||||
RestoreDC(aDC, -1);
|
||||
|
||||
return result;
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef GFX_UNISCRIBESHAPER_H
|
||||
#define GFX_UNISCRIBESHAPER_H
|
||||
|
||||
#include "gfxTypes.h"
|
||||
#include "gfxGDIFont.h"
|
||||
|
||||
#include <usp10.h>
|
||||
#include <cairo-win32.h>
|
||||
|
||||
|
||||
class gfxUniscribeShaper : public gfxFontShaper
|
||||
{
|
||||
public:
|
||||
gfxUniscribeShaper(gfxGDIFont *aFont)
|
||||
: gfxFontShaper(aFont)
|
||||
, mScriptCache(nullptr)
|
||||
{
|
||||
MOZ_COUNT_CTOR(gfxUniscribeShaper);
|
||||
}
|
||||
|
||||
virtual ~gfxUniscribeShaper()
|
||||
{
|
||||
MOZ_COUNT_DTOR(gfxUniscribeShaper);
|
||||
}
|
||||
|
||||
virtual bool ShapeText(gfxContext *aContext,
|
||||
const char16_t *aText,
|
||||
uint32_t aOffset,
|
||||
uint32_t aLength,
|
||||
int32_t aScript,
|
||||
gfxShapedText *aShapedText);
|
||||
|
||||
SCRIPT_CACHE *ScriptCache() { return &mScriptCache; }
|
||||
|
||||
gfxGDIFont *GetFont() { return static_cast<gfxGDIFont*>(mFont); }
|
||||
|
||||
private:
|
||||
SCRIPT_CACHE mScriptCache;
|
||||
|
||||
enum {
|
||||
kUnicodeVS17 = gfxFontUtils::kUnicodeVS17,
|
||||
kUnicodeVS256 = gfxFontUtils::kUnicodeVS256
|
||||
};
|
||||
};
|
||||
|
||||
#endif /* GFX_UNISCRIBESHAPER_H */
|
|
@ -171,13 +171,11 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
|||
'gfxWindowsPlatform.h',
|
||||
'gfxWindowsSurface.h',
|
||||
]
|
||||
# gfxGDIFontList.cpp and gfxGDIShaper.cpp force NSPR logging, so they cannot be built in unified mode.
|
||||
# gfxGDIFontList.cpp forces NSPR logging, so it cannot be built in unified mode.
|
||||
SOURCES += [
|
||||
'gfxGDIFont.cpp',
|
||||
'gfxGDIFontList.cpp',
|
||||
'gfxGDIShaper.cpp',
|
||||
'gfxPDFSurface.cpp',
|
||||
'gfxUniscribeShaper.cpp',
|
||||
'gfxWindowsNativeDrawing.cpp',
|
||||
'gfxWindowsPlatform.cpp',
|
||||
'gfxWindowsSurface.cpp',
|
||||
|
@ -189,8 +187,6 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
|||
'gfxDWriteCommon.cpp',
|
||||
'gfxDWriteFontList.cpp',
|
||||
'gfxDWriteFonts.cpp',
|
||||
'gfxDWriteShaper.cpp',
|
||||
'gfxDWriteTextAnalysis.cpp',
|
||||
]
|
||||
|
||||
# Are we targeting x86 or x64? If so, build gfxAlphaRecoverySSE2.cpp.
|
||||
|
|
|
@ -115,45 +115,31 @@ enum {
|
|||
|
||||
namespace JS {
|
||||
|
||||
struct ClassInfo
|
||||
// Data for tracking memory usage of things hanging off objects.
|
||||
struct ObjectsExtraSizes
|
||||
{
|
||||
#define FOR_EACH_SIZE(macro) \
|
||||
macro(Objects, IsLiveGCThing, objectsGCHeap) \
|
||||
macro(Objects, NotLiveGCThing, objectsMallocHeapSlots) \
|
||||
macro(Objects, NotLiveGCThing, objectsMallocHeapElementsNonAsmJS) \
|
||||
macro(Objects, NotLiveGCThing, objectsMallocHeapElementsAsmJS) \
|
||||
macro(Objects, NotLiveGCThing, objectsNonHeapElementsAsmJS) \
|
||||
macro(Objects, NotLiveGCThing, objectsNonHeapElementsMapped) \
|
||||
macro(Objects, NotLiveGCThing, objectsNonHeapCodeAsmJS) \
|
||||
macro(Objects, NotLiveGCThing, objectsMallocHeapMisc) \
|
||||
\
|
||||
macro(Other, IsLiveGCThing, shapesGCHeapTree) \
|
||||
macro(Other, IsLiveGCThing, shapesGCHeapDict) \
|
||||
macro(Other, IsLiveGCThing, shapesGCHeapBase) \
|
||||
macro(Other, NotLiveGCThing, shapesMallocHeapTreeTables) \
|
||||
macro(Other, NotLiveGCThing, shapesMallocHeapDictTables) \
|
||||
macro(Other, NotLiveGCThing, shapesMallocHeapTreeKids) \
|
||||
macro(Objects, NotLiveGCThing, mallocHeapSlots) \
|
||||
macro(Objects, NotLiveGCThing, mallocHeapElementsNonAsmJS) \
|
||||
macro(Objects, NotLiveGCThing, mallocHeapElementsAsmJS) \
|
||||
macro(Objects, NotLiveGCThing, nonHeapElementsAsmJS) \
|
||||
macro(Objects, NotLiveGCThing, nonHeapElementsMapped) \
|
||||
macro(Objects, NotLiveGCThing, nonHeapCodeAsmJS) \
|
||||
macro(Objects, NotLiveGCThing, mallocHeapAsmJSModuleData) \
|
||||
macro(Objects, NotLiveGCThing, mallocHeapArgumentsData) \
|
||||
macro(Objects, NotLiveGCThing, mallocHeapRegExpStatics) \
|
||||
macro(Objects, NotLiveGCThing, mallocHeapPropertyIteratorData) \
|
||||
macro(Objects, NotLiveGCThing, mallocHeapCtypesData)
|
||||
|
||||
ClassInfo()
|
||||
ObjectsExtraSizes()
|
||||
: FOR_EACH_SIZE(ZERO_SIZE)
|
||||
dummy()
|
||||
{}
|
||||
|
||||
void add(const ClassInfo &other) {
|
||||
void add(const ObjectsExtraSizes &other) {
|
||||
FOR_EACH_SIZE(ADD_OTHER_SIZE)
|
||||
}
|
||||
|
||||
void subtract(const ClassInfo &other) {
|
||||
FOR_EACH_SIZE(SUB_OTHER_SIZE)
|
||||
}
|
||||
|
||||
bool isNotable() const {
|
||||
static const size_t NotabilityThreshold = 16 * 1024;
|
||||
size_t n = 0;
|
||||
FOR_EACH_SIZE(ADD_SIZE_TO_N)
|
||||
return n >= NotabilityThreshold;
|
||||
}
|
||||
|
||||
size_t sizeOfLiveGCThings() const {
|
||||
size_t n = 0;
|
||||
FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING)
|
||||
|
@ -170,29 +156,6 @@ struct ClassInfo
|
|||
#undef FOR_EACH_SIZE
|
||||
};
|
||||
|
||||
// Holds data about a notable class (one whose combined object and shape
|
||||
// instances use more than a certain amount of memory) so we can report it
|
||||
// individually.
|
||||
//
|
||||
// The only difference between this class and ClassInfo is that this class
|
||||
// holds a copy of the filename.
|
||||
struct NotableClassInfo : public ClassInfo
|
||||
{
|
||||
NotableClassInfo();
|
||||
NotableClassInfo(const char *className, const ClassInfo &info);
|
||||
NotableClassInfo(NotableClassInfo &&info);
|
||||
NotableClassInfo &operator=(NotableClassInfo &&info);
|
||||
|
||||
~NotableClassInfo() {
|
||||
js_free(className_);
|
||||
}
|
||||
|
||||
char *className_;
|
||||
|
||||
private:
|
||||
NotableClassInfo(const NotableClassInfo& info) MOZ_DELETE;
|
||||
};
|
||||
|
||||
// Data for tracking JIT-code memory usage.
|
||||
struct CodeSizes
|
||||
{
|
||||
|
@ -523,7 +486,20 @@ struct ZoneStats
|
|||
struct CompartmentStats
|
||||
{
|
||||
#define FOR_EACH_SIZE(macro) \
|
||||
macro(Objects, IsLiveGCThing, objectsGCHeapOrdinary) \
|
||||
macro(Objects, IsLiveGCThing, objectsGCHeapFunction) \
|
||||
macro(Objects, IsLiveGCThing, objectsGCHeapDenseArray) \
|
||||
macro(Objects, IsLiveGCThing, objectsGCHeapSlowArray) \
|
||||
macro(Objects, IsLiveGCThing, objectsGCHeapCrossCompartmentWrapper) \
|
||||
macro(Private, NotLiveGCThing, objectsPrivate) \
|
||||
macro(Other, IsLiveGCThing, shapesGCHeapTreeGlobalParented) \
|
||||
macro(Other, IsLiveGCThing, shapesGCHeapTreeNonGlobalParented) \
|
||||
macro(Other, IsLiveGCThing, shapesGCHeapDict) \
|
||||
macro(Other, IsLiveGCThing, shapesGCHeapBase) \
|
||||
macro(Other, NotLiveGCThing, shapesMallocHeapTreeTables) \
|
||||
macro(Other, NotLiveGCThing, shapesMallocHeapDictTables) \
|
||||
macro(Other, NotLiveGCThing, shapesMallocHeapTreeShapeKids) \
|
||||
macro(Other, NotLiveGCThing, shapesMallocHeapCompartmentTables) \
|
||||
macro(Other, IsLiveGCThing, scriptsGCHeap) \
|
||||
macro(Other, NotLiveGCThing, scriptsMallocHeapData) \
|
||||
macro(Other, NotLiveGCThing, baselineData) \
|
||||
|
@ -534,7 +510,6 @@ struct CompartmentStats
|
|||
macro(Other, NotLiveGCThing, typeInferenceArrayTypeTables) \
|
||||
macro(Other, NotLiveGCThing, typeInferenceObjectTypeTables) \
|
||||
macro(Other, NotLiveGCThing, compartmentObject) \
|
||||
macro(Other, NotLiveGCThing, compartmentTables) \
|
||||
macro(Other, NotLiveGCThing, crossCompartmentWrappersTable) \
|
||||
macro(Other, NotLiveGCThing, regexpCompartment) \
|
||||
macro(Other, NotLiveGCThing, debuggeesSet) \
|
||||
|
@ -542,69 +517,39 @@ struct CompartmentStats
|
|||
|
||||
CompartmentStats()
|
||||
: FOR_EACH_SIZE(ZERO_SIZE)
|
||||
classInfo(),
|
||||
extra(),
|
||||
allClasses(nullptr),
|
||||
notableClasses(),
|
||||
isTotals(true)
|
||||
objectsExtra(),
|
||||
extra()
|
||||
{}
|
||||
|
||||
CompartmentStats(CompartmentStats &&other)
|
||||
CompartmentStats(const CompartmentStats &other)
|
||||
: FOR_EACH_SIZE(COPY_OTHER_SIZE)
|
||||
classInfo(mozilla::Move(other.classInfo)),
|
||||
extra(other.extra),
|
||||
allClasses(other.allClasses),
|
||||
notableClasses(mozilla::Move(other.notableClasses)),
|
||||
isTotals(other.isTotals)
|
||||
{
|
||||
other.allClasses = nullptr;
|
||||
MOZ_ASSERT(!other.isTotals);
|
||||
}
|
||||
objectsExtra(other.objectsExtra),
|
||||
extra(other.extra)
|
||||
{}
|
||||
|
||||
~CompartmentStats() {
|
||||
// |allClasses| is usually deleted and set to nullptr before this
|
||||
// destructor runs. But there are failure cases due to OOMs that may
|
||||
// prevent that, so it doesn't hurt to try again here.
|
||||
js_delete(allClasses);
|
||||
}
|
||||
|
||||
bool initClasses(JSRuntime *rt);
|
||||
|
||||
void addSizes(const CompartmentStats &other) {
|
||||
MOZ_ASSERT(isTotals);
|
||||
void add(const CompartmentStats &other) {
|
||||
FOR_EACH_SIZE(ADD_OTHER_SIZE)
|
||||
classInfo.add(other.classInfo);
|
||||
objectsExtra.add(other.objectsExtra);
|
||||
// Do nothing with |extra|.
|
||||
}
|
||||
|
||||
size_t sizeOfLiveGCThings() const {
|
||||
MOZ_ASSERT(isTotals);
|
||||
size_t n = 0;
|
||||
FOR_EACH_SIZE(ADD_SIZE_TO_N_IF_LIVE_GC_THING)
|
||||
n += classInfo.sizeOfLiveGCThings();
|
||||
n += objectsExtra.sizeOfLiveGCThings();
|
||||
// Do nothing with |extra|.
|
||||
return n;
|
||||
}
|
||||
|
||||
void addToTabSizes(TabSizes *sizes) const {
|
||||
MOZ_ASSERT(isTotals);
|
||||
FOR_EACH_SIZE(ADD_TO_TAB_SIZES);
|
||||
classInfo.addToTabSizes(sizes);
|
||||
objectsExtra.addToTabSizes(sizes);
|
||||
// Do nothing with |extra|.
|
||||
}
|
||||
|
||||
// The class measurements in |classInfo| are initially for all classes. At
|
||||
// the end, if the measurement granularity is FineGrained, we subtract the
|
||||
// measurements of the notable classes and move them into |notableClasses|.
|
||||
FOR_EACH_SIZE(DECL_SIZE)
|
||||
ClassInfo classInfo;
|
||||
void *extra; // This field can be used by embedders.
|
||||
|
||||
typedef js::HashMap<const char*, ClassInfo,
|
||||
js::CStringHashPolicy,
|
||||
js::SystemAllocPolicy> ClassesHashMap;
|
||||
|
||||
// These are similar to |allStrings| and |notableStrings| in ZoneStats.
|
||||
ClassesHashMap *allClasses;
|
||||
js::Vector<NotableClassInfo, 0, js::SystemAllocPolicy> notableClasses;
|
||||
bool isTotals;
|
||||
ObjectsExtraSizes objectsExtra;
|
||||
void *extra; // This field can be used by embedders.
|
||||
|
||||
#undef FOR_EACH_SIZE
|
||||
};
|
||||
|
|
|
@ -401,7 +401,8 @@ endif
|
|||
|
||||
selfhosted.out.h: $(selfhosted_out_h_deps)
|
||||
$(PYTHON) $(srcdir)/builtin/embedjs.py $(SELFHOSTED_DEFINES) \
|
||||
-p '$(CPP)' -m $(srcdir)/js.msg -o $@ $(selfhosting_srcs)
|
||||
-c '$(CCC)' -p '$(PREPROCESS_OPTION)' -m $(srcdir)/js.msg \
|
||||
-o $@ $(selfhosting_srcs)
|
||||
|
||||
###############################################
|
||||
# Generating source package tarballs
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
// by the headers included above.
|
||||
namespace JS {
|
||||
|
||||
class Latin1Chars;
|
||||
class Latin1CharsZ;
|
||||
class ConstTwoByteChars;
|
||||
class TwoByteChars;
|
||||
|
@ -65,6 +66,7 @@ using JS::UndefinedValue;
|
|||
using JS::IsPoisonedPtr;
|
||||
|
||||
using JS::Latin1Char;
|
||||
using JS::Latin1Chars;
|
||||
using JS::Latin1CharsZ;
|
||||
using JS::ConstTwoByteChars;
|
||||
using JS::TwoByteChars;
|
||||
|
|
|
@ -173,8 +173,9 @@ TryEvalJSON(JSContext *cx, JSScript *callerScript,
|
|||
|
||||
if (cp == end) {
|
||||
bool isArray = (chars[0] == '[');
|
||||
JSONParser parser(cx, isArray ? chars : chars + 1U, isArray ? length : length - 2,
|
||||
JSONParser::NoError);
|
||||
JSONParser<jschar> parser(cx, isArray ? chars : chars + 1U,
|
||||
isArray ? length : length - 2,
|
||||
JSONParserBase::NoError);
|
||||
RootedValue tmp(cx);
|
||||
if (!parser.parse(&tmp))
|
||||
return EvalJSON_Failure;
|
||||
|
|
|
@ -1414,13 +1414,13 @@ intl_FormatNumber(JSContext *cx, UNumberFormat *nf, double x, MutableHandleValue
|
|||
if (!chars.resize(INITIAL_STRING_BUFFER_SIZE))
|
||||
return false;
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
int size = unum_formatDouble(nf, x, JSCharToUChar(chars.begin()),
|
||||
int size = unum_formatDouble(nf, x, JSCharToUChar(chars.rawTwoByteBegin()),
|
||||
INITIAL_STRING_BUFFER_SIZE, nullptr, &status);
|
||||
if (status == U_BUFFER_OVERFLOW_ERROR) {
|
||||
if (!chars.resize(size))
|
||||
return false;
|
||||
status = U_ZERO_ERROR;
|
||||
unum_formatDouble(nf, x, JSCharToUChar(chars.begin()),
|
||||
unum_formatDouble(nf, x, JSCharToUChar(chars.rawTwoByteBegin()),
|
||||
size, nullptr, &status);
|
||||
}
|
||||
if (U_FAILURE(status)) {
|
||||
|
@ -1902,12 +1902,13 @@ intl_FormatDateTime(JSContext *cx, UDateFormat *df, double x, MutableHandleValue
|
|||
if (!chars.resize(INITIAL_STRING_BUFFER_SIZE))
|
||||
return false;
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
int size = udat_format(df, x, JSCharToUChar(chars.begin()), INITIAL_STRING_BUFFER_SIZE, nullptr, &status);
|
||||
int size = udat_format(df, x, JSCharToUChar(chars.rawTwoByteBegin()), INITIAL_STRING_BUFFER_SIZE,
|
||||
nullptr, &status);
|
||||
if (status == U_BUFFER_OVERFLOW_ERROR) {
|
||||
if (!chars.resize(size))
|
||||
return false;
|
||||
status = U_ZERO_ERROR;
|
||||
udat_format(df, x, JSCharToUChar(chars.begin()), size, nullptr, &status);
|
||||
udat_format(df, x, JSCharToUChar(chars.rawTwoByteBegin()), size, nullptr, &status);
|
||||
}
|
||||
if (U_FAILURE(status)) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR);
|
||||
|
|
|
@ -205,6 +205,8 @@ js::ObjectToSource(JSContext *cx, HandleObject obj)
|
|||
const jschar *vchars = valstr->getChars(cx);
|
||||
if (!vchars)
|
||||
return nullptr;
|
||||
|
||||
const jschar *start = vchars;
|
||||
size_t vlength = valstr->length();
|
||||
|
||||
/*
|
||||
|
@ -212,7 +214,6 @@ js::ObjectToSource(JSContext *cx, HandleObject obj)
|
|||
* end so that we can put "get" in front of the function definition.
|
||||
*/
|
||||
if (gsop[j] && IsFunctionObject(val[j])) {
|
||||
const jschar *start = vchars;
|
||||
const jschar *end = vchars + vlength;
|
||||
|
||||
uint8_t parenChomp = 0;
|
||||
|
@ -255,7 +256,7 @@ js::ObjectToSource(JSContext *cx, HandleObject obj)
|
|||
if (!buf.append(gsop[j] ? ' ' : ':'))
|
||||
return nullptr;
|
||||
|
||||
if (!buf.append(vchars, vlength))
|
||||
if (!buf.appendSubstring(valstr, vchars - start, vlength))
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
@ -291,7 +292,7 @@ JS_BasicObjectToString(JSContext *cx, HandleObject obj)
|
|||
return cx->names().objectWindow;
|
||||
|
||||
StringBuffer sb(cx);
|
||||
if (!sb.append("[object ") || !sb.appendInflated(className, strlen(className)) ||
|
||||
if (!sb.append("[object ") || !sb.append(className, strlen(className)) ||
|
||||
!sb.append("]"))
|
||||
{
|
||||
return nullptr;
|
||||
|
|
|
@ -176,8 +176,12 @@ EscapeNakedForwardSlashes(JSContext *cx, HandleAtom unescaped)
|
|||
/* There's a forward slash that needs escaping. */
|
||||
if (sb.empty()) {
|
||||
/* This is the first one we've seen, copy everything up to this point. */
|
||||
if (unescaped->hasTwoByteChars() && !sb.ensureTwoByteChars())
|
||||
return nullptr;
|
||||
|
||||
if (!sb.reserve(oldLen + 1))
|
||||
return nullptr;
|
||||
|
||||
sb.infallibleAppend(oldChars, size_t(it - oldChars));
|
||||
}
|
||||
if (!sb.append('\\'))
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
from __future__ import with_statement
|
||||
import re, sys, os, fileinput, subprocess
|
||||
import shlex
|
||||
import which
|
||||
from optparse import OptionParser
|
||||
|
||||
def ToCAsciiArray(lines):
|
||||
|
@ -77,19 +78,21 @@ namespace selfhosted {
|
|||
} // js
|
||||
"""
|
||||
|
||||
def embed(cpp, msgs, sources, c_out, js_out, env):
|
||||
# Clang seems to complain and not output anything if the extension of the
|
||||
# input is not something it recognizes, so just fake a .h here.
|
||||
tmp = 'selfhosted.js.h'
|
||||
with open(tmp, 'wb') as output:
|
||||
output.write('\n'.join([msgs] + ['#include "%(s)s"' % { 's': source } for source in sources]))
|
||||
cmdline = cpp + ['-D%(k)s=%(v)s' % { 'k': k, 'v': env[k] } for k in env] + [tmp]
|
||||
p = subprocess.Popen(cmdline, stdout=subprocess.PIPE)
|
||||
processed = ''
|
||||
for line in p.stdout:
|
||||
if not line.startswith('#'):
|
||||
processed += line
|
||||
os.remove(tmp)
|
||||
MSGS_TEMPLATE = """\
|
||||
#define hash #
|
||||
#define id(x) x
|
||||
#define hashify(x) id(hash)x
|
||||
#define MSG_DEF(name, id, argc, ex, msg) hashify(define) name id
|
||||
#include "%(msgs)s"
|
||||
"""
|
||||
|
||||
def embed(cxx, preprocessorOption, msgs, sources, c_out, js_out, env):
|
||||
combinedSources = '\n'.join([msgs] + ['#include "%(s)s"' % { 's': source } for source in sources])
|
||||
args = ['-D%(k)s=%(v)s' % { 'k': k, 'v': env[k] } for k in env]
|
||||
preprocessed = preprocess(cxx, preprocessorOption, combinedSources, args)
|
||||
processed = '\n'.join([line for line in preprocessed.splitlines() if \
|
||||
(line.strip() and not line.startswith('#'))])
|
||||
|
||||
with open(js_out, 'w') as output:
|
||||
output.write(processed)
|
||||
with open(c_out, 'w') as output:
|
||||
|
@ -114,21 +117,25 @@ def embed(cpp, msgs, sources, c_out, js_out, env):
|
|||
'raw_total_length': len(processed)
|
||||
})
|
||||
|
||||
def process_msgs(cpp, msgs):
|
||||
def preprocess(cxx, preprocessorOption, source, args = []):
|
||||
if (not os.path.exists(cxx[0])):
|
||||
cxx[0] = which.which(cxx[0])
|
||||
# Clang seems to complain and not output anything if the extension of the
|
||||
# input is not something it recognizes, so just fake a .h here.
|
||||
tmp = 'selfhosted.msg.h'
|
||||
with open(tmp, 'wb') as output:
|
||||
output.write("""\
|
||||
#define hash #
|
||||
#define id(x) x
|
||||
#define hashify(x) id(hash)x
|
||||
#define MSG_DEF(name, id, argc, ex, msg) hashify(define) name id
|
||||
#include "%(msgs)s"
|
||||
""" % { 'msgs': msgs })
|
||||
p = subprocess.Popen(cpp + [tmp], stdout=subprocess.PIPE)
|
||||
processed = p.communicate()[0]
|
||||
os.remove(tmp)
|
||||
# input is not something it recognizes, so just fake a .cpp here.
|
||||
tmpIn = 'self-hosting-cpp-input.cpp';
|
||||
tmpOut = 'self-hosting-preprocessed.pp';
|
||||
outputArg = shlex.split(preprocessorOption + tmpOut)
|
||||
|
||||
with open(tmpIn, 'wb') as input:
|
||||
input.write(source)
|
||||
print(' '.join(cxx + outputArg + args + [tmpIn]))
|
||||
result = subprocess.Popen(cxx + outputArg + args + [tmpIn]).wait()
|
||||
if (result != 0):
|
||||
sys.exit(result);
|
||||
with open(tmpOut, 'r') as output:
|
||||
processed = output.read();
|
||||
os.remove(tmpIn)
|
||||
os.remove(tmpOut)
|
||||
return processed
|
||||
|
||||
def main():
|
||||
|
@ -143,7 +150,9 @@ def main():
|
|||
metavar='var=[val]', help='Define a variable')
|
||||
p.add_option('-m', type='string', metavar='jsmsg', default='../js.msg',
|
||||
help='js.msg file')
|
||||
p.add_option('-p', type='string', metavar='cpp', help='Path to C preprocessor')
|
||||
p.add_option('-c', type='string', metavar='cxx', help='Path to C++ compiler')
|
||||
p.add_option('-p', type='string', dest='p', metavar='cxxoption',
|
||||
help='Argument to compiler for preprocessing into an output file')
|
||||
p.add_option('-o', type='string', metavar='filename', default='selfhosted.out.h',
|
||||
help='C array header file')
|
||||
p.add_option('-s', type='string', metavar='jsfilename', default='selfhosted.js',
|
||||
|
@ -151,10 +160,10 @@ def main():
|
|||
(options, sources) = p.parse_args()
|
||||
if not (options.p and sources):
|
||||
p.print_help()
|
||||
exit(1)
|
||||
cpp = shlex.split(options.p)
|
||||
embed(cpp, process_msgs(cpp, options.m),
|
||||
sources, options.o, options.s, env)
|
||||
sys.exit(1)
|
||||
cxx = shlex.split(options.c)
|
||||
msgs = preprocess(cxx, options.p, MSGS_TEMPLATE % { 'msgs': options.m })
|
||||
embed(cxx, options.p, msgs, sources, options.o, options.s, env)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
|
@ -473,6 +473,9 @@ case "$target" in
|
|||
INCREMENTAL_LINKER=1
|
||||
|
||||
unset _MSVC_VER_FILTER
|
||||
|
||||
CFLAGS="$CFLAGS -D_HAS_EXCEPTIONS=0"
|
||||
CXXFLAGS="$CXXFLAGS -D_HAS_EXCEPTIONS=0"
|
||||
elif test -z "$CLANG_CC"; then
|
||||
# Check w32api version
|
||||
_W32API_MAJOR_VERSION=`echo $W32API_VERSION | $AWK -F\. '{ print $1 }'`
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
commit fb25cd08ed5a87640b02f0feeb10a09b37cfddbe (HEAD, origin/clang-cl, clang-cl)
|
||||
Author: Ehsan Akhgari <ehsan@mozilla.com>
|
||||
Date: Wed Jun 11 12:07:24 2014 -0400
|
||||
|
||||
Add support for building with clang-cl
|
||||
|
||||
diff --git a/README b/README
|
||||
index 7aee5b4..9cba257 100644
|
||||
--- a/README
|
||||
+++ b/README
|
||||
@@ -146,12 +146,17 @@ It's also possible to build libffi on Windows platforms with
|
||||
Microsoft's Visual C++ compiler. In this case, use the msvcc.sh
|
||||
wrapper script during configuration like so:
|
||||
|
||||
-path/to/configure CC=path/to/msvcc.sh CXX=path/to/msvcc.sh LD=link CPP=\"cl -nologo -EP\"
|
||||
+path/to/configure CC=path/to/msvcc.sh CXX=path/to/msvcc.sh LD=link CPP="cl -nologo -EP"
|
||||
|
||||
For 64-bit Windows builds, use CC="path/to/msvcc.sh -m64" and
|
||||
CXX="path/to/msvcc.sh -m64". You may also need to specify --build
|
||||
appropriately.
|
||||
|
||||
+It is also possible to build libffi on Windows platforms with the LLVM
|
||||
+project's clang-cl compiler, like below:
|
||||
+
|
||||
+path/to/configure CC="path/to/msvcc.sh -clang-cl" CXX="path/to/msvcc.sh -clang-cl" LD=link CPP="clang-cl -EP"
|
||||
+
|
||||
When building with MSVC under a MingW environment, you may need to
|
||||
remove the line in configure that sets 'fix_srcfile_path' to a 'cygpath'
|
||||
command. ('cygpath' is not present in MingW, and is not required when
|
||||
diff --git a/include/ffi.h.in b/include/ffi.h.in
|
||||
index 70c6179..ebed0aa 100644
|
||||
--- a/include/ffi.h.in
|
||||
+++ b/include/ffi.h.in
|
||||
@@ -68,7 +68,7 @@ extern "C" {
|
||||
|
||||
#ifndef LIBFFI_ASM
|
||||
|
||||
-#ifdef _MSC_VER
|
||||
+#if defined(_MSC_VER) && !defined(__clang__)
|
||||
#define __attribute__(X)
|
||||
#endif
|
||||
|
||||
diff --git a/msvcc.sh b/msvcc.sh
|
||||
index 9208076..4a65b0b 100755
|
||||
--- a/msvcc.sh
|
||||
+++ b/msvcc.sh
|
||||
@@ -63,11 +63,15 @@ do
|
||||
shift 1
|
||||
;;
|
||||
-m64)
|
||||
- cl="cl" # "$MSVC/x86_amd64/cl"
|
||||
ml="ml64" # "$MSVC/x86_amd64/ml64"
|
||||
safeseh=
|
||||
shift 1
|
||||
;;
|
||||
+ -clang-cl)
|
||||
+ cl="clang-cl"
|
||||
+ safeseh=
|
||||
+ shift 1
|
||||
+ ;;
|
||||
-O0)
|
||||
args="$args -Od"
|
||||
shift 1
|
|
@ -146,12 +146,17 @@ It's also possible to build libffi on Windows platforms with
|
|||
Microsoft's Visual C++ compiler. In this case, use the msvcc.sh
|
||||
wrapper script during configuration like so:
|
||||
|
||||
path/to/configure CC=path/to/msvcc.sh CXX=path/to/msvcc.sh LD=link CPP=\"cl -nologo -EP\"
|
||||
path/to/configure CC=path/to/msvcc.sh CXX=path/to/msvcc.sh LD=link CPP="cl -nologo -EP"
|
||||
|
||||
For 64-bit Windows builds, use CC="path/to/msvcc.sh -m64" and
|
||||
CXX="path/to/msvcc.sh -m64". You may also need to specify --build
|
||||
appropriately.
|
||||
|
||||
It is also possible to build libffi on Windows platforms with the LLVM
|
||||
project's clang-cl compiler, like below:
|
||||
|
||||
path/to/configure CC="path/to/msvcc.sh -clang-cl" CXX="path/to/msvcc.sh -clang-cl" LD=link CPP="clang-cl -EP"
|
||||
|
||||
When building with MSVC under a MingW environment, you may need to
|
||||
remove the line in configure that sets 'fix_srcfile_path' to a 'cygpath'
|
||||
command. ('cygpath' is not present in MingW, and is not required when
|
||||
|
|
|
@ -68,7 +68,7 @@ extern "C" {
|
|||
|
||||
#ifndef LIBFFI_ASM
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
#define __attribute__(X)
|
||||
#endif
|
||||
|
||||
|
|
|
@ -63,11 +63,15 @@ do
|
|||
shift 1
|
||||
;;
|
||||
-m64)
|
||||
cl="cl" # "$MSVC/x86_amd64/cl"
|
||||
ml="ml64" # "$MSVC/x86_amd64/ml64"
|
||||
safeseh=
|
||||
shift 1
|
||||
;;
|
||||
-clang-cl)
|
||||
cl="clang-cl"
|
||||
safeseh=
|
||||
shift 1
|
||||
;;
|
||||
-O0)
|
||||
args="$args -Od"
|
||||
shift 1
|
||||
|
|
|
@ -45,23 +45,23 @@ class NameResolver
|
|||
*/
|
||||
bool appendPropertyReference(JSAtom *name) {
|
||||
if (IsIdentifier(name))
|
||||
return buf->append(".") && buf->append(name);
|
||||
return buf->append('.') && buf->append(name);
|
||||
|
||||
/* Quote the string as needed. */
|
||||
JSString *source = js_QuoteString(cx, name, '"');
|
||||
return source && buf->append("[") && buf->append(source) && buf->append("]");
|
||||
return source && buf->append('[') && buf->append(source) && buf->append(']');
|
||||
}
|
||||
|
||||
/* Append a number to buf. */
|
||||
bool appendNumber(double n) {
|
||||
char number[30];
|
||||
int digits = JS_snprintf(number, sizeof(number), "%g", n);
|
||||
return buf->appendInflated(number, digits);
|
||||
return buf->append(number, digits);
|
||||
}
|
||||
|
||||
/* Append "[<n>]" to buf, referencing a property named by a numeric literal. */
|
||||
bool appendNumericPropertyReference(double n) {
|
||||
return buf->append("[") && appendNumber(n) && buf->append("]");
|
||||
return buf->append("[") && appendNumber(n) && buf->append(']');
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -81,9 +81,9 @@ class NameResolver
|
|||
|
||||
case PNK_ELEM:
|
||||
return nameExpression(n->pn_left) &&
|
||||
buf->append("[") &&
|
||||
buf->append('[') &&
|
||||
nameExpression(n->pn_right) &&
|
||||
buf->append("]");
|
||||
buf->append(']');
|
||||
|
||||
case PNK_NUMBER:
|
||||
return appendNumber(n->pn_dval);
|
||||
|
@ -189,7 +189,7 @@ class NameResolver
|
|||
return true;
|
||||
}
|
||||
if (!buf.append(prefix) ||
|
||||
!buf.append("/") ||
|
||||
!buf.append('/') ||
|
||||
!buf.append(fun->displayAtom()))
|
||||
return false;
|
||||
retAtom.set(buf.finishAtom());
|
||||
|
@ -197,7 +197,7 @@ class NameResolver
|
|||
}
|
||||
|
||||
/* If a prefix is specified, then it is a form of namespace */
|
||||
if (prefix != nullptr && (!buf.append(prefix) || !buf.append("/")))
|
||||
if (prefix != nullptr && (!buf.append(prefix) || !buf.append('/')))
|
||||
return false;
|
||||
|
||||
/* Gather all nodes relevant to naming */
|
||||
|
@ -235,7 +235,7 @@ class NameResolver
|
|||
* Don't have consecutive '<' characters, and also don't start
|
||||
* with a '<' character.
|
||||
*/
|
||||
if (!buf.empty() && *(buf.end() - 1) != '<' && !buf.append("<"))
|
||||
if (!buf.empty() && buf.getChar(buf.length() - 1) != '<' && !buf.append('<'))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -245,7 +245,7 @@ class NameResolver
|
|||
* other namespace are rather considered as "contributing" to the outer
|
||||
* function, so give them a contribution symbol here.
|
||||
*/
|
||||
if (!buf.empty() && *(buf.end() - 1) == '/' && !buf.append("<"))
|
||||
if (!buf.empty() && buf.getChar(buf.length() - 1) == '/' && !buf.append('<'))
|
||||
return false;
|
||||
|
||||
if (buf.empty())
|
||||
|
|
|
@ -689,7 +689,7 @@ TokenStream::reportCompileErrorNumberVA(uint32_t offset, unsigned flags, unsigne
|
|||
|
||||
// Unicode and char versions of the window into the offending source
|
||||
// line, without final \n.
|
||||
err.report.uclinebuf = windowBuf.extractWellSized();
|
||||
err.report.uclinebuf = windowBuf.stealChars();
|
||||
if (!err.report.uclinebuf)
|
||||
return false;
|
||||
TwoByteChars tbchars(err.report.uclinebuf, windowLength);
|
||||
|
|
|
@ -576,7 +576,7 @@ AutoGCRooter::trace(JSTracer *trc)
|
|||
}
|
||||
|
||||
case JSONPARSER:
|
||||
static_cast<js::JSONParser *>(this)->trace(trc);
|
||||
static_cast<js::JSONParserBase *>(this)->trace(trc);
|
||||
return;
|
||||
|
||||
case CUSTOM:
|
||||
|
|
|
@ -97,12 +97,56 @@ assertThrowsValue(function() { f(8,2.4) }, 2.4+36);
|
|||
|
||||
assertEq(asmLink(asmCompile('glob', 'imp', USE_ASM + 'var identity=imp.identity; function g(x) { x=+x; return +identity(x) } return g'), null, imp)(13.37), 13.37);
|
||||
|
||||
// Test asm.js => ion paths
|
||||
setJitCompilerOption("ion.usecount.trigger", 20);
|
||||
function ffiInt(a,b,c,d,e,f,g,h,i,j) { return j+1 }
|
||||
var f = asmLink(asmCompile('glob', 'imp', USE_ASM + 'var ffi=imp.ffi; function f(i) { i=i|0; return ffi(i|0,(i+1)|0,(i+2)|0,(i+3)|0,(i+4)|0,(i+5)|0,(i+6)|0,(i+7)|0,(i+8)|0,(i+9)|0)|0 } return f'), null, {ffi:ffiInt});
|
||||
|
||||
// In registers on x64 and ARM, on the stack for x86
|
||||
function ffiIntFew(a,b,c,d) { return d+1 }
|
||||
var f = asmLink(asmCompile('glob', 'imp', USE_ASM + 'var ffi=imp.ffi; function f(i) { i=i|0; return ffi(i|0,(i+1)|0,(i+2)|0,(i+3)|0)|0 } return f'), null, {ffi:ffiIntFew});
|
||||
for (var i = 0; i < 40; i++)
|
||||
assertEq(f(i), i+4);
|
||||
|
||||
// Stack and registers for x64 and ARM, stack for x86
|
||||
function ffiIntMany(a,b,c,d,e,f,g,h,i,j) { return j+1 }
|
||||
var f = asmLink(asmCompile('glob', 'imp', USE_ASM + 'var ffi=imp.ffi; function f(i) { i=i|0; return ffi(i|0,(i+1)|0,(i+2)|0,(i+3)|0,(i+4)|0,(i+5)|0,(i+6)|0,(i+7)|0,(i+8)|0,(i+9)|0)|0 } return f'), null, {ffi:ffiIntMany});
|
||||
for (var i = 0; i < 40; i++)
|
||||
assertEq(f(i), i+10);
|
||||
function ffiDouble(a,b,c,d,e,f,g,h,i,j) { return j+1 }
|
||||
var f = asmLink(asmCompile('glob', 'imp', USE_ASM + 'var ffi=imp.ffi; function f(i) { i=+i; return +ffi(i,i+1.0,i+2.0,i+3.0,i+4.0,i+5.0,i+6.0,i+7.0,i+8.0,i+9.0) } return f'), null, {ffi:ffiDouble});
|
||||
|
||||
// In registers on x64 and ARM, on the stack for x86
|
||||
function ffiDoubleFew(a,b,c,d) { return d+1 }
|
||||
var f = asmLink(asmCompile('glob', 'imp', USE_ASM + 'var ffi=imp.ffi; function f(i) { i=+i; return +ffi(i,i+1.0,i+2.0,i+3.0) } return f'), null, {ffi:ffiDoubleFew});
|
||||
for (var i = 0; i < 40; i++)
|
||||
assertEq(f(i), i+4);
|
||||
|
||||
// Stack and registers for x64 and ARM, stack for x86
|
||||
function ffiDoubleMany(a,b,c,d,e,f,g,h,i,j) { return j+1 }
|
||||
var f = asmLink(asmCompile('glob', 'imp', USE_ASM + 'var ffi=imp.ffi; function f(i) { i=+i; return +ffi(i,i+1.0,i+2.0,i+3.0,i+4.0,i+5.0,i+6.0,i+7.0,i+8.0,i+9.0) } return f'), null, {ffi:ffiDoubleMany});
|
||||
for (var i = 0; i < 40; i++)
|
||||
assertEq(f(i), i+10);
|
||||
|
||||
// Test the throw path
|
||||
function ffiThrow(n) { if (n == 38) throw 'yolo'; }
|
||||
var f = asmLink(asmCompile('glob', 'imp', USE_ASM + 'var ffi=imp.ffi; function f(i) { i=i|0; ffi(i >> 0); } return f'), null, {ffi:ffiThrow});
|
||||
var i = 0;
|
||||
try {
|
||||
for (; i < 40; i++)
|
||||
f(i);
|
||||
throw 'assume unreachable';
|
||||
} catch (e) {
|
||||
assertEq(e, 'yolo');
|
||||
assertEq(i, 38);
|
||||
}
|
||||
|
||||
// OOL conversion paths
|
||||
var INT32_MAX = Math.pow(2, 31) - 1;
|
||||
function ffiOOLConvertInt(n) { if (n == 40) return INT32_MAX + 1; return 42; }
|
||||
var f = asmLink(asmCompile('glob', 'imp', USE_ASM + 'var ffi=imp.ffi; function f(i) { i=i|0; return ffi(i >> 0) | 0; } return f'), null, {ffi:ffiOOLConvertInt});
|
||||
for (var i = 0; i < 40; i++)
|
||||
assertEq(f(i), 42);
|
||||
assertEq(f(40), INT32_MAX + 1 | 0);
|
||||
|
||||
function ffiOOLConvertDouble(n) { if (n == 40) return {valueOf: function() { return 13.37 }}; return 42.5; }
|
||||
var f = asmLink(asmCompile('glob', 'imp', USE_ASM + 'var ffi=imp.ffi; function f(i) { i=i|0; return +ffi(i >> 0); } return f'), null, {ffi:ffiOOLConvertDouble});
|
||||
for (var i = 0; i < 40; i++)
|
||||
assertEq(f(i), 42.5);
|
||||
assertEq(f(40), 13.37);
|
||||
|
|
|
@ -6039,7 +6039,7 @@ LoadJSContextFromActivation(MacroAssembler &masm, Register activation, Register
|
|||
static void
|
||||
AssertStackAlignment(MacroAssembler &masm)
|
||||
{
|
||||
JS_ASSERT((AlignmentAtAsmJSPrologue + masm.framePushed()) % StackAlignment == 0);
|
||||
JS_ASSERT((AsmJSSizeOfRetAddr + masm.framePushed()) % StackAlignment == 0);
|
||||
#ifdef DEBUG
|
||||
Label ok;
|
||||
JS_ASSERT(IsPowerOfTwo(StackAlignment));
|
||||
|
@ -6064,7 +6064,7 @@ StackDecrementForCall(MacroAssembler &masm, unsigned bytesToPush)
|
|||
{
|
||||
// Include extra padding so that, after pushing the bytesToPush,
|
||||
// the stack is aligned for a call instruction.
|
||||
unsigned alreadyPushed = AlignmentAtAsmJSPrologue + masm.framePushed();
|
||||
unsigned alreadyPushed = AsmJSSizeOfRetAddr + masm.framePushed();
|
||||
return AlignBytes(alreadyPushed + bytesToPush, StackAlignment) - alreadyPushed;
|
||||
}
|
||||
|
||||
|
@ -6109,10 +6109,8 @@ GenerateEntry(ModuleCompiler &m, const AsmJSModule::ExportedFunction &exportedFu
|
|||
// PushRegsInMask(NonVolatileRegs).
|
||||
masm.setFramePushed(0);
|
||||
|
||||
// See AsmJSSizeOfRetAddr comment in Assembler-*.h.
|
||||
#if defined(JS_CODEGEN_ARM)
|
||||
// Push lr without incrementing masm.framePushed since this push is
|
||||
// accounted for by AlignmentAtAsmJSPrologue. The masm.ret at the end will
|
||||
// pop.
|
||||
masm.push(lr);
|
||||
#endif // JS_CODEGEN_ARM
|
||||
#if defined(JS_CODEGEN_MIPS)
|
||||
|
@ -6148,7 +6146,7 @@ GenerateEntry(ModuleCompiler &m, const AsmJSModule::ExportedFunction &exportedFu
|
|||
Register argv = ABIArgGenerator::NonArgReturnVolatileReg0;
|
||||
Register scratch = ABIArgGenerator::NonArgReturnVolatileReg1;
|
||||
#if defined(JS_CODEGEN_X86)
|
||||
masm.loadPtr(Address(StackPointer, NativeFrameSize + masm.framePushed()), argv);
|
||||
masm.loadPtr(Address(StackPointer, AsmJSSizeOfRetAddr + masm.framePushed()), argv);
|
||||
#else
|
||||
masm.movePtr(IntArgReg0, argv);
|
||||
#endif
|
||||
|
@ -6370,10 +6368,8 @@ GenerateFFIInterpreterExit(ModuleCompiler &m, const ModuleCompiler::ExitDescript
|
|||
m.setInterpExitOffset(exitIndex);
|
||||
masm.setFramePushed(0);
|
||||
|
||||
// See AsmJSSizeOfRetAddr comment in Assembler-*.h.
|
||||
#if defined(JS_CODEGEN_ARM)
|
||||
// Push lr without incrementing masm.framePushed since this push is
|
||||
// accounted for by AlignmentAtAsmJSPrologue. The masm.ret at the end will
|
||||
// pop.
|
||||
masm.push(lr);
|
||||
#endif
|
||||
#if defined(JS_CODEGEN_MIPS)
|
||||
|
@ -6397,7 +6393,7 @@ GenerateFFIInterpreterExit(ModuleCompiler &m, const ModuleCompiler::ExitDescript
|
|||
masm.reserveStack(stackDec);
|
||||
|
||||
// Fill the argument array.
|
||||
unsigned offsetToCallerStackArgs = AlignmentAtAsmJSPrologue + masm.framePushed();
|
||||
unsigned offsetToCallerStackArgs = AsmJSSizeOfRetAddr + masm.framePushed();
|
||||
Register scratch = ABIArgGenerator::NonArgReturnVolatileReg0;
|
||||
FillArgumentArray(m, exit.sig().args(), offsetToArgv, offsetToCallerStackArgs, scratch);
|
||||
|
||||
|
@ -6546,12 +6542,10 @@ GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit
|
|||
m.setIonExitOffset(exitIndex);
|
||||
masm.setFramePushed(0);
|
||||
|
||||
// See AsmJSSizeOfRetAddr comment in Assembler-*.h.
|
||||
#if defined(JS_CODEGEN_X64)
|
||||
masm.Push(HeapReg);
|
||||
#elif defined(JS_CODEGEN_ARM)
|
||||
// Push lr without incrementing masm.framePushed since this push is
|
||||
// accounted for by AlignmentAtAsmJSPrologue. The masm.ret at the end will
|
||||
// pop.
|
||||
masm.push(lr);
|
||||
|
||||
// The GlobalReg (r10) and HeapReg (r11) also need to be restored before
|
||||
|
@ -6627,7 +6621,7 @@ GenerateFFIIonExit(ModuleCompiler &m, const ModuleCompiler::ExitDescriptor &exit
|
|||
argOffset += sizeof(Value);
|
||||
|
||||
// 5. Fill the arguments
|
||||
unsigned offsetToCallerStackArgs = masm.framePushed() + NativeFrameSize;
|
||||
unsigned offsetToCallerStackArgs = masm.framePushed() + AsmJSSizeOfRetAddr;
|
||||
FillArgumentArray(m, exit.sig().args(), argOffset, offsetToCallerStackArgs, scratch);
|
||||
argOffset += exit.sig().args().length() * sizeof(Value);
|
||||
JS_ASSERT(argOffset == offsetToArgs + argBytes);
|
||||
|
|
|
@ -941,15 +941,15 @@ js::AsmJSModuleToString(JSContext *cx, HandleFunction fun, bool addParenToLambda
|
|||
return nullptr;
|
||||
|
||||
if (PropertyName *argName = module.globalArgumentName()) {
|
||||
if (!out.append(argName->chars(), argName->length()))
|
||||
if (!out.append(argName))
|
||||
return nullptr;
|
||||
}
|
||||
if (PropertyName *argName = module.importArgumentName()) {
|
||||
if (!out.append(", ") || !out.append(argName->chars(), argName->length()))
|
||||
if (!out.append(", ") || !out.append(argName))
|
||||
return nullptr;
|
||||
}
|
||||
if (PropertyName *argName = module.bufferArgumentName()) {
|
||||
if (!out.append(", ") || !out.append(argName->chars(), argName->length()))
|
||||
if (!out.append(", ") || !out.append(argName))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -965,7 +965,7 @@ js::AsmJSModuleToString(JSContext *cx, HandleFunction fun, bool addParenToLambda
|
|||
if (!AppendUseStrictSource(cx, fun, src, out))
|
||||
return nullptr;
|
||||
} else {
|
||||
if (!out.append(src->chars(), src->length()))
|
||||
if (!out.append(src))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -1048,7 +1048,7 @@ js::AsmJSFunctionToString(JSContext *cx, HandleFunction fun)
|
|||
Rooted<JSFlatString*> src(cx, source->substring(cx, begin, end));
|
||||
if (!src)
|
||||
return nullptr;
|
||||
if (!out.append(src->chars(), src->length()))
|
||||
if (!out.append(src))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -8706,7 +8706,7 @@ CodeGenerator::visitAsmJSCall(LAsmJSCall *ins)
|
|||
if (mir->spIncrement())
|
||||
masm.freeStack(mir->spIncrement());
|
||||
|
||||
JS_ASSERT((AlignmentAtAsmJSPrologue + masm.framePushed()) % StackAlignment == 0);
|
||||
JS_ASSERT((AsmJSSizeOfRetAddr + masm.framePushed()) % StackAlignment == 0);
|
||||
|
||||
#ifdef DEBUG
|
||||
Label ok;
|
||||
|
|
|
@ -316,6 +316,15 @@ class InlineList : protected InlineListNode<T>
|
|||
bool empty() const {
|
||||
return begin() == end();
|
||||
}
|
||||
void takeElements(InlineList &l) {
|
||||
MOZ_ASSERT(&l != this, "cannot takeElements from this");
|
||||
Node *lprev = l.prev;
|
||||
static_cast<Node *>(l.next)->prev = this;
|
||||
lprev->next = this->next;
|
||||
static_cast<Node *>(this->next)->prev = l.prev;
|
||||
this->next = l.next;
|
||||
l.clear();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче