Merge last PGO-green changeset of mozilla-inbound to mozilla-central

This commit is contained in:
Ed Morley 2012-07-23 14:32:34 +01:00
Родитель dca08c3a1c 64c27116c3
Коммит b20d292747
47 изменённых файлов: 1016 добавлений и 506 удалений

Просмотреть файл

@ -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,
&currentOffset);
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,
&currentOffset);
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,
&currentOffset);
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,
&currentOffset);
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"
},