Merge m-c to fx-team.
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"revision": "4f6313014c286e7940eb23dc8637395dc1eb0bd7",
|
||||
"revision": "abcc2f6a74c69d6ed28ea29681f86ef1f4fd90ba",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ def InvokeClWithDependencyGeneration(cmdline):
|
|||
cl = subprocess.Popen(cmdline, stdout=subprocess.PIPE)
|
||||
|
||||
mk = Makefile()
|
||||
rule = mk.create_rule(target)
|
||||
rule = mk.create_rule([target])
|
||||
rule.add_dependencies([normcase(source)])
|
||||
for line in cl.stdout:
|
||||
# cl -showIncludes prefixes every header with "Note: including file:"
|
||||
|
|
|
@ -43,7 +43,7 @@ public:
|
|||
: AudioNodeEngine(aNode)
|
||||
, mSource(nullptr)
|
||||
, mDestination(static_cast<AudioNodeStream*> (aDestination->Stream()))
|
||||
, mStart(0)
|
||||
, mStart(-1)
|
||||
, mStop(TRACK_TICKS_MAX)
|
||||
// Keep the default values in sync with OscillatorNode::OscillatorNode.
|
||||
, mFrequency(440.f)
|
||||
|
@ -245,6 +245,11 @@ public:
|
|||
MOZ_ASSERT(mSource == aStream, "Invalid source stream");
|
||||
|
||||
TrackTicks ticks = aStream->GetCurrentPosition();
|
||||
if (mStart == -1) {
|
||||
ComputeSilence(aOutput);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ticks + WEBAUDIO_BLOCK_SIZE < mStart) {
|
||||
// We're not playing yet.
|
||||
ComputeSilence(aOutput);
|
||||
|
|
|
@ -78,6 +78,7 @@ MOCHITEST_FILES := \
|
|||
test_offlineDestinationChannelCountLess.html \
|
||||
test_offlineDestinationChannelCountMore.html \
|
||||
test_oscillatorNode.html \
|
||||
test_oscillatorNodeStart.html \
|
||||
test_pannerNode.html \
|
||||
test_pannerNode_equalPower.html \
|
||||
test_periodicWave.html \
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test the OscillatorNode interface</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="webaudio.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(function() {
|
||||
|
||||
var context = new AudioContext();
|
||||
var osc = context.createOscillator();
|
||||
var sp = context.createScriptProcessor();
|
||||
|
||||
osc.connect(sp);
|
||||
|
||||
sp.onaudioprocess = function (e) {
|
||||
var input = e.inputBuffer.getChannelData(0);
|
||||
var isSilent = true;
|
||||
for (var i = 0; i < input.length; i++) {
|
||||
if (input[i] != 0.0) {
|
||||
isSilent = false;
|
||||
}
|
||||
}
|
||||
sp.onaudioprocess = null;
|
||||
ok(isSilent, "OscillatorNode should be silent before calling start.");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -9,5 +9,7 @@ load 570884.html
|
|||
# Plugin arch is going to change anyway with OOP content so skipping
|
||||
# this test for now is OK.
|
||||
skip-if(browserIsRemote||!haveTestPlugin||http.platform!="X11"||!testPluginIsOOP()) load 598862.html
|
||||
load 626602-1.html
|
||||
|
||||
# SkiaGL is causing a compositor hang here, disable temporarily while that gets resolved in bug 908363
|
||||
skip-if(Android) load 626602-1.html
|
||||
load 752340.html
|
||||
|
|
|
@ -33,6 +33,14 @@ LOCAL_INCLUDES = \
|
|||
-I$(topsrcdir)/content/events/src \
|
||||
$(NULL)
|
||||
|
||||
# TODO: Bug 908038, move this to moz.build
|
||||
WORKER_FILES := worker_buf.js \
|
||||
$(NULL)
|
||||
|
||||
INSTALL_TARGETS += WORKER
|
||||
|
||||
WORKER_DEST = $(FINAL_TARGET)/modules/workers
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
include $(topsrcdir)/ipc/chromium/chromium-config.mk
|
||||
|
||||
|
|
|
@ -321,7 +321,6 @@ NetworkManager.prototype = {
|
|||
state: i.state,
|
||||
type: i.type,
|
||||
name: i.name,
|
||||
dhcp: i.dhcp,
|
||||
ip: i.ip,
|
||||
netmask: i.netmask,
|
||||
broadcast: i.broadcast,
|
||||
|
@ -597,7 +596,7 @@ NetworkManager.prototype = {
|
|||
setDefaultRouteAndDNS: function setDefaultRouteAndDNS(oldInterface) {
|
||||
debug("Going to change route and DNS to " + this.active.name);
|
||||
let options = {
|
||||
cmd: this.active.dhcp ? "runDHCPAndSetDefaultRouteAndDNS" : "setDefaultRouteAndDNS",
|
||||
cmd: "setDefaultRouteAndDNS",
|
||||
ifname: this.active.name,
|
||||
oldIfname: (oldInterface && oldInterface != this.active) ? oldInterface.name : null,
|
||||
gateway_str: this.active.gateway,
|
||||
|
|
|
@ -3351,8 +3351,6 @@ RILNetworkInterface.prototype = {
|
|||
|
||||
name: null,
|
||||
|
||||
dhcp: false,
|
||||
|
||||
ip: null,
|
||||
|
||||
netmask: null,
|
||||
|
|
|
@ -250,21 +250,6 @@ function setDefaultRouteAndDNS(options) {
|
|||
libcutils.property_set("net.dnschange", (parseInt(dnschange, 10) + 1).toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Run DHCP and set default route and DNS servers for a given
|
||||
* network interface.
|
||||
*/
|
||||
function runDHCPAndSetDefaultRouteAndDNS(options) {
|
||||
let dhcp = libnetutils.dhcp_do_request(options.ifname);
|
||||
dhcp.ifname = options.ifname;
|
||||
dhcp.oldIfname = options.oldIfname;
|
||||
|
||||
//TODO this could be race-y... by the time we've finished the DHCP request
|
||||
// and are now fudging with the routes, another network interface may have
|
||||
// come online that's preferred...
|
||||
setDefaultRouteAndDNS(dhcp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove default route for given network interface.
|
||||
*/
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
/**
|
||||
* Information about networks that is exposed to network manager API consumers.
|
||||
*/
|
||||
[scriptable, uuid(d70b9d95-87d5-4ce9-aff7-4323dac79b07)]
|
||||
[scriptable, uuid(04fe5049-1ea8-4b4f-8c27-d23cd24611bb)]
|
||||
interface nsINetworkInterface : nsISupports
|
||||
{
|
||||
const long NETWORK_STATE_UNKNOWN = -1;
|
||||
|
@ -39,11 +39,6 @@ interface nsINetworkInterface : nsISupports
|
|||
*/
|
||||
readonly attribute DOMString name;
|
||||
|
||||
/**
|
||||
* Indicates whether DHCP should be run when the interface connects.
|
||||
*/
|
||||
readonly attribute boolean dhcp;
|
||||
|
||||
/**
|
||||
* IP Address
|
||||
*/
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
"use strict";
|
||||
|
||||
importScripts("ril_consts.js", "systemlibs.js");
|
||||
importScripts("resource://gre/modules/workers/require.js");
|
||||
|
||||
// set to true in ril_consts.js to see debug messages
|
||||
let DEBUG = DEBUG_WORKER;
|
||||
|
@ -56,7 +57,6 @@ const INT32_MAX = 2147483647;
|
|||
const UINT8_SIZE = 1;
|
||||
const UINT16_SIZE = 2;
|
||||
const UINT32_SIZE = 4;
|
||||
const PARCEL_SIZE_SIZE = UINT32_SIZE;
|
||||
|
||||
const PDU_HEX_OCTET_SIZE = 4;
|
||||
|
||||
|
@ -96,631 +96,7 @@ let RILQUIRKS_HAVE_QUERY_ICC_LOCK_RETRY_COUNT = libcutils.property_get("ro.moz.r
|
|||
// Marker object.
|
||||
let PENDING_NETWORK_TYPE = {};
|
||||
|
||||
/**
|
||||
* This object contains helpers buffering incoming data & deconstructing it
|
||||
* into parcels as well as buffering outgoing data & constructing parcels.
|
||||
* For that it maintains two buffers and corresponding uint8 views, indexes.
|
||||
*
|
||||
* The incoming buffer is a circular buffer where we store incoming data.
|
||||
* As soon as a complete parcel is received, it is processed right away, so
|
||||
* the buffer only needs to be large enough to hold one parcel.
|
||||
*
|
||||
* The outgoing buffer is to prepare outgoing parcels. The index is reset
|
||||
* every time a parcel is sent.
|
||||
*/
|
||||
let Buf = {
|
||||
|
||||
INCOMING_BUFFER_LENGTH: 1024,
|
||||
OUTGOING_BUFFER_LENGTH: 1024,
|
||||
|
||||
init: function init() {
|
||||
this.incomingBuffer = new ArrayBuffer(this.INCOMING_BUFFER_LENGTH);
|
||||
this.outgoingBuffer = new ArrayBuffer(this.OUTGOING_BUFFER_LENGTH);
|
||||
|
||||
this.incomingBytes = new Uint8Array(this.incomingBuffer);
|
||||
this.outgoingBytes = new Uint8Array(this.outgoingBuffer);
|
||||
|
||||
// Track where incoming data is read from and written to.
|
||||
this.incomingWriteIndex = 0;
|
||||
this.incomingReadIndex = 0;
|
||||
|
||||
// Leave room for the parcel size for outgoing parcels.
|
||||
this.outgoingIndex = PARCEL_SIZE_SIZE;
|
||||
|
||||
// How many bytes we've read for this parcel so far.
|
||||
this.readIncoming = 0;
|
||||
|
||||
// How many bytes available as parcel data.
|
||||
this.readAvailable = 0;
|
||||
|
||||
// Size of the incoming parcel. If this is zero, we're expecting a new
|
||||
// parcel.
|
||||
this.currentParcelSize = 0;
|
||||
|
||||
// This gets incremented each time we send out a parcel.
|
||||
this.token = 1;
|
||||
|
||||
// Maps tokens we send out with requests to the request type, so that
|
||||
// when we get a response parcel back, we know what request it was for.
|
||||
this.tokenRequestMap = {};
|
||||
|
||||
// This is the token of last solicited response.
|
||||
this.lastSolicitedToken = 0;
|
||||
|
||||
// Queue for storing outgoing override points
|
||||
this.outgoingBufferCalSizeQueue = [];
|
||||
},
|
||||
|
||||
/**
|
||||
* Mark current outgoingIndex as start point for calculation length of data
|
||||
* written to outgoingBuffer.
|
||||
* Mark can be nested for here uses queue to remember marks.
|
||||
*
|
||||
* @param writeFunction
|
||||
* Function to write data length into outgoingBuffer, this function is
|
||||
* also used to allocate buffer for data length.
|
||||
* Raw data size(in Uint8) is provided as parameter calling writeFunction.
|
||||
* If raw data size is not in proper unit for writing, user can adjust
|
||||
* the length value in writeFunction before writing.
|
||||
**/
|
||||
startCalOutgoingSize: function startCalOutgoingSize(writeFunction) {
|
||||
let sizeInfo = {index: this.outgoingIndex,
|
||||
write: writeFunction};
|
||||
|
||||
// Allocate buffer for data lemgtj.
|
||||
writeFunction.call(0);
|
||||
|
||||
// Get size of data length buffer for it is not counted into data size.
|
||||
sizeInfo.size = this.outgoingIndex - sizeInfo.index;
|
||||
|
||||
// Enqueue size calculation information.
|
||||
this.outgoingBufferCalSizeQueue.push(sizeInfo);
|
||||
},
|
||||
|
||||
/**
|
||||
* Calculate data length since last mark, and write it into mark position.
|
||||
**/
|
||||
stopCalOutgoingSize: function stopCalOutgoingSize() {
|
||||
let sizeInfo = this.outgoingBufferCalSizeQueue.pop();
|
||||
|
||||
// Remember current outgoingIndex.
|
||||
let currentOutgoingIndex = this.outgoingIndex;
|
||||
// Calculate data length, in uint8.
|
||||
let writeSize = this.outgoingIndex - sizeInfo.index - sizeInfo.size;
|
||||
|
||||
// Write data length to mark, use same function for allocating buffer to make
|
||||
// sure there is no buffer overloading.
|
||||
this.outgoingIndex = sizeInfo.index;
|
||||
sizeInfo.write(writeSize);
|
||||
|
||||
// Restore outgoingIndex.
|
||||
this.outgoingIndex = currentOutgoingIndex;
|
||||
},
|
||||
|
||||
/**
|
||||
* Grow the incoming buffer.
|
||||
*
|
||||
* @param min_size
|
||||
* Minimum new size. The actual new size will be the the smallest
|
||||
* power of 2 that's larger than this number.
|
||||
*/
|
||||
growIncomingBuffer: function growIncomingBuffer(min_size) {
|
||||
if (DEBUG) {
|
||||
debug("Current buffer of " + this.INCOMING_BUFFER_LENGTH +
|
||||
" can't handle incoming " + min_size + " bytes.");
|
||||
}
|
||||
let oldBytes = this.incomingBytes;
|
||||
this.INCOMING_BUFFER_LENGTH =
|
||||
2 << Math.floor(Math.log(min_size)/Math.log(2));
|
||||
if (DEBUG) debug("New incoming buffer size: " + this.INCOMING_BUFFER_LENGTH);
|
||||
this.incomingBuffer = new ArrayBuffer(this.INCOMING_BUFFER_LENGTH);
|
||||
this.incomingBytes = new Uint8Array(this.incomingBuffer);
|
||||
if (this.incomingReadIndex <= this.incomingWriteIndex) {
|
||||
// Read and write index are in natural order, so we can just copy
|
||||
// the old buffer over to the bigger one without having to worry
|
||||
// about the indexes.
|
||||
this.incomingBytes.set(oldBytes, 0);
|
||||
} else {
|
||||
// The write index has wrapped around but the read index hasn't yet.
|
||||
// Write whatever the read index has left to read until it would
|
||||
// circle around to the beginning of the new buffer, and the rest
|
||||
// behind that.
|
||||
let head = oldBytes.subarray(this.incomingReadIndex);
|
||||
let tail = oldBytes.subarray(0, this.incomingReadIndex);
|
||||
this.incomingBytes.set(head, 0);
|
||||
this.incomingBytes.set(tail, head.length);
|
||||
this.incomingReadIndex = 0;
|
||||
this.incomingWriteIndex += head.length;
|
||||
}
|
||||
if (DEBUG) {
|
||||
debug("New incoming buffer size is " + this.INCOMING_BUFFER_LENGTH);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Grow the outgoing buffer.
|
||||
*
|
||||
* @param min_size
|
||||
* Minimum new size. The actual new size will be the the smallest
|
||||
* power of 2 that's larger than this number.
|
||||
*/
|
||||
growOutgoingBuffer: function growOutgoingBuffer(min_size) {
|
||||
if (DEBUG) {
|
||||
debug("Current buffer of " + this.OUTGOING_BUFFER_LENGTH +
|
||||
" is too small.");
|
||||
}
|
||||
let oldBytes = this.outgoingBytes;
|
||||
this.OUTGOING_BUFFER_LENGTH =
|
||||
2 << Math.floor(Math.log(min_size)/Math.log(2));
|
||||
this.outgoingBuffer = new ArrayBuffer(this.OUTGOING_BUFFER_LENGTH);
|
||||
this.outgoingBytes = new Uint8Array(this.outgoingBuffer);
|
||||
this.outgoingBytes.set(oldBytes, 0);
|
||||
if (DEBUG) {
|
||||
debug("New outgoing buffer size is " + this.OUTGOING_BUFFER_LENGTH);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Functions for reading data from the incoming buffer.
|
||||
*
|
||||
* These are all little endian, apart from readParcelSize();
|
||||
*/
|
||||
|
||||
/**
|
||||
* Ensure position specified is readable.
|
||||
*
|
||||
* @param index
|
||||
* Data position in incoming parcel, valid from 0 to
|
||||
* this.currentParcelSize.
|
||||
*/
|
||||
ensureIncomingAvailable: function ensureIncomingAvailable(index) {
|
||||
if (index >= this.currentParcelSize) {
|
||||
throw new Error("Trying to read data beyond the parcel end!");
|
||||
} else if (index < 0) {
|
||||
throw new Error("Trying to read data before the parcel begin!");
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Seek in current incoming parcel.
|
||||
*
|
||||
* @param offset
|
||||
* Seek offset in relative to current position.
|
||||
*/
|
||||
seekIncoming: function seekIncoming(offset) {
|
||||
// Translate to 0..currentParcelSize
|
||||
let cur = this.currentParcelSize - this.readAvailable;
|
||||
|
||||
let newIndex = cur + offset;
|
||||
this.ensureIncomingAvailable(newIndex);
|
||||
|
||||
// ... incomingReadIndex -->|
|
||||
// 0 new cur currentParcelSize
|
||||
// |================|=======|===================|
|
||||
// |<-- cur -->|<- readAvailable ->|
|
||||
// |<-- newIndex -->|<-- new readAvailable -->|
|
||||
this.readAvailable = this.currentParcelSize - newIndex;
|
||||
|
||||
// Translate back:
|
||||
if (this.incomingReadIndex < cur) {
|
||||
// The incomingReadIndex is wrapped.
|
||||
newIndex += this.INCOMING_BUFFER_LENGTH;
|
||||
}
|
||||
newIndex += (this.incomingReadIndex - cur);
|
||||
newIndex %= this.INCOMING_BUFFER_LENGTH;
|
||||
this.incomingReadIndex = newIndex;
|
||||
},
|
||||
|
||||
readUint8Unchecked: function readUint8Unchecked() {
|
||||
let value = this.incomingBytes[this.incomingReadIndex];
|
||||
this.incomingReadIndex = (this.incomingReadIndex + 1) %
|
||||
this.INCOMING_BUFFER_LENGTH;
|
||||
return value;
|
||||
},
|
||||
|
||||
readUint8: function readUint8() {
|
||||
// Translate to 0..currentParcelSize
|
||||
let cur = this.currentParcelSize - this.readAvailable;
|
||||
this.ensureIncomingAvailable(cur);
|
||||
|
||||
this.readAvailable--;
|
||||
return this.readUint8Unchecked();
|
||||
},
|
||||
|
||||
readUint8Array: function readUint8Array(length) {
|
||||
// Translate to 0..currentParcelSize
|
||||
let last = this.currentParcelSize - this.readAvailable;
|
||||
last += (length - 1);
|
||||
this.ensureIncomingAvailable(last);
|
||||
|
||||
let array = new Uint8Array(length);
|
||||
for (let i = 0; i < length; i++) {
|
||||
array[i] = this.readUint8Unchecked();
|
||||
}
|
||||
|
||||
this.readAvailable -= length;
|
||||
return array;
|
||||
},
|
||||
|
||||
readUint16: function readUint16() {
|
||||
return this.readUint8() | this.readUint8() << 8;
|
||||
},
|
||||
|
||||
readUint32: function readUint32() {
|
||||
return this.readUint8() | this.readUint8() << 8 |
|
||||
this.readUint8() << 16 | this.readUint8() << 24;
|
||||
},
|
||||
|
||||
readUint32List: function readUint32List() {
|
||||
let length = this.readUint32();
|
||||
let ints = [];
|
||||
for (let i = 0; i < length; i++) {
|
||||
ints.push(this.readUint32());
|
||||
}
|
||||
return ints;
|
||||
},
|
||||
|
||||
readString: function readString() {
|
||||
let string_len = this.readUint32();
|
||||
if (string_len < 0 || string_len >= INT32_MAX) {
|
||||
return null;
|
||||
}
|
||||
let s = "";
|
||||
for (let i = 0; i < string_len; i++) {
|
||||
s += String.fromCharCode(this.readUint16());
|
||||
}
|
||||
// Strings are \0\0 delimited, but that isn't part of the length. And
|
||||
// if the string length is even, the delimiter is two characters wide.
|
||||
// It's insane, I know.
|
||||
this.readStringDelimiter(string_len);
|
||||
return s;
|
||||
},
|
||||
|
||||
readStringList: function readStringList() {
|
||||
let num_strings = this.readUint32();
|
||||
let strings = [];
|
||||
for (let i = 0; i < num_strings; i++) {
|
||||
strings.push(this.readString());
|
||||
}
|
||||
return strings;
|
||||
},
|
||||
|
||||
readStringDelimiter: function readStringDelimiter(length) {
|
||||
let delimiter = this.readUint16();
|
||||
if (!(length & 1)) {
|
||||
delimiter |= this.readUint16();
|
||||
}
|
||||
if (DEBUG) {
|
||||
if (delimiter !== 0) {
|
||||
debug("Something's wrong, found string delimiter: " + delimiter);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
readParcelSize: function readParcelSize() {
|
||||
return this.readUint8Unchecked() << 24 |
|
||||
this.readUint8Unchecked() << 16 |
|
||||
this.readUint8Unchecked() << 8 |
|
||||
this.readUint8Unchecked();
|
||||
},
|
||||
|
||||
/**
|
||||
* Functions for writing data to the outgoing buffer.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Ensure position specified is writable.
|
||||
*
|
||||
* @param index
|
||||
* Data position in outgoing parcel, valid from 0 to
|
||||
* this.OUTGOING_BUFFER_LENGTH.
|
||||
*/
|
||||
ensureOutgoingAvailable: function ensureOutgoingAvailable(index) {
|
||||
if (index >= this.OUTGOING_BUFFER_LENGTH) {
|
||||
this.growOutgoingBuffer(index + 1);
|
||||
}
|
||||
},
|
||||
|
||||
writeUint8: function writeUint8(value) {
|
||||
this.ensureOutgoingAvailable(this.outgoingIndex);
|
||||
|
||||
this.outgoingBytes[this.outgoingIndex] = value;
|
||||
this.outgoingIndex++;
|
||||
},
|
||||
|
||||
writeUint16: function writeUint16(value) {
|
||||
this.writeUint8(value & 0xff);
|
||||
this.writeUint8((value >> 8) & 0xff);
|
||||
},
|
||||
|
||||
writeUint32: function writeUint32(value) {
|
||||
this.writeUint8(value & 0xff);
|
||||
this.writeUint8((value >> 8) & 0xff);
|
||||
this.writeUint8((value >> 16) & 0xff);
|
||||
this.writeUint8((value >> 24) & 0xff);
|
||||
},
|
||||
|
||||
writeString: function writeString(value) {
|
||||
if (value == null) {
|
||||
this.writeUint32(-1);
|
||||
return;
|
||||
}
|
||||
this.writeUint32(value.length);
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
this.writeUint16(value.charCodeAt(i));
|
||||
}
|
||||
// Strings are \0\0 delimited, but that isn't part of the length. And
|
||||
// if the string length is even, the delimiter is two characters wide.
|
||||
// It's insane, I know.
|
||||
this.writeStringDelimiter(value.length);
|
||||
},
|
||||
|
||||
writeStringList: function writeStringList(strings) {
|
||||
this.writeUint32(strings.length);
|
||||
for (let i = 0; i < strings.length; i++) {
|
||||
this.writeString(strings[i]);
|
||||
}
|
||||
},
|
||||
|
||||
writeStringDelimiter: function writeStringDelimiter(length) {
|
||||
this.writeUint16(0);
|
||||
if (!(length & 1)) {
|
||||
this.writeUint16(0);
|
||||
}
|
||||
},
|
||||
|
||||
writeParcelSize: function writeParcelSize(value) {
|
||||
/**
|
||||
* Parcel size will always be the first thing in the parcel byte
|
||||
* array, but the last thing written. Store the current index off
|
||||
* to a temporary to be reset after we write the size.
|
||||
*/
|
||||
let currentIndex = this.outgoingIndex;
|
||||
this.outgoingIndex = 0;
|
||||
this.writeUint8((value >> 24) & 0xff);
|
||||
this.writeUint8((value >> 16) & 0xff);
|
||||
this.writeUint8((value >> 8) & 0xff);
|
||||
this.writeUint8(value & 0xff);
|
||||
this.outgoingIndex = currentIndex;
|
||||
},
|
||||
|
||||
copyIncomingToOutgoing: function copyIncomingToOutgoing(length) {
|
||||
if (!length || (length < 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let translatedReadIndexEnd = this.currentParcelSize - this.readAvailable + length - 1;
|
||||
this.ensureIncomingAvailable(translatedReadIndexEnd);
|
||||
|
||||
let translatedWriteIndexEnd = this.outgoingIndex + length - 1;
|
||||
this.ensureOutgoingAvailable(translatedWriteIndexEnd);
|
||||
|
||||
let newIncomingReadIndex = this.incomingReadIndex + length;
|
||||
if (newIncomingReadIndex < this.INCOMING_BUFFER_LENGTH) {
|
||||
// Reading won't cause wrapping, go ahead with builtin copy.
|
||||
this.outgoingBytes.set(this.incomingBytes.subarray(this.incomingReadIndex, newIncomingReadIndex),
|
||||
this.outgoingIndex);
|
||||
} else {
|
||||
// Not so lucky.
|
||||
newIncomingReadIndex %= this.INCOMING_BUFFER_LENGTH;
|
||||
this.outgoingBytes.set(this.incomingBytes.subarray(this.incomingReadIndex, this.INCOMING_BUFFER_LENGTH),
|
||||
this.outgoingIndex);
|
||||
if (newIncomingReadIndex) {
|
||||
let firstPartLength = this.INCOMING_BUFFER_LENGTH - this.incomingReadIndex;
|
||||
this.outgoingBytes.set(this.incomingBytes.subarray(0, newIncomingReadIndex),
|
||||
this.outgoingIndex + firstPartLength);
|
||||
}
|
||||
}
|
||||
|
||||
this.incomingReadIndex = newIncomingReadIndex;
|
||||
this.readAvailable -= length;
|
||||
this.outgoingIndex += length;
|
||||
},
|
||||
|
||||
/**
|
||||
* Parcel management
|
||||
*/
|
||||
|
||||
/**
|
||||
* Write incoming data to the circular buffer.
|
||||
*
|
||||
* @param incoming
|
||||
* Uint8Array containing the incoming data.
|
||||
*/
|
||||
writeToIncoming: function writeToIncoming(incoming) {
|
||||
// We don't have to worry about the head catching the tail since
|
||||
// we process any backlog in parcels immediately, before writing
|
||||
// new data to the buffer. So the only edge case we need to handle
|
||||
// is when the incoming data is larger than the buffer size.
|
||||
let minMustAvailableSize = incoming.length + this.readIncoming;
|
||||
if (minMustAvailableSize > this.INCOMING_BUFFER_LENGTH) {
|
||||
this.growIncomingBuffer(minMustAvailableSize);
|
||||
}
|
||||
|
||||
// We can let the typed arrays do the copying if the incoming data won't
|
||||
// wrap around the edges of the circular buffer.
|
||||
let remaining = this.INCOMING_BUFFER_LENGTH - this.incomingWriteIndex;
|
||||
if (remaining >= incoming.length) {
|
||||
this.incomingBytes.set(incoming, this.incomingWriteIndex);
|
||||
} else {
|
||||
// The incoming data would wrap around it.
|
||||
let head = incoming.subarray(0, remaining);
|
||||
let tail = incoming.subarray(remaining);
|
||||
this.incomingBytes.set(head, this.incomingWriteIndex);
|
||||
this.incomingBytes.set(tail, 0);
|
||||
}
|
||||
this.incomingWriteIndex = (this.incomingWriteIndex + incoming.length) %
|
||||
this.INCOMING_BUFFER_LENGTH;
|
||||
},
|
||||
|
||||
/**
|
||||
* Process incoming data.
|
||||
*
|
||||
* @param incoming
|
||||
* Uint8Array containing the incoming data.
|
||||
*/
|
||||
processIncoming: function processIncoming(incoming) {
|
||||
if (DEBUG) {
|
||||
debug("Received " + incoming.length + " bytes.");
|
||||
debug("Already read " + this.readIncoming);
|
||||
}
|
||||
|
||||
this.writeToIncoming(incoming);
|
||||
this.readIncoming += incoming.length;
|
||||
while (true) {
|
||||
if (!this.currentParcelSize) {
|
||||
// We're expecting a new parcel.
|
||||
if (this.readIncoming < PARCEL_SIZE_SIZE) {
|
||||
// We don't know how big the next parcel is going to be, need more
|
||||
// data.
|
||||
if (DEBUG) debug("Next parcel size unknown, going to sleep.");
|
||||
return;
|
||||
}
|
||||
this.currentParcelSize = this.readParcelSize();
|
||||
if (DEBUG) debug("New incoming parcel of size " +
|
||||
this.currentParcelSize);
|
||||
// The size itself is not included in the size.
|
||||
this.readIncoming -= PARCEL_SIZE_SIZE;
|
||||
}
|
||||
|
||||
if (this.readIncoming < this.currentParcelSize) {
|
||||
// We haven't read enough yet in order to be able to process a parcel.
|
||||
if (DEBUG) debug("Read " + this.readIncoming + ", but parcel size is "
|
||||
+ this.currentParcelSize + ". Going to sleep.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Alright, we have enough data to process at least one whole parcel.
|
||||
// Let's do that.
|
||||
let expectedAfterIndex = (this.incomingReadIndex + this.currentParcelSize)
|
||||
% this.INCOMING_BUFFER_LENGTH;
|
||||
|
||||
if (DEBUG) {
|
||||
let parcel;
|
||||
if (expectedAfterIndex < this.incomingReadIndex) {
|
||||
let head = this.incomingBytes.subarray(this.incomingReadIndex);
|
||||
let tail = this.incomingBytes.subarray(0, expectedAfterIndex);
|
||||
parcel = Array.slice(head).concat(Array.slice(tail));
|
||||
} else {
|
||||
parcel = Array.slice(this.incomingBytes.subarray(
|
||||
this.incomingReadIndex, expectedAfterIndex));
|
||||
}
|
||||
debug("Parcel (size " + this.currentParcelSize + "): " + parcel);
|
||||
}
|
||||
|
||||
if (DEBUG) debug("We have at least one complete parcel.");
|
||||
try {
|
||||
this.readAvailable = this.currentParcelSize;
|
||||
this.processParcel();
|
||||
} catch (ex) {
|
||||
if (DEBUG) debug("Parcel handling threw " + ex + "\n" + ex.stack);
|
||||
}
|
||||
|
||||
// Ensure that the whole parcel was consumed.
|
||||
if (this.incomingReadIndex != expectedAfterIndex) {
|
||||
if (DEBUG) {
|
||||
debug("Parcel handler didn't consume whole parcel, " +
|
||||
Math.abs(expectedAfterIndex - this.incomingReadIndex) +
|
||||
" bytes left over");
|
||||
}
|
||||
this.incomingReadIndex = expectedAfterIndex;
|
||||
}
|
||||
this.readIncoming -= this.currentParcelSize;
|
||||
this.readAvailable = 0;
|
||||
this.currentParcelSize = 0;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Process one parcel.
|
||||
*/
|
||||
processParcel: function processParcel() {
|
||||
let response_type = this.readUint32();
|
||||
|
||||
let request_type, options;
|
||||
if (response_type == RESPONSE_TYPE_SOLICITED) {
|
||||
let token = this.readUint32();
|
||||
let error = this.readUint32();
|
||||
|
||||
options = this.tokenRequestMap[token];
|
||||
if (!options) {
|
||||
if (DEBUG) {
|
||||
debug("Suspicious uninvited request found: " + token + ". Ignored!");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
delete this.tokenRequestMap[token];
|
||||
request_type = options.rilRequestType;
|
||||
|
||||
options.rilRequestError = error;
|
||||
if (DEBUG) {
|
||||
debug("Solicited response for request type " + request_type +
|
||||
", token " + token + ", error " + error);
|
||||
}
|
||||
} else if (response_type == RESPONSE_TYPE_UNSOLICITED) {
|
||||
request_type = this.readUint32();
|
||||
if (DEBUG) debug("Unsolicited response for request type " + request_type);
|
||||
} else {
|
||||
if (DEBUG) debug("Unknown response type: " + response_type);
|
||||
return;
|
||||
}
|
||||
|
||||
RIL.handleParcel(request_type, this.readAvailable, options);
|
||||
},
|
||||
|
||||
/**
|
||||
* Start a new outgoing parcel.
|
||||
*
|
||||
* @param type
|
||||
* Integer specifying the request type.
|
||||
* @param options [optional]
|
||||
* Object containing information about the request, e.g. the
|
||||
* original main thread message object that led to the RIL request.
|
||||
*/
|
||||
newParcel: function newParcel(type, options) {
|
||||
if (DEBUG) debug("New outgoing parcel of type " + type);
|
||||
|
||||
// We're going to leave room for the parcel size at the beginning.
|
||||
this.outgoingIndex = PARCEL_SIZE_SIZE;
|
||||
this.writeUint32(type);
|
||||
let token = this.token;
|
||||
this.writeUint32(token);
|
||||
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
options.rilRequestType = type;
|
||||
options.rilRequestError = null;
|
||||
this.tokenRequestMap[token] = options;
|
||||
this.token++;
|
||||
return token;
|
||||
},
|
||||
|
||||
/**
|
||||
* Communicate with the RIL IPC thread.
|
||||
*/
|
||||
sendParcel: function sendParcel() {
|
||||
// Compute the size of the parcel and write it to the front of the parcel
|
||||
// where we left room for it. Note that he parcel size does not include
|
||||
// the size itself.
|
||||
let parcelSize = this.outgoingIndex - PARCEL_SIZE_SIZE;
|
||||
this.writeParcelSize(parcelSize);
|
||||
|
||||
// This assumes that postRILMessage will make a copy of the ArrayBufferView
|
||||
// right away!
|
||||
let parcel = this.outgoingBytes.subarray(0, this.outgoingIndex);
|
||||
if (DEBUG) debug("Outgoing parcel: " + Array.slice(parcel));
|
||||
postRILMessage(CLIENT_ID, parcel);
|
||||
this.outgoingIndex = PARCEL_SIZE_SIZE;
|
||||
},
|
||||
|
||||
simpleRequest: function simpleRequest(type, options) {
|
||||
this.newParcel(type, options);
|
||||
this.sendParcel();
|
||||
}
|
||||
};
|
||||
|
||||
let Buf = require("resource://gre/modules/workers/worker_buf.js");
|
||||
|
||||
/**
|
||||
* The RIL state machine.
|
||||
|
@ -4468,7 +3844,7 @@ let RIL = {
|
|||
};
|
||||
Buf.newParcel(REQUEST_STK_SEND_ENVELOPE_WITH_STATUS, options);
|
||||
|
||||
Buf.seekIncoming(-1 * (Buf.currentParcelSize - Buf.readAvailable
|
||||
Buf.seekIncoming(-1 * (Buf.getCurrentParcelSize() - Buf.getReadAvailable()
|
||||
- 2 * UINT32_SIZE)); // Skip response_type & request_type.
|
||||
let messageStringLength = Buf.readUint32(); // In semi-octets
|
||||
let smscLength = GsmPDUHelper.readHexOctet(); // In octets, inclusive of TOA
|
||||
|
@ -4577,7 +3953,7 @@ let RIL = {
|
|||
// Write EFsms Status
|
||||
Buf.writeUint32(EFSMS_STATUS_FREE);
|
||||
|
||||
Buf.seekIncoming(-1 * (Buf.currentParcelSize - Buf.readAvailable
|
||||
Buf.seekIncoming(-1 * (Buf.getCurrentParcelSize() - Buf.getReadAvailable()
|
||||
- 2 * UINT32_SIZE)); // Skip response_type & request_type.
|
||||
let messageStringLength = Buf.readUint32(); // In semi-octets
|
||||
let smscLength = GsmPDUHelper.readHexOctet(); // In octets, inclusive of TOA
|
||||
|
@ -4602,7 +3978,7 @@ let RIL = {
|
|||
GsmPDUHelper.writeHexOctet(smscLength);
|
||||
// Write TOA & SMSC Address
|
||||
if (smscLength) {
|
||||
Buf.seekIncoming(-1 * (Buf.currentParcelSize - Buf.readAvailable
|
||||
Buf.seekIncoming(-1 * (Buf.getCurrentParcelSize() - Buf.getReadAvailable()
|
||||
- 2 * UINT32_SIZE // Skip response_type, request_type.
|
||||
- 2 * PDU_HEX_OCTET_SIZE)); // Skip messageStringLength & smscLength.
|
||||
Buf.copyIncomingToOutgoing(PDU_HEX_OCTET_SIZE * smscLength);
|
||||
|
@ -5851,8 +5227,9 @@ RIL[REQUEST_SET_CALL_WAITING] = function REQUEST_SET_CALL_WAITING(length, option
|
|||
RIL[REQUEST_SMS_ACKNOWLEDGE] = null;
|
||||
RIL[REQUEST_GET_IMEI] = function REQUEST_GET_IMEI(length, options) {
|
||||
this.IMEI = Buf.readString();
|
||||
let rilMessageType = options.rilMessageType;
|
||||
// So far we only send the IMEI back to chrome if it was requested via MMI.
|
||||
if (options.rilMessageType !== "sendMMI") {
|
||||
if (rilMessageType !== "sendMMI") {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -7958,7 +7335,7 @@ let GsmPDUHelper = {
|
|||
// Because each PDU octet is converted to two UCS2 char2, we should always
|
||||
// get even messageStringLength in this#_processReceivedSms(). So, we'll
|
||||
// always need two delimitors at the end.
|
||||
if (Buf.readAvailable <= 4) {
|
||||
if (Buf.getReadAvailable() <= 4) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -13388,6 +12765,9 @@ let RuimRecordHelper = {
|
|||
// Initialize buffers. This is a separate function so that unit tests can
|
||||
// re-initialize the buffers at will.
|
||||
Buf.init();
|
||||
Buf.setOutputStream(function (parcel) {
|
||||
postRILMessage(CLIENT_ID, parcel);
|
||||
});
|
||||
|
||||
function onRILMessage(data) {
|
||||
Buf.processIncoming(data);
|
||||
|
|
|
@ -105,6 +105,7 @@ class ResourceUriFileReader:
|
|||
'ril_worker.js': 'modules/ril_worker.js',
|
||||
'ril_consts.js': 'modules/ril_consts.js',
|
||||
'systemlibs.js': 'modules/systemlibs.js',
|
||||
'worker_buf.js': 'modules/workers/worker_buf.js',
|
||||
}
|
||||
|
||||
CODE_OPEN_CHANNEL_BY_URI = '''
|
||||
|
@ -356,3 +357,6 @@ class TestRILCodeQuality(MarionetteTestCase):
|
|||
|
||||
def test_ril_consts(self):
|
||||
self._check('ril_consts.js')
|
||||
|
||||
def test_worker_buf(self):
|
||||
self._check('worker_buf.js')
|
||||
|
|
|
@ -0,0 +1,676 @@
|
|||
/* 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/. */
|
||||
|
||||
const INT32_MAX = 2147483647;
|
||||
const UINT8_SIZE = 1;
|
||||
const UINT16_SIZE = 2;
|
||||
const UINT32_SIZE = 4;
|
||||
const PARCEL_SIZE_SIZE = UINT32_SIZE;
|
||||
|
||||
/**
|
||||
* This object contains helpers buffering incoming data & deconstructing it
|
||||
* into parcels as well as buffering outgoing data & constructing parcels.
|
||||
* For that it maintains two buffers and corresponding uint8 views, indexes.
|
||||
*
|
||||
* The incoming buffer is a circular buffer where we store incoming data.
|
||||
* As soon as a complete parcel is received, it is processed right away, so
|
||||
* the buffer only needs to be large enough to hold one parcel.
|
||||
*
|
||||
* The outgoing buffer is to prepare outgoing parcels. The index is reset
|
||||
* every time a parcel is sent.
|
||||
*/
|
||||
|
||||
let mIncomingBufferLength = 1024;
|
||||
let mOutgoingBufferLength = 1024;
|
||||
let mIncomingBuffer, mOutgoingBuffer, mIncomingBytes, mOutgoingBytes,
|
||||
mIncomingWriteIndex, mIncomingReadIndex, mOutgoingIndex, mReadIncoming,
|
||||
mReadAvailable, mCurrentParcelSize, mToken, mTokenRequestMap,
|
||||
mLasSolicitedToken, mOutgoingBufferCalSizeQueue, mOutputStream;
|
||||
|
||||
function init() {
|
||||
mIncomingBuffer = new ArrayBuffer(mIncomingBufferLength);
|
||||
mOutgoingBuffer = new ArrayBuffer(mOutgoingBufferLength);
|
||||
|
||||
mIncomingBytes = new Uint8Array(mIncomingBuffer);
|
||||
mOutgoingBytes = new Uint8Array(mOutgoingBuffer);
|
||||
|
||||
// Track where incoming data is read from and written to.
|
||||
mIncomingWriteIndex = 0;
|
||||
mIncomingReadIndex = 0;
|
||||
|
||||
// Leave room for the parcel size for outgoing parcels.
|
||||
mOutgoingIndex = PARCEL_SIZE_SIZE;
|
||||
|
||||
// How many bytes we've read for this parcel so far.
|
||||
mReadIncoming = 0;
|
||||
|
||||
// How many bytes available as parcel data.
|
||||
mReadAvailable = 0;
|
||||
|
||||
// Size of the incoming parcel. If this is zero, we're expecting a new
|
||||
// parcel.
|
||||
mCurrentParcelSize = 0;
|
||||
|
||||
// This gets incremented each time we send out a parcel.
|
||||
mToken = 1;
|
||||
|
||||
// Maps tokens we send out with requests to the request type, so that
|
||||
// when we get a response parcel back, we know what request it was for.
|
||||
mTokenRequestMap = {};
|
||||
|
||||
// This is the token of last solicited response.
|
||||
mLasSolicitedToken = 0;
|
||||
|
||||
// Queue for storing outgoing override points
|
||||
mOutgoingBufferCalSizeQueue = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark current mOutgoingIndex as start point for calculation length of data
|
||||
* written to mOutgoingBuffer.
|
||||
* Mark can be nested for here uses queue to remember marks.
|
||||
*
|
||||
* @param writeFunction
|
||||
* Function to write data length into mOutgoingBuffer, this function is
|
||||
* also used to allocate buffer for data length.
|
||||
* Raw data size(in Uint8) is provided as parameter calling writeFunction.
|
||||
* If raw data size is not in proper unit for writing, user can adjust
|
||||
* the length value in writeFunction before writing.
|
||||
**/
|
||||
function startCalOutgoingSize(writeFunction) {
|
||||
let sizeInfo = {index: mOutgoingIndex,
|
||||
write: writeFunction};
|
||||
|
||||
// Allocate buffer for data lemgtj.
|
||||
writeFunction.call(0);
|
||||
|
||||
// Get size of data length buffer for it is not counted into data size.
|
||||
sizeInfo.size = mOutgoingIndex - sizeInfo.index;
|
||||
|
||||
// Enqueue size calculation information.
|
||||
mOutgoingBufferCalSizeQueue.push(sizeInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate data length since last mark, and write it into mark position.
|
||||
**/
|
||||
function stopCalOutgoingSize() {
|
||||
let sizeInfo = mOutgoingBufferCalSizeQueue.pop();
|
||||
|
||||
// Remember current mOutgoingIndex.
|
||||
let currentOutgoingIndex = mOutgoingIndex;
|
||||
// Calculate data length, in uint8.
|
||||
let writeSize = mOutgoingIndex - sizeInfo.index - sizeInfo.size;
|
||||
|
||||
// Write data length to mark, use same function for allocating buffer to make
|
||||
// sure there is no buffer overloading.
|
||||
mOutgoingIndex = sizeInfo.index;
|
||||
sizeInfo.write(writeSize);
|
||||
|
||||
// Restore mOutgoingIndex.
|
||||
mOutgoingIndex = currentOutgoingIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Grow the incoming buffer.
|
||||
*
|
||||
* @param min_size
|
||||
* Minimum new size. The actual new size will be the the smallest
|
||||
* power of 2 that's larger than this number.
|
||||
*/
|
||||
function growIncomingBuffer(min_size) {
|
||||
if (DEBUG) {
|
||||
debug("Current buffer of " + mIncomingBufferLength +
|
||||
" can't handle incoming " + min_size + " bytes.");
|
||||
}
|
||||
let oldBytes = mIncomingBytes;
|
||||
mIncomingBufferLength =
|
||||
2 << Math.floor(Math.log(min_size)/Math.log(2));
|
||||
if (DEBUG) debug("New incoming buffer size: " + mIncomingBufferLength);
|
||||
mIncomingBuffer = new ArrayBuffer(mIncomingBufferLength);
|
||||
mIncomingBytes = new Uint8Array(mIncomingBuffer);
|
||||
if (mIncomingReadIndex <= mIncomingWriteIndex) {
|
||||
// Read and write index are in natural order, so we can just copy
|
||||
// the old buffer over to the bigger one without having to worry
|
||||
// about the indexes.
|
||||
mIncomingBytes.set(oldBytes, 0);
|
||||
} else {
|
||||
// The write index has wrapped around but the read index hasn't yet.
|
||||
// Write whatever the read index has left to read until it would
|
||||
// circle around to the beginning of the new buffer, and the rest
|
||||
// behind that.
|
||||
let head = oldBytes.subarray(mIncomingReadIndex);
|
||||
let tail = oldBytes.subarray(0, mIncomingReadIndex);
|
||||
mIncomingBytes.set(head, 0);
|
||||
mIncomingBytes.set(tail, head.length);
|
||||
mIncomingReadIndex = 0;
|
||||
mIncomingWriteIndex += head.length;
|
||||
}
|
||||
if (DEBUG) {
|
||||
debug("New incoming buffer size is " + mIncomingBufferLength);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Grow the outgoing buffer.
|
||||
*
|
||||
* @param min_size
|
||||
* Minimum new size. The actual new size will be the the smallest
|
||||
* power of 2 that's larger than this number.
|
||||
*/
|
||||
function growOutgoingBuffer(min_size) {
|
||||
if (DEBUG) {
|
||||
debug("Current buffer of " + mOutgoingBufferLength +
|
||||
" is too small.");
|
||||
}
|
||||
let oldBytes = mOutgoingBytes;
|
||||
mOutgoingBufferLength =
|
||||
2 << Math.floor(Math.log(min_size)/Math.log(2));
|
||||
mOutgoingBuffer = new ArrayBuffer(mOutgoingBufferLength);
|
||||
mOutgoingBytes = new Uint8Array(mOutgoingBuffer);
|
||||
mOutgoingBytes.set(oldBytes, 0);
|
||||
if (DEBUG) {
|
||||
debug("New outgoing buffer size is " + mOutgoingBufferLength);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Functions for reading data from the incoming buffer.
|
||||
*
|
||||
* These are all little endian, apart from readParcelSize();
|
||||
*/
|
||||
|
||||
/**
|
||||
* Ensure position specified is readable.
|
||||
*
|
||||
* @param index
|
||||
* Data position in incoming parcel, valid from 0 to
|
||||
* mCurrentParcelSize.
|
||||
*/
|
||||
function ensureIncomingAvailable(index) {
|
||||
if (index >= mCurrentParcelSize) {
|
||||
throw new Error("Trying to read data beyond the parcel end!");
|
||||
} else if (index < 0) {
|
||||
throw new Error("Trying to read data before the parcel begin!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Seek in current incoming parcel.
|
||||
*
|
||||
* @param offset
|
||||
* Seek offset in relative to current position.
|
||||
*/
|
||||
function seekIncoming(offset) {
|
||||
// Translate to 0..mCurrentParcelSize
|
||||
let cur = mCurrentParcelSize - mReadAvailable;
|
||||
|
||||
let newIndex = cur + offset;
|
||||
ensureIncomingAvailable(newIndex);
|
||||
|
||||
// ... mIncomingReadIndex -->|
|
||||
// 0 new cur mCurrentParcelSize
|
||||
// |================|=======|===================|
|
||||
// |<-- cur -->|<- mReadAvailable ->|
|
||||
// |<-- newIndex -->|<-- new mReadAvailable -->|
|
||||
mReadAvailable = mCurrentParcelSize - newIndex;
|
||||
|
||||
// Translate back:
|
||||
if (mIncomingReadIndex < cur) {
|
||||
// The mIncomingReadIndex is wrapped.
|
||||
newIndex += mIncomingBufferLength;
|
||||
}
|
||||
newIndex += (mIncomingReadIndex - cur);
|
||||
newIndex %= mIncomingBufferLength;
|
||||
mIncomingReadIndex = newIndex;
|
||||
}
|
||||
|
||||
function readUint8Unchecked() {
|
||||
let value = mIncomingBytes[mIncomingReadIndex];
|
||||
mIncomingReadIndex = (mIncomingReadIndex + 1) %
|
||||
mIncomingBufferLength;
|
||||
return value;
|
||||
}
|
||||
|
||||
function readUint8() {
|
||||
// Translate to 0..mCurrentParcelSize
|
||||
let cur = mCurrentParcelSize - mReadAvailable;
|
||||
ensureIncomingAvailable(cur);
|
||||
|
||||
mReadAvailable--;
|
||||
return readUint8Unchecked();
|
||||
}
|
||||
|
||||
function readUint8Array(length) {
|
||||
// Translate to 0..mCurrentParcelSize
|
||||
let last = mCurrentParcelSize - mReadAvailable;
|
||||
last += (length - 1);
|
||||
ensureIncomingAvailable(last);
|
||||
|
||||
let array = new Uint8Array(length);
|
||||
for (let i = 0; i < length; i++) {
|
||||
array[i] = readUint8Unchecked();
|
||||
}
|
||||
|
||||
mReadAvailable -= length;
|
||||
return array;
|
||||
}
|
||||
|
||||
function readUint16() {
|
||||
return readUint8() | readUint8() << 8;
|
||||
}
|
||||
|
||||
function readUint32() {
|
||||
return readUint8() | readUint8() << 8 |
|
||||
readUint8() << 16 | readUint8() << 24;
|
||||
}
|
||||
|
||||
function readUint32List() {
|
||||
let length = readUint32();
|
||||
let ints = [];
|
||||
for (let i = 0; i < length; i++) {
|
||||
ints.push(readUint32());
|
||||
}
|
||||
return ints;
|
||||
}
|
||||
|
||||
function readString() {
|
||||
let string_len = readUint32();
|
||||
if (string_len < 0 || string_len >= INT32_MAX) {
|
||||
return null;
|
||||
}
|
||||
let s = "";
|
||||
for (let i = 0; i < string_len; i++) {
|
||||
s += String.fromCharCode(readUint16());
|
||||
}
|
||||
// Strings are \0\0 delimited, but that isn't part of the length. And
|
||||
// if the string length is even, the delimiter is two characters wide.
|
||||
// It's insane, I know.
|
||||
readStringDelimiter(string_len);
|
||||
return s;
|
||||
}
|
||||
|
||||
function readStringList() {
|
||||
let num_strings = readUint32();
|
||||
let strings = [];
|
||||
for (let i = 0; i < num_strings; i++) {
|
||||
strings.push(readString());
|
||||
}
|
||||
return strings;
|
||||
}
|
||||
|
||||
function readStringDelimiter(length) {
|
||||
let delimiter = readUint16();
|
||||
if (!(length & 1)) {
|
||||
delimiter |= readUint16();
|
||||
}
|
||||
if (DEBUG) {
|
||||
if (delimiter !== 0) {
|
||||
debug("Something's wrong, found string delimiter: " + delimiter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function readParcelSize() {
|
||||
return readUint8Unchecked() << 24 |
|
||||
readUint8Unchecked() << 16 |
|
||||
readUint8Unchecked() << 8 |
|
||||
readUint8Unchecked();
|
||||
}
|
||||
|
||||
/**
|
||||
* Functions for writing data to the outgoing buffer.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Ensure position specified is writable.
|
||||
*
|
||||
* @param index
|
||||
* Data position in outgoing parcel, valid from 0 to
|
||||
* mOutgoingBufferLength.
|
||||
*/
|
||||
function ensureOutgoingAvailable(index) {
|
||||
if (index >= mOutgoingBufferLength) {
|
||||
growOutgoingBuffer(index + 1);
|
||||
}
|
||||
}
|
||||
|
||||
function writeUint8(value) {
|
||||
ensureOutgoingAvailable(mOutgoingIndex);
|
||||
|
||||
mOutgoingBytes[mOutgoingIndex] = value;
|
||||
mOutgoingIndex++;
|
||||
}
|
||||
|
||||
function writeUint16(value) {
|
||||
writeUint8(value & 0xff);
|
||||
writeUint8((value >> 8) & 0xff);
|
||||
}
|
||||
|
||||
function writeUint32(value) {
|
||||
writeUint8(value & 0xff);
|
||||
writeUint8((value >> 8) & 0xff);
|
||||
writeUint8((value >> 16) & 0xff);
|
||||
writeUint8((value >> 24) & 0xff);
|
||||
}
|
||||
|
||||
function writeString(value) {
|
||||
if (value == null) {
|
||||
writeUint32(-1);
|
||||
return;
|
||||
}
|
||||
writeUint32(value.length);
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
writeUint16(value.charCodeAt(i));
|
||||
}
|
||||
// Strings are \0\0 delimited, but that isn't part of the length. And
|
||||
// if the string length is even, the delimiter is two characters wide.
|
||||
// It's insane, I know.
|
||||
writeStringDelimiter(value.length);
|
||||
}
|
||||
|
||||
function writeStringList(strings) {
|
||||
writeUint32(strings.length);
|
||||
for (let i = 0; i < strings.length; i++) {
|
||||
writeString(strings[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function writeStringDelimiter(length) {
|
||||
writeUint16(0);
|
||||
if (!(length & 1)) {
|
||||
writeUint16(0);
|
||||
}
|
||||
}
|
||||
|
||||
function writeParcelSize(value) {
|
||||
/**
|
||||
* Parcel size will always be the first thing in the parcel byte
|
||||
* array, but the last thing written. Store the current index off
|
||||
* to a temporary to be reset after we write the size.
|
||||
*/
|
||||
let currentIndex = mOutgoingIndex;
|
||||
mOutgoingIndex = 0;
|
||||
writeUint8((value >> 24) & 0xff);
|
||||
writeUint8((value >> 16) & 0xff);
|
||||
writeUint8((value >> 8) & 0xff);
|
||||
writeUint8(value & 0xff);
|
||||
mOutgoingIndex = currentIndex;
|
||||
}
|
||||
|
||||
function copyIncomingToOutgoing(length) {
|
||||
if (!length || (length < 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let translatedReadIndexEnd = mCurrentParcelSize - mReadAvailable + length - 1;
|
||||
ensureIncomingAvailable(translatedReadIndexEnd);
|
||||
|
||||
let translatedWriteIndexEnd = mOutgoingIndex + length - 1;
|
||||
ensureOutgoingAvailable(translatedWriteIndexEnd);
|
||||
|
||||
let newIncomingReadIndex = mIncomingReadIndex + length;
|
||||
if (newIncomingReadIndex < mIncomingBufferLength) {
|
||||
// Reading won't cause wrapping, go ahead with builtin copy.
|
||||
mOutgoingBytes.set(mIncomingBytes.subarray(mIncomingReadIndex, newIncomingReadIndex),
|
||||
mOutgoingIndex);
|
||||
} else {
|
||||
// Not so lucky.
|
||||
newIncomingReadIndex %= mIncomingBufferLength;
|
||||
mOutgoingBytes.set(mIncomingBytes.subarray(mIncomingReadIndex, mIncomingBufferLength),
|
||||
mOutgoingIndex);
|
||||
if (newIncomingReadIndex) {
|
||||
let firstPartLength = mIncomingBufferLength - mIncomingReadIndex;
|
||||
mOutgoingBytes.set(mIncomingBytes.subarray(0, newIncomingReadIndex),
|
||||
mOutgoingIndex + firstPartLength);
|
||||
}
|
||||
}
|
||||
|
||||
mIncomingReadIndex = newIncomingReadIndex;
|
||||
mReadAvailable -= length;
|
||||
mOutgoingIndex += length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parcel management
|
||||
*/
|
||||
|
||||
/**
|
||||
* Write incoming data to the circular buffer.
|
||||
*
|
||||
* @param incoming
|
||||
* Uint8Array containing the incoming data.
|
||||
*/
|
||||
function writeToIncoming(incoming) {
|
||||
// We don't have to worry about the head catching the tail since
|
||||
// we process any backlog in parcels immediately, before writing
|
||||
// new data to the buffer. So the only edge case we need to handle
|
||||
// is when the incoming data is larger than the buffer size.
|
||||
let minMustAvailableSize = incoming.length + mReadIncoming;
|
||||
if (minMustAvailableSize > mIncomingBufferLength) {
|
||||
growIncomingBuffer(minMustAvailableSize);
|
||||
}
|
||||
|
||||
// We can let the typed arrays do the copying if the incoming data won't
|
||||
// wrap around the edges of the circular buffer.
|
||||
let remaining = mIncomingBufferLength - mIncomingWriteIndex;
|
||||
if (remaining >= incoming.length) {
|
||||
mIncomingBytes.set(incoming, mIncomingWriteIndex);
|
||||
} else {
|
||||
// The incoming data would wrap around it.
|
||||
let head = incoming.subarray(0, remaining);
|
||||
let tail = incoming.subarray(remaining);
|
||||
mIncomingBytes.set(head, mIncomingWriteIndex);
|
||||
mIncomingBytes.set(tail, 0);
|
||||
}
|
||||
mIncomingWriteIndex = (mIncomingWriteIndex + incoming.length) %
|
||||
mIncomingBufferLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process incoming data.
|
||||
*
|
||||
* @param incoming
|
||||
* Uint8Array containing the incoming data.
|
||||
*/
|
||||
function processIncoming(incoming) {
|
||||
if (DEBUG) {
|
||||
debug("Received " + incoming.length + " bytes.");
|
||||
debug("Already read " + mReadIncoming);
|
||||
}
|
||||
|
||||
writeToIncoming(incoming);
|
||||
mReadIncoming += incoming.length;
|
||||
while (true) {
|
||||
if (!mCurrentParcelSize) {
|
||||
// We're expecting a new parcel.
|
||||
if (mReadIncoming < PARCEL_SIZE_SIZE) {
|
||||
// We don't know how big the next parcel is going to be, need more
|
||||
// data.
|
||||
if (DEBUG) debug("Next parcel size unknown, going to sleep.");
|
||||
return;
|
||||
}
|
||||
mCurrentParcelSize = readParcelSize();
|
||||
if (DEBUG) debug("New incoming parcel of size " +
|
||||
mCurrentParcelSize);
|
||||
// The size itself is not included in the size.
|
||||
mReadIncoming -= PARCEL_SIZE_SIZE;
|
||||
}
|
||||
|
||||
if (mReadIncoming < mCurrentParcelSize) {
|
||||
// We haven't read enough yet in order to be able to process a parcel.
|
||||
if (DEBUG) debug("Read " + mReadIncoming + ", but parcel size is "
|
||||
+ mCurrentParcelSize + ". Going to sleep.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Alright, we have enough data to process at least one whole parcel.
|
||||
// Let's do that.
|
||||
let expectedAfterIndex = (mIncomingReadIndex + mCurrentParcelSize)
|
||||
% mIncomingBufferLength;
|
||||
|
||||
if (DEBUG) {
|
||||
let parcel;
|
||||
if (expectedAfterIndex < mIncomingReadIndex) {
|
||||
let head = mIncomingBytes.subarray(mIncomingReadIndex);
|
||||
let tail = mIncomingBytes.subarray(0, expectedAfterIndex);
|
||||
parcel = Array.slice(head).concat(Array.slice(tail));
|
||||
} else {
|
||||
parcel = Array.slice(mIncomingBytes.subarray(
|
||||
mIncomingReadIndex, expectedAfterIndex));
|
||||
}
|
||||
debug("Parcel (size " + mCurrentParcelSize + "): " + parcel);
|
||||
}
|
||||
|
||||
if (DEBUG) debug("We have at least one complete parcel.");
|
||||
try {
|
||||
mReadAvailable = mCurrentParcelSize;
|
||||
processParcel();
|
||||
} catch (ex) {
|
||||
if (DEBUG) debug("Parcel handling threw " + ex + "\n" + ex.stack);
|
||||
}
|
||||
|
||||
// Ensure that the whole parcel was consumed.
|
||||
if (mIncomingReadIndex != expectedAfterIndex) {
|
||||
if (DEBUG) {
|
||||
debug("Parcel handler didn't consume whole parcel, " +
|
||||
Math.abs(expectedAfterIndex - mIncomingReadIndex) +
|
||||
" bytes left over");
|
||||
}
|
||||
mIncomingReadIndex = expectedAfterIndex;
|
||||
}
|
||||
mReadIncoming -= mCurrentParcelSize;
|
||||
mReadAvailable = 0;
|
||||
mCurrentParcelSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process one parcel.
|
||||
*/
|
||||
function processParcel() {
|
||||
let response_type = readUint32();
|
||||
|
||||
let request_type, options;
|
||||
if (response_type == RESPONSE_TYPE_SOLICITED) {
|
||||
let token = readUint32();
|
||||
let error = readUint32();
|
||||
|
||||
options = mTokenRequestMap[token];
|
||||
if (!options) {
|
||||
if (DEBUG) {
|
||||
debug("Suspicious uninvited request found: " + token + ". Ignored!");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
delete mTokenRequestMap[token];
|
||||
request_type = options.rilRequestType;
|
||||
|
||||
options.rilRequestError = error;
|
||||
if (DEBUG) {
|
||||
debug("Solicited response for request type " + request_type +
|
||||
", token " + token + ", error " + error);
|
||||
}
|
||||
} else if (response_type == RESPONSE_TYPE_UNSOLICITED) {
|
||||
request_type = readUint32();
|
||||
if (DEBUG) debug("Unsolicited response for request type " + request_type);
|
||||
} else {
|
||||
if (DEBUG) debug("Unknown response type: " + response_type);
|
||||
return;
|
||||
}
|
||||
|
||||
RIL.handleParcel(request_type, mReadAvailable, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a new outgoing parcel.
|
||||
*
|
||||
* @param type
|
||||
* Integer specifying the request type.
|
||||
* @param options [optional]
|
||||
* Object containing information about the request, e.g. the
|
||||
* original main thread message object that led to the RIL request.
|
||||
*/
|
||||
function newParcel(type, options) {
|
||||
if (DEBUG) debug("New outgoing parcel of type " + type);
|
||||
|
||||
// We're going to leave room for the parcel size at the beginning.
|
||||
mOutgoingIndex = PARCEL_SIZE_SIZE;
|
||||
writeUint32(type);
|
||||
writeUint32(mToken);
|
||||
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
options.rilRequestType = type;
|
||||
options.rilRequestError = null;
|
||||
mTokenRequestMap[mToken] = options;
|
||||
mToken++;
|
||||
return mToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* Communicate with the RIL IPC thread.
|
||||
*/
|
||||
function sendParcel() {
|
||||
// Compute the size of the parcel and write it to the front of the parcel
|
||||
// where we left room for it. Note that he parcel size does not include
|
||||
// the size itself.
|
||||
let parcelSize = mOutgoingIndex - PARCEL_SIZE_SIZE;
|
||||
writeParcelSize(parcelSize);
|
||||
|
||||
// This assumes that postRILMessage will make a copy of the ArrayBufferView
|
||||
// right away!
|
||||
let parcel = mOutgoingBytes.subarray(0, mOutgoingIndex);
|
||||
if (DEBUG) debug("Outgoing parcel: " + Array.slice(parcel));
|
||||
mOutputStream(parcel);
|
||||
mOutgoingIndex = PARCEL_SIZE_SIZE;
|
||||
}
|
||||
|
||||
function setOutputStream(func) {
|
||||
mOutputStream = func;
|
||||
}
|
||||
|
||||
function simpleRequest(type, options) {
|
||||
newParcel(type, options);
|
||||
sendParcel();
|
||||
}
|
||||
|
||||
function getCurrentParcelSize() {
|
||||
return mCurrentParcelSize;
|
||||
}
|
||||
|
||||
function getReadAvailable() {
|
||||
return mReadAvailable;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
init: init,
|
||||
startCalOutgoingSize: startCalOutgoingSize,
|
||||
stopCalOutgoingSize: stopCalOutgoingSize,
|
||||
seekIncoming: seekIncoming,
|
||||
readUint8: readUint8,
|
||||
readUint8Array: readUint8Array,
|
||||
readUint16: readUint16,
|
||||
readUint32: readUint32,
|
||||
readUint32List: readUint32List,
|
||||
readString: readString,
|
||||
readStringList: readStringList,
|
||||
readStringDelimiter: readStringDelimiter,
|
||||
writeUint8: writeUint8,
|
||||
writeUint16: writeUint16,
|
||||
writeUint32: writeUint32,
|
||||
writeString: writeString,
|
||||
writeStringList: writeStringList,
|
||||
writeStringDelimiter: writeStringDelimiter,
|
||||
copyIncomingToOutgoing: copyIncomingToOutgoing,
|
||||
processIncoming: processIncoming,
|
||||
newParcel: newParcel,
|
||||
sendParcel: sendParcel,
|
||||
simpleRequest: simpleRequest,
|
||||
setOutputStream: setOutputStream,
|
||||
getCurrentParcelSize: getCurrentParcelSize,
|
||||
getReadAvailable: getReadAvailable,
|
||||
};
|
|
@ -1826,10 +1826,6 @@ let WifiNetworkInterface = {
|
|||
|
||||
name: null,
|
||||
|
||||
// For now we do our own DHCP. In the future this should be handed off
|
||||
// to the Network Manager.
|
||||
dhcp: false,
|
||||
|
||||
ip: null,
|
||||
|
||||
netmask: null,
|
||||
|
|
|
@ -62,13 +62,17 @@ ImageDataSerializer::InitializeBufferInfo(gfx::IntSize aSize,
|
|||
info->format = aFormat;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
ComputeStride(gfx::SurfaceFormat aFormat, uint32_t aWidth)
|
||||
{
|
||||
return gfx::GetAlignedStride<4>(gfx::BytesPerPixel(aFormat) * aWidth);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ImageDataSerializer::ComputeMinBufferSize(gfx::IntSize aSize,
|
||||
gfx::SurfaceFormat aFormat)
|
||||
{
|
||||
// Note that at the moment we pack the image data with the minimum possible
|
||||
// stride, we may decide to change that if we want aligned stride.
|
||||
uint32_t bufsize = aSize.height * gfx::BytesPerPixel(aFormat) * aSize.width;
|
||||
uint32_t bufsize = aSize.height * ComputeStride(aFormat, aSize.width);
|
||||
return SurfaceBufferInfo::GetOffset()
|
||||
+ gfx::GetAlignedStride<16>(bufsize);
|
||||
}
|
||||
|
@ -107,8 +111,7 @@ ImageDataSerializerBase::GetAsThebesSurface()
|
|||
{
|
||||
MOZ_ASSERT(IsValid());
|
||||
SurfaceBufferInfo* info = GetBufferInfo(mData);
|
||||
uint32_t stride = gfxASurface::BytesPerPixel(
|
||||
gfx::SurfaceFormatToImageFormat(GetFormat())) * info->width;
|
||||
uint32_t stride = ComputeStride(GetFormat(), info->width);
|
||||
gfxIntSize size(info->width, info->height);
|
||||
RefPtr<gfxImageSurface> surf =
|
||||
new gfxImageSurface(GetData(), size, stride,
|
||||
|
@ -122,8 +125,7 @@ ImageDataSerializerBase::GetAsSurface()
|
|||
MOZ_ASSERT(IsValid());
|
||||
SurfaceBufferInfo* info = GetBufferInfo(mData);
|
||||
gfx::IntSize size(info->width, info->height);
|
||||
uint32_t stride = gfxASurface::BytesPerPixel(
|
||||
gfx::SurfaceFormatToImageFormat(GetFormat())) * info->width;
|
||||
uint32_t stride = ComputeStride(GetFormat(), info->width);
|
||||
RefPtr<gfx::DataSourceSurface> surf =
|
||||
gfx::Factory::CreateWrappingDataSourceSurface(GetData(), stride, size, GetFormat());
|
||||
return surf.forget();
|
||||
|
|
|
@ -21,22 +21,29 @@ bool ots_svg_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
|
|||
OpenTypeSVG *svg = new OpenTypeSVG;
|
||||
file->svg = svg;
|
||||
|
||||
std::map<uint32_t, uint32_t> doc_locations;
|
||||
typedef std::map<uint32_t, uint32_t>::iterator lociter_t;
|
||||
|
||||
uint16_t version;
|
||||
uint16_t index_length;
|
||||
if (!table.ReadU16(&version) ||
|
||||
!table.ReadU16(&index_length)) {
|
||||
if (!table.ReadU16(&version)) {
|
||||
NONFATAL_FAILURE("Couldn't read SVG table header");
|
||||
}
|
||||
|
||||
if (version != 1) {
|
||||
if (version != 0) {
|
||||
NONFATAL_FAILURE("Unknown SVG table version");
|
||||
}
|
||||
|
||||
uint32_t max_address = 0;
|
||||
uint32_t total_docs_length = 0;
|
||||
uint32_t doc_index_offset;
|
||||
if (!table.ReadU32(&doc_index_offset)) {
|
||||
NONFATAL_FAILURE("Couldn't read doc index offset from SVG table header");
|
||||
}
|
||||
if (doc_index_offset == 0 || doc_index_offset >= length) {
|
||||
NONFATAL_FAILURE("Invalid doc index offset");
|
||||
}
|
||||
|
||||
uint32_t color_palettes_offset;
|
||||
if (!table.ReadU32(&color_palettes_offset)) {
|
||||
NONFATAL_FAILURE("Couldn't read color palettes offset from SVG table header");
|
||||
}
|
||||
if (color_palettes_offset >= length) {
|
||||
NONFATAL_FAILURE("Invalid doc index offset");
|
||||
}
|
||||
|
||||
uint16_t start_glyph;
|
||||
uint16_t end_glyph;
|
||||
|
@ -44,6 +51,15 @@ bool ots_svg_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
|
|||
uint32_t doc_length;
|
||||
uint16_t last_end_glyph = 0;
|
||||
|
||||
table.set_offset(doc_index_offset);
|
||||
uint16_t index_length;
|
||||
if (!table.ReadU16(&index_length)) {
|
||||
NONFATAL_FAILURE("Couldn't read SVG documents index");
|
||||
}
|
||||
if (index_length == 0) {
|
||||
NONFATAL_FAILURE("Zero-length documents index");
|
||||
}
|
||||
|
||||
for (uint16_t i = 0; i < index_length; i++) {
|
||||
if (!table.ReadU16(&start_glyph) ||
|
||||
!table.ReadU16(&end_glyph) ||
|
||||
|
@ -60,42 +76,16 @@ bool ots_svg_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
|
|||
NONFATAL_FAILURE("SVG table index range overlapping or not sorted");
|
||||
}
|
||||
|
||||
if (doc_locations.find(doc_offset) != doc_locations.end()) {
|
||||
if (doc_locations[doc_offset] != doc_length) {
|
||||
NONFATAL_FAILURE("SVG table contains overlapping document range");
|
||||
}
|
||||
} else {
|
||||
doc_locations[doc_offset] = doc_length;
|
||||
total_docs_length += doc_length;
|
||||
if (doc_offset + doc_length > max_address) {
|
||||
max_address = doc_offset + doc_length;
|
||||
}
|
||||
}
|
||||
|
||||
if (doc_offset > 1024 * 1024 * 1024 ||
|
||||
doc_length > 1024 * 1024 * 1024 ||
|
||||
total_docs_length > 1024 * 1024 * 1024) {
|
||||
doc_length > 1024 * 1024 * 1024) {
|
||||
NONFATAL_FAILURE("Bad SVG document length");
|
||||
}
|
||||
|
||||
last_end_glyph = end_glyph;
|
||||
}
|
||||
|
||||
uint32_t last_end = 4 + 12 * index_length;
|
||||
for (lociter_t iter = doc_locations.begin();
|
||||
iter != doc_locations.end(); ++iter) {
|
||||
if (iter->first != last_end) {
|
||||
NONFATAL_FAILURE("SVG table contains overlapping document range");
|
||||
if (uint64_t(doc_index_offset) + doc_offset + doc_length > length) {
|
||||
NONFATAL_FAILURE("SVG table document overflows table");
|
||||
}
|
||||
last_end = iter->first + iter->second;
|
||||
}
|
||||
|
||||
if (max_address != length) {
|
||||
NONFATAL_FAILURE("Bad SVG document length");
|
||||
}
|
||||
|
||||
if (!table.Skip(total_docs_length)) {
|
||||
NONFATAL_FAILURE("SVG table is too short");
|
||||
last_end_glyph = end_glyph;
|
||||
}
|
||||
|
||||
svg->data = data;
|
||||
|
|
|
@ -264,16 +264,9 @@ gfxFontEntry::TryGetSVGData()
|
|||
return false;
|
||||
}
|
||||
|
||||
hb_blob_t *cmapTable = GetFontTable(TRUETYPE_TAG('c','m','a','p'));
|
||||
if (!cmapTable) {
|
||||
NS_NOTREACHED("using a font with no cmap!");
|
||||
hb_blob_destroy(svgTable);
|
||||
return false;
|
||||
}
|
||||
|
||||
// gfxSVGGlyphs will hb_blob_destroy() the tables when it is finished
|
||||
// with them.
|
||||
mSVGGlyphs = new gfxSVGGlyphs(svgTable, cmapTable);
|
||||
// gfxSVGGlyphs will hb_blob_destroy() the table when it is finished
|
||||
// with it.
|
||||
mSVGGlyphs = new gfxSVGGlyphs(svgTable);
|
||||
}
|
||||
|
||||
return !!mSVGGlyphs;
|
||||
|
|
|
@ -1364,8 +1364,9 @@ gfxPlatform::InitBackendPrefs(uint32_t aCanvasBitmask, uint32_t aContentBitmask)
|
|||
mPreferredCanvasBackend = BACKEND_CAIRO;
|
||||
}
|
||||
mFallbackCanvasBackend = GetCanvasBackendPref(aCanvasBitmask & ~(1 << mPreferredCanvasBackend));
|
||||
mContentBackend = GetContentBackendPref(aContentBitmask);
|
||||
|
||||
mContentBackendBitmask = aContentBitmask;
|
||||
mContentBackend = GetContentBackendPref(mContentBackendBitmask);
|
||||
}
|
||||
|
||||
/* static */ BackendType
|
||||
|
@ -1375,16 +1376,17 @@ gfxPlatform::GetCanvasBackendPref(uint32_t aBackendBitmask)
|
|||
}
|
||||
|
||||
/* static */ BackendType
|
||||
gfxPlatform::GetContentBackendPref(uint32_t aBackendBitmask)
|
||||
gfxPlatform::GetContentBackendPref(uint32_t &aBackendBitmask)
|
||||
{
|
||||
return GetBackendPref("gfx.content.azure.enabled", "gfx.content.azure.backends", aBackendBitmask);
|
||||
}
|
||||
|
||||
/* static */ BackendType
|
||||
gfxPlatform::GetBackendPref(const char* aEnabledPrefName, const char* aBackendPrefName, uint32_t aBackendBitmask)
|
||||
gfxPlatform::GetBackendPref(const char* aEnabledPrefName, const char* aBackendPrefName, uint32_t &aBackendBitmask)
|
||||
{
|
||||
if (aEnabledPrefName &&
|
||||
!Preferences::GetBool(aEnabledPrefName, false)) {
|
||||
aBackendBitmask = 0;
|
||||
return BACKEND_NONE;
|
||||
}
|
||||
|
||||
|
@ -1394,13 +1396,20 @@ gfxPlatform::GetBackendPref(const char* aEnabledPrefName, const char* aBackendPr
|
|||
ParseString(prefString, ',', backendList);
|
||||
}
|
||||
|
||||
uint32_t allowedBackends = 0;
|
||||
BackendType result = BACKEND_NONE;
|
||||
for (uint32_t i = 0; i < backendList.Length(); ++i) {
|
||||
BackendType result = BackendTypeForName(backendList[i]);
|
||||
if ((1 << result) & aBackendBitmask) {
|
||||
return result;
|
||||
BackendType type = BackendTypeForName(backendList[i]);
|
||||
if ((1 << type) & aBackendBitmask) {
|
||||
allowedBackends |= (1 << type);
|
||||
if (result == BACKEND_NONE) {
|
||||
result = type;
|
||||
}
|
||||
}
|
||||
}
|
||||
return BACKEND_NONE;
|
||||
|
||||
aBackendBitmask = allowedBackends;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -637,17 +637,19 @@ protected:
|
|||
* returns the first backend named in the pref gfx.content.azure.backend
|
||||
* which is a component of aBackendBitmask, a bitmask of backend types
|
||||
*/
|
||||
static mozilla::gfx::BackendType GetContentBackendPref(uint32_t aBackendBitmask);
|
||||
static mozilla::gfx::BackendType GetContentBackendPref(uint32_t &aBackendBitmask);
|
||||
|
||||
/**
|
||||
* If aEnabledPrefName is non-null, checks the aEnabledPrefName pref and
|
||||
* returns BACKEND_NONE if the pref is not enabled.
|
||||
* Otherwise it will return the first backend named in aBackendPrefName
|
||||
* allowed by aBackendBitmask, a bitmask of backend types.
|
||||
* It also modifies aBackendBitmask to only include backends that are
|
||||
* allowed given the prefs.
|
||||
*/
|
||||
static mozilla::gfx::BackendType GetBackendPref(const char* aEnabledPrefName,
|
||||
const char* aBackendPrefName,
|
||||
uint32_t aBackendBitmask);
|
||||
uint32_t &aBackendBitmask);
|
||||
/**
|
||||
* Decode the backend enumberation from a string.
|
||||
*/
|
||||
|
|
|
@ -42,23 +42,33 @@ const float gfxSVGGlyphs::SVG_UNITS_PER_EM = 1000.0f;
|
|||
|
||||
const gfxRGBA SimpleTextObjectPaint::sZero = gfxRGBA(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
|
||||
gfxSVGGlyphs::gfxSVGGlyphs(hb_blob_t *aSVGTable, hb_blob_t *aCmapTable)
|
||||
gfxSVGGlyphs::gfxSVGGlyphs(hb_blob_t *aSVGTable)
|
||||
{
|
||||
mSVGData = aSVGTable;
|
||||
|
||||
const char* svgData = hb_blob_get_data(mSVGData, nullptr);
|
||||
unsigned int length;
|
||||
const char* svgData = hb_blob_get_data(mSVGData, &length);
|
||||
mHeader = reinterpret_cast<const Header*>(svgData);
|
||||
mIndex = reinterpret_cast<const IndexEntry*>(svgData + sizeof(Header));
|
||||
mDocIndex = nullptr;
|
||||
|
||||
if (sizeof(Header) <= length && uint16_t(mHeader->mVersion) == 0 &&
|
||||
uint64_t(mHeader->mDocIndexOffset) + 2 <= length) {
|
||||
const DocIndex* docIndex = reinterpret_cast<const DocIndex*>
|
||||
(svgData + mHeader->mDocIndexOffset);
|
||||
// Limit the number of documents to avoid overflow
|
||||
if (uint64_t(mHeader->mDocIndexOffset) + 2 +
|
||||
uint16_t(docIndex->mNumEntries) * sizeof(IndexEntry) <= length) {
|
||||
mDocIndex = docIndex;
|
||||
}
|
||||
}
|
||||
|
||||
mGlyphDocs.Init();
|
||||
mGlyphIdMap.Init();
|
||||
mCmapData = aCmapTable;
|
||||
}
|
||||
|
||||
gfxSVGGlyphs::~gfxSVGGlyphs()
|
||||
{
|
||||
hb_blob_destroy(mSVGData);
|
||||
hb_blob_destroy(mCmapData);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -90,8 +100,13 @@ gfxSVGGlyphs::CompareIndexEntries(const void *aKey, const void *aEntry)
|
|||
gfxSVGGlyphsDocument *
|
||||
gfxSVGGlyphs::FindOrCreateGlyphsDocument(uint32_t aGlyphId)
|
||||
{
|
||||
IndexEntry *entry = (IndexEntry*)bsearch(&aGlyphId, mIndex,
|
||||
uint16_t(mHeader->mIndexLength),
|
||||
if (!mDocIndex) {
|
||||
// Invalid table
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
IndexEntry *entry = (IndexEntry*)bsearch(&aGlyphId, mDocIndex->mEntries,
|
||||
uint16_t(mDocIndex->mNumEntries),
|
||||
sizeof(IndexEntry),
|
||||
CompareIndexEntries);
|
||||
if (!entry) {
|
||||
|
@ -101,10 +116,14 @@ gfxSVGGlyphs::FindOrCreateGlyphsDocument(uint32_t aGlyphId)
|
|||
gfxSVGGlyphsDocument *result = mGlyphDocs.Get(entry->mDocOffset);
|
||||
|
||||
if (!result) {
|
||||
const uint8_t *data = (const uint8_t*)hb_blob_get_data(mSVGData, nullptr);
|
||||
result = new gfxSVGGlyphsDocument(data + entry->mDocOffset,
|
||||
entry->mDocLength, mCmapData);
|
||||
mGlyphDocs.Put(entry->mDocOffset, result);
|
||||
unsigned int length;
|
||||
const uint8_t *data = (const uint8_t*)hb_blob_get_data(mSVGData, &length);
|
||||
if (entry->mDocOffset > 0 &&
|
||||
uint64_t(mHeader->mDocIndexOffset) + entry->mDocOffset + entry->mDocLength <= length) {
|
||||
result = new gfxSVGGlyphsDocument(data + mHeader->mDocIndexOffset + entry->mDocOffset,
|
||||
entry->mDocLength);
|
||||
mGlyphDocs.Put(entry->mDocOffset, result);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -156,20 +175,18 @@ gfxSVGGlyphsDocument::SetupPresentation()
|
|||
* Walk the DOM tree to find all glyph elements and insert them into the lookup
|
||||
* table
|
||||
* @param aElem The element to search from
|
||||
* @param aCmapTable Buffer containing the raw cmap table data
|
||||
*/
|
||||
void
|
||||
gfxSVGGlyphsDocument::FindGlyphElements(Element *aElem, hb_blob_t *aCmapTable)
|
||||
gfxSVGGlyphsDocument::FindGlyphElements(Element *aElem)
|
||||
{
|
||||
for (nsIContent *child = aElem->GetLastChild(); child;
|
||||
child = child->GetPreviousSibling()) {
|
||||
if (!child->IsElement()) {
|
||||
continue;
|
||||
}
|
||||
FindGlyphElements(child->AsElement(), aCmapTable);
|
||||
FindGlyphElements(child->AsElement());
|
||||
}
|
||||
|
||||
InsertGlyphChar(aElem, aCmapTable);
|
||||
InsertGlyphId(aElem);
|
||||
}
|
||||
|
||||
|
@ -235,8 +252,7 @@ gfxSVGGlyphsDocument::GetGlyphElement(uint32_t aGlyphId)
|
|||
return mGlyphIdMap.Get(aGlyphId);
|
||||
}
|
||||
|
||||
gfxSVGGlyphsDocument::gfxSVGGlyphsDocument(const uint8_t *aBuffer, uint32_t aBufLen,
|
||||
hb_blob_t *aCmapTable)
|
||||
gfxSVGGlyphsDocument::gfxSVGGlyphsDocument(const uint8_t *aBuffer, uint32_t aBufLen)
|
||||
{
|
||||
mGlyphIdMap.Init();
|
||||
ParseDocument(aBuffer, aBufLen);
|
||||
|
@ -257,7 +273,7 @@ gfxSVGGlyphsDocument::gfxSVGGlyphsDocument(const uint8_t *aBuffer, uint32_t aBuf
|
|||
return;
|
||||
}
|
||||
|
||||
FindGlyphElements(root, aCmapTable);
|
||||
FindGlyphElements(root);
|
||||
}
|
||||
|
||||
static nsresult
|
||||
|
@ -362,83 +378,28 @@ void
|
|||
gfxSVGGlyphsDocument::InsertGlyphId(Element *aGlyphElement)
|
||||
{
|
||||
nsAutoString glyphIdStr;
|
||||
if (!aGlyphElement->GetAttr(kNameSpaceID_None, nsGkAtoms::glyphid, glyphIdStr)) {
|
||||
static const uint32_t glyphPrefixLength = 5;
|
||||
// The maximum glyph ID is 65535 so the maximum length of the numeric part
|
||||
// is 5.
|
||||
if (!aGlyphElement->GetAttr(kNameSpaceID_None, nsGkAtoms::id, glyphIdStr) ||
|
||||
!StringBeginsWith(glyphIdStr, NS_LITERAL_STRING("glyph")) ||
|
||||
glyphIdStr.Length() > glyphPrefixLength + 5) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
uint32_t glyphId = glyphIdStr.ToInteger(&rv);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
uint32_t id = 0;
|
||||
for (uint32_t i = glyphPrefixLength; i < glyphIdStr.Length(); ++i) {
|
||||
PRUnichar ch = glyphIdStr.CharAt(i);
|
||||
if (ch < '0' || ch > '9') {
|
||||
return;
|
||||
}
|
||||
|
||||
mGlyphIdMap.Put(glyphId, aGlyphElement);
|
||||
}
|
||||
|
||||
// Get the Unicode character at index aPos in the string, and update aPos to
|
||||
// point to the next char (i.e. advance by one or two, depending whether we
|
||||
// found a surrogate pair).
|
||||
// This will assert (and return junk) if the string is not well-formed UTF16.
|
||||
// However, this is only used to process an attribute that comes from the
|
||||
// SVG-glyph XML document, and is not exposed to modification via the DOM,
|
||||
// so it must be well-formed UTF16 data (no unpaired surrogate codepoints)
|
||||
// unless our Unicode handling is seriously broken.
|
||||
static uint32_t
|
||||
NextUSV(const nsAString& aString, uint32_t& aPos)
|
||||
{
|
||||
mozilla::DebugOnly<uint32_t> len = aString.Length();
|
||||
NS_ASSERTION(aPos < len, "already at end of string");
|
||||
|
||||
uint32_t c1 = aString[aPos++];
|
||||
if (NS_IS_HIGH_SURROGATE(c1)) {
|
||||
NS_ASSERTION(aPos < len, "trailing high surrogate");
|
||||
uint32_t c2 = aString[aPos++];
|
||||
NS_ASSERTION(NS_IS_LOW_SURROGATE(c2), "isolated high surrogate");
|
||||
return SURROGATE_TO_UCS4(c1, c2);
|
||||
}
|
||||
|
||||
NS_ASSERTION(!NS_IS_LOW_SURROGATE(c1), "isolated low surrogate");
|
||||
return c1;
|
||||
}
|
||||
|
||||
void
|
||||
gfxSVGGlyphsDocument::InsertGlyphChar(Element *aGlyphElement,
|
||||
hb_blob_t *aCmapTable)
|
||||
{
|
||||
nsAutoString glyphChar;
|
||||
if (!aGlyphElement->GetAttr(kNameSpaceID_None, nsGkAtoms::glyphchar,
|
||||
glyphChar)) {
|
||||
}
|
||||
if (ch == '0' && i == glyphPrefixLength) {
|
||||
return;
|
||||
}
|
||||
id = id * 10 + (ch - '0');
|
||||
}
|
||||
|
||||
uint32_t charCode, varSelector = 0, len = glyphChar.Length(), index = 0;
|
||||
if (!len) {
|
||||
NS_WARNING("glyphchar is empty");
|
||||
return;
|
||||
}
|
||||
|
||||
charCode = NextUSV(glyphChar, index);
|
||||
if (index < len) {
|
||||
varSelector = NextUSV(glyphChar, index);
|
||||
if (!gfxFontUtils::IsVarSelector(varSelector)) {
|
||||
NS_WARNING("glyphchar contains more than one character");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (index < len) {
|
||||
NS_WARNING("glyphchar contains more than one character");
|
||||
return;
|
||||
}
|
||||
|
||||
const uint8_t *data = (const uint8_t*)hb_blob_get_data(aCmapTable, &len);
|
||||
uint32_t glyphId =
|
||||
gfxFontUtils::MapCharToGlyph(data, len, charCode, varSelector);
|
||||
|
||||
if (glyphId) {
|
||||
mGlyphIdMap.Put(glyphId, aGlyphElement);
|
||||
}
|
||||
mGlyphIdMap.Put(id, aGlyphElement);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -33,8 +33,7 @@ class gfxSVGGlyphsDocument
|
|||
typedef gfxFont::DrawMode DrawMode;
|
||||
|
||||
public:
|
||||
gfxSVGGlyphsDocument(const uint8_t *aBuffer, uint32_t aBufLen,
|
||||
hb_blob_t *aCmapTable);
|
||||
gfxSVGGlyphsDocument(const uint8_t *aBuffer, uint32_t aBufLen);
|
||||
|
||||
Element *GetGlyphElement(uint32_t aGlyphId);
|
||||
|
||||
|
@ -49,10 +48,9 @@ private:
|
|||
|
||||
nsresult SetupPresentation();
|
||||
|
||||
void FindGlyphElements(Element *aElement, hb_blob_t *aCmapTable);
|
||||
void FindGlyphElements(Element *aElement);
|
||||
|
||||
void InsertGlyphId(Element *aGlyphElement);
|
||||
void InsertGlyphChar(Element *aGlyphElement, hb_blob_t *aCmapTable);
|
||||
|
||||
nsCOMPtr<nsIDocument> mDocument;
|
||||
nsCOMPtr<nsIContentViewer> mViewer;
|
||||
|
@ -78,16 +76,15 @@ public:
|
|||
|
||||
/**
|
||||
* @param aSVGTable The SVG table from the OpenType font
|
||||
* @param aCmapTable The CMAP table from the OpenType font
|
||||
*
|
||||
* The gfxSVGGlyphs object takes over ownership of the blob references
|
||||
* that are passed in, and will hb_blob_destroy() them when finished;
|
||||
* the caller should -not- destroy these references.
|
||||
*/
|
||||
gfxSVGGlyphs(hb_blob_t *aSVGTable, hb_blob_t *aCmapTable);
|
||||
gfxSVGGlyphs(hb_blob_t *aSVGTable);
|
||||
|
||||
/**
|
||||
* Releases our references to the SVG and cmap tables.
|
||||
* Releases our references to the SVG table.
|
||||
*/
|
||||
~gfxSVGGlyphs();
|
||||
|
||||
|
@ -127,19 +124,24 @@ private:
|
|||
nsBaseHashtable<nsUint32HashKey, Element*, Element*> mGlyphIdMap;
|
||||
|
||||
hb_blob_t *mSVGData;
|
||||
hb_blob_t *mCmapData;
|
||||
|
||||
const struct Header {
|
||||
mozilla::AutoSwap_PRUint16 mVersion;
|
||||
mozilla::AutoSwap_PRUint16 mIndexLength;
|
||||
mozilla::AutoSwap_PRUint32 mDocIndexOffset;
|
||||
mozilla::AutoSwap_PRUint32 mColorPalettesOffset;
|
||||
} *mHeader;
|
||||
|
||||
const struct IndexEntry {
|
||||
struct IndexEntry {
|
||||
mozilla::AutoSwap_PRUint16 mStartGlyph;
|
||||
mozilla::AutoSwap_PRUint16 mEndGlyph;
|
||||
mozilla::AutoSwap_PRUint32 mDocOffset;
|
||||
mozilla::AutoSwap_PRUint32 mDocLength;
|
||||
} *mIndex;
|
||||
};
|
||||
|
||||
const struct DocIndex {
|
||||
mozilla::AutoSwap_PRUint16 mNumEntries;
|
||||
IndexEntry mEntries[1]; /* actual length = mNumEntries */
|
||||
} *mDocIndex;
|
||||
|
||||
static int CompareIndexEntries(const void *_a, const void *_b);
|
||||
};
|
||||
|
|
|
@ -502,7 +502,7 @@ gfxWindowsPlatform::UpdateRenderMode()
|
|||
#endif
|
||||
|
||||
uint32_t canvasMask = 1 << BACKEND_CAIRO;
|
||||
uint32_t contentMask = 1 << BACKEND_CAIRO;
|
||||
uint32_t contentMask = 0;
|
||||
if (mRenderMode == RENDER_DIRECT2D) {
|
||||
canvasMask |= 1 << BACKEND_DIRECT2D;
|
||||
contentMask |= 1 << BACKEND_DIRECT2D;
|
||||
|
|
|
@ -65,7 +65,7 @@ def InvokeClWithDependencyGeneration(cmdline):
|
|||
cl = subprocess.Popen(cmdline, stdout=subprocess.PIPE)
|
||||
|
||||
mk = Makefile()
|
||||
rule = mk.create_rule(target)
|
||||
rule = mk.create_rule([target])
|
||||
rule.add_dependencies([normcase(source)])
|
||||
for line in cl.stdout:
|
||||
# cl -showIncludes prefixes every header with "Note: including file:"
|
||||
|
|
|
@ -40,7 +40,11 @@ fail-if = os == "android"
|
|||
[test_xpcomutils.js]
|
||||
[test_unload.js]
|
||||
[test_attributes.js]
|
||||
# Bug 676965: test fails consistently on Android
|
||||
fail-if = os == "android"
|
||||
[test_params.js]
|
||||
# Bug 676965: test fails consistently on Android
|
||||
fail-if = os == "android"
|
||||
[test_tearoffs.js]
|
||||
[test_want_components.js]
|
||||
[test_components.js]
|
||||
|
|
|
@ -22,31 +22,40 @@ SimpleTest.waitForExplicitFinish();
|
|||
|
||||
var startNow = Date.now();
|
||||
var start = window.mozAnimationStartTime;
|
||||
var firstListenerTime;
|
||||
var secondListenerTime;
|
||||
var firstListenerArg;
|
||||
var secondListenerArg;
|
||||
var thirdListenerTime;
|
||||
|
||||
function secondListener(t) {
|
||||
secondListenerTime = t;
|
||||
// callback arg is wallclock from mozRequestAnimationFrame
|
||||
function thirdListener(t) {
|
||||
thirdListenerTime = t;
|
||||
|
||||
// They really shouldn't be more than 100ms apart, but we can get weird
|
||||
// effects on slow machines. 5 minutes is our test timeout, though.
|
||||
ok(Math.abs(startNow - start) <= 5 * 60 * 1000, "Bogus animation start time");
|
||||
ok(firstListenerTime >= start, "First listener should fire after start");
|
||||
// FIXME: The timer filtering code makes the refresh driver call back in 0ms
|
||||
// sometimes!
|
||||
ok(secondListenerTime >= firstListenerTime,
|
||||
|
||||
ok(secondListenerArg >= firstListenerArg, // callback args from consecutive unprefixed requestAnimationFrame
|
||||
"Second listener should fire after first listener");
|
||||
|
||||
ok(thirdListenerTime >= start, "Third listener should fire after start");
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
function firstListener(t) {
|
||||
firstListenerTime = t;
|
||||
mozRequestAnimationFrame(secondListener);
|
||||
|
||||
// callback arg is from requestAnimationFrame and comparable to performance.now()
|
||||
function secondListener(t) {
|
||||
secondListenerArg = t;
|
||||
mozRequestAnimationFrame(thirdListener);
|
||||
}
|
||||
|
||||
|
||||
function firstListener(t) {
|
||||
firstListenerArg = t;
|
||||
requestAnimationFrame(secondListener);
|
||||
}
|
||||
|
||||
addLoadEvent(function() {
|
||||
setTimeout(function() {
|
||||
mozRequestAnimationFrame(firstListener);
|
||||
requestAnimationFrame(firstListener);
|
||||
}, 100);
|
||||
});
|
||||
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<style type="text/css">
|
||||
/* font with the SVG glyph for the cat face U+1f431 remapped to
|
||||
the BMP smiling-face character U+263a */
|
||||
@font-face { font-family: foo; src: url("resources/cat_face-bmp.ttf"); }
|
||||
body { font-family: foo, sans-serif; font-size: 24px; }
|
||||
td { padding: 2px 10px }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<table>
|
||||
<tr><td>☺</td><td>ネコ</td><td>cat face</td></tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
|
@ -1,16 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<style type="text/css">
|
||||
/* no SVG cat-face glyph, so this should NOT match the testcases */
|
||||
body { font-family: sans-serif; font-size: 24px; }
|
||||
td { padding: 2px 10px }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<table>
|
||||
<tr><td>☺</td><td>ネコ</td><td>cat face</td></tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
|
@ -1,17 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<style type="text/css">
|
||||
/* font with an SVG glyph for the cat face U+1f431 */
|
||||
@font-face { font-family: foo; src: url("resources/cat_face.ttf"); }
|
||||
body { font-family: foo, sans-serif; font-size: 24px; }
|
||||
td { padding: 2px 10px }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<table>
|
||||
<tr><td>🐱</td><td>ネコ</td><td>cat face</td></tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
|
@ -1,5 +1,6 @@
|
|||
pref(gfx.font_rendering.opentype_svg.enabled,false) != svg-glyph-basic.svg svg-glyph-basic-ref.svg
|
||||
pref(gfx.font_rendering.opentype_svg.enabled,true) fails-if(Android||B2G) == svg-glyph-basic.svg svg-glyph-basic-ref.svg # bug 872487
|
||||
pref(gfx.font_rendering.opentype_svg.enabled,true) fails-if(Android||B2G) == svg-glyph-invalid-ids.svg svg-glyph-invalid-ids-ref.svg # bug 872487
|
||||
pref(gfx.font_rendering.opentype_svg.enabled,false) != svg-glyph-positioning.svg svg-glyph-positioning-ref.svg
|
||||
pref(gfx.font_rendering.opentype_svg.enabled,true) fails-if(Android||B2G) == svg-glyph-positioning.svg svg-glyph-positioning-ref.svg # bug 872487
|
||||
pref(gfx.font_rendering.opentype_svg.enabled,true) fails-if(winWidget) == svg-glyph-html.html svg-glyph-html-ref.svg # bug 872486
|
||||
|
@ -18,8 +19,3 @@ pref(gfx.font_rendering.opentype_svg.enabled,true) == svg-glyph-cachedopacity
|
|||
pref(gfx.font_rendering.opentype_svg.enabled,true) == svg-glyph-objectvalue.svg svg-glyph-objectvalue-ref.svg
|
||||
pref(gfx.font_rendering.opentype_svg.enabled,true) fails == svg-glyph-mask.svg svg-glyph-mask-ref.svg # bug 872483
|
||||
|
||||
# test for a non-BMP character in the glyphchar attribute (bug 875629)
|
||||
pref(gfx.font_rendering.opentype_svg.enabled,true) != cat_face-bmp.html cat_face-notref.html
|
||||
pref(gfx.font_rendering.opentype_svg.enabled,true) == cat_face.html cat_face-bmp.html
|
||||
# test for a variation sequence involving a Plane-1 char and Plane-14 variation selector (bug 875629)
|
||||
pref(gfx.font_rendering.opentype_svg.enabled,true) == two_cats-var.html two_cats-ref.html
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
Fonts in this directory:
|
||||
|
||||
rubbish.woff contains an SVG table with the contents of rubbish.txt. This is
|
||||
not a valid SVG table so no SVG glyphs will be used.
|
||||
|
||||
nosvg.woff is derived from the "Liberation" font. It contains no SVG table.
|
||||
|
||||
svg.woff is nosvg.woff with an SVG table added. The
|
||||
table contains the glyph documents glyphs-base.svg, glyphs-invalid.svg,
|
||||
glyphs-objectcolor.svg, glyphs-objectopacity.svg and glyphs-objectstroke.svg.
|
Двоичные данные
layout/reftests/text-svgglyphs/resources/cat_face-bmp.ttf
Двоичные данные
layout/reftests/text-svgglyphs/resources/cat_face.ttf
|
@ -1,22 +1,13 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<!--
|
||||
Basic test SVG glyphs
|
||||
Covers glyph ID range 1 (L\xfe01) to 47 (M)
|
||||
Covers glyph ID 46
|
||||
-->
|
||||
<!-- char = L -->
|
||||
<g glyphid="46">
|
||||
<g id="glyph46">
|
||||
<rect x="100" y="-900" width="800" height="800" stroke-width="50"
|
||||
stroke="black" fill="red"/>
|
||||
<rect x="100" y="-1000" width="100" height="100" stroke="none"
|
||||
fill="turquoise" />
|
||||
</g>
|
||||
|
||||
<!-- L with a UVS selector -->
|
||||
<rect x="100" y="-900" width="800" height="800" stroke-width="50"
|
||||
stroke="black" fill="green" glyphchar="L︁"/>
|
||||
|
||||
<!-- M -->
|
||||
<rect x="50" y="-950" width="900" height="900" stroke-width="100"
|
||||
fill="pink" stroke="hotpink" glyphchar="M"/>
|
||||
|
||||
</svg>
|
||||
|
|
До Ширина: | Высота: | Размер: 664 B После Ширина: | Высота: | Размер: 349 B |
|
@ -0,0 +1,40 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<!--
|
||||
Test handling of invalid ids
|
||||
-->
|
||||
<!-- not valid: leading space not allowed -->
|
||||
<g id="glyph 47">
|
||||
<rect x="100" y="-900" width="800" height="800" stroke-width="50"
|
||||
fill="red"/>
|
||||
</g>
|
||||
<!-- not valid: leading zero not allowed -->
|
||||
<g id="glyph047">
|
||||
<rect x="100" y="-900" width="800" height="800" stroke-width="50"
|
||||
fill="red"/>
|
||||
</g>
|
||||
<!-- not valid: trailing garbage not allowed -->
|
||||
<g id="glyph47xxx">
|
||||
<rect x="100" y="-900" width="800" height="800" stroke-width="50"
|
||||
fill="red"/>
|
||||
</g>
|
||||
<!-- not valid: trailing space not allowed -->
|
||||
<g id="glyph47 ">
|
||||
<rect x="100" y="-900" width="800" height="800" stroke-width="50"
|
||||
fill="red"/>
|
||||
</g>
|
||||
<!-- not valid: floating point not allowed -->
|
||||
<g id="glyph47.0">
|
||||
<rect x="100" y="-900" width="800" height="800" stroke-width="50"
|
||||
fill="red"/>
|
||||
</g>
|
||||
<!-- char = M -->
|
||||
<g id="glyph47">
|
||||
<rect x="100" y="-900" width="800" height="800" stroke-width="50"
|
||||
fill="lime"/>
|
||||
</g>
|
||||
<!-- Ensure first glyph47 is picked -->
|
||||
<g id="glyph47">
|
||||
<rect x="100" y="-900" width="800" height="800" stroke-width="50"
|
||||
fill="red"/>
|
||||
</g>
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 1.2 KiB |
|
@ -6,19 +6,19 @@
|
|||
<!-- -moz-objectfill, no stroke -->
|
||||
<!-- N -->
|
||||
<rect x="100" y="-900" width="800" height="800" stroke-width="50"
|
||||
stroke="none" fill="-moz-objectFill" glyphchar="N"/>
|
||||
stroke="none" fill="-moz-objectFill" id="glyph48"/>
|
||||
|
||||
<!-- O -->
|
||||
<rect x="50" y="-950" width="900" height="900" stroke-width="100"
|
||||
fill="-moz-objectFill" stroke="none" glyphchar="O"/>
|
||||
fill="-moz-objectFill" stroke="none" id="glyph49"/>
|
||||
|
||||
<!-- -moz-objectstroke -->
|
||||
<!-- P -->
|
||||
<rect x="100" y="-900" width="800" height="800" stroke-width="50"
|
||||
stroke="-moz-objectStroke" fill="burlywood" glyphchar="P"/>
|
||||
stroke="-moz-objectStroke" fill="burlywood" id="glyph50"/>
|
||||
|
||||
<!-- both -moz-objectstroke and -moz-objectfill -->
|
||||
<!-- Q -->
|
||||
<rect x="50" y="-950" width="900" height="900" stroke-width="100"
|
||||
fill="-moz-objectStroke" stroke="-moz-objectFill" glyphchar="Q"/>
|
||||
fill="-moz-objectStroke" stroke="-moz-objectFill" id="glyph51"/>
|
||||
</svg>
|
||||
|
|
До Ширина: | Высота: | Размер: 846 B После Ширина: | Высота: | Размер: 842 B |
|
@ -7,19 +7,19 @@
|
|||
<rect x="100" y="-900" width="800" height="800" stroke-width="50"
|
||||
fill="-moz-objectFill" stroke="-moz-objectStroke"
|
||||
fill-opacity="-moz-objectFillOpacity"
|
||||
stroke-opacity="-moz-objectStrokeOpacity" glyphchar="R"/>
|
||||
stroke-opacity="-moz-objectStrokeOpacity" id="glyph52"/>
|
||||
|
||||
<!-- S -->
|
||||
<rect x="100" y="-900" width="800" height="800" stroke-width="50"
|
||||
fill="-moz-objectFill" stroke="-moz-objectStroke"
|
||||
fill-opacity="-moz-objectStrokeOpacity"
|
||||
stroke-opacity="-moz-objectFillOpacity" glyphchar="S"/>
|
||||
stroke-opacity="-moz-objectFillOpacity" id="glyph53"/>
|
||||
|
||||
<!-- T -->
|
||||
<rect x="100" y="-900" width="800" height="800" stroke-width="50"
|
||||
fill="-moz-objectStroke" stroke="-moz-objectFill"
|
||||
fill-opacity="-moz-objectFillOpacity"
|
||||
stroke-opacity="-moz-objectStrokeOpacity" glyphchar="T"/>
|
||||
stroke-opacity="-moz-objectStrokeOpacity" id="glyph54"/>
|
||||
|
||||
<!-- U -->
|
||||
<!-- Test for bug where explicit `inherit' would fail for
|
||||
|
@ -27,23 +27,23 @@
|
|||
<g style="fill-opacity : -moz-objectStrokeOpacity; stroke-opacity : -moz-objectFillOpacity">
|
||||
<rect x="100" y="-900" width="800" height="800" stroke-width="50"
|
||||
fill="-moz-objectStroke" stroke="-moz-objectFill"
|
||||
fill-opacity="inherit" stroke-opacity="inherit" glyphchar="U"/>
|
||||
fill-opacity="inherit" stroke-opacity="inherit" id="glyph55"/>
|
||||
</g>
|
||||
|
||||
<!-- W -->
|
||||
<rect x="100" y="-900" width="800" height="800" stroke-width="50"
|
||||
fill="darkorchid" stroke="goldenrod"
|
||||
fill-opacity="-moz-objectFillOpacity"
|
||||
stroke-opacity="-moz-objectStrokeOpacity" glyphchar="W"/>
|
||||
stroke-opacity="-moz-objectStrokeOpacity" id="glyph57"/>
|
||||
|
||||
<!-- X -->
|
||||
<rect x="100" y="-900" width="800" height="800" stroke-width="50"
|
||||
fill="darkorchid" stroke="goldenrod"
|
||||
fill-opacity="-moz-objectStrokeOpacity"
|
||||
stroke-opacity="-moz-objectFillOpacity" glyphchar="X"/>
|
||||
stroke-opacity="-moz-objectFillOpacity" id="glyph58"/>
|
||||
|
||||
<style type="text/css"><![CDATA[
|
||||
#yparent {
|
||||
#glyph59 {
|
||||
fill-opacity : -moz-objectFillOpacity;
|
||||
stroke-opacity : -moz-objectStrokeOpacity;
|
||||
}
|
||||
|
@ -52,7 +52,7 @@
|
|||
}
|
||||
]]></style>
|
||||
<!-- Y -->
|
||||
<g glyphchar="Y" id="yparent">
|
||||
<g id="glyph59">
|
||||
<rect x="100" y="-900" width="800" height="300" stroke="red" stroke-width="50"/>
|
||||
<rect x="100" y="-400" width="800" height="300" stroke="red" stroke-width="50" id="ychild" />
|
||||
</g>
|
||||
|
|
До Ширина: | Высота: | Размер: 2.2 KiB После Ширина: | Высота: | Размер: 2.1 KiB |
|
@ -6,20 +6,20 @@
|
|||
<!-- a -->
|
||||
<rect x="100" y="-900" width="800" height="800" stroke="powderblue"
|
||||
stroke-width="50" stroke-dashoffset="35"
|
||||
stroke-dasharray="50 50" glyphchar="a" />
|
||||
stroke-dasharray="50 50" id="glyph67" />
|
||||
|
||||
<!-- b -->
|
||||
<rect x="100" y="-900" width="800" height="800" stroke="chartreuse"
|
||||
stroke-width="50" stroke-dashoffset="35"
|
||||
stroke-dasharray="-moz-objectValue" glyphchar="b" />
|
||||
stroke-dasharray="-moz-objectValue" id="glyph68" />
|
||||
|
||||
<!-- c -->
|
||||
<rect x="100" y="-900" width="800" height="800" stroke="sienna"
|
||||
stroke-width="50" stroke-dasharray="50 50"
|
||||
stroke-dashoffset="-moz-objectValue" glyphchar="c" />
|
||||
stroke-dashoffset="-moz-objectValue" id="glyph69" />
|
||||
|
||||
<!-- d -->
|
||||
<rect x="100" y="-900" width="800" height="800" stroke="olivedrab"
|
||||
stroke-width="-moz-objectValue" stroke-dasharray="-moz-objectValue"
|
||||
stroke-dashoffset="-moz-objectValue" glyphchar="d" />
|
||||
stroke-dashoffset="-moz-objectValue" id="glyph70" />
|
||||
</svg>
|
||||
|
|
До Ширина: | Высота: | Размер: 919 B После Ширина: | Высота: | Размер: 915 B |
Двоичные данные
layout/reftests/text-svgglyphs/resources/svg.woff
Двоичные данные
layout/reftests/text-svgglyphs/resources/two_cats.ttf
|
@ -5,8 +5,4 @@
|
|||
<rect x="20" y="0" width="20" height="20" stroke="none"
|
||||
fill="turquoise" />
|
||||
</g>
|
||||
<rect x="10" y="210" width="180" height="180" stroke-width="20"
|
||||
fill="pink" stroke="hotpink" />
|
||||
<rect x="20" y="420" width="160" height="160" stroke-width="10"
|
||||
stroke="black" fill="green" />
|
||||
</svg>
|
||||
|
|
До Ширина: | Высота: | Размер: 452 B После Ширина: | Высота: | Размер: 249 B |
|
@ -14,7 +14,7 @@
|
|||
]]>
|
||||
</style>
|
||||
<!--
|
||||
Test that SVG glyphs are being drawn instead of TrueType glyphs
|
||||
Test that SVG glyphs are being drawn instead of TrueType glyphs
|
||||
Also testing that this does not happen if the
|
||||
gfx.font_rendering.opentype_svg.enabled preference is set to true.
|
||||
-->
|
||||
|
@ -22,12 +22,4 @@
|
|||
<text x="0" y="200">
|
||||
L
|
||||
</text>
|
||||
<!-- glyphchar -->
|
||||
<text x="0" y="400">
|
||||
M
|
||||
</text>
|
||||
<!-- glyphchar with UVS selector -->
|
||||
<text x="0" y="600">
|
||||
L︁
|
||||
</text>
|
||||
</svg>
|
||||
|
|
До Ширина: | Высота: | Размер: 723 B После Ширина: | Высота: | Размер: 579 B |
|
@ -0,0 +1,6 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<g>
|
||||
<rect x="20" y="20" width="160" height="160" stroke-width="10"
|
||||
fill="lime" />
|
||||
</g>
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 149 B |
|
@ -0,0 +1,22 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<style type="text/css">
|
||||
<![CDATA[
|
||||
@font-face {
|
||||
font-family: "Liberation";
|
||||
src:url(resources/svg.woff);
|
||||
}
|
||||
text
|
||||
{
|
||||
font-family: Liberation;
|
||||
font-size: 200px;
|
||||
}
|
||||
]]>
|
||||
</style>
|
||||
<!--
|
||||
Test that the right SVG glyph is picked from a document containing various
|
||||
invalid glyph IDs.
|
||||
-->
|
||||
<text x="0" y="200">
|
||||
M
|
||||
</text>
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 448 B |
|
@ -1,15 +1,19 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<!-- M -->
|
||||
<rect x="10" y="10" width="180" height="180" stroke-width="20"
|
||||
fill="pink" stroke="hotpink" />
|
||||
|
||||
<!-- L -->
|
||||
<rect x="220" y="20" width="160" height="160" stroke-width="10"
|
||||
<rect x="20" y="20" width="160" height="160" stroke-width="10"
|
||||
stroke="black" fill="red" />
|
||||
<rect x="220" y="0" width="20" height="20" stroke="none"
|
||||
<rect x="20" y="0" width="20" height="20" stroke="none"
|
||||
fill="turquoise" />
|
||||
|
||||
<!-- L with UVS -->
|
||||
<rect x="370" y="20" width="160" height="160" stroke-width="10"
|
||||
stroke="black" fill="green" />
|
||||
<!-- L -->
|
||||
<rect x="170" y="20" width="160" height="160" stroke-width="10"
|
||||
stroke="black" fill="red" />
|
||||
<rect x="170" y="0" width="20" height="20" stroke="none"
|
||||
fill="turquoise" />
|
||||
|
||||
<!-- L -->
|
||||
<rect x="320" y="20" width="160" height="160" stroke-width="10"
|
||||
stroke="black" fill="red" />
|
||||
<rect x="320" y="0" width="20" height="20" stroke="none"
|
||||
fill="turquoise" />
|
||||
</svg>
|
||||
|
|
До Ширина: | Высота: | Размер: 482 B После Ширина: | Высота: | Размер: 633 B |
|
@ -14,10 +14,10 @@
|
|||
]]>
|
||||
</style>
|
||||
<!--
|
||||
Test that we're rendering in the right place in the middle of a
|
||||
Test that we're rendering in the right place in the middle of a
|
||||
text run
|
||||
-->
|
||||
<text x="0" y="200">
|
||||
MLL︁
|
||||
LLL
|
||||
</text>
|
||||
</svg>
|
||||
|
|
До Ширина: | Высота: | Размер: 462 B После Ширина: | Высота: | Размер: 452 B |
|
@ -1,17 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<style type="text/css">
|
||||
@font-face { font-family: foo; src: url("resources/two_cats.ttf"); }
|
||||
body { font-family: foo, sans-serif; font-size: 24px; }
|
||||
td { padding: 2px 10px }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<table>
|
||||
<tr><td>🐱</td><td>ネコ</td><td>cat face</td></tr>
|
||||
<tr><td>😻</td><td>目がハート(ネコ)</td><td>smiling cat face with heart shaped eyes</td></tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
|
@ -1,18 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<style type="text/css">
|
||||
@font-face { font-family: foo; src: url("resources/two_cats.ttf"); }
|
||||
body { font-family: foo, sans-serif; font-size: 24px; }
|
||||
td { padding: 2px 10px }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<table>
|
||||
<!-- the Plane-14 variation selector U+E0100 should change U+1F431 to the "heart shaped eyes" cat face -->
|
||||
<tr><td>🐱</td><td>ネコ</td><td>cat face</td></tr>
|
||||
<tr><td>🐱󠄀</td><td>目がハート(ネコ)</td><td>smiling cat face with heart shaped eyes</td></tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
|
@ -1831,17 +1831,14 @@ nsSVGUtils::PaintSVGGlyph(Element* aElement, gfxContext* aContext,
|
|||
{
|
||||
nsIFrame* frame = aElement->GetPrimaryFrame();
|
||||
nsISVGChildFrame* svgFrame = do_QueryFrame(frame);
|
||||
MOZ_ASSERT(!frame || svgFrame, "Non SVG frame for SVG glyph");
|
||||
if (svgFrame) {
|
||||
nsRenderingContext context;
|
||||
context.Init(frame->PresContext()->DeviceContext(), aContext);
|
||||
context.AddUserData(&gfxTextObjectPaint::sUserDataKey, aObjectPaint, nullptr);
|
||||
nsresult rv = svgFrame->PaintSVG(&context, nullptr);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
return true;
|
||||
}
|
||||
if (!svgFrame) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
nsRenderingContext context;
|
||||
context.Init(frame->PresContext()->DeviceContext(), aContext);
|
||||
context.AddUserData(&gfxTextObjectPaint::sUserDataKey, aObjectPaint, nullptr);
|
||||
nsresult rv = svgFrame->PaintSVG(&context, nullptr);
|
||||
return NS_SUCCEEDED(rv);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -1851,15 +1848,14 @@ nsSVGUtils::GetSVGGlyphExtents(Element* aElement,
|
|||
{
|
||||
nsIFrame* frame = aElement->GetPrimaryFrame();
|
||||
nsISVGChildFrame* svgFrame = do_QueryFrame(frame);
|
||||
MOZ_ASSERT(!frame || svgFrame, "Non SVG frame for SVG glyph");
|
||||
if (svgFrame) {
|
||||
*aResult = svgFrame->GetBBoxContribution(aSVGToAppSpace,
|
||||
nsSVGUtils::eBBoxIncludeFill | nsSVGUtils::eBBoxIncludeFillGeometry |
|
||||
nsSVGUtils::eBBoxIncludeStroke | nsSVGUtils::eBBoxIncludeStrokeGeometry |
|
||||
nsSVGUtils::eBBoxIncludeMarkers);
|
||||
return true;
|
||||
if (!svgFrame) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
*aResult = svgFrame->GetBBoxContribution(aSVGToAppSpace,
|
||||
nsSVGUtils::eBBoxIncludeFill | nsSVGUtils::eBBoxIncludeFillGeometry |
|
||||
nsSVGUtils::eBBoxIncludeStroke | nsSVGUtils::eBBoxIncludeStrokeGeometry |
|
||||
nsSVGUtils::eBBoxIncludeMarkers);
|
||||
return true;
|
||||
}
|
||||
|
||||
nsRect
|
||||
|
|
|
@ -3,6 +3,8 @@ head = head_channels.js head_cache.js
|
|||
tail =
|
||||
|
||||
[test_304_responses.js]
|
||||
# Bug 675039: test hangs on Android-armv6
|
||||
skip-if = os == "android"
|
||||
[test_cacheForOfflineUse_no-store.js]
|
||||
[test_307_redirect.js]
|
||||
[test_NetUtil.js]
|
||||
|
@ -15,7 +17,11 @@ tail =
|
|||
[test_authpromptwrapper.js]
|
||||
[test_backgroundfilesaver.js]
|
||||
[test_bug203271.js]
|
||||
# Bug 675039: intermittent fail on Android-armv6
|
||||
skip-if = os == "android"
|
||||
[test_bug248970_cache.js]
|
||||
# Bug 675039: intermittent fail on Android-armv6
|
||||
skip-if = os == "android"
|
||||
[test_bug248970_cookie.js]
|
||||
[test_bug261425.js]
|
||||
[test_bug263127.js]
|
||||
|
@ -25,6 +31,8 @@ tail =
|
|||
[test_bug336501.js]
|
||||
[test_bug337744.js]
|
||||
[test_bug365133.js]
|
||||
# Bug 675039: intermittent fail on Android-armv6
|
||||
skip-if = os == "android"
|
||||
[test_bug368702.js]
|
||||
[test_bug369787.js]
|
||||
[test_bug371473.js]
|
||||
|
@ -43,31 +51,55 @@ tail =
|
|||
[test_bug455311.js]
|
||||
[test_bug455598.js]
|
||||
[test_bug468426.js]
|
||||
# Bug 675039: intermittent fail on Android-armv6
|
||||
skip-if = os == "android"
|
||||
[test_bug468594.js]
|
||||
# Bug 675039: intermittent fail on Android-armv6
|
||||
skip-if = os == "android"
|
||||
[test_bug470716.js]
|
||||
[test_bug479413.js]
|
||||
[test_bug479485.js]
|
||||
[test_bug482601.js]
|
||||
# Bug 675039: intermittent fail on Android-armv6
|
||||
skip-if = os == "android"
|
||||
[test_bug484684.js]
|
||||
# Bug 675039: intermittent fail on Android-armv6
|
||||
skip-if = os == "android"
|
||||
[test_bug490095.js]
|
||||
# Bug 675039: intermittent fail on Android-armv6
|
||||
skip-if = os == "android"
|
||||
[test_bug504014.js]
|
||||
[test_bug510359.js]
|
||||
[test_bug515583.js]
|
||||
# Bug 675039: intermittent fail on Android-armv6
|
||||
skip-if = os == "android"
|
||||
[test_bug528292.js]
|
||||
[test_bug536324_64bit_content_length.js]
|
||||
[test_bug540566.js]
|
||||
# Bug 675039: intermittent fail on Android-armv6
|
||||
skip-if = os == "android"
|
||||
[test_bug543805.js]
|
||||
# Bug 675039: intermittent fail on Android-armv6
|
||||
skip-if = os == "android"
|
||||
[test_bug553970.js]
|
||||
[test_bug561042.js]
|
||||
# Bug 675039: test fails on Android 4.0
|
||||
skip-if = os == "android"
|
||||
[test_bug561276.js]
|
||||
[test_bug580508.js]
|
||||
[test_bug586908.js]
|
||||
[test_bug596443.js]
|
||||
# Bug 675039: intermittent fail on Android
|
||||
skip-if = os == "android"
|
||||
[test_bug618835.js]
|
||||
[test_bug633743.js]
|
||||
# Bug 675039: intermittent fail on Android-armv6
|
||||
skip-if = os == "android"
|
||||
[test_bug650995.js]
|
||||
[test_bug652761.js]
|
||||
[test_bug651100.js]
|
||||
# Bug 675039: intermittent hang on Android-x86
|
||||
skip-if = os == "android"
|
||||
[test_bug654926.js]
|
||||
[test_bug654926_doom_and_read.js]
|
||||
[test_bug654926_test_seek.js]
|
||||
|
@ -76,6 +108,8 @@ tail =
|
|||
[test_bug667907.js]
|
||||
[test_bug667818.js]
|
||||
[test_bug669001.js]
|
||||
# Bug 675039: intermittent fail on Android-armv6
|
||||
skip-if = os == "android"
|
||||
[test_bug712914_secinfo_validation.js]
|
||||
[test_bug770243.js]
|
||||
[test_bug894586.js]
|
||||
|
@ -83,6 +117,8 @@ tail =
|
|||
skip-if = bits != 32
|
||||
[test_doomentry.js]
|
||||
[test_cacheflags.js]
|
||||
# Bug 675039: intermittent fail on Android-armv6
|
||||
skip-if = os == "android"
|
||||
[test_cache_jar.js]
|
||||
[test_channel_close.js]
|
||||
[test_compareURIs.js]
|
||||
|
@ -112,6 +148,8 @@ skip-if = bits != 32
|
|||
[test_freshconnection.js]
|
||||
[test_gre_resources.js]
|
||||
[test_gzipped_206.js]
|
||||
# Bug 675039: intermittent fail on Android-armv6
|
||||
skip-if = os == "android"
|
||||
[test_head.js]
|
||||
[test_header_Accept-Language.js]
|
||||
[test_headers.js]
|
||||
|
@ -140,6 +178,8 @@ skip-if = os == "win"
|
|||
[test_plaintext_sniff.js]
|
||||
[test_post.js]
|
||||
[test_private_necko_channel.js]
|
||||
# Bug 675039: intermittent fail on Android-armv6
|
||||
skip-if = os == "android"
|
||||
[test_private_cookie_changed.js]
|
||||
[test_progress.js]
|
||||
[test_protocolproxyservice.js]
|
||||
|
@ -151,6 +191,8 @@ skip-if = os == "win"
|
|||
[test_range_requests.js]
|
||||
[test_readline.js]
|
||||
[test_redirect-caching_canceled.js]
|
||||
# Bug 675039: intermittent fail on Android-armv6
|
||||
skip-if = os == "android"
|
||||
[test_redirect-caching_failure.js]
|
||||
# Bug 675039: test fails consistently on Android
|
||||
fail-if = os == "android"
|
||||
|
@ -193,6 +235,8 @@ run-sequentially = Hardcoded hash value includes port 4444.
|
|||
run-sequentially = Hardcoded hash value includes port 4444.
|
||||
[test_bug826063.js]
|
||||
[test_bug812167.js]
|
||||
# Bug 675039: intermittent fail on Android-armv6
|
||||
skip-if = os == "android"
|
||||
[test_tldservice_nextsubdomain.js]
|
||||
[test_about_protocol.js]
|
||||
[test_bug856978.js]
|
||||
|
|
|
@ -102,12 +102,14 @@ class BackendMakeFile(object):
|
|||
if self.xpt_name:
|
||||
self.fh.write('XPT_NAME := %s\n' % self.xpt_name)
|
||||
|
||||
# We just recompile all xpidls because it's easier and less error
|
||||
# prone.
|
||||
self.fh.write('NONRECURSIVE_TARGETS += export\n')
|
||||
self.fh.write('NONRECURSIVE_TARGETS_export += xpidl\n')
|
||||
self.fh.write('NONRECURSIVE_TARGETS_export_xpidl_DIRECTORY = '
|
||||
'$(DEPTH)/config/makefiles/xpidl\n')
|
||||
'$(DEPTH)/config/makefiles/precompile\n')
|
||||
self.fh.write('NONRECURSIVE_TARGETS_export_xpidl_TARGETS += '
|
||||
'xpt/%s' % self.xpt_name)
|
||||
'xpidl\n')
|
||||
|
||||
return self.fh.close()
|
||||
|
||||
|
@ -417,8 +419,19 @@ class RecursiveMakeBackend(CommonBackend):
|
|||
|
||||
for module in xpt_modules:
|
||||
deps = sorted(modules[module])
|
||||
idl_deps = ['$(dist_idl_dir)/%s.idl' % dep for dep in deps]
|
||||
rules.extend([
|
||||
'$(idl_xpt_dir)/%s.xpt:' % module,
|
||||
# It may seem strange to have the .idl files listed as
|
||||
# prerequisites both here and in the auto-generated .pp files.
|
||||
# It is necessary to list them here to handle the case where a
|
||||
# new .idl is added to an xpt. If we add a new .idl and nothing
|
||||
# else has changed, the new .idl won't be referenced anywhere
|
||||
# except in the command invocation. Therefore, the .xpt won't
|
||||
# be rebuilt because the dependencies say it is up to date. By
|
||||
# listing the .idls here, we ensure the make file has a
|
||||
# reference to the new .idl. Since the new .idl presumably has
|
||||
# an mtime newer than the .xpt, it will trigger xpt generation.
|
||||
'$(idl_xpt_dir)/%s.xpt: %s' % (module, ' '.join(idl_deps)),
|
||||
'\t@echo "$(notdir $@)"',
|
||||
'\t$(idlprocess) $(basename $(notdir $@)) %s' % ' '.join(deps),
|
||||
'',
|
||||
|
|
|
@ -3,8 +3,14 @@ head = head_psm.js
|
|||
tail =
|
||||
|
||||
[test_certificate_usages.js]
|
||||
# Bug 676972: test fails consistently on Android
|
||||
fail-if = os == "android"
|
||||
[test_signed_apps.js]
|
||||
# Bug 676972: test fails consistently on Android
|
||||
fail-if = os == "android"
|
||||
[test_signed_apps-marketplace.js]
|
||||
# Bug 676972: test fails consistently on Android
|
||||
fail-if = os == "android"
|
||||
[test_datasignatureverifier.js]
|
||||
# Bug 676972: test hangs consistently on Android
|
||||
skip-if = os == "android"
|
||||
|
@ -17,3 +23,5 @@ skip-if = os == "android"
|
|||
[test_sts_preloadlist_perwindowpb.js]
|
||||
[test_sts_preloadlist_selfdestruct.js]
|
||||
[test_ocsp_stapling.js]
|
||||
# Bug 676972: test fails consistently on Android
|
||||
fail-if = os == "android"
|
||||
|
|
|
@ -22,6 +22,8 @@ fail-if = os == "android"
|
|||
[test_statement_wrapper_automatically.js]
|
||||
[test_storage_aggregates.js]
|
||||
[test_storage_connection.js]
|
||||
# Bug 676981: test fails consistently on Android
|
||||
fail-if = os == "android"
|
||||
[test_storage_fulltextindex.js]
|
||||
[test_storage_function.js]
|
||||
[test_storage_progresshandler.js]
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
; 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:chrome/test/unit/xpcshell.ini]
|
||||
[include:intl/locale/tests/unit/xpcshell.ini]
|
||||
[include:netwerk/cookie/test/unit/xpcshell.ini]
|
||||
|
@ -46,3 +47,22 @@
|
|||
[include:browser/components/privatebrowsing/test/unit/xpcshell.ini]
|
||||
[include:browser/modules/test/unit/xpcshell.ini]
|
||||
[include:toolkit/components/telemetry/tests/unit/xpcshell.ini]
|
||||
[include:netwerk/test/unit/xpcshell.ini]
|
||||
[include:intl/strres/tests/unit/xpcshell.ini]
|
||||
[include:intl/unicharutil/tests/unit/xpcshell.ini]
|
||||
[include:intl/uconv/tests/unit/xpcshell.ini]
|
||||
[include:uriloader/exthandler/tests/unit/xpcshell.ini]
|
||||
[include:services/datareporting/tests/xpcshell/xpcshell.ini]
|
||||
[include:storage/test/unit/xpcshell.ini]
|
||||
[include:docshell/test/unit/xpcshell.ini]
|
||||
[include:js/xpconnect/tests/unit/xpcshell.ini]
|
||||
[include:js/jsd/test/xpcshell.ini]
|
||||
[include:browser/devtools/shared/test/unit/xpcshell.ini]
|
||||
[include:browser/components/migration/tests/unit/xpcshell.ini]
|
||||
[include:browser/components/places/tests/unit/xpcshell.ini]
|
||||
[include:browser/components/sessionstore/test/unit/xpcshell.ini]
|
||||
[include:browser/components/shell/test/unit/xpcshell.ini]
|
||||
[include:browser/components/dirprovider/tests/unit/xpcshell.ini]
|
||||
[include:browser/components/downloads/test/unit/xpcshell.ini]
|
||||
[include:browser/components/feeds/test/unit/xpcshell.ini]
|
||||
[include:security/manager/ssl/tests/unit/xpcshell.ini]
|
||||
|
|
|
@ -25,3 +25,5 @@ skip-if = os == "android"
|
|||
skip-if = os == "android"
|
||||
[test_store.js]
|
||||
[test_well-known.js]
|
||||
# Bug 905340 - http port dependency causes failure on Android 4.0
|
||||
skip-if = os == "android"
|
||||
|
|
|
@ -57,6 +57,8 @@ class TimeStamp;
|
|||
|
||||
#ifndef MOZ_ENABLE_PROFILER_SPS
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct JSContext;
|
||||
class JSObject;
|
||||
|
||||
|
|
|
@ -8,3 +8,5 @@ tail = tail_handlerService.js
|
|||
# Bug 676997: test consistently fails on Android
|
||||
fail-if = os == "android"
|
||||
[test_punycodeURIs.js]
|
||||
# Bug 676997: test consistently fails on Android
|
||||
fail-if = os == "android"
|
||||
|
|
|
@ -3359,7 +3359,16 @@ NSEvent* gLastDragMouseDownEvent = nil;
|
|||
new gfxQuartzSurface(aContext, backingSize);
|
||||
targetSurface->SetAllowUseAsSource(false);
|
||||
|
||||
nsRefPtr<gfxContext> targetContext = new gfxContext(targetSurface);
|
||||
nsRefPtr<gfxContext> targetContext;
|
||||
if (gfxPlatform::GetPlatform()->SupportsAzureContentForType(mozilla::gfx::BACKEND_CAIRO)) {
|
||||
RefPtr<mozilla::gfx::DrawTarget> dt =
|
||||
gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(targetSurface,
|
||||
mozilla::gfx::IntSize(backingSize.width,
|
||||
backingSize.height));
|
||||
targetContext = new gfxContext(dt);
|
||||
} else {
|
||||
targetContext = new gfxContext(targetSurface);
|
||||
}
|
||||
|
||||
// Set up the clip region.
|
||||
nsIntRegionRectIterator iter(region);
|
||||
|
|
|
@ -9,11 +9,11 @@
|
|||
#include "nsISupports.h"
|
||||
#include "nsColor.h"
|
||||
#include "nsRect.h"
|
||||
#include "nsStringGlue.h"
|
||||
|
||||
#include "nsEvent.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsWidgetInitData.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "mozilla/layers/LayersTypes.h"
|
||||
|
|
|
@ -76,8 +76,7 @@ WinUtils::Initialize()
|
|||
if (!sDwmDll && WinUtils::GetWindowsVersion() >= WinUtils::VISTA_VERSION) {
|
||||
sDwmDll = ::LoadLibraryW(kDwmLibraryName);
|
||||
|
||||
// MSDN: "If the function succeeds, the return value is greater than 31."
|
||||
if (uintptr_t(sDwmDll) > 31) {
|
||||
if (sDwmDll) {
|
||||
dwmExtendFrameIntoClientAreaPtr = (DwmExtendFrameIntoClientAreaProc)::GetProcAddress(sDwmDll, "DwmExtendFrameIntoClientArea");
|
||||
dwmIsCompositionEnabledPtr = (DwmIsCompositionEnabledProc)::GetProcAddress(sDwmDll, "DwmIsCompositionEnabled");
|
||||
dwmSetIconicThumbnailPtr = (DwmSetIconicThumbnailProc)::GetProcAddress(sDwmDll, "DwmSetIconicThumbnail");
|
||||
|
|
|
@ -7,6 +7,8 @@ tail =
|
|||
[test_bug332389.js]
|
||||
[test_bug333505.js]
|
||||
[test_bug364285-1.js]
|
||||
# Bug 902073: test fails consistently on Android x86
|
||||
skip-if = os == "android"
|
||||
[test_bug374754.js]
|
||||
[test_bug476919.js]
|
||||
# Bug 676998: test fails consistently on Android
|
||||
|
|