зеркало из https://github.com/mozilla/gecko-dev.git
Merge last PGO-green changeset of mozilla-inbound to mozilla-central
This commit is contained in:
Коммит
b20d292747
|
@ -11995,7 +11995,7 @@ NS_IMETHODIMP
|
|||
nsDocShell::SetIsBrowserElement()
|
||||
{
|
||||
if (mIsBrowserFrame) {
|
||||
NS_ERROR("You should not call SetIsBrowser() more than once.");
|
||||
NS_ERROR("You should not call SetIsBrowserElement() more than once.");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,16 +14,16 @@ Cu.import("resource://gre/modules/mms_consts.js");
|
|||
let DEBUG; // set to true to see debug messages
|
||||
|
||||
function translatePduErrorToStatus(error) {
|
||||
switch (error) {
|
||||
case MMS_PDU_ERROR_OK:
|
||||
return MMS_PDU_STATUS_RETRIEVED;
|
||||
case MMS_PDU_ERROR_TRANSIENT_FAILURE:
|
||||
case MMS_PDU_ERROR_TRANSIENT_MESSAGE_NOT_FOUND:
|
||||
case MMS_PDU_ERROR_TRANSIENT_NETWORK_PROBLEM:
|
||||
return MMS_PDU_STATUS_DEFERRED;
|
||||
default:
|
||||
return MMS_PDU_STATUS_UNRECOGNISED;
|
||||
if (error == MMS_PDU_ERROR_OK) {
|
||||
return MMS_PDU_STATUS_RETRIEVED;
|
||||
}
|
||||
|
||||
if ((error >= MMS_PDU_ERROR_TRANSIENT_FAILURE)
|
||||
&& (error < MMS_PDU_ERROR_PERMANENT_FAILURE)) {
|
||||
return MMS_PDU_STATUS_DEFERRED;
|
||||
}
|
||||
|
||||
return MMS_PDU_STATUS_UNRECOGNISED;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -70,7 +70,13 @@ let BooleanValue = {
|
|||
* @see OMA-TS-MMS_ENC-V1_3-20110913-A section 8
|
||||
*/
|
||||
let Address = {
|
||||
decode: function (data) {
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object to store encoded raw data.
|
||||
*
|
||||
* @return An object of two string-typed attributes: address and type.
|
||||
*/
|
||||
decode: function decode(data) {
|
||||
let str = EncodedStringValue.decode(data);
|
||||
|
||||
let result;
|
||||
|
@ -398,30 +404,15 @@ let Parameter = {
|
|||
};
|
||||
|
||||
/**
|
||||
* Encoded-string-value = Text-string | Value-length Char-set Text-string
|
||||
* The Char-set values are registered by IANA as MIBEnum value.
|
||||
* The Char-set values are registered by IANA as MIBEnum value and SHALL be
|
||||
* encoded as Integer-value.
|
||||
*
|
||||
* Encoded-string-value = Text-string | Value-length Char-set Text-string
|
||||
*
|
||||
* @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.19
|
||||
* @see OMA-TS-MMS_CONF-V1_3-20110913-A clause 10.2.1
|
||||
*/
|
||||
let EncodedStringValue = {
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object containing raw PDU data.
|
||||
*
|
||||
* @return Decoded string.
|
||||
*/
|
||||
decode: function decode(data) {
|
||||
return WSP.decodeAlternatives(data, null,
|
||||
WSP.TextString, CharsetEncodedString);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Charset-encoded-string = Value-length Char-set Text-string
|
||||
*
|
||||
* @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.19
|
||||
*/
|
||||
let CharsetEncodedString = {
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object containing raw PDU data.
|
||||
|
@ -432,11 +423,11 @@ let CharsetEncodedString = {
|
|||
* @throws NotWellKnownEncodingError if decoded well-known charset number is
|
||||
* not registered or supported.
|
||||
*/
|
||||
decode: function decode(data) {
|
||||
decodeCharsetEncodedString: function decodeCharsetEncodedString(data) {
|
||||
let length = WSP.ValueLength.decode(data);
|
||||
let end = data.offset + length;
|
||||
|
||||
let charset = WSP.ShortInteger.decode(data);
|
||||
let charset = WSP.IntegerValue.decode(data);
|
||||
let entry = WSP.WSP_WELL_KNOWN_CHARSETS[charset];
|
||||
if (!entry) {
|
||||
throw new WSP.NotWellKnownEncodingError(
|
||||
|
@ -477,11 +468,27 @@ let CharsetEncodedString = {
|
|||
|
||||
return str;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object containing raw PDU data.
|
||||
*
|
||||
* @return Decoded string.
|
||||
*/
|
||||
decode: function decode(data) {
|
||||
let begin = data.offset;
|
||||
try {
|
||||
return WSP.TextString.decode(data);
|
||||
} catch (e) {
|
||||
data.offset = begin;
|
||||
return this.decodeCharsetEncodedString(data);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Expiry-value = Value-length (Absolute-token Date-value | Relative-token Delta-seconds-value)
|
||||
* Address-token = <Octet 128>
|
||||
* Absolute-token = <Octet 128>
|
||||
* Relative-token = <Octet 129>
|
||||
*
|
||||
* @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.20
|
||||
|
@ -531,7 +538,8 @@ let FromValue = {
|
|||
* @param data
|
||||
* A wrapped object containing raw PDU data.
|
||||
*
|
||||
* @return Decoded string or null for MMS Proxy-Relay Insert-Address mode.
|
||||
* @return A decoded Address-value or null for MMS Proxy-Relay Insert-Address
|
||||
* mode.
|
||||
*
|
||||
* @throws CodeError if decoded token equals to neither 128 nor 129.
|
||||
*/
|
||||
|
@ -619,32 +627,15 @@ let PreviouslySentDateValue = {
|
|||
|
||||
/**
|
||||
* Message-class-value = Class-identifier | Token-text
|
||||
* Class-identifier = Personal | Advertisement | Informational | Auto
|
||||
* Personal = <Octet 128>
|
||||
* Advertisement = <Octet 129>
|
||||
* Informational = <Octet 130>
|
||||
* Auto = <Octet 131>
|
||||
*
|
||||
* @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.27
|
||||
*/
|
||||
let MessageClassValue = {
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object containing raw PDU data.
|
||||
*
|
||||
* @return A decoded string.
|
||||
*/
|
||||
decode: function decode(data) {
|
||||
return WSP.decodeAlternatives(data, null,
|
||||
ClassIdentifier, WSP.TokenText);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Class-identifier = Personal | Advertisement | Informational | Auto
|
||||
* Personal = <Octet 128>
|
||||
* Advertisement = <Octet 129>
|
||||
* Informational = <Octet 130>
|
||||
* Auto = <Octet 131>
|
||||
*
|
||||
* @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.27
|
||||
*/
|
||||
let ClassIdentifier = {
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object containing raw PDU data.
|
||||
|
@ -653,7 +644,7 @@ let ClassIdentifier = {
|
|||
*
|
||||
* @throws CodeError if decoded value is not in the range 128..131.
|
||||
*/
|
||||
decode: function decode(data) {
|
||||
decodeClassIdentifier: function decodeClassIdentifier(data) {
|
||||
let value = WSP.Octet.decode(data);
|
||||
switch (value) {
|
||||
case 128: return "personal";
|
||||
|
@ -664,6 +655,22 @@ let ClassIdentifier = {
|
|||
|
||||
throw new WSP.CodeError("Class-identifier: invalid id " + value);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object containing raw PDU data.
|
||||
*
|
||||
* @return A decoded string.
|
||||
*/
|
||||
decode: function decode(data) {
|
||||
let begin = data.offset;
|
||||
try {
|
||||
return this.decodeClassIdentifier(data);
|
||||
} catch (e) {
|
||||
data.offset = begin;
|
||||
return WSP.TokenText.decode(data);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -720,7 +727,7 @@ let MmFlagsValue = {
|
|||
* A wrapped object containing raw PDU data.
|
||||
*
|
||||
* @return Decoded object containing an integer `type` and an string-typed
|
||||
* `address` attributes.
|
||||
* `text` attributes.
|
||||
*
|
||||
* @throws CodeError if decoded value is not in the range 128..130.
|
||||
*/
|
||||
|
@ -874,25 +881,14 @@ let RetrieveStatusValue = {
|
|||
*/
|
||||
decode: function decode(data) {
|
||||
let value = WSP.Octet.decode(data);
|
||||
if ((value == 128)
|
||||
|| ((value >= 192) && (value <= 194))
|
||||
|| ((value >= 224) && (value <= 227))) {
|
||||
if (value == MMS_PDU_ERROR_OK) {
|
||||
return value;
|
||||
}
|
||||
|
||||
if ((value >= 195) && (value <= 223)) {
|
||||
// The values 195 through 223 are reserved for future use to indicate
|
||||
// other transient failures. An MMS Client MUST react the same to a value
|
||||
// in range 195 to 223 as it does to the value 192
|
||||
// (Error-transient-failure).
|
||||
return MMS_PDU_ERROR_TRANSIENT_FAILURE;
|
||||
if ((value >= MMS_PDU_ERROR_TRANSIENT_FAILURE) && (value < 256)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
// The values 228 through 255 are reserved for future use to indicate
|
||||
// other permanent failures. An MMS Client MUST react the same to a value
|
||||
// in range 228 to 255 as it does to the value 224
|
||||
// (Error-permanent-failure).
|
||||
|
||||
// Any other values SHALL NOT be used. They are reserved for future use.
|
||||
// An MMS Client that receives such a reserved value MUST react the same
|
||||
// as it does to the value 224 (Error-permanent-failure).
|
||||
|
@ -1020,11 +1016,13 @@ let PduHelper = {
|
|||
|
||||
/**
|
||||
* Check existences of all mandatory fields of a MMS message. Also sets `type`
|
||||
* and `typeinfo` for convient access.
|
||||
* for convenient access.
|
||||
*
|
||||
* @param msg
|
||||
* A MMS message object.
|
||||
*
|
||||
* @return The corresponding entry in MMS_PDU_TYPES;
|
||||
*
|
||||
* @throws FatalCodeError if the PDU type is not supported yet.
|
||||
*/
|
||||
checkMandatoryFields: function checkMandatoryFields(msg) {
|
||||
|
@ -1039,9 +1037,10 @@ let PduHelper = {
|
|||
WSP.ensureHeader(msg.headers, name);
|
||||
});
|
||||
|
||||
// Setup convient alias that referenced frequently.
|
||||
// Setup convenient alias that referenced frequently.
|
||||
msg.type = type;
|
||||
msg.typeinfo = entry;
|
||||
|
||||
return entry;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1061,9 +1060,8 @@ let PduHelper = {
|
|||
msg.headers = this.parseHeaders(data, msg.headers);
|
||||
|
||||
// Validity checks
|
||||
this.checkMandatoryFields(msg);
|
||||
|
||||
if (msg.typeinfo.hasContent) {
|
||||
let typeinfo = this.checkMandatoryFields(msg);
|
||||
if (typeinfo.hasContent) {
|
||||
this.parseContent(data, msg);
|
||||
}
|
||||
} catch (e) {
|
||||
|
@ -1161,7 +1159,7 @@ let PduHelper = {
|
|||
|
||||
try {
|
||||
// Validity checks
|
||||
this.checkMandatoryFields(msg);
|
||||
let typeinfo = this.checkMandatoryFields(msg);
|
||||
|
||||
let data = this.encodeHeaders(null, msg.headers);
|
||||
debug("Composed PDU Header: " + JSON.stringify(data.array));
|
||||
|
@ -1195,6 +1193,7 @@ const MMS_PDU_TYPES = (function () {
|
|||
"x-mms-content-location"]);
|
||||
add(MMS_PDU_TYPE_RETRIEVE_CONF, true, ["x-mms-message-type",
|
||||
"x-mms-mms-version",
|
||||
"date",
|
||||
"content-type"]);
|
||||
add(MMS_PDU_TYPE_NOTIFYRESP_IND, false, ["x-mms-message-type",
|
||||
"x-mms-transaction-id",
|
||||
|
@ -1247,7 +1246,7 @@ const MMS_HEADER_FIELDS = (function () {
|
|||
add("x-mms-retrieve-status", 0x19, RetrieveStatusValue);
|
||||
add("x-mms-retrieve-text", 0x1A, EncodedStringValue);
|
||||
//add("x-mms-read-status", 0x1B);
|
||||
add("x-mms-reply-charging", 0x1C, WSP.ReplyChargingValue);
|
||||
add("x-mms-reply-charging", 0x1C, ReplyChargingValue);
|
||||
add("x-mms-reply-charging-deadline", 0x1D, ExpiryValue);
|
||||
add("x-mms-reply-charging-id", 0x1E, WSP.TextString);
|
||||
add("x-mms-reply-charging-size", 0x1F, WSP.LongInteger);
|
||||
|
@ -1300,7 +1299,7 @@ const MMS_WELL_KNOWN_PARAMS = (function () {
|
|||
params[name] = params[number] = entry;
|
||||
}
|
||||
|
||||
add("type", 0x02, WSP.ConstrainedEncoding);
|
||||
add("type", 0x02, WSP.TypeValue);
|
||||
|
||||
return params;
|
||||
})();
|
||||
|
@ -1330,12 +1329,16 @@ const EXPORTED_SYMBOLS = ALL_CONST_SYMBOLS.concat([
|
|||
"EncodedStringValue",
|
||||
"ExpiryValue",
|
||||
"FromValue",
|
||||
"PreviouslySentByValue",
|
||||
"PreviouslySentDateValue",
|
||||
"MessageClassValue",
|
||||
"ClassIdentifier",
|
||||
"MessageTypeValue",
|
||||
"MmFlagsValue",
|
||||
"MmStateValue",
|
||||
"PriorityValue",
|
||||
"RecommendedRetrievalModeValue",
|
||||
"ReplyChargingValue",
|
||||
"RetrieveStatusValue",
|
||||
"StatusValue",
|
||||
|
||||
// Parser
|
||||
|
|
|
@ -487,7 +487,7 @@ let Token = {
|
|||
// Fallback to throw CodeError
|
||||
} else {
|
||||
Octet.encode(data, token.charCodeAt(0));
|
||||
return;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -697,7 +697,7 @@ let ShortInteger = {
|
|||
* @throws CodeError if the octet read is larger-equal than 0x80.
|
||||
*/
|
||||
encode: function encode(data, value) {
|
||||
if (value & 0x80) {
|
||||
if (value >= 0x80) {
|
||||
throw new CodeError("Short-integer: invalid value " + value);
|
||||
}
|
||||
|
||||
|
@ -1038,6 +1038,37 @@ let UriValue = {
|
|||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Internal coder for "type" parameter.
|
||||
*
|
||||
* Type-value = Constrained-encoding
|
||||
*
|
||||
* @see WAP-230-WSP-20010705-a table 38
|
||||
*/
|
||||
let TypeValue = {
|
||||
/**
|
||||
* @param data
|
||||
* A wrapped object containing raw PDU data.
|
||||
*
|
||||
* @return Decoded content type string.
|
||||
*/
|
||||
decode: function decode(data) {
|
||||
let numOrStr = ConstrainedEncoding.decode(data);
|
||||
if (typeof numOrStr == "string") {
|
||||
return numOrStr.toLowerCase();
|
||||
}
|
||||
|
||||
let number = numOrStr;
|
||||
let entry = WSP_WELL_KNOWN_CONTENT_TYPES[number];
|
||||
if (!entry) {
|
||||
throw new NotWellKnownEncodingError(
|
||||
"Constrained-media: not well known media " + number);
|
||||
}
|
||||
|
||||
return entry.type;
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Parameter = Typed-parameter | Untyped-parameter
|
||||
*
|
||||
|
@ -1539,23 +1570,8 @@ let ContentTypeValue = {
|
|||
* is not registered or supported.
|
||||
*/
|
||||
decodeConstrainedMedia: function decodeConstrainedMedia(data) {
|
||||
let numOrStr = ConstrainedEncoding.decode(data);
|
||||
if (typeof numOrStr == "string") {
|
||||
return {
|
||||
media: numOrStr.toLowerCase(),
|
||||
params: null,
|
||||
};
|
||||
}
|
||||
|
||||
let number = numOrStr;
|
||||
let entry = WSP_WELL_KNOWN_CONTENT_TYPES[number];
|
||||
if (!entry) {
|
||||
throw new NotWellKnownEncodingError(
|
||||
"Constrained-media: not well known media " + number);
|
||||
}
|
||||
|
||||
return {
|
||||
media: entry.type,
|
||||
media: TypeValue.decode(data),
|
||||
params: null,
|
||||
};
|
||||
},
|
||||
|
@ -1991,7 +2007,7 @@ const WSP_WELL_KNOWN_PARAMS = (function () {
|
|||
//add("filename", 0x06); Deprecated
|
||||
add("differences", 0x07, FieldName);
|
||||
add("padding", 0x08, ShortInteger);
|
||||
add("type", 0x09, ConstrainedEncoding);
|
||||
add("type", 0x09, TypeValue);
|
||||
add("start", 0x0A, TextValue); // Deprecated, but used in some carriers, eg. T-Mobile.
|
||||
//add("start-info", 0x0B); Deprecated
|
||||
//add("comment", 0x0C); Deprecated
|
||||
|
@ -2109,6 +2125,7 @@ const EXPORTED_SYMBOLS = ALL_CONST_SYMBOLS.concat([
|
|||
"QValue",
|
||||
"VersionValue",
|
||||
"UriValue",
|
||||
"TypeValue",
|
||||
"Parameter",
|
||||
"Header",
|
||||
"WellKnownHeader",
|
||||
|
|
|
@ -33,16 +33,18 @@ const MMS_PDU_TYPE_CANCEL_CONF = 151;
|
|||
// @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.34
|
||||
const MMS_VERSION = (0x01 << 4) | 0x03;
|
||||
|
||||
// Common Status Values
|
||||
const MMS_PDU_ERROR_OK = 128;
|
||||
const MMS_PDU_ERROR_TRANSIENT_FAILURE = 192;
|
||||
const MMS_PDU_ERROR_PERMANENT_FAILURE = 224;
|
||||
|
||||
// X-Mms-Retrieve-Status values
|
||||
// @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.50
|
||||
const MMS_PDU_ERROR_OK = 128;
|
||||
const MMS_PDU_ERROR_TRANSIENT_FAILURE = 192;
|
||||
const MMS_PDU_ERROR_TRANSIENT_MESSAGE_NOT_FOUND = 193;
|
||||
const MMS_PDU_ERROR_TRANSIENT_NETWORK_PROBLEM = 194;
|
||||
const MMS_PDU_ERROR_PERMANENT_FAILURE = 224;
|
||||
const MMS_PDU_ERROR_PERMANENT_SERVICE_DENIED = 225;
|
||||
const MMS_PDU_ERROR_PERMANENT_MESSAGE_NOT_FOUND = 226;
|
||||
const MMS_PDU_ERROR_PERMANENT_CONTENT_UNSUPPORTED = 227;
|
||||
const MMS_PDU_RETRIEVE_ERROR_TRANSIENT_MESSAGE_NOT_FOUND = 193;
|
||||
const MMS_PDU_RETRIEVE_ERROR_TRANSIENT_NETWORK_PROBLEM = 194;
|
||||
const MMS_PDU_RETRIEVE_ERROR_PERMANENT_SERVICE_DENIED = 225;
|
||||
const MMS_PDU_RETRIEVE_ERROR_PERMANENT_MESSAGE_NOT_FOUND = 226;
|
||||
const MMS_PDU_RETRIEVE_ERROR_PERMANENT_CONTENT_UNSUPPORTED = 227;
|
||||
|
||||
// X-Mms-Status values
|
||||
// @see OMA-TS-MMS_ENC-V1_3-20110913-A clause 7.3.54
|
||||
|
|
|
@ -54,7 +54,7 @@ function wsp_test_func(func, data, expect) {
|
|||
let result_str = JSON.stringify(func(data));
|
||||
let expect_str = JSON.stringify(expect);
|
||||
if (result_str !== expect_str) {
|
||||
do_throw("expect decoded value: '" + expect_str + "', got '" + result_str + "'");
|
||||
do_throw("expect value: '" + expect_str + "', got '" + result_str + "'");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -97,8 +97,8 @@ add_test(function test_HeaderField_decode() {
|
|||
add_test(function test_HeaderField_encode() {
|
||||
// Test for MmsHeader
|
||||
wsp_encode_test(MMS.HeaderField, {name: "X-Mms-Message-Type",
|
||||
value: MMS.MMS_PDU_TYPE_SEND_REQ},
|
||||
[0x80 | 0x0C, MMS.MMS_PDU_TYPE_SEND_REQ]);
|
||||
value: MMS_PDU_TYPE_SEND_REQ},
|
||||
[0x80 | 0x0C, MMS_PDU_TYPE_SEND_REQ]);
|
||||
// Test for ApplicationHeader
|
||||
wsp_encode_test(MMS.HeaderField, {name: "a", value: "B"}, [97, 0, 66, 0]);
|
||||
|
||||
|
@ -132,8 +132,8 @@ add_test(function test_MmsHeader_encode() {
|
|||
null, "NotWellKnownEncodingError");
|
||||
// Test for normal header
|
||||
wsp_encode_test(MMS.MmsHeader, {name: "X-Mms-Message-Type",
|
||||
value: MMS.MMS_PDU_TYPE_SEND_REQ},
|
||||
[0x80 | 0x0C, MMS.MMS_PDU_TYPE_SEND_REQ]);
|
||||
value: MMS_PDU_TYPE_SEND_REQ},
|
||||
[0x80 | 0x0C, MMS_PDU_TYPE_SEND_REQ]);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
@ -164,24 +164,44 @@ add_test(function test_ContentClassValue_decode() {
|
|||
|
||||
add_test(function test_ContentLocationValue_decode() {
|
||||
// Test for MMS_PDU_TYPE_MBOX_DELETE_CONF & MMS_PDU_TYPE_DELETE_CONF
|
||||
wsp_decode_test_ex(function (data) {
|
||||
data.array[0] = data.array.length - 1;
|
||||
|
||||
function test(type, statusCount, exception) {
|
||||
function decode(data) {
|
||||
let options = {};
|
||||
options["x-mms-message-type"] = /*MMS.MMS_PDU_TYPE_MBOX_DELETE_CONF*/146;
|
||||
if (type) {
|
||||
options["x-mms-message-type"] = type;
|
||||
}
|
||||
return MMS.ContentLocationValue.decode(data, options);
|
||||
}, [0, 0x80 | 0x00].concat(strToCharCodeArray("http://no.such.com/path")),
|
||||
{statusCount: 0, uri: "http://no.such.com/path"}
|
||||
);
|
||||
wsp_decode_test_ex(function (data) {
|
||||
data.array[0] = data.array.length - 1;
|
||||
}
|
||||
|
||||
let options = {};
|
||||
options["x-mms-message-type"] = /*MMS.MMS_PDU_TYPE_DELETE_CONF*/149;
|
||||
return MMS.ContentLocationValue.decode(data, options);
|
||||
}, [0, 0x80 | 0x00].concat(strToCharCodeArray("http://no.such.com/path")),
|
||||
{statusCount: 0, uri: "http://no.such.com/path"}
|
||||
);
|
||||
let uri = "http://no.such.com/path";
|
||||
|
||||
let data = strToCharCodeArray(uri);
|
||||
if (statusCount != null) {
|
||||
data = [data.length + 1, statusCount | 0x80].concat(data);
|
||||
}
|
||||
|
||||
let expected;
|
||||
if (!exception) {
|
||||
expected = {};
|
||||
if (statusCount != null) {
|
||||
expected.statusCount = statusCount;
|
||||
}
|
||||
expected.uri = uri;
|
||||
}
|
||||
|
||||
do_print("data = " + JSON.stringify(data));
|
||||
wsp_decode_test_ex(decode, data, expected, exception);
|
||||
}
|
||||
|
||||
test(null, null, "FatalCodeError");
|
||||
for (let type = MMS_PDU_TYPE_SEND_REQ; type <= MMS_PDU_TYPE_CANCEL_CONF; type++) {
|
||||
if ((type == MMS_PDU_TYPE_MBOX_DELETE_CONF)
|
||||
|| (type == MMS_PDU_TYPE_DELETE_CONF)) {
|
||||
test(type, 1, null);
|
||||
} else {
|
||||
test(type, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
@ -263,19 +283,9 @@ add_test(function test_EncodedStringValue_decode() {
|
|||
.createInstance(Ci.nsIScriptableUnicodeConverter);
|
||||
conv.charset = entry.converter;
|
||||
|
||||
let raw;
|
||||
try {
|
||||
let raw = conv.convertToByteArray(str).concat([0]);
|
||||
if (raw[0] >= 128) {
|
||||
wsp_decode_test(MMS.EncodedStringValue,
|
||||
[raw.length + 2, 0x80 | entry.number, 127].concat(raw), str);
|
||||
} else {
|
||||
wsp_decode_test(MMS.EncodedStringValue,
|
||||
[raw.length + 1, 0x80 | entry.number].concat(raw), str);
|
||||
}
|
||||
} catch (e) {
|
||||
do_print("Can't convert test string to byte array with " + entry.converter);
|
||||
}
|
||||
let raw = conv.convertToByteArray(str).concat([0]);
|
||||
wsp_decode_test(MMS.EncodedStringValue,
|
||||
[raw.length + 2, 0x80 | entry.number, 127].concat(raw), str);
|
||||
}
|
||||
|
||||
run_next_test();
|
||||
|
@ -291,7 +301,7 @@ add_test(function test_ExpiryValue_decode() {
|
|||
// Test for Absolute-token Date-value
|
||||
wsp_decode_test(MMS.ExpiryValue, [3, 128, 1, 0x80], new Date(0x80 * 1000));
|
||||
// Test for Relative-token Delta-seconds-value
|
||||
wsp_decode_test(MMS.ExpiryValue, [3, 129, 0x80], 0);
|
||||
wsp_decode_test(MMS.ExpiryValue, [2, 129, 0x80], 0);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
@ -334,7 +344,7 @@ add_test(function test_FromValue_decode() {
|
|||
wsp_decode_test(MMS.FromValue, [1, 129], null);
|
||||
// Test for Address-present-token:
|
||||
let (addr = strToCharCodeArray("+123/TYPE=PLMN")) {
|
||||
wsp_decode_test(MMS.FromValue, [addr.length + 2, 128].concat(addr),
|
||||
wsp_decode_test(MMS.FromValue, [addr.length + 1, 128].concat(addr),
|
||||
{address: "+123", type: "PLMN"});
|
||||
}
|
||||
|
||||
|
@ -345,6 +355,28 @@ add_test(function test_FromValue_decode() {
|
|||
// Test target: MessageClassValue
|
||||
//
|
||||
|
||||
//// MessageClassValue.decodeClassIdentifier ////
|
||||
|
||||
add_test(function test_MessageClassValue_decodeClassIdentifier() {
|
||||
let (IDs = ["personal", "advertisement", "informational", "auto"]) {
|
||||
for (let i = 0; i < 256; i++) {
|
||||
if ((i >= 128) && (i <= 131)) {
|
||||
wsp_decode_test_ex(function (data) {
|
||||
return MMS.MessageClassValue.decodeClassIdentifier(data);
|
||||
}, [i], IDs[i - 128]
|
||||
);
|
||||
} else {
|
||||
wsp_decode_test_ex(function (data) {
|
||||
return MMS.MessageClassValue.decodeClassIdentifier(data);
|
||||
}, [i], null, "CodeError"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//// MessageClassValue.decode ////
|
||||
|
||||
add_test(function test_MessageClassValue_decode() {
|
||||
|
@ -354,26 +386,6 @@ add_test(function test_MessageClassValue_decode() {
|
|||
run_next_test();
|
||||
});
|
||||
|
||||
//
|
||||
// Test target: ClassIdentifier
|
||||
//
|
||||
|
||||
//// ClassIdentifier.decode ////
|
||||
|
||||
add_test(function test_ClassIdentifier_decode() {
|
||||
let (IDs = ["personal", "advertisement", "informational", "auto"]) {
|
||||
for (let i = 0; i < 256; i++) {
|
||||
if ((i >= 128) && (i <= 131)) {
|
||||
wsp_decode_test(MMS.ClassIdentifier, [i], IDs[i - 128]);
|
||||
} else {
|
||||
wsp_decode_test(MMS.ClassIdentifier, [i], null, "CodeError");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//
|
||||
// Test target: MessageTypeValue
|
||||
//
|
||||
|
@ -433,9 +445,9 @@ add_test(function test_MmFlagsValue_decode() {
|
|||
add_test(function test_MmStateValue_decode() {
|
||||
for (let i = 0; i < 256; i++) {
|
||||
if ((i >= 128) && (i <= 132)) {
|
||||
wsp_decode_test(MMS.MmStateValue, [i, 0], i);
|
||||
wsp_decode_test(MMS.MmStateValue, [i], i);
|
||||
} else {
|
||||
wsp_decode_test(MMS.MmStateValue, [i, 0], null, "CodeError");
|
||||
wsp_decode_test(MMS.MmStateValue, [i], null, "CodeError");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -504,14 +516,12 @@ add_test(function test_ReplyChargingValue_decode() {
|
|||
|
||||
add_test(function test_RetrieveStatusValue_decode() {
|
||||
for (let i = 0; i < 256; i++) {
|
||||
if ((i == 128)
|
||||
|| ((i >= 192) && (i <= 194))
|
||||
|| ((i >= 224) && (i <= 227))) {
|
||||
if ((i == MMS_PDU_ERROR_OK)
|
||||
|| (i >= MMS_PDU_ERROR_TRANSIENT_FAILURE)) {
|
||||
wsp_decode_test(MMS.RetrieveStatusValue, [i], i);
|
||||
} else if ((i >= 195) && (i <= 223)) {
|
||||
wsp_decode_test(MMS.RetrieveStatusValue, [i], 192);
|
||||
} else {
|
||||
wsp_decode_test(MMS.RetrieveStatusValue, [i], 224);
|
||||
wsp_decode_test(MMS.RetrieveStatusValue, [i],
|
||||
MMS_PDU_ERROR_PERMANENT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,35 +27,21 @@ add_test(function test_ensureHeader() {
|
|||
//
|
||||
|
||||
add_test(function test_skipValue() {
|
||||
function func(data) {
|
||||
return WSP.skipValue(data);
|
||||
}
|
||||
|
||||
// Test for zero-valued first octet:
|
||||
wsp_decode_test_ex(function (data) {
|
||||
return WSP.skipValue(data);
|
||||
}, [0], null
|
||||
);
|
||||
wsp_decode_test_ex(func, [0], null);
|
||||
// Test first octet < 31
|
||||
wsp_decode_test_ex(function (data) {
|
||||
return WSP.skipValue(data);
|
||||
}, [1, 2], [2]
|
||||
);
|
||||
wsp_decode_test_ex(func, [1, 2], [2]);
|
||||
// Test first octet = 31
|
||||
wsp_decode_test_ex(function (data) {
|
||||
return WSP.skipValue(data);
|
||||
}, [31, 0], null
|
||||
);
|
||||
wsp_decode_test_ex(function (data) {
|
||||
return WSP.skipValue(data);
|
||||
}, [31, 1, 2], [2]
|
||||
);
|
||||
wsp_decode_test_ex(func, [31, 0], null);
|
||||
wsp_decode_test_ex(func, [31, 1, 2], [2]);
|
||||
// Test first octet <= 127
|
||||
wsp_decode_test_ex(function (data) {
|
||||
return WSP.skipValue(data);
|
||||
}, strToCharCodeArray("Hello world!"), "Hello world!"
|
||||
);
|
||||
wsp_decode_test_ex(func, strToCharCodeArray("Hello world!"), "Hello world!");
|
||||
// Test first octet >= 128
|
||||
wsp_decode_test_ex(function (data) {
|
||||
return WSP.skipValue(data);
|
||||
}, [0x80 | 0x01], 0x01
|
||||
);
|
||||
wsp_decode_test_ex(func, [0x80 | 0x01], 0x01);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
@ -495,7 +481,7 @@ add_test(function test_DateValue_decode() {
|
|||
//
|
||||
// Test target: DeltaSecondsValue
|
||||
//
|
||||
// DeltaSecondsValue is only an alias of IntegerValue.
|
||||
// DeltaSecondsValue is only an alias of IntegerValue.
|
||||
|
||||
//
|
||||
// Test target: QValue
|
||||
|
@ -554,6 +540,24 @@ add_test(function test_UriValue_decode() {
|
|||
run_next_test();
|
||||
});
|
||||
|
||||
//
|
||||
// Test target: TypeValue
|
||||
//
|
||||
|
||||
//// TypeValue.decode ////
|
||||
|
||||
add_test(function test_TypeValue_decode() {
|
||||
// Test for string-typed return value from ConstrainedEncoding
|
||||
wsp_decode_test(WSP.TypeValue, [65, 0], "a");
|
||||
// Test for number-typed return value from ConstrainedEncoding
|
||||
wsp_decode_test(WSP.TypeValue, [0x33 | 0x80],
|
||||
"application/vnd.wap.multipart.related");
|
||||
// Test for NotWellKnownEncodingError
|
||||
wsp_decode_test(WSP.TypeValue, [0x80], null, "NotWellKnownEncodingError");
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
//
|
||||
// Test target: Parameter
|
||||
//
|
||||
|
@ -561,41 +565,26 @@ add_test(function test_UriValue_decode() {
|
|||
//// Parameter.decodeTypedParameter ////
|
||||
|
||||
add_test(function test_Parameter_decodeTypedParameter() {
|
||||
function func(data) {
|
||||
return WSP.Parameter.decodeTypedParameter(data);
|
||||
}
|
||||
|
||||
// Test for array-typed return value from IntegerValue
|
||||
wsp_decode_test_ex(function (data) {
|
||||
return WSP.Parameter.decodeTypedParameter(data);
|
||||
}, [7, 0, 0, 0, 0, 0, 0, 0], null, "CodeError"
|
||||
);
|
||||
wsp_decode_test_ex(func, [7, 0, 0, 0, 0, 0, 0, 0], null, "CodeError");
|
||||
// Test for number-typed return value from IntegerValue
|
||||
wsp_decode_test_ex(function (data) {
|
||||
return WSP.Parameter.decodeTypedParameter(data);
|
||||
}, [1, 0, 0], {name: "q", value: null}
|
||||
);
|
||||
wsp_decode_test_ex(func, [1, 0, 0], {name: "q", value: null});
|
||||
// Test for NotWellKnownEncodingError
|
||||
wsp_decode_test_ex(function (data) {
|
||||
return WSP.Parameter.decodeTypedParameter(data);
|
||||
}, [1, 0xFF], null, "NotWellKnownEncodingError"
|
||||
);
|
||||
wsp_decode_test_ex(func, [1, 0xFF], null, "NotWellKnownEncodingError");
|
||||
// Test for parameter specific decoder
|
||||
wsp_decode_test_ex(function (data) {
|
||||
return WSP.Parameter.decodeTypedParameter(data);
|
||||
}, [1, 0, 100], {name: "q", value: 0.99}
|
||||
);
|
||||
wsp_decode_test_ex(func, [1, 0, 100], {name: "q", value: 0.99});
|
||||
// Test for TextValue
|
||||
wsp_decode_test_ex(function (data) {
|
||||
return WSP.Parameter.decodeTypedParameter(data);
|
||||
}, [1, 0x10, 48, 46, 57, 57, 0], {name: "secure", value: "0.99"}
|
||||
);
|
||||
wsp_decode_test_ex(func, [1, 0x10, 48, 46, 57, 57, 0],
|
||||
{name: "secure", value: "0.99"});
|
||||
// Test for TextString
|
||||
wsp_decode_test_ex(function (data) {
|
||||
return WSP.Parameter.decodeTypedParameter(data);
|
||||
}, [1, 0x19, 60, 115, 109, 105, 108, 62, 0], {name: "start", value: "<smil>"}
|
||||
);
|
||||
wsp_decode_test_ex(func, [1, 0x19, 60, 115, 109, 105, 108, 62, 0],
|
||||
{name: "start", value: "<smil>"});
|
||||
// Test for skipValue
|
||||
wsp_decode_test_ex(function (data) {
|
||||
return WSP.Parameter.decodeTypedParameter(data);
|
||||
}, [1, 0x19, 128], null
|
||||
);
|
||||
wsp_decode_test_ex(func, [1, 0x19, 128], null);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
@ -603,24 +592,16 @@ add_test(function test_Parameter_decodeTypedParameter() {
|
|||
//// Parameter.decodeUntypedParameter ////
|
||||
|
||||
add_test(function test_Parameter_decodeUntypedParameter() {
|
||||
wsp_decode_test_ex(function (data) {
|
||||
return WSP.Parameter.decodeUntypedParameter(data);
|
||||
}, [1], null, "CodeError"
|
||||
);
|
||||
wsp_decode_test_ex(function (data) {
|
||||
return WSP.Parameter.decodeUntypedParameter(data);
|
||||
}, [65, 0, 0], {name: "a", value: null}
|
||||
);
|
||||
function func (data) {
|
||||
return WSP.Parameter.decodeUntypedParameter(data);
|
||||
}
|
||||
|
||||
wsp_decode_test_ex(func, [1], null, "CodeError");
|
||||
wsp_decode_test_ex(func, [65, 0, 0], {name: "a", value: null});
|
||||
// Test for IntegerValue
|
||||
wsp_decode_test_ex(function (data) {
|
||||
return WSP.Parameter.decodeUntypedParameter(data);
|
||||
}, [65, 0, 1, 0], {name: "a", value: 0}
|
||||
);
|
||||
wsp_decode_test_ex(func, [65, 0, 1, 0], {name: "a", value: 0});
|
||||
// Test for TextValue
|
||||
wsp_decode_test_ex(function (data) {
|
||||
return WSP.Parameter.decodeUntypedParameter(data);
|
||||
}, [65, 0, 66, 0], {name: "a", value: "B"}
|
||||
);
|
||||
wsp_decode_test_ex(func, [65, 0, 66, 0], {name: "a", value: "B"});
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
@ -628,14 +609,9 @@ add_test(function test_Parameter_decodeUntypedParameter() {
|
|||
//// Parameter.decode ////
|
||||
|
||||
add_test(function test_Parameter_decode() {
|
||||
wsp_decode_test_ex(function (data) {
|
||||
return WSP.Parameter.decode(data);
|
||||
}, [1, 0x19, 60, 115, 109, 105, 108, 62, 0], {name: "start", value: "<smil>"}
|
||||
);
|
||||
wsp_decode_test_ex(function (data) {
|
||||
return WSP.Parameter.decode(data);
|
||||
}, [65, 0, 66, 0], {name: "a", value: "B"}
|
||||
);
|
||||
wsp_decode_test(WSP.Parameter, [1, 0x19, 60, 115, 109, 105, 108, 62, 0],
|
||||
{name: "start", value: "<smil>"});
|
||||
wsp_decode_test(WSP.Parameter, [65, 0, 66, 0], {name: "a", value: "B"});
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
@ -797,21 +773,17 @@ add_test(function test_WellKnownCharset_decode() {
|
|||
//// ContentTypeValue.decodeConstrainedMedia ////
|
||||
|
||||
add_test(function test_ContentTypeValue_decodeConstrainedMedia() {
|
||||
function func(data) {
|
||||
return WSP.ContentTypeValue.decodeConstrainedMedia(data);
|
||||
}
|
||||
|
||||
// Test for string-typed return value from ConstrainedEncoding
|
||||
wsp_decode_test_ex(function (data) {
|
||||
return WSP.ContentTypeValue.decodeConstrainedMedia(data);
|
||||
}, [65, 0], {media: "a", params: null}
|
||||
);
|
||||
wsp_decode_test_ex(func, [65, 0], {media: "a", params: null});
|
||||
// Test for number-typed return value from ConstrainedEncoding
|
||||
wsp_decode_test_ex(function (data) {
|
||||
return WSP.ContentTypeValue.decodeConstrainedMedia(data);
|
||||
}, [0x33 | 0x80], {media: "application/vnd.wap.multipart.related", params: null}
|
||||
);
|
||||
wsp_decode_test_ex(func, [0x33 | 0x80],
|
||||
{media: "application/vnd.wap.multipart.related", params: null});
|
||||
// Test for NotWellKnownEncodingError
|
||||
wsp_decode_test_ex(function (data) {
|
||||
return WSP.ContentTypeValue.decodeConstrainedMedia(data);
|
||||
}, [0x80], null, "NotWellKnownEncodingError"
|
||||
);
|
||||
wsp_decode_test_ex(func, [0x80], null, "NotWellKnownEncodingError");
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
@ -819,20 +791,15 @@ add_test(function test_ContentTypeValue_decodeConstrainedMedia() {
|
|||
//// ContentTypeValue.decodeMedia ////
|
||||
|
||||
add_test(function test_ContentTypeValue_decodeMedia() {
|
||||
function func(data) {
|
||||
return WSP.ContentTypeValue.decodeMedia(data);
|
||||
}
|
||||
|
||||
// Test for NullTerminatedTexts
|
||||
wsp_decode_test_ex(function (data) {
|
||||
return WSP.ContentTypeValue.decodeMedia(data);
|
||||
}, [65, 0], "a"
|
||||
);
|
||||
wsp_decode_test_ex(func, [65, 0], "a");
|
||||
// Test for IntegerValue
|
||||
wsp_decode_test_ex(function (data) {
|
||||
return WSP.ContentTypeValue.decodeMedia(data);
|
||||
}, [0x3E | 0x80], "application/vnd.wap.mms-message"
|
||||
);
|
||||
wsp_decode_test_ex(function (data) {
|
||||
return WSP.ContentTypeValue.decodeMedia(data);
|
||||
}, [0x80], null, "NotWellKnownEncodingError"
|
||||
);
|
||||
wsp_decode_test_ex(func, [0x3E | 0x80], "application/vnd.wap.mms-message");
|
||||
wsp_decode_test_ex(func, [0x80], null, "NotWellKnownEncodingError");
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#define MOZILLA_GFX_BASERECT_H_
|
||||
|
||||
#include <cmath>
|
||||
#include <mozilla/Assertions.h>
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
@ -276,6 +277,26 @@ struct BaseRect {
|
|||
T XMost() const { return x + width; }
|
||||
T YMost() const { return y + height; }
|
||||
|
||||
// Moves one edge of the rect without moving the opposite edge.
|
||||
void SetLeftEdge(T aX) {
|
||||
MOZ_ASSERT(aX <= XMost());
|
||||
width = XMost() - aX;
|
||||
x = aX;
|
||||
}
|
||||
void SetRightEdge(T aXMost) {
|
||||
MOZ_ASSERT(aXMost >= x);
|
||||
width = aXMost - x;
|
||||
}
|
||||
void SetTopEdge(T aY) {
|
||||
MOZ_ASSERT(aY <= YMost());
|
||||
height = YMost() - aY;
|
||||
y = aY;
|
||||
}
|
||||
void SetBottomEdge(T aYMost) {
|
||||
MOZ_ASSERT(aYMost >= y);
|
||||
height = aYMost - y;
|
||||
}
|
||||
|
||||
// Round the rectangle edges to integer coordinates, such that the rounded
|
||||
// rectangle has the same set of pixel centers as the original rectangle.
|
||||
// Edges at offset 0.5 round up.
|
||||
|
|
|
@ -302,6 +302,13 @@ public:
|
|||
|
||||
bool IsSnappingEffectiveTransforms() { return mSnapEffectiveTransforms; }
|
||||
|
||||
/**
|
||||
* Returns true if this LayerManager can properly support layers with
|
||||
* SURFACE_COMPONENT_ALPHA. This can include disabling component
|
||||
* alpha if required.
|
||||
*/
|
||||
virtual bool AreComponentAlphaLayersEnabled() { return true; }
|
||||
|
||||
/**
|
||||
* CONSTRUCTION PHASE ONLY
|
||||
* Set the root layer. The root layer is initially null. If there is
|
||||
|
|
|
@ -64,14 +64,6 @@ public:
|
|||
void* aCallbackData,
|
||||
ReadbackProcessor* aReadback) {}
|
||||
|
||||
/**
|
||||
* Implementations return true here if they *must* retain their
|
||||
* layer contents. This is true of shadowable layers with shadows,
|
||||
* because there's no target on which to composite directly in the
|
||||
* layer-publishing child process.
|
||||
*/
|
||||
virtual bool MustRetainContent() { return false; }
|
||||
|
||||
/**
|
||||
* Layers will get this call when their layer manager is destroyed, this
|
||||
* indicates they should clear resources they don't really need after their
|
||||
|
|
|
@ -94,6 +94,8 @@ public:
|
|||
virtual void EndTransaction(DrawThebesLayerCallback aCallback,
|
||||
void* aCallbackData,
|
||||
EndTransactionFlags aFlags = END_DEFAULT);
|
||||
virtual bool AreComponentAlphaLayersEnabled() { return HasShadowManager(); }
|
||||
|
||||
void AbortTransaction();
|
||||
|
||||
virtual void SetRoot(Layer* aLayer);
|
||||
|
|
|
@ -106,10 +106,7 @@ BasicThebesLayer::PaintThebes(gfxContext* aContext,
|
|||
gfxASurface::CONTENT_COLOR_ALPHA;
|
||||
float opacity = GetEffectiveOpacity();
|
||||
|
||||
if (!BasicManager()->IsRetained() ||
|
||||
(!canUseOpaqueSurface &&
|
||||
(mContentFlags & CONTENT_COMPONENT_ALPHA) &&
|
||||
!MustRetainContent())) {
|
||||
if (!BasicManager()->IsRetained()) {
|
||||
NS_ASSERTION(readbackUpdates.IsEmpty(), "Can't do readback for non-retained layer");
|
||||
|
||||
mValidRegion.SetEmpty();
|
||||
|
|
|
@ -140,7 +140,6 @@ public:
|
|||
|
||||
virtual Layer* AsLayer() { return this; }
|
||||
virtual ShadowableLayer* AsShadowableLayer() { return this; }
|
||||
virtual bool MustRetainContent() { return HasShadow(); }
|
||||
|
||||
void SetBackBufferAndAttrs(const OptionalThebesBuffer& aBuffer,
|
||||
const nsIntRegion& aValidRegion,
|
||||
|
|
|
@ -175,9 +175,6 @@ public:
|
|||
mValidRegion.Sub(mValidRegion, aRegion);
|
||||
}
|
||||
|
||||
// BasicImplData
|
||||
virtual bool MustRetainContent() { return HasShadow(); }
|
||||
|
||||
// Shadow methods
|
||||
virtual void FillSpecificAttributes(SpecificLayerAttributes& aAttrs);
|
||||
virtual ShadowableLayer* AsShadowableLayer() { return this; }
|
||||
|
|
|
@ -17,6 +17,10 @@
|
|||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
static const float EPSILON = 0.0001;
|
||||
|
||||
/**
|
||||
|
@ -31,6 +35,17 @@ static const PRInt32 PAN_REPAINT_INTERVAL = 250;
|
|||
*/
|
||||
static const PRInt32 FLING_REPAINT_INTERVAL = 75;
|
||||
|
||||
/**
|
||||
* Minimum amount of speed along an axis before we begin painting far ahead by
|
||||
* adjusting the displayport.
|
||||
*/
|
||||
static const float MIN_SKATE_SPEED = 0.5f;
|
||||
|
||||
/**
|
||||
* Angle from axis within which we stay axis-locked.
|
||||
*/
|
||||
static const float AXIS_LOCK_ANGLE = M_PI / 6.0;
|
||||
|
||||
AsyncPanZoomController::AsyncPanZoomController(GeckoContentController* aGeckoContentController,
|
||||
GestureBehavior aGestures)
|
||||
: mGeckoContentController(aGeckoContentController),
|
||||
|
@ -208,10 +223,6 @@ nsEventStatus AsyncPanZoomController::OnTouchStart(const MultiTouchInput& aEvent
|
|||
}
|
||||
|
||||
nsEventStatus AsyncPanZoomController::OnTouchMove(const MultiTouchInput& aEvent) {
|
||||
SingleTouchData& touch = GetFirstSingleTouch(aEvent);
|
||||
nsIntPoint point = touch.mScreenPoint;
|
||||
PRInt32 xPos = point.x, yPos = point.y;
|
||||
|
||||
switch (mState) {
|
||||
case FLING:
|
||||
case NOTHING:
|
||||
|
@ -220,14 +231,12 @@ nsEventStatus AsyncPanZoomController::OnTouchMove(const MultiTouchInput& aEvent)
|
|||
return nsEventStatus_eIgnore;
|
||||
|
||||
case TOUCHING: {
|
||||
float panThreshold = 1.0f/16.0f * mDPI;
|
||||
if (PanDistance(aEvent) < panThreshold) {
|
||||
float panThreshold = 1.0f/2.0f * mDPI;
|
||||
UpdateWithTouchAtDevicePoint(aEvent);
|
||||
if (PanDistance() < panThreshold) {
|
||||
return nsEventStatus_eIgnore;
|
||||
}
|
||||
mLastRepaint = aEvent.mTime;
|
||||
mX.StartTouch(xPos);
|
||||
mY.StartTouch(yPos);
|
||||
mState = PANNING;
|
||||
StartPanning(aEvent);
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
}
|
||||
|
||||
|
@ -266,7 +275,6 @@ nsEventStatus AsyncPanZoomController::OnTouchEnd(const MultiTouchInput& aEvent)
|
|||
RequestContentRepaint();
|
||||
}
|
||||
mState = FLING;
|
||||
mLastSampleTime = TimeStamp::Now();
|
||||
return nsEventStatus_eConsumeNoDefault;
|
||||
case PINCHING:
|
||||
mState = NOTHING;
|
||||
|
@ -423,12 +431,7 @@ nsEventStatus AsyncPanZoomController::OnCancelTap(const TapGestureInput& aEvent)
|
|||
return nsEventStatus_eIgnore;
|
||||
}
|
||||
|
||||
float AsyncPanZoomController::PanDistance(const MultiTouchInput& aEvent) {
|
||||
SingleTouchData& touch = GetFirstSingleTouch(aEvent);
|
||||
nsIntPoint point = touch.mScreenPoint;
|
||||
PRInt32 xPos = point.x, yPos = point.y;
|
||||
mX.UpdateWithTouchAtDevicePoint(xPos, 0);
|
||||
mY.UpdateWithTouchAtDevicePoint(yPos, 0);
|
||||
float AsyncPanZoomController::PanDistance() {
|
||||
return NS_hypot(mX.PanDistance(), mY.PanDistance()) * mFrameMetrics.mResolution.width;
|
||||
}
|
||||
|
||||
|
@ -439,27 +442,61 @@ const nsPoint AsyncPanZoomController::GetVelocityVector() {
|
|||
);
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::TrackTouch(const MultiTouchInput& aEvent) {
|
||||
void AsyncPanZoomController::StartPanning(const MultiTouchInput& aEvent) {
|
||||
SingleTouchData& touch = GetFirstSingleTouch(aEvent);
|
||||
|
||||
float dx = mX.PanDistance(),
|
||||
dy = mY.PanDistance();
|
||||
|
||||
double angle = atan2(dy, dx); // range [-pi, pi]
|
||||
angle = fabs(angle); // range [0, pi]
|
||||
|
||||
mX.StartTouch(touch.mScreenPoint.x);
|
||||
mY.StartTouch(touch.mScreenPoint.y);
|
||||
mState = PANNING;
|
||||
mLastRepaint = aEvent.mTime;
|
||||
|
||||
if (angle < AXIS_LOCK_ANGLE || angle > (M_PI - AXIS_LOCK_ANGLE)) {
|
||||
mY.LockPanning();
|
||||
} else if (fabsf(angle - M_PI / 2) < AXIS_LOCK_ANGLE) {
|
||||
mX.LockPanning();
|
||||
}
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::UpdateWithTouchAtDevicePoint(const MultiTouchInput& aEvent) {
|
||||
SingleTouchData& touch = GetFirstSingleTouch(aEvent);
|
||||
nsIntPoint point = touch.mScreenPoint;
|
||||
PRInt32 xPos = point.x, yPos = point.y, timeDelta = aEvent.mTime - mLastEventTime;
|
||||
PRInt32 xPos = point.x, yPos = point.y;
|
||||
TimeDuration timeDelta = TimeDuration().FromMilliseconds(aEvent.mTime - mLastEventTime);
|
||||
|
||||
// Probably a duplicate event, just throw it away.
|
||||
if (!timeDelta) {
|
||||
if (timeDelta.ToMilliseconds() <= EPSILON) {
|
||||
return;
|
||||
}
|
||||
|
||||
mX.UpdateWithTouchAtDevicePoint(xPos, timeDelta);
|
||||
mY.UpdateWithTouchAtDevicePoint(yPos, timeDelta);
|
||||
}
|
||||
|
||||
void AsyncPanZoomController::TrackTouch(const MultiTouchInput& aEvent) {
|
||||
TimeDuration timeDelta = TimeDuration().FromMilliseconds(aEvent.mTime - mLastEventTime);
|
||||
|
||||
// Probably a duplicate event, just throw it away.
|
||||
if (timeDelta.ToMilliseconds() <= EPSILON) {
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateWithTouchAtDevicePoint(aEvent);
|
||||
|
||||
{
|
||||
MonitorAutoLock monitor(mMonitor);
|
||||
mX.UpdateWithTouchAtDevicePoint(xPos, timeDelta);
|
||||
mY.UpdateWithTouchAtDevicePoint(yPos, timeDelta);
|
||||
|
||||
// We want to inversely scale it because when you're zoomed further in, a
|
||||
// larger swipe should move you a shorter distance.
|
||||
float inverseScale = 1 / mFrameMetrics.mResolution.width;
|
||||
|
||||
PRInt32 xDisplacement = mX.UpdateAndGetDisplacement(inverseScale);
|
||||
PRInt32 yDisplacement = mY.UpdateAndGetDisplacement(inverseScale);
|
||||
PRInt32 xDisplacement = mX.GetDisplacementForDuration(inverseScale, timeDelta);
|
||||
PRInt32 yDisplacement = mY.GetDisplacementForDuration(inverseScale, timeDelta);
|
||||
if (!xDisplacement && !yDisplacement) {
|
||||
return;
|
||||
}
|
||||
|
@ -483,7 +520,10 @@ bool AsyncPanZoomController::DoFling(const TimeDuration& aDelta) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!mX.FlingApplyFrictionOrCancel(aDelta) && !mY.FlingApplyFrictionOrCancel(aDelta)) {
|
||||
bool shouldContinueFlingX = mX.FlingApplyFrictionOrCancel(aDelta),
|
||||
shouldContinueFlingY = mY.FlingApplyFrictionOrCancel(aDelta);
|
||||
// If we shouldn't continue the fling, let's just stop and repaint.
|
||||
if (!shouldContinueFlingX && !shouldContinueFlingY) {
|
||||
RequestContentRepaint();
|
||||
mState = NOTHING;
|
||||
return false;
|
||||
|
@ -494,8 +534,8 @@ bool AsyncPanZoomController::DoFling(const TimeDuration& aDelta) {
|
|||
float inverseScale = 1 / mFrameMetrics.mResolution.width;
|
||||
|
||||
ScrollBy(nsIntPoint(
|
||||
mX.UpdateAndGetDisplacement(inverseScale),
|
||||
mY.UpdateAndGetDisplacement(inverseScale)
|
||||
mX.GetDisplacementForDuration(inverseScale, aDelta),
|
||||
mY.GetDisplacementForDuration(inverseScale, aDelta)
|
||||
));
|
||||
RequestContentRepaint();
|
||||
|
||||
|
@ -561,15 +601,8 @@ const nsIntRect AsyncPanZoomController::CalculatePendingDisplayPort() {
|
|||
nsIntRect viewport = mFrameMetrics.mViewport;
|
||||
viewport.ScaleRoundIn(1 / scale);
|
||||
|
||||
const float SIZE_MULTIPLIER = 2.0f;
|
||||
nsIntPoint scrollOffset = mFrameMetrics.mViewportScrollOffset;
|
||||
gfx::Rect contentRect = mFrameMetrics.mCSSContentRect;
|
||||
|
||||
// Paint a larger portion of the screen than just what we can see. This makes
|
||||
// it less likely that we'll checkerboard when panning around and Gecko hasn't
|
||||
// repainted yet.
|
||||
float desiredWidth = viewport.width * SIZE_MULTIPLIER,
|
||||
desiredHeight = viewport.height * SIZE_MULTIPLIER;
|
||||
nsPoint velocity = GetVelocityVector();
|
||||
|
||||
// The displayport is relative to the current scroll offset. Here's a little
|
||||
// diagram to make it easier to see:
|
||||
|
@ -595,32 +628,40 @@ const nsIntRect AsyncPanZoomController::CalculatePendingDisplayPort() {
|
|||
// viewport marks the current scroll offset. From the @ symbol to the far left
|
||||
// and far top, it is clear that this distance is 1/4 of the displayport's
|
||||
// height/width dimension.
|
||||
gfx::Rect displayPort(-desiredWidth / 4, -desiredHeight / 4, desiredWidth, desiredHeight);
|
||||
const float STATIONARY_SIZE_MULTIPLIER = 2.0f;
|
||||
const float SKATE_SIZE_MULTIPLIER = 3.0f;
|
||||
gfx::Rect displayPort(0, 0,
|
||||
viewport.width * STATIONARY_SIZE_MULTIPLIER,
|
||||
viewport.height * STATIONARY_SIZE_MULTIPLIER);
|
||||
|
||||
// Check if the desired boundaries go over the CSS page rect along the top or
|
||||
// left. If they do, shift them to the right or down.
|
||||
float oldDisplayPortX = displayPort.x, oldDisplayPortY = displayPort.y;
|
||||
if (displayPort.X() + scrollOffset.x < contentRect.X()) {
|
||||
displayPort.x = contentRect.X() - scrollOffset.x;
|
||||
}
|
||||
if (displayPort.Y() + scrollOffset.y < contentRect.Y()) {
|
||||
displayPort.y = contentRect.Y() - scrollOffset.y;
|
||||
// Iff there's motion along only one axis of movement, and it's above a
|
||||
// threshold, then we want to paint a larger area in the direction of that
|
||||
// motion so that it's less likely to checkerboard. Also note that the other
|
||||
// axis doesn't need its displayport enlarged beyond the viewport dimension,
|
||||
// since it is impossible for it to checkerboard along that axis until motion
|
||||
// begins on it.
|
||||
if (fabsf(velocity.x) > MIN_SKATE_SPEED && fabsf(velocity.y) < MIN_SKATE_SPEED) {
|
||||
displayPort.height = viewport.height;
|
||||
displayPort.width = viewport.width * SKATE_SIZE_MULTIPLIER;
|
||||
displayPort.x = velocity.x > 0 ? 0 : viewport.width - displayPort.width;
|
||||
} else if (fabsf(velocity.x) < MIN_SKATE_SPEED && fabsf(velocity.y) > MIN_SKATE_SPEED) {
|
||||
displayPort.width = viewport.width;
|
||||
displayPort.height = viewport.height * SKATE_SIZE_MULTIPLIER;
|
||||
displayPort.y = velocity.y > 0 ? 0 : viewport.height - displayPort.height;
|
||||
} else {
|
||||
displayPort.x = -displayPort.width / 4;
|
||||
displayPort.y = -displayPort.height / 4;
|
||||
}
|
||||
|
||||
// We don't need to paint the extra area that was going to overlap with the
|
||||
// content rect. Subtract out this extra width or height.
|
||||
displayPort.width -= displayPort.x - oldDisplayPortX;
|
||||
displayPort.height -= displayPort.y - oldDisplayPortY;
|
||||
|
||||
// Check if the desired boundaries go over the CSS page rect along the right
|
||||
// or bottom. If they do, subtract out some height or width such that they
|
||||
// perfectly align with the end of the CSS page rect.
|
||||
if (displayPort.XMost() + scrollOffset.x > contentRect.XMost()) {
|
||||
displayPort.width = NS_MAX(0.0f, contentRect.XMost() - (displayPort.X() + scrollOffset.x));
|
||||
}
|
||||
if (displayPort.YMost() + scrollOffset.y > contentRect.YMost()) {
|
||||
displayPort.height = NS_MAX(0.0f, contentRect.YMost() - (displayPort.Y() + scrollOffset.y));
|
||||
}
|
||||
gfx::Rect shiftedDisplayPort = displayPort;
|
||||
// Both the scroll offset and displayport are in CSS pixels. We're scaling
|
||||
// the scroll offset because Gecko will internally scale the displayport by
|
||||
// the resolution, so we'll get clipping at the far bottom or far right if we
|
||||
// directly get the intersection of the displayport offset by the scroll
|
||||
// offset and the CSS content rect.
|
||||
shiftedDisplayPort.MoveBy(scrollOffset.x / scale, scrollOffset.y / scale);
|
||||
displayPort = shiftedDisplayPort.Intersect(mFrameMetrics.mCSSContentRect);
|
||||
displayPort.MoveBy(-scrollOffset.x / scale, -scrollOffset.y / scale);
|
||||
|
||||
// Round the displayport so we don't get any truncation, then get the nsIntRect
|
||||
// from this.
|
||||
|
@ -707,6 +748,11 @@ void AsyncPanZoomController::NotifyLayersUpdated(const FrameMetrics& aViewportFr
|
|||
mFrameMetrics.mResolution.width = 1 / mFrameMetrics.mResolution.width;
|
||||
mFrameMetrics.mResolution.height = 1 / mFrameMetrics.mResolution.height;
|
||||
SetPageRect(mFrameMetrics.mCSSContentRect);
|
||||
|
||||
// Bug 776413/fixme: Request a repaint as soon as a page is loaded so that
|
||||
// we get a larger displayport. This is very bad because we're wasting a
|
||||
// paint and not initializating the displayport correctly.
|
||||
RequestContentRepaint();
|
||||
} else if (!mFrameMetrics.mContentRect.IsEqualEdges(aViewportFrame.mContentRect)) {
|
||||
mFrameMetrics.mCSSContentRect = aViewportFrame.mCSSContentRect;
|
||||
SetPageRect(mFrameMetrics.mCSSContentRect);
|
||||
|
|
|
@ -264,7 +264,7 @@ protected:
|
|||
* current touch (this only makes sense if a touch is currently happening and
|
||||
* OnTouchMove() is being invoked).
|
||||
*/
|
||||
float PanDistance(const MultiTouchInput& aEvent);
|
||||
float PanDistance();
|
||||
|
||||
/**
|
||||
* Gets a vector of the velocities of each axis.
|
||||
|
@ -278,6 +278,18 @@ protected:
|
|||
*/
|
||||
SingleTouchData& GetFirstSingleTouch(const MultiTouchInput& aEvent);
|
||||
|
||||
/**
|
||||
* Sets up anything needed for panning. This may lock one of the axes if the
|
||||
* angle of movement is heavily skewed towards it.
|
||||
*/
|
||||
void StartPanning(const MultiTouchInput& aStartPoint);
|
||||
|
||||
/**
|
||||
* Wrapper for Axis::UpdateWithTouchAtDevicePoint(). Calls this function for
|
||||
* both axes and factors in the time delta from the last update.
|
||||
*/
|
||||
void UpdateWithTouchAtDevicePoint(const MultiTouchInput& aEvent);
|
||||
|
||||
/**
|
||||
* Does any panning required due to a new touch event.
|
||||
*/
|
||||
|
|
|
@ -10,13 +10,7 @@
|
|||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
static const float EPSILON = 0.0001;
|
||||
|
||||
/**
|
||||
* Milliseconds per frame, used to judge how much displacement should have
|
||||
* happened every frame based on the velocity calculated from touch events.
|
||||
*/
|
||||
static const float MS_PER_FRAME = 1000.0f / 60.0f;
|
||||
static const float EPSILON = 0.0001f;
|
||||
|
||||
/**
|
||||
* Maximum acceleration that can happen between two frames. Velocity is
|
||||
|
@ -24,44 +18,49 @@ static const float MS_PER_FRAME = 1000.0f / 60.0f;
|
|||
* or we get a touch point very far away from the previous position for some
|
||||
* reason.
|
||||
*/
|
||||
static const float MAX_EVENT_ACCELERATION = 12;
|
||||
static const float MAX_EVENT_ACCELERATION = 0.5f;
|
||||
|
||||
/**
|
||||
* Amount of friction applied during flings when going above
|
||||
* VELOCITY_THRESHOLD.
|
||||
*/
|
||||
static const float FLING_FRICTION_FAST = 0.010;
|
||||
static const float FLING_FRICTION_FAST = 0.0025f;
|
||||
|
||||
/**
|
||||
* Amount of friction applied during flings when going below
|
||||
* VELOCITY_THRESHOLD.
|
||||
*/
|
||||
static const float FLING_FRICTION_SLOW = 0.008;
|
||||
static const float FLING_FRICTION_SLOW = 0.0015f;
|
||||
|
||||
/**
|
||||
* Maximum velocity before fling friction increases.
|
||||
*/
|
||||
static const float VELOCITY_THRESHOLD = 10;
|
||||
static const float VELOCITY_THRESHOLD = 1.0f;
|
||||
|
||||
/**
|
||||
* When flinging, if the velocity goes below this number, we just stop the
|
||||
* animation completely. This is to prevent asymptotically approaching 0
|
||||
* velocity and rerendering unnecessarily.
|
||||
*/
|
||||
static const float FLING_STOPPED_THRESHOLD = 0.1f;
|
||||
static const float FLING_STOPPED_THRESHOLD = 0.01f;
|
||||
|
||||
Axis::Axis(AsyncPanZoomController* aAsyncPanZoomController)
|
||||
: mPos(0.0f),
|
||||
mVelocity(0.0f),
|
||||
mAsyncPanZoomController(aAsyncPanZoomController)
|
||||
mAsyncPanZoomController(aAsyncPanZoomController),
|
||||
mLockPanning(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Axis::UpdateWithTouchAtDevicePoint(PRInt32 aPos, PRInt32 aTimeDelta) {
|
||||
float newVelocity = MS_PER_FRAME * (mPos - aPos) / aTimeDelta;
|
||||
void Axis::UpdateWithTouchAtDevicePoint(PRInt32 aPos, const TimeDuration& aTimeDelta) {
|
||||
if (mLockPanning) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool curVelocityIsLow = fabsf(newVelocity) < 1.0f;
|
||||
float newVelocity = (mPos - aPos) / aTimeDelta.ToMilliseconds();
|
||||
|
||||
bool curVelocityIsLow = fabsf(newVelocity) < 0.01f;
|
||||
bool directionChange = (mVelocity > 0) != (newVelocity != 0);
|
||||
|
||||
// If a direction change has happened, or the current velocity due to this new
|
||||
|
@ -69,7 +68,7 @@ void Axis::UpdateWithTouchAtDevicePoint(PRInt32 aPos, PRInt32 aTimeDelta) {
|
|||
if (curVelocityIsLow || (directionChange && fabs(newVelocity) - EPSILON <= 0.0f)) {
|
||||
mVelocity = newVelocity;
|
||||
} else {
|
||||
float maxChange = fabsf(mVelocity * aTimeDelta * MAX_EVENT_ACCELERATION);
|
||||
float maxChange = fabsf(mVelocity * aTimeDelta.ToMilliseconds() * MAX_EVENT_ACCELERATION);
|
||||
mVelocity = NS_MIN(mVelocity + maxChange, NS_MAX(mVelocity - maxChange, newVelocity));
|
||||
}
|
||||
|
||||
|
@ -81,10 +80,11 @@ void Axis::StartTouch(PRInt32 aPos) {
|
|||
mStartPos = aPos;
|
||||
mPos = aPos;
|
||||
mVelocity = 0.0f;
|
||||
mLockPanning = false;
|
||||
}
|
||||
|
||||
PRInt32 Axis::UpdateAndGetDisplacement(float aScale) {
|
||||
PRInt32 displacement = NS_lround(mVelocity * aScale);
|
||||
PRInt32 Axis::GetDisplacementForDuration(float aScale, const TimeDuration& aDelta) {
|
||||
PRInt32 displacement = NS_lround(mVelocity * aScale * aDelta.ToMilliseconds());
|
||||
// If this displacement will cause an overscroll, throttle it. Can potentially
|
||||
// bring it to 0 even if the velocity is high.
|
||||
if (DisplacementWillOverscroll(displacement) != OVERSCROLL_NONE) {
|
||||
|
@ -101,6 +101,10 @@ void Axis::StopTouch() {
|
|||
mVelocity = 0.0f;
|
||||
}
|
||||
|
||||
void Axis::LockPanning() {
|
||||
mLockPanning = true;
|
||||
}
|
||||
|
||||
bool Axis::FlingApplyFrictionOrCancel(const TimeDuration& aDelta) {
|
||||
if (fabsf(mVelocity) <= FLING_STOPPED_THRESHOLD) {
|
||||
// If the velocity is very low, just set it to 0 and stop the fling,
|
||||
|
@ -109,9 +113,9 @@ bool Axis::FlingApplyFrictionOrCancel(const TimeDuration& aDelta) {
|
|||
mVelocity = 0.0f;
|
||||
return false;
|
||||
} else if (fabsf(mVelocity) >= VELOCITY_THRESHOLD) {
|
||||
mVelocity *= 1.0f - FLING_FRICTION_FAST * aDelta.ToMilliseconds();
|
||||
mVelocity *= NS_MAX(1.0f - FLING_FRICTION_FAST * aDelta.ToMilliseconds(), 0.0);
|
||||
} else {
|
||||
mVelocity *= 1.0f - FLING_FRICTION_SLOW * aDelta.ToMilliseconds();
|
||||
mVelocity *= NS_MAX(1.0f - FLING_FRICTION_SLOW * aDelta.ToMilliseconds(), 0.0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ public:
|
|||
* indicating how long it has been since the previous one. This triggers a
|
||||
* recalculation of velocity.
|
||||
*/
|
||||
void UpdateWithTouchAtDevicePoint(PRInt32 aPos, PRInt32 aTimeDelta);
|
||||
void UpdateWithTouchAtDevicePoint(PRInt32 aPos, const TimeDuration& aTimeDelta);
|
||||
|
||||
/**
|
||||
* Notify this Axis that a touch has begun, i.e. the user has put their finger
|
||||
|
@ -58,17 +58,25 @@ public:
|
|||
*/
|
||||
void StopTouch();
|
||||
|
||||
/**
|
||||
* Sets axis locking. This prevents any panning along this axis. If the
|
||||
* current touch point is updated and the axis is locked, the velocity will
|
||||
* not be recalculated. Any already-existing velocity will however stay the
|
||||
* same.
|
||||
*/
|
||||
void LockPanning();
|
||||
|
||||
/**
|
||||
* Gets displacement that should have happened since the previous touch.
|
||||
* Note: Does not reset the displacement. It gets recalculated on the next
|
||||
* updateWithTouchAtDevicePoint(), however it is not safe to assume this will
|
||||
* UpdateWithTouchAtDevicePoint(), however it is not safe to assume this will
|
||||
* be the same on every call. This also checks for page boundaries and will
|
||||
* return an adjusted displacement to prevent the viewport from overscrolling
|
||||
* the page rect. An example of where this might matter is when you call it,
|
||||
* apply a displacement that takes you to the boundary of the page, then call
|
||||
* it again. The result will be different in this case.
|
||||
*/
|
||||
PRInt32 UpdateAndGetDisplacement(float aScale);
|
||||
PRInt32 GetDisplacementForDuration(float aScale, const TimeDuration& aDelta);
|
||||
|
||||
/**
|
||||
* Gets the distance between the starting position of the touch supplied in
|
||||
|
@ -164,6 +172,7 @@ protected:
|
|||
PRInt32 mStartPos;
|
||||
float mVelocity;
|
||||
nsRefPtr<AsyncPanZoomController> mAsyncPanZoomController;
|
||||
bool mLockPanning;
|
||||
};
|
||||
|
||||
class AxisX : public Axis {
|
||||
|
|
|
@ -1379,6 +1379,20 @@ nsIntRegion nsRegion::ToNearestPixels (nscoord aAppUnitsPerPixel) const
|
|||
return ToPixels(aAppUnitsPerPixel, false);
|
||||
}
|
||||
|
||||
nsIntRegion nsRegion::ScaleToNearestPixels (float aScaleX, float aScaleY,
|
||||
nscoord aAppUnitsPerPixel) const
|
||||
{
|
||||
nsIntRegion result;
|
||||
nsRegionRectIterator rgnIter(*this);
|
||||
const nsRect* currentRect;
|
||||
while ((currentRect = rgnIter.Next())) {
|
||||
nsIntRect deviceRect =
|
||||
currentRect->ScaleToNearestPixels(aScaleX, aScaleY, aAppUnitsPerPixel);
|
||||
result.Or(result, deviceRect);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
nsIntRegion nsRegion::ScaleToOutsidePixels (float aScaleX, float aScaleY,
|
||||
nscoord aAppUnitsPerPixel) const
|
||||
{
|
||||
|
@ -1393,6 +1407,67 @@ nsIntRegion nsRegion::ScaleToOutsidePixels (float aScaleX, float aScaleY,
|
|||
return result;
|
||||
}
|
||||
|
||||
nsIntRegion nsRegion::ScaleToInsidePixels (float aScaleX, float aScaleY,
|
||||
nscoord aAppUnitsPerPixel) const
|
||||
{
|
||||
/* When scaling a rect, walk forward through the rect list up until the y value is greater
|
||||
* than the current rect's YMost() value.
|
||||
*
|
||||
* For each rect found, check if the rects have a touching edge (in unscaled coordinates),
|
||||
* and if one edge is entirely contained within the other.
|
||||
*
|
||||
* If it is, then the contained edge can be moved (in scaled pixels) to ensure that no
|
||||
* gap exists.
|
||||
*
|
||||
* Since this could be potentially expensive - O(n^2), we only attempt this algorithm
|
||||
* for the first rect.
|
||||
*/
|
||||
|
||||
nsIntRegion result;
|
||||
RgnRect* pRect = mRectListHead.next;
|
||||
RgnRect* first = pRect;
|
||||
|
||||
nsIntRect firstDeviceRect;
|
||||
if (pRect != &mRectListHead) {
|
||||
firstDeviceRect =
|
||||
pRect->ScaleToInsidePixels(aScaleX, aScaleY, aAppUnitsPerPixel);
|
||||
pRect = pRect->next;
|
||||
}
|
||||
|
||||
while (pRect != &mRectListHead)
|
||||
{
|
||||
nsIntRect deviceRect =
|
||||
pRect->ScaleToInsidePixels(aScaleX, aScaleY, aAppUnitsPerPixel);
|
||||
|
||||
if (pRect->y <= first->YMost()) {
|
||||
if (pRect->XMost() == first->x && pRect->YMost() <= first->YMost()) {
|
||||
// pRect is touching on the left edge of the first rect and contained within
|
||||
// the length of its left edge
|
||||
deviceRect.SetRightEdge(firstDeviceRect.x);
|
||||
} else if (pRect->x == first->XMost() && pRect->YMost() <= first->YMost()) {
|
||||
// pRect is touching on the right edge of the first rect and contained within
|
||||
// the length of its right edge
|
||||
deviceRect.SetLeftEdge(firstDeviceRect.XMost());
|
||||
} else if (pRect->y == first->YMost()) {
|
||||
// The bottom of the first rect is on the same line as the top of pRect, but
|
||||
// they aren't necessarily contained.
|
||||
if (pRect->x <= first->x && pRect->XMost() >= first->XMost()) {
|
||||
// The top of pRect contains the bottom of the first rect
|
||||
firstDeviceRect.SetBottomEdge(deviceRect.y);
|
||||
} else if (pRect->x >= first->x && pRect->XMost() <= first->XMost()) {
|
||||
// The bottom of the first contains the top of pRect
|
||||
deviceRect.SetTopEdge(firstDeviceRect.YMost());
|
||||
}
|
||||
}
|
||||
}
|
||||
pRect = pRect->next;
|
||||
result.Or(result, deviceRect);
|
||||
}
|
||||
|
||||
result.Or(result, firstDeviceRect);
|
||||
return result;
|
||||
}
|
||||
|
||||
// A cell's "value" is a pair consisting of
|
||||
// a) the area of the subrectangle it corresponds to, if it's in
|
||||
// aContainingRect and in the region, 0 otherwise
|
||||
|
|
|
@ -155,6 +155,8 @@ public:
|
|||
nsRegion& ScaleRoundOut(float aXScale, float aYScale);
|
||||
nsRegion& ScaleInverseRoundOut(float aXScale, float aYScale);
|
||||
nsIntRegion ScaleToOutsidePixels (float aXScale, float aYScale, nscoord aAppUnitsPerPixel) const;
|
||||
nsIntRegion ScaleToInsidePixels (float aXScale, float aYScale, nscoord aAppUnitsPerPixel) const;
|
||||
nsIntRegion ScaleToNearestPixels (float aXScale, float aYScale, nscoord aAppUnitsPerPixel) const;
|
||||
nsIntRegion ToOutsidePixels (nscoord aAppUnitsPerPixel) const;
|
||||
nsIntRegion ToNearestPixels (nscoord aAppUnitsPerPixel) const;
|
||||
|
||||
|
|
|
@ -488,6 +488,13 @@ gfxASurface::MovePixels(const nsIntRect& aSourceRect,
|
|||
nsRefPtr<gfxASurface> tmp =
|
||||
CreateSimilarSurface(GetContentType(),
|
||||
gfxIntSize(aSourceRect.width, aSourceRect.height));
|
||||
// CreateSimilarSurface can return nsnull if the current surface is
|
||||
// in an error state. This isn't good, but its better to carry
|
||||
// on with the error surface instead of crashing.
|
||||
NS_ASSERTION(tmp, "Must have temporary surface to move pixels!");
|
||||
if (!tmp) {
|
||||
return;
|
||||
}
|
||||
nsRefPtr<gfxContext> ctx = new gfxContext(tmp);
|
||||
ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
|
||||
ctx->SetSource(this, gfxPoint(-aSourceRect.x, -aSourceRect.y));
|
||||
|
|
|
@ -147,6 +147,10 @@ public:
|
|||
CollectOldLayers();
|
||||
}
|
||||
|
||||
enum ProcessDisplayItemsFlags {
|
||||
NO_COMPONENT_ALPHA = 0x01,
|
||||
};
|
||||
|
||||
void AddInvalidThebesContent(const nsIntRegion& aRegion)
|
||||
{
|
||||
mInvalidThebesContent.Or(mInvalidThebesContent, aRegion);
|
||||
|
@ -162,7 +166,8 @@ public:
|
|||
* if no clipping is required
|
||||
*/
|
||||
void ProcessDisplayItems(const nsDisplayList& aList,
|
||||
FrameLayerBuilder::Clip& aClip);
|
||||
FrameLayerBuilder::Clip& aClip,
|
||||
PRUint32 aFlags);
|
||||
/**
|
||||
* This finalizes all the open ThebesLayers by popping every element off
|
||||
* mThebesLayerDataStack, then sets the children of the container layer
|
||||
|
@ -182,6 +187,11 @@ public:
|
|||
return aRect.ScaleToNearestPixels(mParameters.mXScale, mParameters.mYScale,
|
||||
mAppUnitsPerDevPixel);
|
||||
}
|
||||
nsIntRegion ScaleRegionToNearestPixels(const nsRegion& aRegion)
|
||||
{
|
||||
return aRegion.ScaleToNearestPixels(mParameters.mXScale, mParameters.mYScale,
|
||||
mAppUnitsPerDevPixel);
|
||||
}
|
||||
nsIntRect ScaleToOutsidePixels(const nsRect& aRect, bool aSnap)
|
||||
{
|
||||
if (aSnap && mSnappingEnabled) {
|
||||
|
@ -199,6 +209,15 @@ public:
|
|||
mAppUnitsPerDevPixel);
|
||||
}
|
||||
|
||||
nsIntRegion ScaleRegionToInsidePixels(const nsRegion& aRegion, bool aSnap)
|
||||
{
|
||||
if (aSnap && mSnappingEnabled) {
|
||||
return ScaleRegionToNearestPixels(aRegion);
|
||||
}
|
||||
return aRegion.ScaleToInsidePixels(mParameters.mXScale, mParameters.mYScale,
|
||||
mAppUnitsPerDevPixel);
|
||||
}
|
||||
|
||||
const FrameLayerBuilder::ContainerParameters& ScaleParameters() { return mParameters; };
|
||||
|
||||
protected:
|
||||
|
@ -780,8 +799,11 @@ FrameLayerBuilder::UpdateDisplayItemDataForFrame(DisplayItemDataEntry* aEntry,
|
|||
FrameProperties props = f->Properties();
|
||||
DisplayItemDataEntry* newDisplayItems =
|
||||
builder ? builder->mNewDisplayItemData.GetEntry(f) : nsnull;
|
||||
if (!newDisplayItems) {
|
||||
if (!newDisplayItems || newDisplayItems->mData.IsEmpty()) {
|
||||
// This frame was visible, but isn't anymore.
|
||||
if (newDisplayItems) {
|
||||
builder->mNewDisplayItemData.RawRemoveEntry(newDisplayItems);
|
||||
}
|
||||
bool found;
|
||||
props.Remove(LayerManagerDataProperty(), &found);
|
||||
NS_ASSERTION(found, "How can the frame property be missing?");
|
||||
|
@ -1482,17 +1504,23 @@ ContainerState::ThebesLayerData::Accumulate(ContainerState* aState,
|
|||
bool snap;
|
||||
nsRegion opaque = aItem->GetOpaqueRegion(aState->mBuilder, &snap);
|
||||
if (!opaque.IsEmpty()) {
|
||||
nsRegion opaqueClipped;
|
||||
nsRegionRectIterator iter(opaque);
|
||||
for (const nsRect* r = iter.Next(); r; r = iter.Next()) {
|
||||
opaqueClipped.Or(opaqueClipped, aClip.ApproximateIntersect(*r));
|
||||
}
|
||||
|
||||
nsIntRegion opaquePixels = aState->ScaleRegionToInsidePixels(opaqueClipped, snap);
|
||||
|
||||
nsIntRegionRectIterator iter2(opaquePixels);
|
||||
for (const nsIntRect* r = iter2.Next(); r; r = iter2.Next()) {
|
||||
// We don't use SimplifyInward here since it's not defined exactly
|
||||
// what it will discard. For our purposes the most important case
|
||||
// is a large opaque background at the bottom of z-order (e.g.,
|
||||
// a canvas background), so we need to make sure that the first rect
|
||||
// we see doesn't get discarded.
|
||||
nsIntRect rect =
|
||||
aState->ScaleToInsidePixels(aClip.ApproximateIntersect(*r), snap);
|
||||
nsIntRegion tmp;
|
||||
tmp.Or(mOpaqueRegion, rect);
|
||||
tmp.Or(mOpaqueRegion, *r);
|
||||
// Opaque display items in chrome documents whose window is partially
|
||||
// transparent are always added to the opaque region. This helps ensure
|
||||
// that we get as much subpixel-AA as possible in the chrome.
|
||||
|
@ -1673,7 +1701,8 @@ PaintInactiveLayer(nsDisplayListBuilder* aBuilder,
|
|||
*/
|
||||
void
|
||||
ContainerState::ProcessDisplayItems(const nsDisplayList& aList,
|
||||
FrameLayerBuilder::Clip& aClip)
|
||||
FrameLayerBuilder::Clip& aClip,
|
||||
PRUint32 aFlags)
|
||||
{
|
||||
SAMPLE_LABEL("ContainerState", "ProcessDisplayItems");
|
||||
for (nsDisplayItem* item = aList.GetBottom(); item; item = item->GetAbove()) {
|
||||
|
@ -1681,7 +1710,7 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList,
|
|||
if (type == nsDisplayItem::TYPE_CLIP ||
|
||||
type == nsDisplayItem::TYPE_CLIP_ROUNDED_RECT) {
|
||||
FrameLayerBuilder::Clip childClip(aClip, item);
|
||||
ProcessDisplayItems(*item->GetList(), childClip);
|
||||
ProcessDisplayItems(*item->GetList(), childClip, aFlags);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1703,13 +1732,22 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList,
|
|||
|
||||
LayerState layerState = item->GetLayerState(mBuilder, mManager, mParameters);
|
||||
|
||||
nsIFrame* activeScrolledRoot =
|
||||
nsLayoutUtils::GetActiveScrolledRootFor(item, mBuilder);
|
||||
nsIFrame* activeScrolledRoot;
|
||||
bool forceInactive = false;
|
||||
if (aFlags & NO_COMPONENT_ALPHA) {
|
||||
activeScrolledRoot =
|
||||
nsLayoutUtils::GetActiveScrolledRootFor(mContainerFrame,
|
||||
mBuilder->ReferenceFrame());
|
||||
forceInactive = true;
|
||||
} else {
|
||||
activeScrolledRoot = nsLayoutUtils::GetActiveScrolledRootFor(item, mBuilder);
|
||||
}
|
||||
|
||||
// Assign the item to a layer
|
||||
if (layerState == LAYER_ACTIVE_FORCE ||
|
||||
layerState == LAYER_ACTIVE_EMPTY ||
|
||||
layerState == LAYER_ACTIVE) {
|
||||
(!forceInactive &&
|
||||
(layerState == LAYER_ACTIVE_EMPTY ||
|
||||
layerState == LAYER_ACTIVE))) {
|
||||
|
||||
// LAYER_ACTIVE_EMPTY means the layer is created just for its metadata.
|
||||
// We should never see an empty layer with any visible content!
|
||||
|
@ -1880,9 +1918,11 @@ FrameLayerBuilder::AddThebesDisplayItem(ThebesLayer* aLayer,
|
|||
ThebesLayerItemsEntry* entry = mThebesLayerItems.PutEntry(aLayer);
|
||||
if (entry) {
|
||||
entry->mContainerLayerFrame = aContainerLayerFrame;
|
||||
entry->mContainerLayerGeneration = mContainerLayerGeneration;
|
||||
NS_ASSERTION(aItem->GetUnderlyingFrame(), "Must have frame");
|
||||
ClippedDisplayItem* cdi =
|
||||
entry->mItems.AppendElement(ClippedDisplayItem(aItem, aClip));
|
||||
entry->mItems.AppendElement(ClippedDisplayItem(aItem, aClip,
|
||||
mContainerLayerGeneration));
|
||||
cdi->mInactiveLayer = aLayerState != LAYER_NONE;
|
||||
}
|
||||
}
|
||||
|
@ -1897,8 +1937,9 @@ FrameLayerBuilder::AddLayerDisplayItem(Layer* aLayer,
|
|||
|
||||
nsIFrame* f = aItem->GetUnderlyingFrame();
|
||||
DisplayItemDataEntry* entry = mNewDisplayItemData.PutEntry(f);
|
||||
entry->mContainerLayerGeneration = mContainerLayerGeneration;
|
||||
if (entry) {
|
||||
entry->mData.AppendElement(DisplayItemData(aLayer, aItem->GetPerFrameKey(), aLayerState));
|
||||
entry->mData.AppendElement(DisplayItemData(aLayer, aItem->GetPerFrameKey(), aLayerState, mContainerLayerGeneration));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1906,8 +1947,11 @@ nsIntPoint
|
|||
FrameLayerBuilder::GetLastPaintOffset(ThebesLayer* aLayer)
|
||||
{
|
||||
ThebesLayerItemsEntry* entry = mThebesLayerItems.PutEntry(aLayer);
|
||||
if (entry && entry->mHasExplicitLastPaintOffset)
|
||||
return entry->mLastPaintOffset;
|
||||
if (entry) {
|
||||
entry->mContainerLayerGeneration = mContainerLayerGeneration;
|
||||
if (entry->mHasExplicitLastPaintOffset)
|
||||
return entry->mLastPaintOffset;
|
||||
}
|
||||
return GetTranslationForThebesLayer(aLayer);
|
||||
}
|
||||
|
||||
|
@ -1916,6 +1960,7 @@ FrameLayerBuilder::SaveLastPaintOffset(ThebesLayer* aLayer)
|
|||
{
|
||||
ThebesLayerItemsEntry* entry = mThebesLayerItems.PutEntry(aLayer);
|
||||
if (entry) {
|
||||
entry->mContainerLayerGeneration = mContainerLayerGeneration;
|
||||
entry->mLastPaintOffset = GetTranslationForThebesLayer(aLayer);
|
||||
entry->mHasExplicitLastPaintOffset = true;
|
||||
}
|
||||
|
@ -2124,6 +2169,44 @@ ApplyThebesLayerInvalidation(nsDisplayListBuilder* aBuilder,
|
|||
}
|
||||
}
|
||||
|
||||
/* static */ PLDHashOperator
|
||||
FrameLayerBuilder::RestoreDisplayItemData(DisplayItemDataEntry* aEntry, void* aUserArg)
|
||||
{
|
||||
PRUint32 *generation = static_cast<PRUint32*>(aUserArg);
|
||||
|
||||
if (aEntry->mContainerLayerGeneration >= *generation) {
|
||||
return PL_DHASH_REMOVE;
|
||||
}
|
||||
|
||||
for (PRUint32 i = 0; i < aEntry->mData.Length(); i++) {
|
||||
if (aEntry->mData[i].mContainerLayerGeneration >= *generation) {
|
||||
aEntry->mData.TruncateLength(i);
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
/* static */ PLDHashOperator
|
||||
FrameLayerBuilder::RestoreThebesLayerItemEntries(ThebesLayerItemsEntry* aEntry, void* aUserArg)
|
||||
{
|
||||
PRUint32 *generation = static_cast<PRUint32*>(aUserArg);
|
||||
|
||||
if (aEntry->mContainerLayerGeneration >= *generation) {
|
||||
return PL_DHASH_REMOVE;
|
||||
}
|
||||
|
||||
for (PRUint32 i = 0; i < aEntry->mItems.Length(); i++) {
|
||||
if (aEntry->mItems[i].mContainerLayerGeneration >= *generation) {
|
||||
aEntry->mItems.TruncateLength(i);
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
already_AddRefed<ContainerLayer>
|
||||
FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
|
@ -2179,75 +2262,117 @@ FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder,
|
|||
ContainerParameters scaleParameters =
|
||||
ChooseScaleAndSetTransform(this, aContainerFrame, aTransform, aParameters,
|
||||
containerLayer);
|
||||
ContainerState state(aBuilder, aManager, GetLayerBuilderForManager(aManager),
|
||||
aContainerFrame, containerLayer, scaleParameters);
|
||||
|
||||
PRUint32 oldGeneration = mContainerLayerGeneration;
|
||||
mContainerLayerGeneration = ++mMaxContainerLayerGeneration;
|
||||
|
||||
nsRefPtr<RefCountedRegion> thebesLayerInvalidRegion = nsnull;
|
||||
if (aManager == mRetainingManager) {
|
||||
FrameProperties props = aContainerFrame->Properties();
|
||||
RefCountedRegion* thebesLayerInvalidRegion = nsnull;
|
||||
DisplayItemDataEntry* entry = mNewDisplayItemData.PutEntry(aContainerFrame);
|
||||
if (entry) {
|
||||
entry->mData.AppendElement(
|
||||
DisplayItemData(containerLayer, containerDisplayItemKey, LAYER_ACTIVE));
|
||||
DisplayItemData(containerLayer, containerDisplayItemKey,
|
||||
LAYER_ACTIVE, mContainerLayerGeneration));
|
||||
thebesLayerInvalidRegion = static_cast<RefCountedRegion*>
|
||||
(props.Get(ThebesLayerInvalidRegionProperty()));
|
||||
if (!thebesLayerInvalidRegion) {
|
||||
thebesLayerInvalidRegion = new RefCountedRegion();
|
||||
}
|
||||
entry->mInvalidRegion = thebesLayerInvalidRegion;
|
||||
}
|
||||
nsPoint currentOffset;
|
||||
ApplyThebesLayerInvalidation(aBuilder, aContainerFrame, aContainerItem, state,
|
||||
¤tOffset);
|
||||
SetHasContainerLayer(aContainerFrame, currentOffset);
|
||||
|
||||
nsAutoTArray<nsIFrame*,4> mergedFrames;
|
||||
if (aContainerItem) {
|
||||
aContainerItem->GetMergedFrames(&mergedFrames);
|
||||
}
|
||||
for (PRUint32 i = 0; i < mergedFrames.Length(); ++i) {
|
||||
nsIFrame* mergedFrame = mergedFrames[i];
|
||||
DisplayItemDataEntry* entry = mNewDisplayItemData.PutEntry(mergedFrame);
|
||||
if (entry) {
|
||||
// Ensure that UpdateDisplayItemDataForFrame recognizes that we
|
||||
// still have a container layer associated with this frame.
|
||||
entry->mIsSharingContainerLayer = true;
|
||||
|
||||
// Store the invalid region property in case this frame is represented
|
||||
// by multiple container layers. This is cleared and set when iterating
|
||||
// over the DisplayItemDataEntry's in WillEndTransaction.
|
||||
entry->mInvalidRegion = thebesLayerInvalidRegion;
|
||||
}
|
||||
ApplyThebesLayerInvalidation(aBuilder, mergedFrame, nsnull, state,
|
||||
¤tOffset);
|
||||
SetHasContainerLayer(mergedFrame, currentOffset);
|
||||
entry->mContainerLayerGeneration = mContainerLayerGeneration;
|
||||
}
|
||||
}
|
||||
|
||||
Clip clip;
|
||||
state.ProcessDisplayItems(aChildren, clip);
|
||||
|
||||
// Set CONTENT_COMPONENT_ALPHA if any of our children have it.
|
||||
// This is suboptimal ... a child could have text that's over transparent
|
||||
// pixels in its own layer, but over opaque parts of previous siblings.
|
||||
nsRect bounds;
|
||||
nsIntRect pixBounds;
|
||||
PRInt32 appUnitsPerDevPixel;
|
||||
PRUint32 stateFlags =
|
||||
(aContainerFrame->GetStateBits() & NS_FRAME_NO_COMPONENT_ALPHA) ?
|
||||
ContainerState::NO_COMPONENT_ALPHA : 0;
|
||||
PRUint32 flags;
|
||||
state.Finish(&flags);
|
||||
bool flattenedLayers = false;
|
||||
while (true) {
|
||||
ContainerState state(aBuilder, aManager, GetLayerBuilderForManager(aManager),
|
||||
aContainerFrame, containerLayer, scaleParameters);
|
||||
if (flattenedLayers) {
|
||||
state.SetInvalidateAllThebesContent();
|
||||
}
|
||||
|
||||
if (aManager == mRetainingManager) {
|
||||
nsPoint currentOffset;
|
||||
ApplyThebesLayerInvalidation(aBuilder, aContainerFrame, aContainerItem, state,
|
||||
¤tOffset);
|
||||
SetHasContainerLayer(aContainerFrame, currentOffset);
|
||||
|
||||
nsAutoTArray<nsIFrame*,4> mergedFrames;
|
||||
if (aContainerItem) {
|
||||
aContainerItem->GetMergedFrames(&mergedFrames);
|
||||
}
|
||||
for (PRUint32 i = 0; i < mergedFrames.Length(); ++i) {
|
||||
nsIFrame* mergedFrame = mergedFrames[i];
|
||||
DisplayItemDataEntry* entry = mNewDisplayItemData.PutEntry(mergedFrame);
|
||||
if (entry) {
|
||||
// Ensure that UpdateDisplayItemDataForFrame recognizes that we
|
||||
// still have a container layer associated with this frame.
|
||||
entry->mIsSharingContainerLayer = true;
|
||||
|
||||
// Store the invalid region property in case this frame is represented
|
||||
// by multiple container layers. This is cleared and set when iterating
|
||||
// over the DisplayItemDataEntry's in WillEndTransaction.
|
||||
entry->mInvalidRegion = thebesLayerInvalidRegion;
|
||||
}
|
||||
ApplyThebesLayerInvalidation(aBuilder, mergedFrame, nsnull, state,
|
||||
¤tOffset);
|
||||
SetHasContainerLayer(mergedFrame, currentOffset);
|
||||
}
|
||||
}
|
||||
|
||||
Clip clip;
|
||||
state.ProcessDisplayItems(aChildren, clip, stateFlags);
|
||||
|
||||
// Set CONTENT_COMPONENT_ALPHA if any of our children have it.
|
||||
// This is suboptimal ... a child could have text that's over transparent
|
||||
// pixels in its own layer, but over opaque parts of previous siblings.
|
||||
state.Finish(&flags);
|
||||
bounds = state.GetChildrenBounds();
|
||||
pixBounds = state.ScaleToOutsidePixels(bounds, false);
|
||||
appUnitsPerDevPixel = state.GetAppUnitsPerDevPixel();
|
||||
|
||||
if ((flags & Layer::CONTENT_COMPONENT_ALPHA) &&
|
||||
mRetainingManager &&
|
||||
!mRetainingManager->AreComponentAlphaLayersEnabled() &&
|
||||
!stateFlags) {
|
||||
// Since we don't want any component alpha layers on BasicLayers, we repeat
|
||||
// the layer building process with this explicitely forced off.
|
||||
// We restore the previous FrameLayerBuilder state since the first set
|
||||
// of layer building will have changed it.
|
||||
stateFlags = ContainerState::NO_COMPONENT_ALPHA;
|
||||
mNewDisplayItemData.EnumerateEntries(RestoreDisplayItemData,
|
||||
&mContainerLayerGeneration);
|
||||
mThebesLayerItems.EnumerateEntries(RestoreThebesLayerItemEntries,
|
||||
&mContainerLayerGeneration);
|
||||
aContainerFrame->AddStateBits(NS_FRAME_NO_COMPONENT_ALPHA);
|
||||
flattenedLayers = true;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
nsRect bounds = state.GetChildrenBounds();
|
||||
NS_ASSERTION(bounds.IsEqualInterior(aChildren.GetBounds(aBuilder)), "Wrong bounds");
|
||||
nsIntRect pixBounds = state.ScaleToOutsidePixels(bounds, false);
|
||||
containerLayer->SetVisibleRegion(pixBounds);
|
||||
// Make sure that rounding the visible region out didn't add any area
|
||||
// we won't paint
|
||||
if (aChildren.IsOpaque() && !aChildren.NeedsTransparentSurface()) {
|
||||
bounds.ScaleRoundIn(scaleParameters.mXScale, scaleParameters.mYScale);
|
||||
if (bounds.Contains(pixBounds.ToAppUnits(state.GetAppUnitsPerDevPixel()))) {
|
||||
if (bounds.Contains(pixBounds.ToAppUnits(appUnitsPerDevPixel))) {
|
||||
// Clear CONTENT_COMPONENT_ALPHA
|
||||
flags = Layer::CONTENT_OPAQUE;
|
||||
}
|
||||
}
|
||||
containerLayer->SetContentFlags(flags);
|
||||
|
||||
mContainerLayerGeneration = oldGeneration;
|
||||
return containerLayer.forget();
|
||||
}
|
||||
|
||||
|
|
|
@ -123,7 +123,9 @@ public:
|
|||
FrameLayerBuilder() :
|
||||
mRetainingManager(nsnull),
|
||||
mDetectedDOMModification(false),
|
||||
mInvalidateAllLayers(false)
|
||||
mInvalidateAllLayers(false),
|
||||
mContainerLayerGeneration(0),
|
||||
mMaxContainerLayerGeneration(0)
|
||||
{
|
||||
MOZ_COUNT_CTOR(FrameLayerBuilder);
|
||||
mNewDisplayItemData.Init();
|
||||
|
@ -467,11 +469,16 @@ protected:
|
|||
*/
|
||||
class DisplayItemData {
|
||||
public:
|
||||
DisplayItemData(Layer* aLayer, PRUint32 aKey, LayerState aLayerState)
|
||||
: mLayer(aLayer), mDisplayItemKey(aKey), mLayerState(aLayerState) {}
|
||||
DisplayItemData(Layer* aLayer, PRUint32 aKey, LayerState aLayerState, PRUint32 aGeneration)
|
||||
: mLayer(aLayer)
|
||||
, mDisplayItemKey(aKey)
|
||||
, mContainerLayerGeneration(aGeneration)
|
||||
, mLayerState(aLayerState)
|
||||
{}
|
||||
|
||||
nsRefPtr<Layer> mLayer;
|
||||
PRUint32 mDisplayItemKey;
|
||||
PRUint32 mContainerLayerGeneration;
|
||||
LayerState mLayerState;
|
||||
};
|
||||
|
||||
|
@ -495,12 +502,14 @@ protected:
|
|||
// array and invalid region. Be careful.
|
||||
mData.SwapElements(toCopy.mData);
|
||||
mInvalidRegion.swap(toCopy.mInvalidRegion);
|
||||
mContainerLayerGeneration = toCopy.mContainerLayerGeneration;
|
||||
}
|
||||
|
||||
bool HasNonEmptyContainerLayer();
|
||||
|
||||
nsAutoTArray<DisplayItemData, 1> mData;
|
||||
nsRefPtr<RefCountedRegion> mInvalidRegion;
|
||||
PRUint32 mContainerLayerGeneration;
|
||||
bool mIsSharingContainerLayer;
|
||||
|
||||
enum { ALLOW_MEMMOVE = false };
|
||||
|
@ -544,13 +553,14 @@ protected:
|
|||
* mItem always has an underlying frame.
|
||||
*/
|
||||
struct ClippedDisplayItem {
|
||||
ClippedDisplayItem(nsDisplayItem* aItem, const Clip& aClip)
|
||||
: mItem(aItem), mClip(aClip)
|
||||
ClippedDisplayItem(nsDisplayItem* aItem, const Clip& aClip, PRUint32 aGeneration)
|
||||
: mItem(aItem), mClip(aClip), mContainerLayerGeneration(aGeneration)
|
||||
{
|
||||
}
|
||||
|
||||
nsDisplayItem* mItem;
|
||||
Clip mClip;
|
||||
PRUint32 mContainerLayerGeneration;
|
||||
bool mInactiveLayer;
|
||||
};
|
||||
|
||||
|
@ -575,6 +585,7 @@ public:
|
|||
// The translation set on this ThebesLayer before we started updating the
|
||||
// layer tree.
|
||||
nsIntPoint mLastPaintOffset;
|
||||
PRUint32 mContainerLayerGeneration;
|
||||
bool mHasExplicitLastPaintOffset;
|
||||
/**
|
||||
* The first mCommonClipCount rounded rectangle clips are identical for
|
||||
|
@ -602,6 +613,11 @@ protected:
|
|||
void* aUserArg);
|
||||
static PLDHashOperator StoreNewDisplayItemData(DisplayItemDataEntry* aEntry,
|
||||
void* aUserArg);
|
||||
static PLDHashOperator RestoreDisplayItemData(DisplayItemDataEntry* aEntry,
|
||||
void *aUserArg);
|
||||
|
||||
static PLDHashOperator RestoreThebesLayerItemEntries(ThebesLayerItemsEntry* aEntry,
|
||||
void *aUserArg);
|
||||
|
||||
/**
|
||||
* Returns true if the DOM has been modified since we started painting,
|
||||
|
@ -643,6 +659,9 @@ protected:
|
|||
* during this paint.
|
||||
*/
|
||||
bool mInvalidateAllLayers;
|
||||
|
||||
PRUint32 mContainerLayerGeneration;
|
||||
PRUint32 mMaxContainerLayerGeneration;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -64,7 +64,8 @@ nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
|
|||
mSyncDecodeImages(false),
|
||||
mIsPaintingToWindow(false),
|
||||
mHasDisplayPort(false),
|
||||
mHasFixedItems(false)
|
||||
mHasFixedItems(false),
|
||||
mIsCompositingCheap(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsDisplayListBuilder);
|
||||
PL_InitArenaPool(&mPool, "displayListArena", 1024,
|
||||
|
@ -648,8 +649,10 @@ void nsDisplayList::PaintForFrame(nsDisplayListBuilder* aBuilder,
|
|||
|
||||
layerManager->SetRoot(root);
|
||||
layerBuilder->WillEndTransaction(layerManager);
|
||||
bool temp = aBuilder->SetIsCompositingCheap(layerManager->IsCompositingCheap());
|
||||
layerManager->EndTransaction(FrameLayerBuilder::DrawThebesLayer,
|
||||
aBuilder);
|
||||
aBuilder->SetIsCompositingCheap(temp);
|
||||
layerBuilder->DidEndTransaction(layerManager);
|
||||
|
||||
if (aFlags & PAINT_FLUSH_LAYERS) {
|
||||
|
@ -1090,6 +1093,65 @@ static bool RoundedRectContainsRect(const nsRect& aRoundedRect,
|
|||
return rgn.Contains(aContainedRect);
|
||||
}
|
||||
|
||||
bool
|
||||
nsDisplayBackground::IsSingleFixedPositionImage(nsDisplayListBuilder* aBuilder, const nsRect& aClipRect)
|
||||
{
|
||||
if (mIsThemed)
|
||||
return false;
|
||||
|
||||
nsPresContext* presContext = mFrame->PresContext();
|
||||
nsStyleContext* bgSC;
|
||||
if (!nsCSSRendering::FindBackground(presContext, mFrame, &bgSC))
|
||||
return false;
|
||||
|
||||
bool drawBackgroundImage;
|
||||
bool drawBackgroundColor;
|
||||
nsCSSRendering::DetermineBackgroundColor(presContext,
|
||||
bgSC,
|
||||
mFrame,
|
||||
drawBackgroundImage,
|
||||
drawBackgroundColor);
|
||||
|
||||
// For now we don't know how to draw image layers with a background color.
|
||||
if (!drawBackgroundImage || drawBackgroundColor)
|
||||
return false;
|
||||
|
||||
const nsStyleBackground *bg = bgSC->GetStyleBackground();
|
||||
|
||||
// We could pretty easily support multiple image layers, but for now we
|
||||
// just punt here.
|
||||
if (bg->mLayers.Length() != 1)
|
||||
return false;
|
||||
|
||||
PRUint32 flags = aBuilder->GetBackgroundPaintFlags();
|
||||
nsPoint offset = ToReferenceFrame();
|
||||
nsRect borderArea = nsRect(offset, mFrame->GetSize());
|
||||
|
||||
const nsStyleBackground::Layer &layer = bg->mLayers[0];
|
||||
|
||||
if (layer.mAttachment != NS_STYLE_BG_ATTACHMENT_FIXED)
|
||||
return false;
|
||||
|
||||
nsBackgroundLayerState state =
|
||||
nsCSSRendering::PrepareBackgroundLayer(presContext,
|
||||
mFrame,
|
||||
flags,
|
||||
borderArea,
|
||||
aClipRect,
|
||||
*bg,
|
||||
layer);
|
||||
|
||||
nsImageRenderer* imageRenderer = &state.mImageRenderer;
|
||||
// We only care about images here, not gradients.
|
||||
if (!imageRenderer->IsRasterImage())
|
||||
return false;
|
||||
|
||||
PRInt32 appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
|
||||
mDestRect = nsLayoutUtils::RectToGfxRect(state.mFillArea, appUnitsPerDevPixel);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
nsDisplayBackground::TryOptimizeToImageLayer(nsDisplayListBuilder* aBuilder)
|
||||
{
|
||||
|
@ -1456,6 +1518,7 @@ nsDisplayBackground::ShouldFixToViewport(nsDisplayListBuilder* aBuilder)
|
|||
void
|
||||
nsDisplayBackground::Paint(nsDisplayListBuilder* aBuilder,
|
||||
nsRenderingContext* aCtx) {
|
||||
|
||||
nsPoint offset = ToReferenceFrame();
|
||||
PRUint32 flags = aBuilder->GetBackgroundPaintFlags();
|
||||
nsDisplayItem* nextItem = GetAbove();
|
||||
|
|
|
@ -221,6 +221,13 @@ public:
|
|||
*/
|
||||
void SetPaintingToWindow(bool aToWindow) { mIsPaintingToWindow = aToWindow; }
|
||||
bool IsPaintingToWindow() const { return mIsPaintingToWindow; }
|
||||
|
||||
bool SetIsCompositingCheap(bool aCompositingCheap) {
|
||||
bool temp = mIsCompositingCheap;
|
||||
mIsCompositingCheap = aCompositingCheap;
|
||||
return temp;
|
||||
}
|
||||
bool IsCompositingCheap() const { return mIsCompositingCheap; }
|
||||
/**
|
||||
* Display the caret if needed.
|
||||
*/
|
||||
|
@ -528,6 +535,7 @@ private:
|
|||
bool mIsPaintingToWindow;
|
||||
bool mHasDisplayPort;
|
||||
bool mHasFixedItems;
|
||||
bool mIsCompositingCheap;
|
||||
};
|
||||
|
||||
class nsDisplayItem;
|
||||
|
@ -1607,6 +1615,7 @@ protected:
|
|||
const nsRect& aRect, bool* aSnap);
|
||||
|
||||
bool TryOptimizeToImageLayer(nsDisplayListBuilder* aBuilder);
|
||||
bool IsSingleFixedPositionImage(nsDisplayListBuilder* aBuilder, const nsRect& aClipRect);
|
||||
void ConfigureLayer(ImageLayer* aLayer);
|
||||
|
||||
/* Used to cache mFrame->IsThemed() since it isn't a cheap call */
|
||||
|
@ -1893,7 +1902,7 @@ public:
|
|||
LayerManager* aManager,
|
||||
const ContainerParameters& aParameters)
|
||||
{
|
||||
return mozilla::LAYER_ACTIVE;
|
||||
return mozilla::LAYER_ACTIVE_FORCE;
|
||||
}
|
||||
virtual bool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem)
|
||||
{
|
||||
|
|
|
@ -152,6 +152,7 @@ PrintDisplayListTo(nsDisplayListBuilder* aBuilder, const nsDisplayList& aList,
|
|||
}
|
||||
nscolor color;
|
||||
nsRect vis = i->GetVisibleRect();
|
||||
nsRect component = i->GetComponentAlphaBounds(aBuilder);
|
||||
nsDisplayList* list = i->GetList();
|
||||
nsRegion opaque;
|
||||
if (i->GetType() == nsDisplayItem::TYPE_TRANSFORM) {
|
||||
|
@ -169,12 +170,16 @@ PrintDisplayListTo(nsDisplayListBuilder* aBuilder, const nsDisplayList& aList,
|
|||
string.AppendInt((PRUint64)i);
|
||||
fprintf(aOutput, "<a href=\"javascript:ViewImage('%s')\">", string.BeginReading());
|
||||
}
|
||||
fprintf(aOutput, "%s %p(%s) (%d,%d,%d,%d)(%d,%d,%d,%d)%s%s",
|
||||
fprintf(aOutput, "%s %p(%s) (%d,%d,%d,%d)(%d,%d,%d,%d)(%d,%d,%d,%d)%s",
|
||||
i->Name(), (void*)f, NS_ConvertUTF16toUTF8(fName).get(),
|
||||
rect.x, rect.y, rect.width, rect.height,
|
||||
vis.x, vis.y, vis.width, vis.height,
|
||||
opaque.IsEmpty() ? "" : " opaque",
|
||||
component.x, component.y, component.width, component.height,
|
||||
i->IsUniform(aBuilder, &color) ? " uniform" : "");
|
||||
nsRegionRectIterator iter(opaque);
|
||||
for (const nsRect* r = iter.Next(); r; r = iter.Next()) {
|
||||
printf("(opaque %d,%d,%d,%d)", r->x, r->y, r->width, r->height);
|
||||
}
|
||||
if (i->Painted()) {
|
||||
fprintf(aOutput, "</a>");
|
||||
}
|
||||
|
|
|
@ -1642,6 +1642,10 @@ PresShell::InitialReflow(nscoord aWidth, nscoord aHeight)
|
|||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
for (nsIFrame* f = rootFrame; f; f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
|
||||
f->RemoveStateBits(NS_FRAME_NO_COMPONENT_ALPHA);
|
||||
}
|
||||
|
||||
Element *root = mDocument->GetRootElement();
|
||||
|
||||
if (root) {
|
||||
|
|
|
@ -185,6 +185,16 @@ nsRect nsCanvasFrame::CanvasArea() const
|
|||
return result;
|
||||
}
|
||||
|
||||
static void BlitSurface(gfxContext* aDest, const gfxRect& aRect, gfxASurface* aSource)
|
||||
{
|
||||
aDest->Translate(gfxPoint(aRect.x, aRect.y));
|
||||
aDest->SetSource(aSource);
|
||||
aDest->NewPath();
|
||||
aDest->Rectangle(gfxRect(0, 0, aRect.width, aRect.height));
|
||||
aDest->Fill();
|
||||
aDest->Translate(-gfxPoint(aRect.x, aRect.y));
|
||||
}
|
||||
|
||||
void
|
||||
nsDisplayCanvasBackground::Paint(nsDisplayListBuilder* aBuilder,
|
||||
nsRenderingContext* aCtx)
|
||||
|
@ -192,17 +202,46 @@ nsDisplayCanvasBackground::Paint(nsDisplayListBuilder* aBuilder,
|
|||
nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame);
|
||||
nsPoint offset = ToReferenceFrame();
|
||||
nsRect bgClipRect = frame->CanvasArea() + offset;
|
||||
|
||||
if (NS_GET_A(mExtraBackgroundColor) > 0) {
|
||||
aCtx->SetColor(mExtraBackgroundColor);
|
||||
aCtx->FillRect(bgClipRect);
|
||||
}
|
||||
|
||||
nsCSSRendering::PaintBackground(mFrame->PresContext(), *aCtx, mFrame,
|
||||
mVisibleRect,
|
||||
bool snap;
|
||||
nsRect bounds = GetBounds(aBuilder, &snap);
|
||||
nsIntRect pixelRect = bounds.ToOutsidePixels(mFrame->PresContext()->AppUnitsPerDevPixel());
|
||||
nsRenderingContext context;
|
||||
nsRefPtr<gfxContext> dest = aCtx->ThebesContext();
|
||||
nsRefPtr<gfxASurface> surf;
|
||||
nsRefPtr<gfxContext> ctx;
|
||||
#ifndef MOZ_GFX_OPTIMIZE_MOBILE
|
||||
if (IsSingleFixedPositionImage(aBuilder, bgClipRect) && aBuilder->IsPaintingToWindow() && !aBuilder->IsCompositingCheap()) {
|
||||
surf = static_cast<gfxASurface*>(GetUnderlyingFrame()->Properties().Get(nsIFrame::CachedBackgroundImage()));
|
||||
nsRefPtr<gfxASurface> destSurf = dest->CurrentSurface();
|
||||
if (surf && surf->GetType() == destSurf->GetType()) {
|
||||
BlitSurface(dest, mDestRect, surf);
|
||||
return;
|
||||
}
|
||||
surf = destSurf->CreateSimilarSurface(gfxASurface::CONTENT_COLOR_ALPHA, gfxIntSize(ceil(mDestRect.width), ceil(mDestRect.height)));
|
||||
if (surf) {
|
||||
ctx = new gfxContext(surf);
|
||||
ctx->Translate(-gfxPoint(mDestRect.x, mDestRect.y));
|
||||
context.Init(aCtx->DeviceContext(), ctx);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
nsCSSRendering::PaintBackground(mFrame->PresContext(), surf ? context : *aCtx, mFrame,
|
||||
surf ? bounds : mVisibleRect,
|
||||
nsRect(offset, mFrame->GetSize()),
|
||||
aBuilder->GetBackgroundPaintFlags(),
|
||||
&bgClipRect);
|
||||
if (surf) {
|
||||
BlitSurface(dest, mDestRect, surf);
|
||||
|
||||
GetUnderlyingFrame()->Properties().Set(nsIFrame::CachedBackgroundImage(), surf.forget().get());
|
||||
GetUnderlyingFrame()->AddStateBits(NS_FRAME_HAS_CACHED_BACKGROUND);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -252,6 +252,15 @@ nsIFrame::MarkAsAbsoluteContainingBlock() {
|
|||
Properties().Set(AbsoluteContainingBlockProperty(), new nsAbsoluteContainingBlock(GetAbsoluteListID()));
|
||||
}
|
||||
|
||||
void
|
||||
nsIFrame::ClearDisplayItemCache()
|
||||
{
|
||||
if (GetStateBits() & NS_FRAME_HAS_CACHED_BACKGROUND) {
|
||||
Properties().Delete(CachedBackgroundImage());
|
||||
RemoveStateBits(NS_FRAME_HAS_CACHED_BACKGROUND);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
nsIFrame::CheckAndClearPaintedState()
|
||||
{
|
||||
|
@ -4695,6 +4704,7 @@ void
|
|||
nsIFrame::InvalidateInternal(const nsRect& aDamageRect, nscoord aX, nscoord aY,
|
||||
nsIFrame* aForChild, PRUint32 aFlags)
|
||||
{
|
||||
ClearDisplayItemCache();
|
||||
nsSVGEffects::InvalidateDirectRenderingObservers(this);
|
||||
if (nsSVGIntegrationUtils::UsingEffectsForFrame(this)) {
|
||||
nsRect r = nsSVGIntegrationUtils::AdjustInvalidAreaForSVGEffects(this,
|
||||
|
|
|
@ -1797,7 +1797,8 @@ CanScrollWithBlitting(nsIFrame* aFrame)
|
|||
for (nsIFrame* f = aFrame; f;
|
||||
f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
|
||||
if (nsSVGIntegrationUtils::UsingEffectsForFrame(f) ||
|
||||
f->IsFrameOfType(nsIFrame::eSVG)) {
|
||||
f->IsFrameOfType(nsIFrame::eSVG) ||
|
||||
f->GetStateBits() & NS_FRAME_NO_COMPONENT_ALPHA) {
|
||||
return false;
|
||||
}
|
||||
if (nsLayoutUtils::IsPopup(f))
|
||||
|
|
|
@ -288,6 +288,15 @@ typedef PRUint64 nsFrameState;
|
|||
// Is this frame allowed to have generated (::before/::after) content?
|
||||
#define NS_FRAME_MAY_HAVE_GENERATED_CONTENT NS_FRAME_STATE_BIT(44)
|
||||
|
||||
// This bit is set on frames that create ContainerLayers with component
|
||||
// alpha children. With BasicLayers we avoid creating these, so we mark
|
||||
// the frames for future reference.
|
||||
#define NS_FRAME_NO_COMPONENT_ALPHA NS_FRAME_STATE_BIT(45)
|
||||
|
||||
// Frame has a cached rasterization of anV
|
||||
// nsDisplayBackground display item
|
||||
#define NS_FRAME_HAS_CACHED_BACKGROUND NS_FRAME_STATE_BIT(46)
|
||||
|
||||
// Box layout bits
|
||||
#define NS_STATE_IS_HORIZONTAL NS_FRAME_STATE_BIT(22)
|
||||
#define NS_STATE_IS_DIRECTION_NORMAL NS_FRAME_STATE_BIT(31)
|
||||
|
@ -868,6 +877,11 @@ public:
|
|||
delete static_cast<nsOverflowAreas*>(aPropertyValue);
|
||||
}
|
||||
|
||||
static void DestroySurface(void* aPropertyValue)
|
||||
{
|
||||
static_cast<gfxASurface*>(aPropertyValue)->Release();
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// XXX Workaround MSVC issue by making the static FramePropertyDescriptor
|
||||
// non-const. See bug 555727.
|
||||
|
@ -911,6 +925,8 @@ public:
|
|||
|
||||
NS_DECLARE_FRAME_PROPERTY(LineBaselineOffset, nsnull)
|
||||
|
||||
NS_DECLARE_FRAME_PROPERTY(CachedBackgroundImage, DestroySurface)
|
||||
|
||||
/**
|
||||
* Return the distance between the border edge of the frame and the
|
||||
* margin edge of the frame. Like GetRect(), returns the dimensions
|
||||
|
@ -2587,6 +2603,8 @@ NS_PTR_TO_INT32(frame->Properties().Get(nsIFrame::ParagraphDepthProperty()))
|
|||
*/
|
||||
virtual bool IsFocusable(PRInt32 *aTabIndex = nsnull, bool aWithMouse = false);
|
||||
|
||||
void ClearDisplayItemCache();
|
||||
|
||||
// BOX LAYOUT METHODS
|
||||
// These methods have been migrated from nsIBox and are in the process of
|
||||
// being refactored. DO NOT USE OUTSIDE OF XUL.
|
||||
|
|
|
@ -167,7 +167,7 @@ public:
|
|||
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
|
||||
LayerManager* aManager,
|
||||
const ContainerParameters& aParameters)
|
||||
{ return mozilla::LAYER_ACTIVE; }
|
||||
{ return mozilla::LAYER_ACTIVE_FORCE; }
|
||||
|
||||
NS_OVERRIDE
|
||||
virtual already_AddRefed<Layer>
|
||||
|
|
|
@ -13,7 +13,7 @@ document.addEventListener("MozReftestInvalidate", function scrollDownAllTheWay (
|
|||
margin: 20px;
|
||||
width: 300px;
|
||||
height: 400px;
|
||||
overflow-y: auto;
|
||||
overflow-y: hidden;
|
||||
background: -moz-linear-gradient(#FFF, #FFF);
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ document.addEventListener("MozReftestInvalidate", function scrollOnePixelDown ()
|
|||
margin: 20px;
|
||||
width: 300px;
|
||||
height: 400px;
|
||||
overflow-y: auto;
|
||||
overflow-y: hidden;
|
||||
background: -moz-linear-gradient(#FFF, #FFF);
|
||||
}
|
||||
|
||||
|
|
|
@ -929,7 +929,10 @@ nsTextBoxFrame::DoLayout(nsBoxLayoutState& aBoxLayoutState)
|
|||
nsRect
|
||||
nsTextBoxFrame::GetComponentAlphaBounds()
|
||||
{
|
||||
return GetVisualOverflowRectRelativeToSelf();
|
||||
if (GetStyleText()->mTextShadow) {
|
||||
return GetVisualOverflowRectRelativeToSelf();
|
||||
}
|
||||
return mTextDrawRect;
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIURI;
|
||||
interface nsIPrincipal;
|
||||
interface nsIChannel;
|
||||
|
||||
/**
|
||||
|
@ -30,14 +30,14 @@ interface nsIURIClassifierCallback : nsISupports
|
|||
* The URI classifier service checks a URI against lists of phishing
|
||||
* and malware sites.
|
||||
*/
|
||||
[scriptable, uuid(2de5c563-1203-43dd-a212-f5d56d530b6f)]
|
||||
[scriptable, uuid(617f1002-ec55-42c4-a7b0-ebb221ba9fa2)]
|
||||
interface nsIURIClassifier : nsISupports
|
||||
{
|
||||
/**
|
||||
* Classify a URI.
|
||||
* Classify a Principal using it's URI, appId and InBrowserElement state.
|
||||
*
|
||||
* @param aURI
|
||||
* The URI that should be checked by the URI classifier.
|
||||
* @param aPrincipal
|
||||
* The principal that should be checked by the URI classifier.
|
||||
* @param aCallback
|
||||
* The URI classifier will call this callback when the URI has been
|
||||
* classified.
|
||||
|
@ -47,6 +47,6 @@ interface nsIURIClassifier : nsISupports
|
|||
* <code>true</code> if classification will be performed. The
|
||||
* callback will be called.
|
||||
*/
|
||||
boolean classify(in nsIURI aURI,
|
||||
boolean classify(in nsIPrincipal aPrincipal,
|
||||
in nsIURIClassifierCallback aCallback);
|
||||
};
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "nsICachingChannel.h"
|
||||
#include "nsICacheEntryDescriptor.h"
|
||||
#include "prlog.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
|
||||
#if defined(PR_LOGGING)
|
||||
//
|
||||
|
@ -85,8 +86,17 @@ nsChannelClassifier::Start(nsIChannel *aChannel)
|
|||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIScriptSecurityManager> securityManager =
|
||||
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
rv = securityManager->GetChannelPrincipal(aChannel,
|
||||
getter_AddRefs(principal));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool expectCallback;
|
||||
rv = uriClassifier->Classify(uri, this, &expectCallback);
|
||||
rv = uriClassifier->Classify(principal, this, &expectCallback);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (expectCallback) {
|
||||
|
|
|
@ -312,7 +312,7 @@ PROT_ListManager.prototype.stopUpdateChecker = function() {
|
|||
* and querying them could throw.
|
||||
*
|
||||
* @param table String Name of the table that we want to consult
|
||||
* @param key String Key for table lookup
|
||||
* @param key Principal being used to lookup the database
|
||||
* @param callback nsIUrlListManagerCallback (ie., Function) given false or the
|
||||
* value in the table corresponding to key. If the table name does not
|
||||
* exist, we return false, too.
|
||||
|
|
|
@ -11,6 +11,7 @@ class nsUrlClassifierLookupResult;
|
|||
[ptr] native ResultArray(nsTArray<nsUrlClassifierLookupResult>);
|
||||
|
||||
interface nsIUrlClassifierHashCompleter;
|
||||
interface nsIPrincipal;
|
||||
|
||||
// Interface for JS function callbacks
|
||||
[scriptable, function, uuid(4ca27b6b-a674-4b3d-ab30-d21e2da2dffb)]
|
||||
|
@ -71,18 +72,17 @@ interface nsIUrlClassifierUpdateObserver : nsISupports {
|
|||
* It provides async methods for querying and updating the database. As the
|
||||
* methods complete, they call the callback function.
|
||||
*/
|
||||
[scriptable, uuid(7aae3f3a-527d-488b-a448-45dca6db0e80)]
|
||||
[scriptable, uuid(e326ec41-46fd-4127-ad3c-3c58b2cdf196)]
|
||||
interface nsIUrlClassifierDBService : nsISupports
|
||||
{
|
||||
/**
|
||||
* Looks up a key in the database.
|
||||
*
|
||||
* @param key: The URL to search for. This URL will be canonicalized
|
||||
* by the service.
|
||||
* @param key: The principal containing the information to search.
|
||||
* @param c: The callback will be called with a comma-separated list
|
||||
* of tables to which the key belongs.
|
||||
*/
|
||||
void lookup(in ACString spec,
|
||||
void lookup(in nsIPrincipal principal,
|
||||
in nsIUrlClassifierCallback c);
|
||||
|
||||
/**
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "prnetdb.h"
|
||||
#include "zlib.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsIPrincipal.h"
|
||||
|
||||
// Needed to interpert mozIStorageConnection::GetLastError
|
||||
#include <sqlite3.h>
|
||||
|
@ -1829,7 +1830,7 @@ nsUrlClassifierDBServiceWorker::AddNoise(PRInt64 nearID,
|
|||
|
||||
// Lookup a key in the db.
|
||||
NS_IMETHODIMP
|
||||
nsUrlClassifierDBServiceWorker::Lookup(const nsACString& spec,
|
||||
nsUrlClassifierDBServiceWorker::Lookup(nsIPrincipal* aPrincipal,
|
||||
nsIUrlClassifierCallback* c)
|
||||
{
|
||||
return HandlePendingLookups();
|
||||
|
@ -4238,10 +4239,11 @@ nsUrlClassifierDBService::Init()
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsUrlClassifierDBService::Classify(nsIURI *uri,
|
||||
nsUrlClassifierDBService::Classify(nsIPrincipal* aPrincipal,
|
||||
nsIURIClassifierCallback* c,
|
||||
bool* result)
|
||||
{
|
||||
NS_ENSURE_ARG(aPrincipal);
|
||||
NS_ENSURE_TRUE(gDbBackgroundThread, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
if (!(mCheckMalware || mCheckPhishing)) {
|
||||
|
@ -4253,7 +4255,7 @@ nsUrlClassifierDBService::Classify(nsIURI *uri,
|
|||
new nsUrlClassifierClassifyCallback(c, mCheckMalware, mCheckPhishing);
|
||||
if (!callback) return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
nsresult rv = LookupURI(uri, callback, false, result);
|
||||
nsresult rv = LookupURI(aPrincipal, callback, false, result);
|
||||
if (rv == NS_ERROR_MALFORMED_URI) {
|
||||
*result = false;
|
||||
// The URI had no hostname, don't try to classify it.
|
||||
|
@ -4265,38 +4267,36 @@ nsUrlClassifierDBService::Classify(nsIURI *uri,
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsUrlClassifierDBService::Lookup(const nsACString& spec,
|
||||
nsUrlClassifierDBService::Lookup(nsIPrincipal* aPrincipal,
|
||||
nsIUrlClassifierCallback* c)
|
||||
{
|
||||
NS_ENSURE_TRUE(gDbBackgroundThread, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(uri), spec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
uri = NS_GetInnermostURI(uri);
|
||||
if (!uri) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
bool didLookup;
|
||||
return LookupURI(uri, c, true, &didLookup);
|
||||
bool dummy;
|
||||
return LookupURI(aPrincipal, c, true, &dummy);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsUrlClassifierDBService::LookupURI(nsIURI* uri,
|
||||
nsUrlClassifierDBService::LookupURI(nsIPrincipal* aPrincipal,
|
||||
nsIUrlClassifierCallback* c,
|
||||
bool forceLookup,
|
||||
bool *didLookup)
|
||||
{
|
||||
NS_ENSURE_TRUE(gDbBackgroundThread, NS_ERROR_NOT_INITIALIZED);
|
||||
NS_ENSURE_ARG(aPrincipal);
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsresult rv = aPrincipal->GetURI(getter_AddRefs(uri));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
uri = NS_GetInnermostURI(uri);
|
||||
NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE);
|
||||
|
||||
nsCAutoString key;
|
||||
// Canonicalize the url
|
||||
nsCOMPtr<nsIUrlClassifierUtils> utilsService =
|
||||
do_GetService(NS_URLCLASSIFIERUTILS_CONTRACTID);
|
||||
nsresult rv = utilsService->GetKeyForURI(uri, key);
|
||||
rv = utilsService->GetKeyForURI(uri, key);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
|
@ -4315,7 +4315,10 @@ nsUrlClassifierDBService::LookupURI(nsIURI* uri,
|
|||
|
||||
if (permissionManager) {
|
||||
PRUint32 perm;
|
||||
permissionManager->TestPermission(uri, "safe-browsing", &perm);
|
||||
rv = permissionManager->TestPermissionFromPrincipal(aPrincipal,
|
||||
"safe-browsing", &perm);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
clean |= (perm == nsIPermissionManager::ALLOW_ACTION);
|
||||
}
|
||||
}
|
||||
|
@ -4342,7 +4345,7 @@ nsUrlClassifierDBService::LookupURI(nsIURI* uri,
|
|||
rv = mWorker->QueueLookup(key, proxyCallback);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return mWorkerProxy->Lookup(EmptyCString(), nsnull);
|
||||
return mWorkerProxy->Lookup(nsnull, nsnull);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
|
||||
class nsUrlClassifierDBServiceWorker;
|
||||
class nsIThread;
|
||||
class nsIURI;
|
||||
|
||||
// This is a proxy class that just creates a background thread and delagates
|
||||
// calls to the background thread.
|
||||
|
@ -66,7 +67,7 @@ private:
|
|||
// Disallow copy constructor
|
||||
nsUrlClassifierDBService(nsUrlClassifierDBService&);
|
||||
|
||||
nsresult LookupURI(nsIURI* uri, nsIUrlClassifierCallback* c,
|
||||
nsresult LookupURI(nsIPrincipal* aPrincipal, nsIUrlClassifierCallback* c,
|
||||
bool forceCheck, bool *didCheck);
|
||||
|
||||
// Close db connection and join the background thread if it exists.
|
||||
|
|
|
@ -20,17 +20,17 @@ NS_IMPL_THREADSAFE_ISUPPORTS1(UrlClassifierDBServiceWorkerProxy,
|
|||
nsIUrlClassifierDBServiceWorker)
|
||||
|
||||
NS_IMETHODIMP
|
||||
UrlClassifierDBServiceWorkerProxy::Lookup(const nsACString& aSpec,
|
||||
UrlClassifierDBServiceWorkerProxy::Lookup(nsIPrincipal* aPrincipal,
|
||||
nsIUrlClassifierCallback* aCB)
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> r = new LookupRunnable(mTarget, aSpec, aCB);
|
||||
nsCOMPtr<nsIRunnable> r = new LookupRunnable(mTarget, aPrincipal, aCB);
|
||||
return DispatchToWorkerThread(r);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
UrlClassifierDBServiceWorkerProxy::LookupRunnable::Run()
|
||||
{
|
||||
mTarget->Lookup(mSpec, mCB);
|
||||
(void) mTarget->Lookup(mPrincipal, mCB);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "nsIUrlClassifierDBService.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsIPrincipal.h"
|
||||
|
||||
/**
|
||||
* Thread proxy from the main thread to the worker thread.
|
||||
|
@ -29,10 +30,10 @@ public:
|
|||
{
|
||||
public:
|
||||
LookupRunnable(nsIUrlClassifierDBServiceWorker* aTarget,
|
||||
const nsACString& aSpec,
|
||||
nsIPrincipal* aPrincipal,
|
||||
nsIUrlClassifierCallback* aCB)
|
||||
: mTarget(aTarget)
|
||||
, mSpec(aSpec)
|
||||
, mPrincipal(aPrincipal)
|
||||
, mCB(aCB)
|
||||
{ }
|
||||
|
||||
|
@ -40,7 +41,7 @@ public:
|
|||
|
||||
private:
|
||||
nsCOMPtr<nsIUrlClassifierDBServiceWorker> mTarget;
|
||||
nsCString mSpec;
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
nsCOMPtr<nsIUrlClassifierCallback> mCB;
|
||||
};
|
||||
|
||||
|
|
|
@ -15,6 +15,9 @@ var dirSvc = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProper
|
|||
|
||||
var iosvc = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
|
||||
|
||||
var secMan = Cc["@mozilla.org/scriptsecuritymanager;1"]
|
||||
.getService(Ci.nsIScriptSecurityManager);
|
||||
|
||||
// Disable hashcompleter noise for tests
|
||||
var prefBranch = Cc["@mozilla.org/preferences-service;1"].
|
||||
getService(Ci.nsIPrefBranch);
|
||||
|
@ -181,7 +184,8 @@ checkUrls: function(urls, expected, cb)
|
|||
var doLookup = function() {
|
||||
if (urls.length > 0) {
|
||||
var fragment = urls.shift();
|
||||
dbservice.lookup("http://" + fragment,
|
||||
var principal = secMan.getNoAppCodebasePrincipal(iosvc.newURI("http://" + fragment, null, null));
|
||||
dbservice.lookup(principal,
|
||||
function(arg) {
|
||||
do_check_eq(expected, arg);
|
||||
doLookup();
|
||||
|
|
|
@ -14,13 +14,16 @@ function testCleanHostKeys() {
|
|||
|
||||
// Check with a clean host key
|
||||
var uri = ios.newURI("http://bar.com/a", null, null);
|
||||
let principal = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
|
||||
.getService(Components.interfaces.nsIScriptSecurityManager)
|
||||
.getNoAppCodebasePrincipal(uri);
|
||||
|
||||
// Use the nsIURIClassifier interface (the
|
||||
// nsIUrlClassifierDBService will always queue a lookup,
|
||||
// nsIURIClassifier won't if the host key is known to be clean.
|
||||
var classifier = dbservice.QueryInterface(Ci.nsIURIClassifier);
|
||||
var result = classifier.classify(uri, function(errorCode) {
|
||||
var result2 = classifier.classify(uri, function() {
|
||||
var result = classifier.classify(principal, function(errorCode) {
|
||||
var result2 = classifier.classify(principal, function() {
|
||||
do_throw("shouldn't get a callback");
|
||||
});
|
||||
// second call shouldn't result in a callback.
|
||||
|
@ -50,12 +53,15 @@ function testUpdate() {
|
|||
doStreamUpdate(preUpdate, function() {
|
||||
// First lookup won't happen...
|
||||
var uri = ios.newURI("http://foo.com/a", null, null);
|
||||
let principal = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
|
||||
.getService(Components.interfaces.nsIScriptSecurityManager)
|
||||
.getNoAppCodebasePrincipal(uri);
|
||||
|
||||
// Use the nsIURIClassifier interface (the
|
||||
// nsIUrlClassifierDBService will always queue a lookup,
|
||||
// nsIURIClassifier won't if the host key is known to be clean.
|
||||
var classifier = dbservice.QueryInterface(Ci.nsIURIClassifier);
|
||||
var result = classifier.classify(uri, function(errorCode) {
|
||||
var result = classifier.classify(principal, function(errorCode) {
|
||||
// shouldn't arrive here
|
||||
do_check_eq(errorCode, Cr.NS_OK);
|
||||
do_throw("shouldn't get a callback");
|
||||
|
@ -70,7 +76,7 @@ function testUpdate() {
|
|||
"urls" : addUrls
|
||||
}]);
|
||||
doStreamUpdate(update, function() {
|
||||
var result2 = classifier.classify(uri, function(errorCode) {
|
||||
var result2 = classifier.classify(principal, function(errorCode) {
|
||||
do_check_neq(errorCode, Cr.NS_OK);
|
||||
runNextTest();
|
||||
});
|
||||
|
@ -120,8 +126,11 @@ function testResetFullCache() {
|
|||
|
||||
var spec = uris2.pop();
|
||||
var uri = ios.newURI("http://" + spec, null, null);
|
||||
let principal = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
|
||||
.getService(Components.interfaces.nsIScriptSecurityManager)
|
||||
.getNoAppCodebasePrincipal(uri);
|
||||
|
||||
var result = classifier.classify(uri, function(errorCode) {
|
||||
var result = classifier.classify(principal, function(errorCode) {
|
||||
});
|
||||
runSecondLookup();
|
||||
// now look up a few more times.
|
||||
|
@ -146,7 +155,10 @@ function testResetFullCache() {
|
|||
|
||||
uris2.push(spec);
|
||||
var uri = ios.newURI("http://" + spec, null, null);
|
||||
var result = classifier.classify(uri, function(errorCode) {
|
||||
let principal = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
|
||||
.getService(Components.interfaces.nsIScriptSecurityManager)
|
||||
.getNoAppCodebasePrincipal(uri);
|
||||
var result = classifier.classify(principal, function(errorCode) {
|
||||
});
|
||||
runInitialLookup();
|
||||
// None of these will generate a callback
|
||||
|
|
|
@ -95,7 +95,8 @@ function checkNoHost()
|
|||
// Looking up a no-host uri such as a data: uri should throw an exception.
|
||||
var exception;
|
||||
try {
|
||||
dbservice.lookup("data:text/html,<b>test</b>");
|
||||
var principal = secMan.getNoAppCodebasePrincipal(iosvc.newURI("data:text/html,<b>test</b>", null, null));
|
||||
dbservice.lookup(principal);
|
||||
|
||||
exception = false;
|
||||
} catch(e) {
|
||||
|
@ -184,18 +185,22 @@ function malwareExists(result) {
|
|||
function checkState()
|
||||
{
|
||||
numExpecting = 0;
|
||||
|
||||
for (var key in phishExpected) {
|
||||
dbservice.lookup("http://" + key, phishExists, true);
|
||||
var principal = secMan.getNoAppCodebasePrincipal(iosvc.newURI("http://" + key, null, null));
|
||||
dbservice.lookup(principal, phishExists, true);
|
||||
numExpecting++;
|
||||
}
|
||||
|
||||
for (var key in phishUnexpected) {
|
||||
dbservice.lookup("http://" + key, phishDoesntExist, true);
|
||||
var principal = secMan.getNoAppCodebasePrincipal(iosvc.newURI("http://" + key, null, null));
|
||||
dbservice.lookup(principal, phishDoesntExist, true);
|
||||
numExpecting++;
|
||||
}
|
||||
|
||||
for (var key in malwareExpected) {
|
||||
dbservice.lookup("http://" + key, malwareExists, true);
|
||||
var principal = secMan.getNoAppCodebasePrincipal(iosvc.newURI("http://" + key, null, null));
|
||||
dbservice.lookup(principal, malwareExists, true);
|
||||
numExpecting++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1496,18 +1496,23 @@ var AddonDatabase = {
|
|||
getAllIcons: "SELECT addon_internal_id, size, url FROM icon " +
|
||||
"ORDER BY addon_internal_id, size",
|
||||
|
||||
insertAddon: "INSERT INTO addon VALUES (NULL, :id, :type, :name, :version, " +
|
||||
":creator, :creatorURL, :description, :fullDescription, " +
|
||||
":developerComments, :eula, :homepageURL, :supportURL, " +
|
||||
":contributionURL, :contributionAmount, :averageRating, " +
|
||||
":reviewCount, :reviewURL, :totalDownloads, :weeklyDownloads, " +
|
||||
":dailyUsers, :sourceURI, :repositoryStatus, :size, :updateDate)",
|
||||
insertAddon: "INSERT INTO addon (id, type, name, version, " +
|
||||
"creator, creatorURL, description, fullDescription, " +
|
||||
"developerComments, eula, homepageURL, supportURL, " +
|
||||
"contributionURL, contributionAmount, averageRating, " +
|
||||
"reviewCount, reviewURL, totalDownloads, weeklyDownloads, " +
|
||||
"dailyUsers, sourceURI, repositoryStatus, size, updateDate) " +
|
||||
"VALUES (:id, :type, :name, :version, :creator, :creatorURL, " +
|
||||
":description, :fullDescription, :developerComments, :eula, " +
|
||||
":homepageURL, :supportURL, :contributionURL, " +
|
||||
":contributionAmount, :averageRating, :reviewCount, " +
|
||||
":reviewURL, :totalDownloads, :weeklyDownloads, :dailyUsers, " +
|
||||
":sourceURI, :repositoryStatus, :size, :updateDate)",
|
||||
|
||||
insertDeveloper: "INSERT INTO developer VALUES (:addon_internal_id, " +
|
||||
insertDeveloper: "INSERT INTO developer (addon_internal_id, " +
|
||||
"num, name, url) VALUES (:addon_internal_id, " +
|
||||
":num, :name, :url)",
|
||||
|
||||
// We specify column names here because the columns
|
||||
// could be out of order due to schema changes.
|
||||
insertScreenshot: "INSERT INTO screenshot (addon_internal_id, " +
|
||||
"num, url, width, height, thumbnailURL, " +
|
||||
"thumbnailWidth, thumbnailHeight, caption) " +
|
||||
|
@ -1515,12 +1520,16 @@ var AddonDatabase = {
|
|||
":num, :url, :width, :height, :thumbnailURL, " +
|
||||
":thumbnailWidth, :thumbnailHeight, :caption)",
|
||||
|
||||
insertCompatibilityOverride: "INSERT INTO compatibility_override VALUES " +
|
||||
insertCompatibilityOverride: "INSERT INTO compatibility_override " +
|
||||
"(addon_internal_id, num, type, " +
|
||||
"minVersion, maxVersion, appID, " +
|
||||
"appMinVersion, appMaxVersion) VALUES " +
|
||||
"(:addon_internal_id, :num, :type, " +
|
||||
":minVersion, :maxVersion, :appID, " +
|
||||
":appMinVersion, :appMaxVersion)",
|
||||
|
||||
insertIcon: "INSERT INTO icon VALUES (:addon_internal_id, :size, :url)",
|
||||
insertIcon: "INSERT INTO icon (addon_internal_id, size, url) " +
|
||||
"VALUES (:addon_internal_id, :size, :url)",
|
||||
|
||||
emptyAddon: "DELETE FROM addon"
|
||||
},
|
||||
|
|
Загрузка…
Ссылка в новой задаче