author | Noemi Erli <nerli@mozilla.com> |
Fri, 23 Mar 2018 00:51:42 +0200 | |
changeset 409599 | 6c82708c26ee0e21142c78d9c031723f32fce3fd |
parent 409598 | 8bf380faae74e4921be6000496ca09d4a2c44e8d (current diff) |
parent 409596 | e4304fffb4f0b9808dd8a29df7a1f6a0e692e79b (diff) |
child 409600 | e02bfb1c5596b8e82409c4f4ac74076d5b43ba1d |
push id | 101247 |
push user | nerli@mozilla.com |
push date | Thu, 22 Mar 2018 23:00:51 +0000 |
treeherder | mozilla-inbound@02e384bdf97d [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | merge |
milestone | 61.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/Cargo.lock +++ b/Cargo.lock @@ -16,17 +16,17 @@ name = "ansi_term" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "app_units" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "arrayvec" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ @@ -45,19 +45,19 @@ source = "registry+https://github.com/ru dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "audioipc" -version = "0.2.1" +version = "0.2.2" dependencies = [ - "bincode 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bincode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "cubeb 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "memmap 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -68,32 +68,32 @@ dependencies = [ "tokio-io 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-uds 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "audioipc-client" version = "0.3.0" dependencies = [ - "audioipc 0.2.1", + "audioipc 0.2.2", "cubeb-backend 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "foreign-types 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-core 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-uds 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "audioipc-server" version = "0.2.2" dependencies = [ - "audioipc 0.2.1", + "audioipc 0.2.2", "bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "cubeb 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", "lazycell 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -112,17 +112,17 @@ dependencies = [ [[package]] name = "binary-space-partition" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bincode" -version = "0.9.1" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "bindgen" @@ -557,17 +557,17 @@ name = "error-chain" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "euclid" version = "0.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "fallible" version = "0.0.1" dependencies = [ "hashglobe 0.1.0", @@ -844,17 +844,17 @@ dependencies = [ "bindgen 0.33.2 (registry+https://github.com/rust-lang/crates.io-index)", "cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "mozjs_sys 0.0.0", - "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "kernel32-sys" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1193,40 +1193,43 @@ dependencies = [ [[package]] name = "num" version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-integer" version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-iter" version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-traits" -version = "0.1.41" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "num-traits" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "num_cpus" @@ -1236,17 +1239,17 @@ dependencies = [ "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ordered-float" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", "unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "owning_ref" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ @@ -1326,17 +1329,17 @@ source = "registry+https://github.com/ru [[package]] name = "plane-split" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "binary-space-partition 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "podio" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1640,17 +1643,17 @@ dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "malloc_size_of 0.0.1", "malloc_size_of_derive 0.0.1", "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "nsstring 0.1.0", "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "ordered-float 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "selectors 0.19.0", @@ -2011,46 +2014,46 @@ dependencies = [ "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "webrender" version = "0.57.0" dependencies = [ "app_units 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bincode 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bincode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "core-foundation 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "core-graphics 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "core-text 9.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "dwrote 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)", "freetype 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "gleam 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", "plane-split 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "ron 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "thread_profiler 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", "webrender_api 0.57.0", ] [[package]] name = "webrender_api" version = "0.57.0" dependencies = [ "app_units 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "bincode 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bincode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "core-foundation 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "core-graphics 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "dwrote 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.27 (git+https://github.com/gankro/serde?branch=deserialize_from_enums4)", @@ -2181,17 +2184,17 @@ dependencies = [ "checksum aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "500909c4f87a9e52355b26626d890833e9e1d53ac566db76c36faa984b889699" "checksum ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6b3568b48b7cefa6b8ce125f9bb4989e52fbcc29ebea88df04cc7c5f12f70455" "checksum app_units 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "29069a9b483f7780aebb55dafb360c6225eefdc1f98c8d336a65148fd10c37b1" "checksum arrayvec 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2f0ef4a9820019a0c91d918918c93dc71d469f581a49b47ddc1d285d4270bbe2" "checksum atomic_refcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fb2dcb6e6d35f20276943cc04bb98e538b348d525a04ac79c10021561d202f21" "checksum atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d912da0db7fa85514874458ca3651fe2cddace8d0b0505571dbdcd41ab490159" "checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9" "checksum binary-space-partition 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "88ceb0d16c4fd0e42876e298d7d3ce3780dd9ebdcbe4199816a32c77e08597ff" -"checksum bincode 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9d3fb369af639822830328794eba2501b3479652fcd021b2aeb1ed4984202afd" +"checksum bincode 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bda13183df33055cbb84b847becce220d392df502ebe7a4a78d7021771ed94d0" "checksum bindgen 0.33.2 (registry+https://github.com/rust-lang/crates.io-index)" = "603ed8d8392ace9581e834e26bd09799bf1e989a79bd1aedbb893e72962bdc6e" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" "checksum bitreader 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "80b13e2ab064ff3aa0bdbf1eff533f9822dc37899821f5f98c67f263eab51707" "checksum boxfnonce 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8380105befe91099e6f69206164072c05bc92427ff6aa8a5171388317346dd75" "checksum build_const 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e90dc84f5e62d2ebe7676b83c22d33b6db8bd27340fb6ffbff0a364efa0cb9c9" "checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23" "checksum bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d828f97b58cc5de3e40c421d0cf2132d6b2da4ee0e11b8632fa838f0f9333ad6" @@ -2284,17 +2287,17 @@ dependencies = [ "checksum mp4parse_fallible 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6626c2aef76eb8f984eef02e475883d3fe9112e114720446c5810fc5f045cd30" "checksum msdos_time 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "65ba9d75bcea84e07812618fedf284a64776c2f2ea0cad6bca7f69739695a958" "checksum net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)" = "3a80f842784ef6c9a958b68b7516bc7e35883c614004dd94959a4dca1b716c09" "checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" "checksum nom 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b8c256fd9471521bcb84c3cdba98921497f1a331cbc15b8030fc63b82050ce" "checksum num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "a311b77ebdc5dd4cf6449d81e4135d9f0e3b153839ac90e648a8ef538f923525" "checksum num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "d1452e8b06e448a07f0e6ebb0bb1d92b8890eea63288c0b627331d53514d0fba" "checksum num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "7485fcc84f85b4ecd0ea527b14189281cf27d60e583ae65ebc9c088b13dffe01" -"checksum num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "cacfcab5eb48250ee7d0c7896b51a2c5eec99c1feea5f32025635f5ae4b00070" +"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" "checksum num-traits 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e7de20f146db9d920c45ee8ed8f71681fd9ade71909b48c3acbd766aa504cf10" "checksum num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "514f0d73e64be53ff320680ca671b64fe3fb91da01e1ae2ddc99eb51d453b20d" "checksum ordered-float 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "da12c96037889ae0be29dd2bdd260e5a62a7df24e6466d5a15bb8131c1c200a8" "checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" "checksum parking_lot 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9fd9d732f2de194336fb02fe11f9eed13d9e76f13f4315b4d88a14ca411750cd" "checksum parking_lot_core 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6c677d78851950b3aec390e681a411f78cc250cba277d4f578758a377f727970" "checksum peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" "checksum percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de154f638187706bde41d9b4738748933d64e6b37bdbffc0b47a97d16a6ae356"
--- a/accessible/base/StyleInfo.cpp +++ b/accessible/base/StyleInfo.cpp @@ -12,45 +12,45 @@ #include "nsIFrame.h" using namespace mozilla; using namespace mozilla::a11y; StyleInfo::StyleInfo(dom::Element* aElement) : mElement(aElement) { - mStyleContext = - nsComputedDOMStyle::GetStyleContextNoFlush(aElement, nullptr); + mComputedStyle = + nsComputedDOMStyle::GetComputedStyleNoFlush(aElement, nullptr); } void StyleInfo::Display(nsAString& aValue) { aValue.Truncate(); AppendASCIItoUTF16( - nsCSSProps::ValueToKeyword(mStyleContext->StyleDisplay()->mDisplay, + nsCSSProps::ValueToKeyword(mComputedStyle->StyleDisplay()->mDisplay, nsCSSProps::kDisplayKTable), aValue); } void StyleInfo::TextAlign(nsAString& aValue) { aValue.Truncate(); AppendASCIItoUTF16( - nsCSSProps::ValueToKeyword(mStyleContext->StyleText()->mTextAlign, + nsCSSProps::ValueToKeyword(mComputedStyle->StyleText()->mTextAlign, nsCSSProps::kTextAlignKTable), aValue); } void StyleInfo::TextIndent(nsAString& aValue) { aValue.Truncate(); const nsStyleCoord& styleCoord = - mStyleContext->StyleText()->mTextIndent; + mComputedStyle->StyleText()->mTextIndent; nscoord coordVal = 0; switch (styleCoord.GetUnit()) { case eStyleUnit_Coord: coordVal = styleCoord.GetCoordValue(); aValue.AppendFloat(nsPresContext::AppUnitsToFloatCSSPixels(coordVal)); aValue.AppendLiteral("px"); break;
--- a/accessible/base/StyleInfo.h +++ b/accessible/base/StyleInfo.h @@ -3,17 +3,17 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef _mozilla_a11y_style_h_ #define _mozilla_a11y_style_h_ #include "mozilla/gfx/Types.h" -#include "nsStyleContext.h" +#include "mozilla/ComputedStyle.h" namespace mozilla { namespace a11y { class StyleInfo { public: explicit StyleInfo(dom::Element* aElement); @@ -34,15 +34,15 @@ public: private: StyleInfo() = delete; StyleInfo(const StyleInfo&) = delete; StyleInfo& operator = (const StyleInfo&) = delete; void Margin(Side aSide, nsAString& aValue); dom::Element* mElement; - RefPtr<nsStyleContext> mStyleContext; + RefPtr<ComputedStyle> mComputedStyle; }; } // namespace a11y } // namespace mozilla #endif
--- a/accessible/ipc/win/HandlerProvider.cpp +++ b/accessible/ipc/win/HandlerProvider.cpp @@ -214,22 +214,16 @@ HandlerProvider::BuildStaticIA2Data( // IA2 should always be present, so something has // gone very wrong if this fails. aOutData->mIA2 = nullptr; return; } // Some of these interfaces aren't present on all accessibles, // so it's not a failure if these interfaces can't be fetched. - hr = aInterceptor->GetInterceptorForIID(IID_IEnumVARIANT, - (void**)&aOutData->mIEnumVARIANT); - if (FAILED(hr)) { - aOutData->mIEnumVARIANT = nullptr; - } - hr = aInterceptor->GetInterceptorForIID(IID_IAccessibleHypertext2, (void**)&aOutData->mIAHypertext); if (FAILED(hr)) { aOutData->mIAHypertext = nullptr; } hr = aInterceptor->GetInterceptorForIID(IID_IAccessibleHyperlink, (void**)&aOutData->mIAHyperlink); @@ -756,11 +750,159 @@ HandlerProvider::get_RelationsInfo(IARel &HandlerProvider::GetRelationsInfoMainThread, aRelations, aNRelations, &hr)) { return E_FAIL; } return hr; } +// Helper function for GetAllChildrenMainThread. +static bool +SetChildDataForTextLeaf(NEWEST_IA2_INTERFACE* acc, AccChildData& data) +{ + const VARIANT kChildIdSelf = {VT_I4}; + VARIANT varVal; + + // 1. Check whether this is a text leaf. + + // 1.1. A text leaf always has ROLE_SYSTEM_TEXT or ROLE_SYSTEM_WHITESPACE. + HRESULT hr = acc->get_accRole(kChildIdSelf, &varVal); + if (FAILED(hr)) { + return false; + } + if (varVal.vt != VT_I4) { + return false; + } + long role = varVal.lVal; + if (role != ROLE_SYSTEM_TEXT && role != ROLE_SYSTEM_WHITESPACE) { + return false; + } + + // 1.2. A text leaf doesn't support IAccessibleText. + RefPtr<IAccessibleText> iaText; + hr = acc->QueryInterface(IID_IAccessibleText, getter_AddRefs(iaText)); + if (SUCCEEDED(hr)) { + return false; + } + + // 1.3. A text leaf doesn't have children. + long count; + hr = acc->get_accChildCount(&count); + if (FAILED(hr) || count != 0) { + return false; + } + + // 2. Update |data| with the data for this text leaf. + // Because marshaling objects is more expensive than marshaling other data, + // we just marshal the data we need for text leaf children, rather than + // marshaling the full accessible object. + + // |data| has already been zeroed, so we don't need to do anything if these + // calls fail. + acc->get_accName(kChildIdSelf, &data.mText); + data.mTextRole = role; + acc->get_uniqueID(&data.mTextId); + acc->get_accState(kChildIdSelf, &varVal); + data.mTextState = varVal.lVal; + acc->accLocation(&data.mTextLeft, &data.mTextTop, &data.mTextWidth, + &data.mTextHeight, kChildIdSelf); + + return true; +} + +void +HandlerProvider::GetAllChildrenMainThread(AccChildData** aChildren, + ULONG* aNChildren, + HRESULT* hr) +{ + MOZ_ASSERT(aChildren); + MOZ_ASSERT(aNChildren); + MOZ_ASSERT(NS_IsMainThread()); + + if (!mTargetUnk) { + *hr = CO_E_OBJNOTCONNECTED; + return; + } + + RefPtr<NEWEST_IA2_INTERFACE> acc; + *hr = mTargetUnk.get()->QueryInterface(NEWEST_IA2_IID, + getter_AddRefs(acc)); + if (FAILED(*hr)) { + return; + } + + long count; + *hr = acc->get_accChildCount(&count); + if (FAILED(*hr)) { + return; + } + MOZ_ASSERT(count >= 0); + + if (count == 0) { + *aChildren = nullptr; + *aNChildren = 0; + return; + } + + RefPtr<IEnumVARIANT> enumVar; + *hr = mTargetUnk.get()->QueryInterface(IID_IEnumVARIANT, + getter_AddRefs(enumVar)); + if (FAILED(*hr)) { + return; + } + + auto rawChildren = MakeUnique<VARIANT[]>(count); + *hr = enumVar->Next((ULONG)count, rawChildren.get(), aNChildren); + if (FAILED(*hr)) { + *aChildren = nullptr; + *aNChildren = 0; + return; + } + + *aChildren = static_cast<AccChildData*>(::CoTaskMemAlloc( + sizeof(AccChildData) * *aNChildren)); + for (ULONG index = 0; index < *aNChildren; ++index) { + (*aChildren)[index] = {}; + AccChildData& child = (*aChildren)[index]; + + MOZ_ASSERT(rawChildren[index].vt == VT_DISPATCH); + MOZ_ASSERT(rawChildren[index].pdispVal); + RefPtr<NEWEST_IA2_INTERFACE> childAcc; + *hr = rawChildren[index].pdispVal->QueryInterface(NEWEST_IA2_IID, + getter_AddRefs(childAcc)); + rawChildren[index].pdispVal->Release(); + MOZ_ASSERT(SUCCEEDED(*hr)); + if (FAILED(*hr)) { + continue; + } + + if (!SetChildDataForTextLeaf(childAcc, child)) { + // This isn't a text leaf. Marshal the accessible. + childAcc.forget(&child.mAccessible); + // We must wrap this accessible in an Interceptor. + ToWrappedObject(&child.mAccessible); + } + } + + *hr = S_OK; +} + +HRESULT +HandlerProvider::get_AllChildren(AccChildData** aChildren, + ULONG* aNChildren) +{ + MOZ_ASSERT(mscom::IsCurrentThreadMTA()); + + HRESULT hr; + if (!mscom::InvokeOnMainThread("HandlerProvider::GetAllChildrenMainThread", + this, + &HandlerProvider::GetAllChildrenMainThread, + aChildren, aNChildren, &hr)) { + return E_FAIL; + } + + return hr; +} + } // namespace a11y } // namespace mozilla
--- a/accessible/ipc/win/HandlerProvider.h +++ b/accessible/ipc/win/HandlerProvider.h @@ -59,16 +59,18 @@ public: STDMETHODIMP Refresh(DynamicIA2Data* aOutData) override; STDMETHODIMP get_AllTextInfo(BSTR* aText, IAccessibleHyperlink*** aHyperlinks, long* aNHyperlinks, IA2TextSegment** aAttribRuns, long* aNAttribRuns) override; STDMETHODIMP get_RelationsInfo(IARelationData** aRelations, long* aNRelations) override; + STDMETHODIMP get_AllChildren(AccChildData** aChildren, + ULONG* aNChildren) override; private: ~HandlerProvider() = default; void SetHandlerControlOnMainThread(DWORD aPid, mscom::ProxyUniquePtr<IHandlerControl> aCtrl); void GetAndSerializePayload(const MutexAutoLock&, NotNull<mscom::IInterceptor*> aInterceptor); @@ -90,16 +92,18 @@ private: IAccessibleHyperlink*** aHyperlinks, long* aNHyperlinks, IA2TextSegment** aAttribRuns, long* aNAttribRuns, HRESULT* result); void GetRelationsInfoMainThread(IARelationData** aRelations, long* aNRelations, HRESULT* result); + void GetAllChildrenMainThread(AccChildData** aChildren, ULONG* aNChildren, + HRESULT* result); Atomic<uint32_t> mRefCnt; Mutex mMutex; // Protects mSerializer const IID mTargetUnkIid; mscom::InterceptorTargetPtr<IUnknown> mTargetUnk; // Constant, main thread only UniquePtr<mscom::StructToStream> mSerializer; RefPtr<IUnknown> mFastMarshalUnk; };
--- a/accessible/ipc/win/handler/AccessibleHandler.cpp +++ b/accessible/ipc/win/handler/AccessibleHandler.cpp @@ -7,16 +7,17 @@ #if defined(MOZILLA_INTERNAL_API) #error This code is NOT for internal Gecko use! #endif // defined(MOZILLA_INTERNAL_API) #define INITGUID #include "AccessibleHandler.h" #include "AccessibleHandlerControl.h" +#include "HandlerChildEnumerator.h" #include "HandlerRelation.h" #include "Factory.h" #include "HandlerData.h" #include "mozilla/ArrayUtils.h" #include "mozilla/a11y/HandlerDataCleanup.h" #include "mozilla/mscom/Registration.h" #include "mozilla/UniquePtr.h" @@ -352,19 +353,17 @@ AccessibleHandler::QueryHandlerInterface return S_OK; } if (HasPayload()) { // The proxy manager caches interfaces marshaled in the payload // and returns them on QI without a cross-process call. // However, it doesn't know about interfaces which don't exist. // We can determine this from the payload. - if ((aIid == IID_IEnumVARIANT && - !mCachedData.mStaticData.mIEnumVARIANT) || - ((aIid == IID_IAccessibleText || aIid == IID_IAccessibleHypertext || + if (((aIid == IID_IAccessibleText || aIid == IID_IAccessibleHypertext || aIid == IID_IAccessibleHypertext2) && !mCachedData.mStaticData.mIAHypertext) || ((aIid == IID_IAccessibleAction || aIid == IID_IAccessibleHyperlink) && !mCachedData.mStaticData.mIAHyperlink) || (aIid == IID_IAccessibleTable && !mCachedData.mStaticData.mIATable) || (aIid == IID_IAccessibleTable2 && !mCachedData.mStaticData.mIATable2) || @@ -401,16 +400,26 @@ AccessibleHandler::QueryHandlerInterface } if (aIid == IID_IProvideClassInfo) { RefPtr<IProvideClassInfo> clsInfo(this); clsInfo.forget(aOutInterface); return S_OK; } + if (aIid == IID_IEnumVARIANT && mCachedData.mGeckoBackChannel) { + if (&mCachedData.mDynamicData.mChildCount == 0) { + return E_NOINTERFACE; + } + RefPtr<IEnumVARIANT> childEnum( + new HandlerChildEnumerator(this, mCachedData.mGeckoBackChannel)); + childEnum.forget(aOutInterface); + return S_OK; + } + return E_NOINTERFACE; } HRESULT AccessibleHandler::ReadHandlerPayload(IStream* aStream, REFIID aIid) { if (!aStream) { return E_INVALIDARG;
new file mode 100644 --- /dev/null +++ b/accessible/ipc/win/handler/HandlerChildEnumerator.cpp @@ -0,0 +1,183 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#if defined(MOZILLA_INTERNAL_API) +#error This code is NOT for internal Gecko use! +#endif // defined(MOZILLA_INTERNAL_API) + +#include "HandlerChildEnumerator.h" +#include "HandlerTextLeaf.h" +#include "mozilla/Assertions.h" + +namespace mozilla { +namespace a11y { + +HandlerChildEnumerator::HandlerChildEnumerator(AccessibleHandler* aHandler, + IGeckoBackChannel* aGeckoBackChannel) + : mHandler(aHandler) + , mGeckoBackChannel(aGeckoBackChannel) + , mChildCount(0) + , mNextChild(0) +{ + MOZ_ASSERT(aHandler); + MOZ_ASSERT(aGeckoBackChannel); +} + +HandlerChildEnumerator::HandlerChildEnumerator( + const HandlerChildEnumerator& aEnumerator) + : mHandler(aEnumerator.mHandler) + , mGeckoBackChannel(aEnumerator.mGeckoBackChannel) + , mChildCount(aEnumerator.mChildCount) + , mNextChild(aEnumerator.mNextChild) +{ + if (mChildCount == 0) { + return; + } + mChildren = MakeUnique<VARIANT[]>(mChildCount); + CopyMemory(mChildren.get(), aEnumerator.mChildren.get(), + sizeof(VARIANT) * mChildCount); + for (ULONG index = 0; index < mChildCount; ++index) { + mChildren[index].pdispVal->AddRef(); + } +} + +HandlerChildEnumerator::~HandlerChildEnumerator() +{ + ClearCache(); +} + +void +HandlerChildEnumerator::ClearCache() +{ + if (!mChildren) { + return; + } + + for (ULONG index = 0; index < mChildCount; ++index) { + mChildren[index].pdispVal->Release(); + } + + mChildren = nullptr; + mChildCount = 0; +} + +HRESULT +HandlerChildEnumerator::MaybeCacheChildren() +{ + if (mChildren) { + // Already cached. + return S_OK; + } + + AccChildData* children; + HRESULT hr = mGeckoBackChannel->get_AllChildren(&children, &mChildCount); + if (FAILED(hr)) { + mChildCount = 0; + ClearCache(); + return hr; + } + + HWND hwnd = nullptr; + hr = mHandler->get_windowHandle(&hwnd); + MOZ_ASSERT(SUCCEEDED(hr)); + + RefPtr<IDispatch> parent; + hr = mHandler->QueryInterface(IID_IDispatch, getter_AddRefs(parent)); + MOZ_ASSERT(SUCCEEDED(hr)); + + mChildren = MakeUnique<VARIANT[]>(mChildCount); + for (ULONG index = 0; index < mChildCount; ++index) { + AccChildData& data = children[index]; + VARIANT& child = mChildren[index]; + if (data.mAccessible) { + RefPtr<IDispatch> disp; + hr = data.mAccessible->QueryInterface(IID_IDispatch, + getter_AddRefs(disp)); + data.mAccessible->Release(); + MOZ_ASSERT(SUCCEEDED(hr)); + if (FAILED(hr)) { + child.vt = VT_EMPTY; + continue; + } + child.vt = VT_DISPATCH; + disp.forget(&child.pdispVal); + } else { + // Text leaf. + RefPtr<IDispatch> leaf( + new HandlerTextLeaf(parent, index, hwnd, data)); + child.vt = VT_DISPATCH; + leaf.forget(&child.pdispVal); + } + } + + ::CoTaskMemFree(children); + return S_OK; +} + +IMPL_IUNKNOWN_QUERY_HEAD(HandlerChildEnumerator) +IMPL_IUNKNOWN_QUERY_IFACE(IEnumVARIANT) +IMPL_IUNKNOWN_QUERY_TAIL_AGGREGATED(mHandler) + +/*** IEnumVARIANT ***/ + +HRESULT +HandlerChildEnumerator::Clone(IEnumVARIANT** aPpEnum) +{ + RefPtr<HandlerChildEnumerator> newEnum(new HandlerChildEnumerator(*this)); + newEnum.forget(aPpEnum); + return S_OK; +} + +HRESULT +HandlerChildEnumerator::Next(ULONG aCelt, VARIANT* aRgVar, + ULONG* aPCeltFetched) +{ + if (!aRgVar || aCelt == 0) { + return E_INVALIDARG; + } + + HRESULT hr = MaybeCacheChildren(); + if (FAILED(hr)) { + return hr; + } + + for (ULONG index = 0; index < aCelt; ++index) { + if (mNextChild >= mChildCount) { + // Less elements remaining than were requested. + if (aPCeltFetched) { + *aPCeltFetched = index; + } + return S_FALSE; + } + aRgVar[index] = mChildren[mNextChild]; + aRgVar[index].pdispVal->AddRef(); + ++mNextChild; + } + *aPCeltFetched = aCelt; + return S_OK; +} + +HRESULT +HandlerChildEnumerator::Reset() +{ + mNextChild = 0; + ClearCache(); + return S_OK; +} + +HRESULT +HandlerChildEnumerator::Skip(ULONG aCelt) +{ + mNextChild += aCelt; + if (mNextChild > mChildCount) { + // Less elements remaining than the client requested to skip. + return S_FALSE; + } + return S_OK; +} + +} // namespace a11y +} // namespace mozilla
new file mode 100644 --- /dev/null +++ b/accessible/ipc/win/handler/HandlerChildEnumerator.h @@ -0,0 +1,52 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#if defined(MOZILLA_INTERNAL_API) +#error This code is NOT for internal Gecko use! +#endif // defined(MOZILLA_INTERNAL_API) + +#ifndef mozilla_a11y_HandlerChildEnumerator_h +#define mozilla_a11y_HandlerChildEnumerator_h + +#include "AccessibleHandler.h" +#include "IUnknownImpl.h" +#include "mozilla/RefPtr.h" + +namespace mozilla { +namespace a11y { + +class HandlerChildEnumerator final : public IEnumVARIANT +{ +public: + explicit HandlerChildEnumerator(AccessibleHandler* aHandler, + IGeckoBackChannel* aGeckoBackChannel); + + DECL_IUNKNOWN + + // IEnumVARIANT + STDMETHODIMP Clone(IEnumVARIANT** aPpEnum) override; + STDMETHODIMP Next(ULONG aCelt, VARIANT* aRgVar, + ULONG* aPCeltFetched) override; + STDMETHODIMP Reset() override; + STDMETHODIMP Skip(ULONG aCelt) override; + +private: + explicit HandlerChildEnumerator(const HandlerChildEnumerator& aEnumerator); + ~HandlerChildEnumerator(); + void ClearCache(); + HRESULT MaybeCacheChildren(); + + RefPtr<AccessibleHandler> mHandler; + RefPtr<IGeckoBackChannel> mGeckoBackChannel; + UniquePtr<VARIANT[]> mChildren; + ULONG mChildCount; + ULONG mNextChild; +}; + +} // namespace a11y +} // namespace mozilla + +#endif // mozilla_a11y_HandlerChildEnumerator_h
--- a/accessible/ipc/win/handler/HandlerData.idl +++ b/accessible/ipc/win/handler/HandlerData.idl @@ -2,31 +2,29 @@ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla-config.h" #include "AccessibleHandler.h" -import "oaidl.idl"; import "ocidl.idl"; import "ServProv.idl"; import "Accessible2_3.idl"; import "AccessibleHypertext2.idl"; import "AccessibleHyperlink.idl"; import "AccessibleTable.idl"; import "AccessibleTable2.idl"; import "AccessibleTableCell.idl"; typedef struct _StaticIA2Data { NEWEST_IA2_INTERFACE* mIA2; - IEnumVARIANT* mIEnumVARIANT; IAccessibleHypertext2* mIAHypertext; IAccessibleHyperlink* mIAHyperlink; IAccessibleTable* mIATable; IAccessibleTable2* mIATable2; IAccessibleTableCell* mIATableCell; } StaticIA2Data; typedef struct _DynamicIA2Data @@ -146,31 +144,47 @@ interface IHandlerControl : IUnknown } typedef struct _IARelationData { BSTR mType; long mNTargets; } IARelationData; +typedef struct _AccChildData +{ + NEWEST_IA2_INTERFACE* mAccessible; + BSTR mText; + long mTextRole; + long mTextId; + long mTextState; + long mTextLeft; + long mTextTop; + long mTextWidth; + long mTextHeight; +} AccChildData; + [object, uuid(IGECKOBACKCHANNEL_IID), pointer_default(unique)] interface IGeckoBackChannel : IUnknown { [propput] HRESULT HandlerControl([in] long aPid, [in] IHandlerControl* aCtrl); HRESULT Refresh([out] DynamicIA2Data* aOutData); [propget] HRESULT AllTextInfo([out] BSTR* aText, [out, size_is(,*aNHyperlinks)] IAccessibleHyperlink*** aHyperlinks, [out] long* aNHyperlinks, [out, size_is(,*aNAttribRuns)] IA2TextSegment** aAttribRuns, [out] long* aNAttribRuns); [propget] HRESULT RelationsInfo( [out, size_is(,*aNRelations)] IARelationData** aRelations, [out] long* aNRelations); + [propget] HRESULT AllChildren( + [out, size_is(,*aNChildren)] AccChildData** aChildren, + [out] ULONG* aNChildren); } [uuid(1e545f07-f108-4912-9471-546827a80983)] library AccessibleHandlerTypeLib { /** * This definition is required in order for the handler implementation to * support IDispatch (aka Automation). This is used by interpreted language
--- a/accessible/ipc/win/handler/HandlerDataCleanup.h +++ b/accessible/ipc/win/handler/HandlerDataCleanup.h @@ -18,19 +18,16 @@ ReleaseStaticIA2DataInterfaces(StaticIA2 { // Only interfaces of the proxied object wrapped by this handler should be // released here, never other objects! // For example, if StaticIA2Data were to include accParent in future, // that must not be released here. if (aData.mIA2) { aData.mIA2->Release(); } - if (aData.mIEnumVARIANT) { - aData.mIEnumVARIANT->Release(); - } if (aData.mIAHypertext) { aData.mIAHypertext->Release(); } if (aData.mIAHyperlink) { aData.mIAHyperlink->Release(); } if (aData.mIATable) { aData.mIATable->Release();
new file mode 100644 --- /dev/null +++ b/accessible/ipc/win/handler/HandlerTextLeaf.cpp @@ -0,0 +1,402 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#if defined(MOZILLA_INTERNAL_API) +#error This code is NOT for internal Gecko use! +#endif // defined(MOZILLA_INTERNAL_API) + +#include "HandlerTextLeaf.h" +#include "mozilla/Assertions.h" + +namespace mozilla { +namespace a11y { + +HandlerTextLeaf::HandlerTextLeaf(IDispatch* aParent, + long aIndexInParent, HWND aHwnd, + AccChildData& aData) +: mParent(aParent) +, mIndexInParent(aIndexInParent) +, mHwnd(aHwnd) +, mData(aData) +{ + MOZ_ASSERT(aParent); +} + +HandlerTextLeaf::~HandlerTextLeaf() +{ + if (mData.mText) { + ::SysFreeString(mData.mText); + } +} + +IMPL_IUNKNOWN_QUERY_HEAD(HandlerTextLeaf) +IMPL_IUNKNOWN_QUERY_IFACE(IDispatch) +IMPL_IUNKNOWN_QUERY_IFACE(IAccessible) +IMPL_IUNKNOWN_QUERY_IFACE(IAccessible2) +IMPL_IUNKNOWN_QUERY_IFACE(IServiceProvider) +IMPL_IUNKNOWN_QUERY_TAIL + +/*** IDispatch ***/ + +HRESULT +HandlerTextLeaf::GetTypeInfoCount(UINT *pctinfo) +{ + return E_NOTIMPL; +} + +HRESULT +HandlerTextLeaf::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) +{ + return E_NOTIMPL; +} + +HRESULT +HandlerTextLeaf::GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, + LCID lcid, DISPID *rgDispId) +{ + return E_NOTIMPL; +} + +HRESULT +HandlerTextLeaf::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, + WORD wFlags, DISPPARAMS *pDispParams, + VARIANT *pVarResult, EXCEPINFO *pExcepInfo, + UINT *puArgErr) +{ + return E_NOTIMPL; +} + +/*** IAccessible ***/ + +HRESULT +HandlerTextLeaf::get_accParent(IDispatch **ppdispParent) +{ + if (!ppdispParent) { + return E_INVALIDARG; + } + + RefPtr<IDispatch> parent(mParent); + parent.forget(ppdispParent); + return S_OK; +} + +HRESULT +HandlerTextLeaf::get_accChildCount(long *pcountChildren) +{ + if (!pcountChildren) { + return E_INVALIDARG; + } + + *pcountChildren = 0; + return S_OK; +} + +HRESULT +HandlerTextLeaf::get_accChild(VARIANT varChild, IDispatch **ppdispChild) +{ + return E_NOTIMPL; +} + +HRESULT +HandlerTextLeaf::get_accName(VARIANT varChild, BSTR *pszName) +{ + if (varChild.lVal != CHILDID_SELF || !pszName) { + return E_INVALIDARG; + } + + *pszName = CopyBSTR(mData.mText); + return S_OK; +} + +HRESULT +HandlerTextLeaf::get_accValue(VARIANT varChild, BSTR *pszValue) +{ + return E_NOTIMPL; +} + +HRESULT +HandlerTextLeaf::get_accDescription(VARIANT varChild, BSTR *pszDescription) +{ + return E_NOTIMPL; +} + +HRESULT +HandlerTextLeaf::get_accRole(VARIANT varChild, VARIANT *pvarRole) +{ + if (varChild.lVal != CHILDID_SELF || !pvarRole) { + return E_INVALIDARG; + } + + pvarRole->vt = VT_I4; + pvarRole->lVal = mData.mTextRole; + return S_OK; +} + +HRESULT +HandlerTextLeaf::get_accState(VARIANT varChild, VARIANT *pvarState) +{ + if (varChild.lVal != CHILDID_SELF || !pvarState) { + return E_INVALIDARG; + } + + pvarState->vt = VT_I4; + pvarState->lVal = mData.mTextState; + return S_OK; +} + +HRESULT +HandlerTextLeaf::get_accHelp(VARIANT varChild, BSTR *pszHelp) +{ + return E_NOTIMPL; +} + +HRESULT +HandlerTextLeaf::get_accHelpTopic(BSTR *pszHelpFile, VARIANT varChild, + long *pidTopic) +{ + return E_NOTIMPL; +} + +HRESULT +HandlerTextLeaf::get_accKeyboardShortcut(VARIANT varChild, + BSTR *pszKeyboardShortcut) +{ + return E_NOTIMPL; +} + +HRESULT +HandlerTextLeaf::get_accFocus(VARIANT *pvarChild) +{ + return E_NOTIMPL; +} + +HRESULT +HandlerTextLeaf::get_accSelection(VARIANT *pvarChildren) +{ + return E_NOTIMPL; +} + +HRESULT +HandlerTextLeaf::get_accDefaultAction(VARIANT varChild, + BSTR *pszDefaultAction) +{ + return E_NOTIMPL; +} + +HRESULT +HandlerTextLeaf::accSelect(long flagsSelect, VARIANT varChild) +{ + return E_NOTIMPL; +} + +HRESULT +HandlerTextLeaf::accLocation(long *pxLeft, long *pyTop, long *pcxWidth, + long *pcyHeight, VARIANT varChild) +{ + if (varChild.lVal != CHILDID_SELF || !pxLeft || !pyTop || !pcxWidth || + !pcyHeight) { + return E_INVALIDARG; + } + + *pxLeft = mData.mTextLeft; + *pyTop = mData.mTextTop; + *pcxWidth = mData.mTextWidth; + *pcyHeight = mData.mTextHeight; + return S_OK; +} + +HRESULT +HandlerTextLeaf::accNavigate(long navDir, VARIANT varStart, + VARIANT *pvarEndUpAt) +{ + return E_NOTIMPL; +} + +HRESULT +HandlerTextLeaf::accHitTest( long xLeft, long yTop, VARIANT *pvarChild) +{ + return E_NOTIMPL; +} + +HRESULT +HandlerTextLeaf::accDoDefaultAction(VARIANT varChild) +{ + return E_NOTIMPL; +} + +HRESULT +HandlerTextLeaf::put_accName(VARIANT varChild, BSTR szName) +{ + return E_NOTIMPL; +} + +HRESULT +HandlerTextLeaf::put_accValue(VARIANT varChild, BSTR szValue) +{ + return E_NOTIMPL; +} + +/*** IAccessible2 ***/ + +HRESULT +HandlerTextLeaf::get_nRelations(long* nRelations) +{ + return E_NOTIMPL; +} + +HRESULT +HandlerTextLeaf::get_relation(long relationIndex, + IAccessibleRelation** relation) +{ + return E_NOTIMPL; +} + +HRESULT +HandlerTextLeaf::get_relations(long maxRelations, + IAccessibleRelation** relations, + long* nRelations) +{ + return E_NOTIMPL; +} + +HRESULT +HandlerTextLeaf::role(long* role) +{ + if (!role) { + return E_INVALIDARG; + } + + *role = mData.mTextRole; + return S_OK; +} + +HRESULT +HandlerTextLeaf::scrollTo(IA2ScrollType scrollType) +{ + return E_NOTIMPL; +} + +HRESULT +HandlerTextLeaf::scrollToPoint(IA2CoordinateType coordinateType, long x, + long y) +{ + return E_NOTIMPL; +} + +HRESULT +HandlerTextLeaf::get_groupPosition(long* groupLevel, long* similarItemsInGroup, + long* positionInGroup) +{ + return E_NOTIMPL; +} + +HRESULT +HandlerTextLeaf::get_states(AccessibleStates* states) +{ + if (!states) { + return E_INVALIDARG; + } + + *states = 0; + return S_OK; +} + +HRESULT +HandlerTextLeaf::get_extendedRole(BSTR* extendedRole) +{ + return E_NOTIMPL; +} + +HRESULT +HandlerTextLeaf::get_localizedExtendedRole(BSTR* localizedExtendedRole) +{ + return E_NOTIMPL; +} + +HRESULT +HandlerTextLeaf::get_nExtendedStates(long* nExtendedStates) +{ + return E_NOTIMPL; +} + +HRESULT +HandlerTextLeaf::get_extendedStates(long maxExtendedStates, + BSTR** extendedStates, + long* nExtendedStates) +{ + return E_NOTIMPL; +} + +HRESULT +HandlerTextLeaf::get_localizedExtendedStates(long maxLocalizedExtendedStates, + BSTR** localizedExtendedStates, + long* nLocalizedExtendedStates) +{ + return E_NOTIMPL; +} + +HRESULT +HandlerTextLeaf::get_uniqueID(long* uniqueID) +{ + if (!uniqueID) { + return E_INVALIDARG; + } + + *uniqueID = mData.mTextId; + return S_OK; +} + +HRESULT +HandlerTextLeaf::get_windowHandle(HWND* windowHandle) +{ + if (!windowHandle) { + return E_INVALIDARG; + } + + *windowHandle = mHwnd; + return S_OK; +} + +HRESULT +HandlerTextLeaf::get_indexInParent(long* indexInParent) +{ + if (!indexInParent) { + return E_INVALIDARG; + } + + *indexInParent = mIndexInParent; + return S_OK; +} + +HRESULT +HandlerTextLeaf::get_locale(IA2Locale* locale) +{ + return E_NOTIMPL; +} + +HRESULT +HandlerTextLeaf::get_attributes(BSTR* attributes) +{ + return E_NOTIMPL; +} + +/*** IServiceProvider ***/ + +HRESULT +HandlerTextLeaf::QueryService(REFGUID aServiceId, REFIID aIid, + void** aOutInterface) +{ + if (aIid == IID_IAccessible2) { + RefPtr<IAccessible2> ia2(this); + ia2.forget(aOutInterface); + return S_OK; + } + + return E_INVALIDARG; +} + +} // namespace a11y +} // namespace mozilla
new file mode 100644 --- /dev/null +++ b/accessible/ipc/win/handler/HandlerTextLeaf.h @@ -0,0 +1,110 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#if defined(MOZILLA_INTERNAL_API) +#error This code is NOT for internal Gecko use! +#endif // defined(MOZILLA_INTERNAL_API) + +#ifndef mozilla_a11y_HandlerTextLeaf_h +#define mozilla_a11y_HandlerTextLeaf_h + +#include "AccessibleHandler.h" +#include "IUnknownImpl.h" +#include "mozilla/RefPtr.h" + +namespace mozilla { +namespace a11y { + +class HandlerTextLeaf final : public IAccessible2 + , public IServiceProvider +{ +public: + explicit HandlerTextLeaf(IDispatch* aParent, long aIndexInParent, + HWND aHwnd, AccChildData& aData); + + DECL_IUNKNOWN + + // IDispatch + STDMETHODIMP GetTypeInfoCount(UINT *pctinfo) override; + STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) override; + STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, + LCID lcid, DISPID *rgDispId) override; + STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, + DISPPARAMS *pDispParams, VARIANT *pVarResult, + EXCEPINFO *pExcepInfo, UINT *puArgErr) override; + + // IAccessible + STDMETHODIMP get_accParent(IDispatch **ppdispParent) override; + STDMETHODIMP get_accChildCount(long *pcountChildren) override; + STDMETHODIMP get_accChild(VARIANT varChild, IDispatch **ppdispChild) override; + STDMETHODIMP get_accName(VARIANT varChild, BSTR *pszName) override; + STDMETHODIMP get_accValue(VARIANT varChild, BSTR *pszValue) override; + STDMETHODIMP get_accDescription(VARIANT varChild, BSTR *pszDescription) override; + STDMETHODIMP get_accRole(VARIANT varChild, VARIANT *pvarRole) override; + STDMETHODIMP get_accState(VARIANT varChild, VARIANT *pvarState) override; + STDMETHODIMP get_accHelp(VARIANT varChild, BSTR *pszHelp) override; + STDMETHODIMP get_accHelpTopic(BSTR *pszHelpFile, VARIANT varChild, + long *pidTopic) override; + STDMETHODIMP get_accKeyboardShortcut(VARIANT varChild, + BSTR *pszKeyboardShortcut) override; + STDMETHODIMP get_accFocus(VARIANT *pvarChild) override; + STDMETHODIMP get_accSelection(VARIANT *pvarChildren) override; + STDMETHODIMP get_accDefaultAction(VARIANT varChild, + BSTR *pszDefaultAction) override; + STDMETHODIMP accSelect(long flagsSelect, VARIANT varChild) override; + STDMETHODIMP accLocation(long *pxLeft, long *pyTop, long *pcxWidth, + long *pcyHeight, VARIANT varChild) override; + STDMETHODIMP accNavigate(long navDir, VARIANT varStart, + VARIANT *pvarEndUpAt) override; + STDMETHODIMP accHitTest( long xLeft, long yTop, VARIANT *pvarChild) override; + STDMETHODIMP accDoDefaultAction(VARIANT varChild) override; + STDMETHODIMP put_accName(VARIANT varChild, BSTR szName) override; + STDMETHODIMP put_accValue(VARIANT varChild, BSTR szValue) override; + + // IAccessible2 + STDMETHODIMP get_nRelations(long* nRelations) override; + STDMETHODIMP get_relation(long relationIndex, + IAccessibleRelation** relation) override; + STDMETHODIMP get_relations(long maxRelations, IAccessibleRelation** relations, + long* nRelations) override; + STDMETHODIMP role(long* role) override; + STDMETHODIMP scrollTo(IA2ScrollType scrollType) override; + STDMETHODIMP scrollToPoint(IA2CoordinateType coordinateType, long x, + long y) override; + STDMETHODIMP get_groupPosition(long* groupLevel, long* similarItemsInGroup, + long* positionInGroup) override; + STDMETHODIMP get_states(AccessibleStates* states) override; + STDMETHODIMP get_extendedRole(BSTR* extendedRole) override; + STDMETHODIMP get_localizedExtendedRole(BSTR* localizedExtendedRole) override; + STDMETHODIMP get_nExtendedStates(long* nExtendedStates) override; + STDMETHODIMP get_extendedStates(long maxExtendedStates, BSTR** extendedStates, + long* nExtendedStates) override; + STDMETHODIMP get_localizedExtendedStates(long maxLocalizedExtendedStates, + BSTR** localizedExtendedStates, + long* nLocalizedExtendedStates) override; + STDMETHODIMP get_uniqueID(long* uniqueID) override; + STDMETHODIMP get_windowHandle(HWND* windowHandle) override; + STDMETHODIMP get_indexInParent(long* indexInParent) override; + STDMETHODIMP get_locale(IA2Locale* locale) override; + STDMETHODIMP get_attributes(BSTR* attributes) override; + + // IServiceProvider + STDMETHODIMP QueryService(REFGUID aServiceId, REFIID aIid, + void** aOutInterface) override; + +private: + ~HandlerTextLeaf(); + + RefPtr<IDispatch> mParent; + long mIndexInParent; + HWND mHwnd; + AccChildData mData; +}; + +} // namespace a11y +} // namespace mozilla + +#endif // mozilla_a11y_HandlerTextLeaf_h
--- a/accessible/ipc/win/handler/moz.build +++ b/accessible/ipc/win/handler/moz.build @@ -18,17 +18,19 @@ LOCAL_INCLUDES += [ SOURCES += [ '!dlldata.c', '!HandlerData_c.c', '!HandlerData_i.c', '!HandlerData_p.c', 'AccessibleHandler.cpp', 'AccessibleHandlerControl.cpp', + 'HandlerChildEnumerator.cpp', 'HandlerRelation.cpp', + 'HandlerTextLeaf.cpp', ] GENERATED_FILES += [ 'dlldata.c', 'HandlerData.h', 'HandlerData.tlb', 'HandlerData_c.c', 'HandlerData_i.c',
--- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -1226,17 +1226,30 @@ var gBrowserInit = { document.documentElement.setAttribute("height", height); if (width < TARGET_WIDTH && height < TARGET_HEIGHT) { document.documentElement.setAttribute("sizemode", "maximized"); } } new LightweightThemeConsumer(document); + CompactTheme.init(); + TabsInTitlebar.init(); + + if (window.matchMedia("(-moz-os-version: windows-win8)").matches && + window.matchMedia("(-moz-windows-default-theme)").matches) { + let windowFrameColor = new Color(...ChromeUtils.import("resource:///modules/Windows8WindowFrameColor.jsm", {}) + .Windows8WindowFrameColor.get()); + // Default to black for foreground text. + if (!windowFrameColor.isContrastRatioAcceptable(new Color(0, 0, 0))) { + document.documentElement.setAttribute("darkwindowframe", "true"); + } + } + ToolbarIconColor.init(); }, onDOMContentLoaded() { gBrowser = window._gBrowser; delete window._gBrowser; gBrowser.init(); window.QueryInterface(Ci.nsIInterfaceRequestor) @@ -1314,17 +1327,16 @@ var gBrowserInit = { // loading the frame script to ensure that we don't miss any // message sent between when the frame script is loaded and when // the listener is registered. DOMEventHandler.init(); gPageStyleMenu.init(); LanguageDetectionListener.init(); BrowserOnClick.init(); FeedHandler.init(); - CompactTheme.init(); AboutCapabilitiesListener.init(); TrackingProtection.init(); CaptivePortalWatcher.init(); ZoomUI.init(window); let mm = window.getGroupMessageManager("browsers"); mm.loadFrameScript("chrome://browser/content/tab-content.js", true); mm.loadFrameScript("chrome://browser/content/content.js", true); @@ -1363,28 +1375,16 @@ var gBrowserInit = { // Misc. inits. TabletModeUpdater.init(); CombinedStopReload.ensureInitialized(); gPrivateBrowsingUI.init(); BrowserPageActions.init(); gAccessibilityServiceIndicator.init(); - if (window.matchMedia("(-moz-os-version: windows-win8)").matches && - window.matchMedia("(-moz-windows-default-theme)").matches) { - let windowFrameColor = new Color(...ChromeUtils.import("resource:///modules/Windows8WindowFrameColor.jsm", {}) - .Windows8WindowFrameColor.get()); - // Default to black for foreground text. - if (!windowFrameColor.isContrastRatioAcceptable(new Color(0, 0, 0))) { - document.documentElement.setAttribute("darkwindowframe", "true"); - } - } - - ToolbarIconColor.init(); - gRemoteControl.updateVisualCue(Marionette.running); // If we are given a tab to swap in, take care of it before first paint to // avoid an about:blank flash. let tabToOpen = window.arguments && window.arguments[0]; if (tabToOpen instanceof XULElement) { // Clear the reference to the tab from the arguments array. window.arguments[0] = null;
--- a/browser/base/content/tabbrowser.js +++ b/browser/base/content/tabbrowser.js @@ -54,25 +54,19 @@ window._gBrowser = { // To correctly handle keypresses for potential FindAsYouType, while // the tab's find bar is not yet initialized. this._findAsYouType = Services.prefs.getBoolPref("accessibility.typeaheadfind"); Services.prefs.addObserver("accessibility.typeaheadfind", this); messageManager.addMessageListener("Findbar:Keypress", this); XPCOMUtils.defineLazyPreferenceGetter(this, "animationsEnabled", - "toolkit.cosmeticAnimations.enabled", true); + "toolkit.cosmeticAnimations.enabled"); XPCOMUtils.defineLazyPreferenceGetter(this, "schedulePressureDefaultCount", - "browser.schedulePressure.defaultCount", 3); - XPCOMUtils.defineLazyPreferenceGetter(this, "tabWarmingEnabled", - "browser.tabs.remote.warmup.enabled", false); - XPCOMUtils.defineLazyPreferenceGetter(this, "tabWarmingMax", - "browser.tabs.remote.warmup.maxTabs", 3); - XPCOMUtils.defineLazyPreferenceGetter(this, "tabWarmingUnloadDelay" /* ms */, - "browser.tabs.remote.warmup.unloadDelayMs", 2000); + "browser.schedulePressure.defaultCount"); this._setupEventListeners(); }, ownerGlobal: window, ownerDocument: document,
--- a/browser/base/content/test/performance/browser_toolbariconcolor_restyles.js +++ b/browser/base/content/test/performance/browser_toolbariconcolor_restyles.js @@ -12,16 +12,22 @@ add_task(async function test_toolbar_ele // create a window and snapshot the elementsStyled let win1 = await BrowserTestUtils.openNewBrowserWindow(); await new Promise(resolve => waitForFocus(resolve, win1)); // create a 2nd window and snapshot the elementsStyled let win2 = await BrowserTestUtils.openNewBrowserWindow(); await new Promise(resolve => waitForFocus(resolve, win2)); + // (De)-activate both windows once before we take a measurement. The first + // (de-)activation may flush styles, after that the style data should be + // cached. + Services.focus.activeWindow = win1; + Services.focus.activeWindow = win2; + // Flush any pending styles before we take a measurement. win1.getComputedStyle(win1.document.firstElementChild); win2.getComputedStyle(win2.document.firstElementChild); // Clear the focused element from each window so that when // we raise them, the focus of the element doesn't cause an // unrelated style flush. Services.focus.clearFocus(win1);
--- a/browser/base/content/test/webrtc/browser_devices_get_user_media_multi_process.js +++ b/browser/base/content/test/webrtc/browser_devices_get_user_media_multi_process.js @@ -181,27 +181,26 @@ var gTests = [ ok(webrtcUI.showGlobalIndicator, "webrtcUI wants the global indicator shown"); ok(webrtcUI.showCameraIndicator, "webrtcUI wants the camera indicator shown"); ok(!webrtcUI.showMicrophoneIndicator, "webrtcUI wants the mic indicator hidden"); is(webrtcUI.getActiveStreams(true).length, 2, "2 active camera streams"); is(webrtcUI.getActiveStreams(true, true, true).length, 2, "2 active streams"); info("removing the second tab"); - // FIXME: This should wait for indicator update instead (bug 1444007). - let sessionStorePromise = BrowserTestUtils.waitForSessionStoreUpdate(tab); BrowserTestUtils.removeTab(tab); - await sessionStorePromise; // Check that we still show the sharing indicators for the first tab's stream. - await TestUtils.waitForCondition(() => webrtcUI.showCameraIndicator); + await Promise.all([ + TestUtils.waitForCondition(() => webrtcUI.showCameraIndicator), + TestUtils.waitForCondition(() => webrtcUI.getActiveStreams(true).length == 1), + ]); ok(webrtcUI.showGlobalIndicator, "webrtcUI wants the global indicator shown"); ok(webrtcUI.showCameraIndicator, "webrtcUI wants the camera indicator shown"); ok(!webrtcUI.showMicrophoneIndicator, "webrtcUI wants the mic indicator hidden"); - is(webrtcUI.getActiveStreams(true).length, 1, "1 active camera stream"); is(webrtcUI.getActiveStreams(true, true, true).length, 1, "1 active stream"); await checkSharingUI({video: true}); // When both tabs use the same content process, the frame script for the // first tab receives observer notifications for things happening in the // second tab, so let's clear the observer call counts before we cleanup // in the first tab.
--- a/browser/components/extensions/ext-bookmarks.js +++ b/browser/components/extensions/ext-bookmarks.js @@ -66,22 +66,17 @@ const getTree = (rootGuid, onlyChildren) ? node.children.map(child => convert(child, node)) : []; } } return treenode; } - return PlacesUtils.promiseBookmarksTree(rootGuid, { - excludeItemsCallback: item => { - return item.annos && - item.annos.find(a => a.name == PlacesUtils.EXCLUDE_FROM_BACKUP_ANNO); - }, - }).then(root => { + return PlacesUtils.promiseBookmarksTree(rootGuid).then(root => { if (onlyChildren) { let children = root.children || []; return children.map(child => convert(child, root)); } let treenode = convert(root, null); treenode.parentId = root.parentGuid; // It seems like the array always just contains the root node. return [treenode];
--- a/browser/components/extensions/ext-pageAction.js +++ b/browser/components/extensions/ext-pageAction.js @@ -227,19 +227,18 @@ this.pageAction = class extends Extensio * Triggers this page action for the given window, with the same effects as * if it were clicked by a user. * * This has no effect if the page action is hidden for the selected tab. * * @param {Window} window */ triggerAction(window) { - let pageAction = pageActionMap.get(this.extension); - if (pageAction.getProperty(window.gBrowser.selectedTab, "show")) { - pageAction.handleClick(window); + if (this.isShown(window.gBrowser.selectedTab)) { + this.handleClick(window); } } handleEvent(event) { switch (event.type) { case "popupshowing": const menu = event.target; const trigger = menu.triggerNode;
--- a/browser/components/extensions/test/browser/browser_ext_commands_execute_page_action.js +++ b/browser/components/extensions/test/browser/browser_ext_commands_execute_page_action.js @@ -1,12 +1,14 @@ /* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ /* vim: set sts=2 sw=2 et tw=80: */ "use strict"; +const scriptPage = url => `<html><head><meta charset="utf-8"><script src="${url}"></script></head><body>Test Popup</body></html>`; + add_task(async function test_execute_page_action_without_popup() { let extension = ExtensionTestUtils.loadExtension({ manifest: { "commands": { "_execute_page_action": { "suggested_key": { "default": "Alt+Shift+J", }, @@ -54,34 +56,33 @@ add_task(async function test_execute_pag }); await extension.startup(); await extension.awaitFinish("page-action-without-popup"); await extension.unload(); }); add_task(async function test_execute_page_action_with_popup() { - let scriptPage = url => `<html><head><meta charset="utf-8"><script src="${url}"></script></head><body>Test Popup</body></html>`; - let extension = ExtensionTestUtils.loadExtension({ manifest: { "commands": { "_execute_page_action": { "suggested_key": { "default": "Alt+Shift+J", }, }, "send-keys-command": { "suggested_key": { "default": "Alt+Shift+3", }, }, }, "page_action": { "default_popup": "popup.html", + "browser_style": true, }, }, files: { "popup.html": scriptPage("popup.js"), "popup.js": function() { browser.runtime.sendMessage("popup-opened"); }, @@ -126,8 +127,43 @@ add_task(async function test_execute_pag EventUtils.synthesizeKey("j", {altKey: true, shiftKey: true}); EventUtils.synthesizeKey("3", {altKey: true, shiftKey: true}); }); await extension.startup(); await extension.awaitFinish("page-action-with-popup"); await extension.unload(); }); + +add_task(async function test_execute_page_action_with_matching() { + let extension = ExtensionTestUtils.loadExtension({ + manifest: { + "commands": { + "_execute_page_action": { + "suggested_key": { + "default": "Alt+Shift+J", + }, + }, + }, + "page_action": { + "default_popup": "popup.html", + "show_matches": ["<all_urls>"], + "browser_style": true, + }, + }, + + files: { + "popup.html": scriptPage("popup.js"), + "popup.js": function() { + window.addEventListener("load", () => { + browser.test.notifyPass("page-action-with-popup"); + }, {once: true}); + }, + }, + }); + + await extension.startup(); + let tab = await BrowserTestUtils.openNewForegroundTab(window.gBrowser, "http://example.com/"); + EventUtils.synthesizeKey("j", {altKey: true, shiftKey: true}); + await extension.awaitFinish("page-action-with-popup"); + await extension.unload(); + BrowserTestUtils.removeTab(tab); +});
--- a/browser/components/migration/AutoMigrate.jsm +++ b/browser/components/migration/AutoMigrate.jsm @@ -605,27 +605,29 @@ const AutoMigrate = { this._errorMap.logins++; } } } } }, async _removeSomeVisits(visits) { + // It is necessary to recreate URL and date objects because the data + // can be serialized through JSON that destroys those objects. for (let urlVisits of visits) { let urlObj; try { urlObj = new URL(urlVisits.url); } catch (ex) { continue; } let visitData = { url: urlObj, - beginDate: PlacesUtils.toDate(urlVisits.first), - endDate: PlacesUtils.toDate(urlVisits.last), + beginDate: new Date(urlVisits.first), + endDate: new Date(urlVisits.last), limit: urlVisits.visitCount, }; try { await PlacesUtils.history.removeVisitsByFilter(visitData); } catch (ex) { this._errorMap.visits++; try { visitData.url = visitData.url.href;
--- a/browser/components/migration/ChromeProfileMigrator.js +++ b/browser/components/migration/ChromeProfileMigrator.js @@ -268,53 +268,39 @@ async function GetHistoryResource(aProfi query += " AND last_visit_time > " + maxAge; } if (LIMIT) { query += " ORDER BY last_visit_time DESC LIMIT " + LIMIT; } let rows = await MigrationUtils.getRowsFromDBWithoutLocks(historyPath, "Chrome history", query); - let places = []; + let pageInfos = []; for (let row of rows) { try { // if having typed_count, we changes transition type to typed. - let transType = PlacesUtils.history.TRANSITION_LINK; + let transition = PlacesUtils.history.TRANSITIONS.LINK; if (row.getResultByName("typed_count") > 0) - transType = PlacesUtils.history.TRANSITION_TYPED; + transition = PlacesUtils.history.TRANSITIONS.TYPED; - places.push({ - uri: NetUtil.newURI(row.getResultByName("url")), + pageInfos.push({ title: row.getResultByName("title"), + url: new URL(row.getResultByName("url")), visits: [{ - transitionType: transType, - visitDate: chromeTimeToDate( - row.getResultByName( - "last_visit_time")) * 1000, + transition, + date: chromeTimeToDate(row.getResultByName("last_visit_time")), }], }); } catch (e) { Cu.reportError(e); } } - if (places.length > 0) { - await new Promise((resolve, reject) => { - MigrationUtils.insertVisitsWrapper(places, { - ignoreErrors: true, - ignoreResults: true, - handleCompletion(updatedCount) { - if (updatedCount > 0) { - resolve(); - } else { - reject(new Error("Couldn't add visits")); - } - }, - }); - }); + if (pageInfos.length > 0) { + await MigrationUtils.insertVisitsWrapper(pageInfos); } })().then(() => { aCallback(true); }, ex => { Cu.reportError(ex); aCallback(false); }); }, };
--- a/browser/components/migration/EdgeProfileMigrator.js +++ b/browser/components/migration/EdgeProfileMigrator.js @@ -104,52 +104,46 @@ EdgeTypedURLMigrator.prototype = { }, get exists() { return this._typedURLs.size > 0; }, migrate(aCallback) { let typedURLs = this._typedURLs; - let places = []; + let pageInfos = []; for (let [urlString, time] of typedURLs) { - let uri; + let url; try { - uri = Services.io.newURI(urlString); - if (!["http", "https", "ftp"].includes(uri.scheme)) { + url = new URL(urlString); + if (!["http", "https", "ftp"].includes(url.scheme)) { continue; } } catch (ex) { Cu.reportError(ex); continue; } - // Note that the time will be in microseconds (PRTime), - // and Date.now() returns milliseconds. Places expects PRTime, - // so we multiply the Date.now return value to make up the difference. - let visitDate = time || (Date.now() * 1000); - places.push({ - uri, - visits: [{ transitionType: Ci.nsINavHistoryService.TRANSITION_TYPED, - visitDate}], + pageInfos.push({ + url, + visits: [{ + transition: PlacesUtils.history.TRANSITIONS.TYPED, + date: time ? PlacesUtils.toDate(time) : new Date(), + }], }); } - if (places.length == 0) { + if (pageInfos.length == 0) { aCallback(typedURLs.size == 0); return; } - MigrationUtils.insertVisitsWrapper(places, { - ignoreErrors: true, - ignoreResults: true, - handleCompletion(updatedCount) { - aCallback(updatedCount > 0); - }, - }); + MigrationUtils.insertVisitsWrapper(pageInfos).then( + () => aCallback(true), + () => aCallback(false)); }, }; function EdgeReadingListMigrator(dbOverride) { this.dbOverride = dbOverride; } EdgeReadingListMigrator.prototype = {
--- a/browser/components/migration/IEProfileMigrator.js +++ b/browser/components/migration/IEProfileMigrator.js @@ -33,68 +33,62 @@ function History() { History.prototype = { type: MigrationUtils.resourceTypes.HISTORY, get exists() { return true; }, migrate: function H_migrate(aCallback) { - let places = []; + let pageInfos = []; let typedURLs = MSMigrationUtils.getTypedURLs("Software\\Microsoft\\Internet Explorer"); let historyEnumerator = Cc["@mozilla.org/profile/migrator/iehistoryenumerator;1"]. createInstance(Ci.nsISimpleEnumerator); while (historyEnumerator.hasMoreElements()) { let entry = historyEnumerator.getNext().QueryInterface(Ci.nsIPropertyBag2); - let uri = entry.get("uri").QueryInterface(Ci.nsIURI); + let url = entry.get("uri").QueryInterface(Ci.nsIURI); // MSIE stores some types of URLs in its history that we don't handle, // like HTMLHelp and others. Since we don't properly map handling for // all of them we just avoid importing them. - if (!["http", "https", "ftp", "file"].includes(uri.scheme)) { + if (!["http", "https", "ftp", "file"].includes(url.scheme)) { continue; } let title = entry.get("title"); // Embed visits have no title and don't need to be imported. if (title.length == 0) { continue; } // The typed urls are already fixed-up, so we can use them for comparison. - let transitionType = typedURLs.has(uri.spec) ? - Ci.nsINavHistoryService.TRANSITION_TYPED : - Ci.nsINavHistoryService.TRANSITION_LINK; + let transition = typedURLs.has(url.spec) ? + PlacesUtils.history.TRANSITIONS.LINK : + PlacesUtils.history.TRANSITIONS.TYPED; // use the current date if we have no visits for this entry. - // Note that the entry will have a time in microseconds (PRTime), - // and Date.now() returns milliseconds. Places expects PRTime, - // so we multiply the Date.now return value to make up the difference. - let lastVisitTime = entry.get("time") || (Date.now() * 1000); + let time = entry.get("time"); - places.push( - { uri, - title, - visits: [{ transitionType, - visitDate: lastVisitTime }], - } - ); + pageInfos.push({ + url, + title, + visits: [{ + transition, + date: time ? PlacesUtils.toDate(entry.get("time")) : new Date(), + }], + }); } // Check whether there is any history to import. - if (places.length == 0) { + if (pageInfos.length == 0) { aCallback(true); return; } - MigrationUtils.insertVisitsWrapper(places, { - ignoreErrors: true, - ignoreResults: true, - handleCompletion(updatedCount) { - aCallback(updatedCount > 0); - }, - }); + MigrationUtils.insertVisitsWrapper(pageInfos).then( + () => aCallback(true), + () => aCallback(false)); }, }; // IE form password migrator supporting windows from XP until 7 and IE from 7 until 11 function IE7FormPasswords() { // used to distinguish between this migrator and other passwords migrators in tests. this.name = "IE7FormPasswords"; }
--- a/browser/components/migration/MigrationUtils.jsm +++ b/browser/components/migration/MigrationUtils.jsm @@ -1037,22 +1037,22 @@ var MigrationUtils = Object.freeze({ for (let bm of insertedItems) { let {parentGuid, guid, lastModified, type} = bm; bmData.push({parentGuid, guid, lastModified, type}); } } }, ex => Cu.reportError(ex)); }, - insertVisitsWrapper(places, options) { - this._importQuantities.history += places.length; + insertVisitsWrapper(pageInfos) { + this._importQuantities.history += pageInfos.length; if (gKeepUndoData) { - this._updateHistoryUndo(places); + this._updateHistoryUndo(pageInfos); } - return PlacesUtils.asyncHistory.updatePlaces(places, options, true); + return PlacesUtils.history.insertMany(pageInfos); }, async insertLoginsWrapper(logins) { this._importQuantities.logins += logins.length; let inserted = await LoginHelper.maybeImportLogins(logins); // Note that this means that if we import a login that has a newer password // than we know about, we will update the login, and an undo of the import // will not revert this. This seems preferable over removing the login @@ -1096,30 +1096,36 @@ var MigrationUtils = Object.freeze({ stopAndRetrieveUndoData() { let undoData = gUndoData; gUndoData = null; gKeepUndoData = false; return this._postProcessUndoData(undoData); }, - _updateHistoryUndo(places) { + _updateHistoryUndo(pageInfos) { let visits = gUndoData.get("visits"); let visitMap = new Map(visits.map(v => [v.url, v])); - for (let place of places) { - let visitCount = place.visits.length; + for (let pageInfo of pageInfos) { + let visitCount = pageInfo.visits.length; let first, last; if (visitCount > 1) { - let visitDates = place.visits.map(v => v.visitDate); - first = Math.min.apply(Math, visitDates); - last = Math.max.apply(Math, visitDates); + let dates = pageInfo.visits.map(v => v.date); + first = Math.min.apply(Math, dates); + last = Math.max.apply(Math, dates); } else { - first = last = place.visits[0].visitDate; + first = last = pageInfo.visits[0].date; } - let url = place.uri.spec; + let url = pageInfo.url; + if (url instanceof Ci.nsIURI) { + url = pageInfo.url.spec; + } else if (typeof url != "string") { + pageInfo.url.href; + } + try { new URL(url); } catch (ex) { // This won't save and we won't need to 'undo' it, so ignore this URL. continue; } if (!visitMap.has(url)) { visitMap.set(url, {url, visitCount, first, last});
--- a/browser/components/migration/SafariProfileMigrator.js +++ b/browser/components/migration/SafariProfileMigrator.js @@ -12,18 +12,16 @@ ChromeUtils.import("resource://gre/modul ChromeUtils.import("resource:///modules/MigrationUtils.jsm"); ChromeUtils.defineModuleGetter(this, "Downloads", "resource://gre/modules/Downloads.jsm"); ChromeUtils.defineModuleGetter(this, "PropertyListUtils", "resource://gre/modules/PropertyListUtils.jsm"); ChromeUtils.defineModuleGetter(this, "PlacesUtils", "resource://gre/modules/PlacesUtils.jsm"); -ChromeUtils.defineModuleGetter(this, "NetUtil", - "resource://gre/modules/NetUtil.jsm"); ChromeUtils.defineModuleGetter(this, "FormHistory", "resource://gre/modules/FormHistory.jsm"); Cu.importGlobalProperties(["URL"]); function Bookmarks(aBookmarksFile) { this._file = aBookmarksFile; } @@ -188,61 +186,65 @@ History.prototype = { // The visit date is stored as a string, so it's not read as a Date // object by PropertyListUtils. _parseCocoaDate: function H___parseCocoaDate(aCocoaDateStr) { let asDouble = parseFloat(aCocoaDateStr); if (!isNaN(asDouble)) { // reference date of NSDate. let date = new Date("1 January 2001, GMT"); date.setMilliseconds(asDouble * 1000); - return date * 1000; + return date; } - return 0; + return new Date(); }, migrate: function H_migrate(aCallback) { PropertyListUtils.read(this._file, aDict => { try { if (!aDict) throw new Error("Could not read history property list"); if (!aDict.has("WebHistoryDates")) throw new Error("Unexpected history-property list format"); - // Safari's History file contains only top-level urls. It does not - // distinguish between typed urls and linked urls. - let transType = PlacesUtils.history.TRANSITION_LINK; - - let places = []; + let pageInfos = []; let entries = aDict.get("WebHistoryDates"); + let failedOnce = false; for (let entry of entries) { if (entry.has("lastVisitedDate")) { - let visitDate = this._parseCocoaDate(entry.get("lastVisitedDate")); + let date = this._parseCocoaDate(entry.get("lastVisitedDate")); try { - places.push({ uri: NetUtil.newURI(entry.get("")), - title: entry.get("title"), - visits: [{ transitionType: transType, - visitDate }] }); + pageInfos.push({ + url: new URL(entry.get("")), + title: entry.get("title"), + visits: [{ + // Safari's History file contains only top-level urls. It does not + // distinguish between typed urls and linked urls. + transition: PlacesUtils.history.TRANSITIONS.LINK, + date, + }], + }); } catch (ex) { // Safari's History file may contain malformed URIs which // will be ignored. Cu.reportError(ex); + failedOnce = true; } } } - if (places.length > 0) { - MigrationUtils.insertVisitsWrapper(places, { - ignoreErrors: true, - ignoreResults: true, - handleCompletion(updatedCount) { - aCallback(updatedCount > 0); - }, - }); - } else { - aCallback(false); + if (pageInfos.length == 0) { + // If we failed at least once, then we didn't succeed in importing, + // otherwise we didn't actually have anything to import, so we'll + // report it as a success. + aCallback(!failedOnce); + return; } + + MigrationUtils.insertVisitsWrapper(pageInfos).then( + () => aCallback(true), + () => aCallback(false)); } catch (ex) { Cu.reportError(ex); aCallback(false); } }); }, };
--- a/browser/components/migration/tests/unit/test_automigration.js +++ b/browser/components/migration/tests/unit/test_automigration.js @@ -1,16 +1,16 @@ "use strict"; ChromeUtils.import("resource:///modules/AutoMigrate.jsm", this); let gShimmedMigratorKeyPicker = null; let gShimmedMigrator = null; -const kUsecPerMin = 60 * 1000000; +const kMsecPerMin = 60 * 1000; // This is really a proxy on MigrationUtils, but if we specify that directly, // we get in trouble because the object itself is frozen, and Proxies can't // return a different value to an object when directly proxying a frozen // object. let AutoMigrateBackstage = ChromeUtils.import("resource:///modules/AutoMigrate.jsm", {}); AutoMigrateBackstage.MigrationUtils = new Proxy({}, { @@ -256,37 +256,37 @@ add_task(async function checkUndoRemoval title: "Some example bookmark", }); let bookmark = await PlacesUtils.bookmarks.fetch({url: "http://www.example.org/"}); Assert.ok(bookmark, "Should have a bookmark before undo"); Assert.equal(bookmark.title, "Some example bookmark", "Should have correct bookmark before undo."); // Insert 2 history visits - let now_uSec = Date.now() * 1000; + let now = new Date(); let visitedURI = Services.io.newURI("http://www.example.com/"); let frecencyUpdatePromise = new Promise(resolve => { let observer = { onManyFrecenciesChanged() { PlacesUtils.history.removeObserver(observer); resolve(); }, }; PlacesUtils.history.addObserver(observer); }); await MigrationUtils.insertVisitsWrapper([{ - uri: visitedURI, + url: visitedURI, visits: [ { - transitionType: PlacesUtils.history.TRANSITION_LINK, - visitDate: now_uSec, + transition: PlacesUtils.history.TRANSITION_LINK, + date: now, }, { - transitionType: PlacesUtils.history.TRANSITION_LINK, - visitDate: now_uSec - 100 * kUsecPerMin, + transition: PlacesUtils.history.TRANSITION_LINK, + date: new Date(now - 100 * kMsecPerMin), }, ], }]); await frecencyUpdatePromise; // Verify that both visits get reported. let opts = PlacesUtils.history.getNewQueryOptions(); opts.resultType = opts.RESULTS_AS_VISIT; @@ -491,103 +491,103 @@ add_task(async function testLoginsRemova Assert.equal(1, LoginHelper.searchLoginsWithObject({hostname: "https://example.org", formSubmitURL: "https://example.org/"}).length, "changed example.org entry should have persisted."); Services.logins.removeAllLogins(); }); add_task(async function checkUndoVisitsState() { MigrationUtils.initializeUndoData(); await MigrationUtils.insertVisitsWrapper([{ - uri: NetUtil.newURI("http://www.example.com/"), + url: NetUtil.newURI("http://www.example.com/"), title: "Example", visits: [{ - visitDate: new Date("2015-07-10").getTime() * 1000, - transitionType: Ci.nsINavHistoryService.TRANSITION_LINK, + date: new Date("2015-07-10"), + transition: Ci.nsINavHistoryService.TRANSITION_LINK, }, { - visitDate: new Date("2015-09-10").getTime() * 1000, - transitionType: Ci.nsINavHistoryService.TRANSITION_LINK, + date: new Date("2015-09-10"), + transition: Ci.nsINavHistoryService.TRANSITION_LINK, }, { - visitDate: new Date("2015-08-10").getTime() * 1000, - transitionType: Ci.nsINavHistoryService.TRANSITION_LINK, + date: new Date("2015-08-10"), + transition: Ci.nsINavHistoryService.TRANSITION_LINK, }], }, { - uri: NetUtil.newURI("http://www.example.org/"), + url: Services.io.newURI("http://www.example.org/"), title: "Example", visits: [{ - visitDate: new Date("2016-04-03").getTime() * 1000, - transitionType: Ci.nsINavHistoryService.TRANSITION_LINK, + date: new Date("2016-04-03"), + transition: Ci.nsINavHistoryService.TRANSITION_LINK, }, { - visitDate: new Date("2015-08-03").getTime() * 1000, - transitionType: Ci.nsINavHistoryService.TRANSITION_LINK, + date: new Date("2015-08-03"), + transition: Ci.nsINavHistoryService.TRANSITION_LINK, }], }, { - uri: NetUtil.newURI("http://www.example.com/"), + url: "http://www.example.com/", title: "Example", visits: [{ - visitDate: new Date("2015-10-10").getTime() * 1000, - transitionType: Ci.nsINavHistoryService.TRANSITION_LINK, + date: new Date("2015-10-10"), + transition: Ci.nsINavHistoryService.TRANSITION_LINK, }], }]); let undoVisitData = (await MigrationUtils.stopAndRetrieveUndoData()).get("visits"); Assert.deepEqual(Array.from(undoVisitData.map(v => v.url)).sort(), ["http://www.example.com/", "http://www.example.org/"]); Assert.deepEqual(undoVisitData.find(v => v.url == "http://www.example.com/"), { url: "http://www.example.com/", visitCount: 4, - first: new Date("2015-07-10").getTime() * 1000, - last: new Date("2015-10-10").getTime() * 1000, + first: new Date("2015-07-10").getTime(), + last: new Date("2015-10-10").getTime(), }); Assert.deepEqual(undoVisitData.find(v => v.url == "http://www.example.org/"), { url: "http://www.example.org/", visitCount: 2, - first: new Date("2015-08-03").getTime() * 1000, - last: new Date("2016-04-03").getTime() * 1000, + first: new Date("2015-08-03").getTime(), + last: new Date("2016-04-03").getTime(), }); await PlacesUtils.history.clear(); }); add_task(async function checkUndoVisitsState() { MigrationUtils.initializeUndoData(); await MigrationUtils.insertVisitsWrapper([{ - uri: NetUtil.newURI("http://www.example.com/"), + url: NetUtil.newURI("http://www.example.com/"), title: "Example", visits: [{ - visitDate: new Date("2015-07-10").getTime() * 1000, - transitionType: Ci.nsINavHistoryService.TRANSITION_LINK, + date: new Date("2015-07-10"), + transition: Ci.nsINavHistoryService.TRANSITION_LINK, }, { - visitDate: new Date("2015-09-10").getTime() * 1000, - transitionType: Ci.nsINavHistoryService.TRANSITION_LINK, + date: new Date("2015-09-10"), + transition: Ci.nsINavHistoryService.TRANSITION_LINK, }, { - visitDate: new Date("2015-08-10").getTime() * 1000, - transitionType: Ci.nsINavHistoryService.TRANSITION_LINK, + date: new Date("2015-08-10"), + transition: Ci.nsINavHistoryService.TRANSITION_LINK, }], }, { - uri: NetUtil.newURI("http://www.example.org/"), + url: NetUtil.newURI("http://www.example.org/"), title: "Example", visits: [{ - visitDate: new Date("2016-04-03").getTime() * 1000, - transitionType: Ci.nsINavHistoryService.TRANSITION_LINK, + date: new Date("2016-04-03"), + transition: Ci.nsINavHistoryService.TRANSITION_LINK, }, { - visitDate: new Date("2015-08-03").getTime() * 1000, - transitionType: Ci.nsINavHistoryService.TRANSITION_LINK, + date: new Date("2015-08-03"), + transition: Ci.nsINavHistoryService.TRANSITION_LINK, }], }, { - uri: NetUtil.newURI("http://www.example.com/"), + url: NetUtil.newURI("http://www.example.com/"), title: "Example", visits: [{ - visitDate: new Date("2015-10-10").getTime() * 1000, - transitionType: Ci.nsINavHistoryService.TRANSITION_LINK, + date: new Date("2015-10-10"), + transition: Ci.nsINavHistoryService.TRANSITION_LINK, }], }, { - uri: NetUtil.newURI("http://www.mozilla.org/"), + url: NetUtil.newURI("http://www.mozilla.org/"), title: "Example", visits: [{ - visitDate: new Date("2015-01-01").getTime() * 1000, - transitionType: Ci.nsINavHistoryService.TRANSITION_LINK, + date: new Date("2015-01-01"), + transition: Ci.nsINavHistoryService.TRANSITION_LINK, }], }]); // We have to wait until frecency updates have been handled in order // to accurately determine whether we're doing the right thing. let frecencyUpdatesHandled = new Promise(resolve => { PlacesUtils.history.addObserver({ onManyFrecenciesChanged() {
--- a/browser/components/places/PlacesUIUtils.jsm +++ b/browser/components/places/PlacesUIUtils.jsm @@ -816,33 +816,28 @@ var PlacesUIUtils = { * @param queryString * the query string to check (a place: href) * @return whether or not queryString represents a folder shortcut. * @throws if queryString is malformed. */ isFolderShortcutQueryString(queryString) { // Based on GetSimpleBookmarksQueryFolder in nsNavHistory.cpp. - let queriesParam = { }, optionsParam = { }; - PlacesUtils.history.queryStringToQueries(queryString, - queriesParam, - { }, - optionsParam); - let queries = queries.value; - if (queries.length == 0) - throw new Error(`Invalid place: uri: ${queryString}`); - return queries.length == 1 && - queries[0].folderCount == 1 && - !queries[0].hasBeginTime && - !queries[0].hasEndTime && - !queries[0].hasDomain && - !queries[0].hasURI && - !queries[0].hasSearchTerms && - !queries[0].tags.length == 0 && - optionsParam.value.maxResults == 0; + let query = {}, options = {}; + PlacesUtils.history.queryStringToQuery(queryString, query, options); + query = query.value; + options = options.value; + return query.folderCount == 1 && + !query.hasBeginTime && + !query.hasEndTime && + !query.hasDomain && + !query.hasURI && + !query.hasSearchTerms && + !query.tags.length == 0 && + options.maxResults == 0; }, /** * Helpers for consumers of editBookmarkOverlay which don't have a node as their input. * * Given a bookmark object for either a url bookmark or a folder, returned by * Bookmarks.fetch (see Bookmark.jsm), this creates a node-like object suitable for * initialising the edit overlay with it.
--- a/browser/components/places/content/browserPlacesViews.js +++ b/browser/components/places/content/browserPlacesViews.js @@ -48,23 +48,19 @@ PlacesViewBase.prototype = { _place: "", get place() { return this._place; }, set place(val) { this._place = val; let history = PlacesUtils.history; - let queries = { }, options = { }; - history.queryStringToQueries(val, queries, { }, options); - if (!queries.value.length) - queries.value = [history.getNewQuery()]; - - let result = history.executeQueries(queries.value, queries.value.length, - options.value); + let query = {}, options = {}; + history.queryStringToQuery(val, query, options); + let result = history.executeQuery(query.value, options.value); result.addObserver(this); return val; }, _result: null, get result() { return this._result; },
--- a/browser/components/places/content/controller.js +++ b/browser/components/places/content/controller.js @@ -218,22 +218,22 @@ PlacesController.prototype = { case "placesCmd_paste": this.paste().catch(Cu.reportError); break; case "cmd_delete": case "placesCmd_delete": this.remove("Remove Selection").catch(Cu.reportError); break; case "placesCmd_deleteDataHost": - var host; + let host; if (PlacesUtils.nodeIsHost(this._view.selectedNode)) { - var queries = this._view.selectedNode.getQueries(); - host = queries[0].domain; - } else + host = this._view.selectedNode.query.domain; + } else { host = Services.io.newURI(this._view.selectedNode.uri).host; + } let {ForgetAboutSite} = ChromeUtils.import("resource://gre/modules/ForgetAboutSite.jsm", {}); ForgetAboutSite.removeDataFromDomain(host) .catch(Cu.reportError); break; case "cmd_selectAll": this.selectAll(); break; case "placesCmd_open": @@ -905,17 +905,17 @@ PlacesController.prototype = { * @note history deletes are not undoable. */ _removeHistoryContainer: function PC__removeHistoryContainer(aContainerNode) { if (PlacesUtils.nodeIsHost(aContainerNode)) { // Site container. PlacesUtils.history.removePagesFromHost(aContainerNode.title, true); } else if (PlacesUtils.nodeIsDay(aContainerNode)) { // Day container. - let query = aContainerNode.getQueries()[0]; + let query = aContainerNode.query; let beginTime = query.beginTime; let endTime = query.endTime; if (!query || !beginTime || !endTime) throw new Error("A valid date container query should exist!"); // We want to exclude beginTime from the removal because // removePagesByTimeframe includes both extremes, while date containers // exclude the lower extreme. So, if we would not exclude it, we would // end up removing more history than requested.
--- a/browser/components/places/content/history-panel.js +++ b/browser/components/places/content/history-panel.js @@ -81,16 +81,16 @@ function searchHistory(aInput) { options.includeHidden = !!aInput; if (gHistoryGrouping == "lastvisited") this.TelemetryStopwatch.start("HISTORY_LASTVISITED_TREE_QUERY_TIME_MS"); // call load() on the tree manually // instead of setting the place attribute in history-panel.xul // otherwise, we will end up calling load() twice - gHistoryTree.load([query], options); + gHistoryTree.load(query, options); if (gHistoryGrouping == "lastvisited") this.TelemetryStopwatch.finish("HISTORY_LASTVISITED_TREE_QUERY_TIME_MS"); } window.addEventListener("SidebarFocused", () => gSearchBox.focus());
--- a/browser/components/places/content/places.js +++ b/browser/components/places/content/places.js @@ -390,23 +390,16 @@ var PlacesOrganizer = { /** * Returns the options associated with the query currently loaded in the * main places pane. */ getCurrentOptions: function PO_getCurrentOptions() { return PlacesUtils.asQuery(ContentArea.currentView.result.root).queryOptions; }, - /** - * Returns the queries associated with the query currently loaded in the - * main places pane. - */ - getCurrentQueries: function PO_getCurrentQueries() { - return PlacesUtils.asQuery(ContentArea.currentView.result.root).getQueries(); - }, /** * Show the migration wizard for importing passwords, * cookies, history, preferences, and bookmarks. */ importFromBrowser: function PO_importFromBrowser() { // We pass in the type of source we're using for use in telemetry: MigrationUtils.showMigrationWizard(window, [MigrationUtils.MIGRATION_ENTRYPOINT_PLACES]);
--- a/browser/components/places/content/tree.xml +++ b/browser/components/places/content/tree.xml @@ -93,27 +93,26 @@ if (folderRestrict) { query.setFolders(folderRestrict, folderRestrict.length); options.queryType = options.QUERY_TYPE_BOOKMARKS; } options.includeHidden = !!includeHidden; - this.load([query], options); + this.load(query, options); ]]></body> </method> <method name="load"> - <parameter name="queries"/> + <parameter name="query"/> <parameter name="options"/> <body><![CDATA[ let result = PlacesUtils.history - .executeQueries(queries, queries.length, - options); + .executeQuery(query, options); let callback; if (this.flatList) { let onOpenFlatContainer = this.onOpenFlatContainer; if (onOpenFlatContainer) callback = new Function("aContainer", onOpenFlatContainer); } if (!this._controller) { @@ -283,26 +282,19 @@ <!-- nsIPlacesView --> <property name="place"> <getter><![CDATA[ return this.getAttribute("place"); ]]></getter> <setter><![CDATA[ this.setAttribute("place", val); - var queriesRef = { }; - var queryCountRef = { }; - var optionsRef = { }; - PlacesUtils.history.queryStringToQueries(val, queriesRef, queryCountRef, optionsRef); - if (queryCountRef.value == 0) - queriesRef.value = [PlacesUtils.history.getNewQuery()]; - if (!optionsRef.value) - optionsRef.value = PlacesUtils.history.getNewQueryOptions(); - - this.load(queriesRef.value, optionsRef.value); + let query = {}, options = {}; + PlacesUtils.history.queryStringToQuery(val, query, options); + this.load(query.value, options.value); return val; ]]></setter> </property> <!-- nsIPlacesView --> <property name="hasSelection"> <getter><![CDATA[
--- a/browser/components/places/tests/browser/browser.ini +++ b/browser/components/places/tests/browser/browser.ini @@ -99,16 +99,17 @@ skip-if = os == "mac" && debug # bug 140 [browser_toolbar_drop_text.js] [browser_toolbar_overflow.js] [browser_toolbarbutton_menu_context.js] [browser_views_iconsupdate.js] [browser_bug485100-change-case-loses-tag.js] [browser_editBookmark_tags_liveUpdate.js] [browser_bug427633_no_newfolder_if_noip.js] [browser_editBookmark_keywords.js] +skip-if = (os == 'win' && ccov) # Bug 1423667 [browser_bug631374_tags_selector_scroll.js] support-files = favicon-normal16.png [browser_views_liveupdate.js] [browser_bookmark_all_tabs.js] support-files = bookmark_dummy_1.html bookmark_dummy_2.html
--- a/browser/components/places/tests/browser/browser_library_middleclick.js +++ b/browser/components/places/tests/browser/browser_library_middleclick.js @@ -136,17 +136,17 @@ gTests.push({ // Create a bookmarks query containing our bookmarks. var hs = PlacesUtils.history; var options = hs.getNewQueryOptions(); options.queryType = Ci.nsINavHistoryQueryOptions.QUERY_TYPE_BOOKMARKS; var query = hs.getNewQuery(); // The colon included in the terms selects only about: URIs. If not included // we also may get pages like about.html included in the query result. query.searchTerms = "about:"; - var queryString = hs.queriesToQueryString([query], 1, options); + var queryString = hs.queryToQueryString(query, options); this._query = await PlacesUtils.bookmarks.insert({ index: 0, // it must be the first parentGuid: PlacesUtils.bookmarks.unfiledGuid, title: "Query", url: queryString, }); // Select unsorted bookmarks root in the left pane.
--- a/browser/components/places/tests/browser/browser_library_search.js +++ b/browser/components/places/tests/browser/browser_library_search.js @@ -61,23 +61,23 @@ async function search(aFolderGuid, aSear } } // Second, ensure that searching updates the content tree and search UI // properly. let searchBox = doc.getElementById("searchFilter"); searchBox.value = aSearchStr; gLibrary.PlacesSearchBox.search(searchBox.value); - let queries = {}; - PlacesUtils.history.queryStringToQueries(contentTree.result.root.uri, queries, {}, {}); + let query = {}; + PlacesUtils.history.queryStringToQuery(contentTree.result.root.uri, query, {}); if (aSearchStr) { - Assert.equal(queries.value[0].searchTerms, aSearchStr, + Assert.equal(query.value.searchTerms, aSearchStr, "Content tree's searchTerms should be text in search box"); } else { - Assert.equal(queries.value[0].hasSearchTerms, false, + Assert.equal(query.value.hasSearchTerms, false, "Content tree's searchTerms should not exist after search reset"); } } add_task(async function test() { // Add visits, a bookmark and a tag. await PlacesTestUtils.addVisits( [{ uri: Services.io.newURI(TEST_URL), visitDate: Date.now() * 1000,
--- a/browser/components/places/tests/chrome/test_0_bug510634.xul +++ b/browser/components/places/tests/chrome/test_0_bug510634.xul @@ -49,18 +49,17 @@ // The query-property is set on the title column for each row. let titleColumn = tree.treeBoxObject.columns.getColumnAt(0); // Open All Bookmarks tree.selectItems([PlacesUtils.virtualAllBookmarksGuid]); PlacesUtils.asContainer(tree.selectedNode).containerOpen = true; is(tree.selectedNode.uri, - "place:type=" + Ci.nsINavHistoryQueryOptions.RESULTS_AS_ROOTS_QUERY + - "&queryType=" + Ci.nsINavHistoryQueryOptions.QUERY_TYPE_BOOKMARKS, + "place:type=" + Ci.nsINavHistoryQueryOptions.RESULTS_AS_ROOTS_QUERY, "Opened All Bookmarks"); const topLevelGuids = [ PlacesUtils.virtualHistoryGuid, PlacesUtils.virtualDownloadsGuid, PlacesUtils.virtualTagsGuid, PlacesUtils.virtualAllBookmarksGuid ];
--- a/browser/components/places/tests/chrome/test_bug549192.xul +++ b/browser/components/places/tests/chrome/test_bug549192.xul @@ -85,17 +85,17 @@ visitDate: newTimeInMicroseconds(), transition: ttype }]; await PlacesTestUtils.addVisits(places); // Make a history query. let query = PlacesUtils.history.getNewQuery(); let opts = PlacesUtils.history.getNewQueryOptions(); opts.sortingMode = opts.SORT_BY_DATE_DESCENDING; - let queryURI = PlacesUtils.history.queriesToQueryString([query], 1, opts); + let queryURI = PlacesUtils.history.queryToQueryString(query, opts); // Setup the places tree contents. var tree = document.getElementById("tree"); tree.place = queryURI; // loop through the rows and check them. let treeView = tree.view; let selection = treeView.selection;
--- a/browser/components/places/tests/chrome/test_bug549491.xul +++ b/browser/components/places/tests/chrome/test_bug549491.xul @@ -52,17 +52,17 @@ await PlacesTestUtils.addVisits({ uri: Services.io.newURI("http://example.tld/"), transition: PlacesUtils.history.TRANSITION_TYPED }); // Make a history query. let query = PlacesUtils.history.getNewQuery(); let opts = PlacesUtils.history.getNewQueryOptions(); - let queryURI = PlacesUtils.history.queriesToQueryString([query], 1, opts); + let queryURI = PlacesUtils.history.queryToQueryString(query, opts); // Setup the places tree contents. let tree = document.getElementById("tree"); tree.place = queryURI; let rootNode = tree.result.root; let obs = tree.view.QueryInterface(Ci.nsINavHistoryResultObserver); obs.nodeHistoryDetailsChanged(rootNode, rootNode.time, rootNode.accessCount);
--- a/browser/components/places/tests/chrome/test_treeview_date.xul +++ b/browser/components/places/tests/chrome/test_treeview_date.xul @@ -86,17 +86,17 @@ url: "http://at.midnight.com/", title: "A bookmark at midnight", type: PlacesUtils.bookmarks.TYPE_BOOKMARK }); // Make a history query. let query = PlacesUtils.history.getNewQuery(); let opts = PlacesUtils.history.getNewQueryOptions(); - let queryURI = PlacesUtils.history.queriesToQueryString([query], 1, opts); + let queryURI = PlacesUtils.history.queryToQueryString(query, opts); // Setup the places tree contents. let tree = document.getElementById("tree"); tree.place = queryURI; // loop through the rows and check formatting let treeView = tree.view; let rc = treeView.rowCount;
--- a/browser/components/shell/nsGNOMEShellService.cpp +++ b/browser/components/shell/nsGNOMEShellService.cpp @@ -210,17 +210,17 @@ NS_IMETHODIMP nsGNOMEShellService::IsDefaultBrowser(bool aStartupCheck, bool aForAllTypes, bool* aIsDefaultBrowser) { *aIsDefaultBrowser = false; if (IsRunningAsASnap()) { const gchar *argv[] = { "xdg-settings", "check", "default-web-browser", - "firefox_firefox.desktop", nullptr }; + "firefox.desktop", nullptr }; GSpawnFlags flags = static_cast<GSpawnFlags>(G_SPAWN_SEARCH_PATH | G_SPAWN_STDERR_TO_DEV_NULL); gchar *output = nullptr; gint exit_status = 0; if (!g_spawn_sync(nullptr, (gchar **) argv, nullptr, flags, nullptr, nullptr, &output, nullptr, &exit_status, nullptr)) { return NS_OK; } @@ -282,17 +282,17 @@ nsGNOMEShellService::SetDefaultBrowser(b { #ifdef DEBUG if (aForAllUsers) NS_WARNING("Setting the default browser for all users is not yet supported"); #endif if (IsRunningAsASnap()) { const gchar *argv[] = { "xdg-settings", "set", "default-web-browser", - "firefox_firefox.desktop", nullptr }; + "firefox.desktop", nullptr }; GSpawnFlags flags = static_cast<GSpawnFlags>(G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL); g_spawn_sync(nullptr, (gchar **) argv, nullptr, flags, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); return NS_OK; }
--- a/browser/locales/en-US/browser/preferences/preferences.ftl +++ b/browser/locales/en-US/browser/preferences/preferences.ftl @@ -11,21 +11,16 @@ do-not-track-option-always = pref-page = .title = { PLATFORM() -> [windows] Options *[other] Preferences } -# This string is currently used only in Firefox 60 and will be removed when not -# needed for x-channel. See bug 1445686 for details. -search-input = - .style = width: 15.4em - # This is used to determine the width of the search field in about:preferences, # in order to make the entire placeholder string visible # # Please keep the placeholder string short to avoid truncation. # # Notice: The value of the `.style` attribute is a CSS string, and the `width` # is the name of the CSS property. It is intended only to adjust the element's width. # Do not translate.
--- a/browser/modules/AsyncTabSwitcher.jsm +++ b/browser/modules/AsyncTabSwitcher.jsm @@ -9,16 +9,23 @@ var EXPORTED_SYMBOLS = ["AsyncTabSwitche ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); XPCOMUtils.defineLazyModuleGetters(this, { AppConstants: "resource://gre/modules/AppConstants.jsm", Services: "resource://gre/modules/Services.jsm", TelemetryStopwatch: "resource://gre/modules/TelemetryStopwatch.jsm", }); +XPCOMUtils.defineLazyPreferenceGetter(this, "gTabWarmingEnabled", + "browser.tabs.remote.warmup.enabled"); +XPCOMUtils.defineLazyPreferenceGetter(this, "gTabWarmingMax", + "browser.tabs.remote.warmup.maxTabs"); +XPCOMUtils.defineLazyPreferenceGetter(this, "gTabWarmingUnloadDelayMs", + "browser.tabs.remote.warmup.unloadDelayMs"); + /** * The tab switcher is responsible for asynchronously switching * tabs in e10s. It waits until the new tab is ready (i.e., the * layer tree is available) before switching to it. Then it * unloads the layer tree for the old tab. * * The tab switcher is a state machine. For each tab, it * maintains state about whether the layer tree for the tab is @@ -596,17 +603,17 @@ class AsyncTabSwitcher { // handlers, which might cause finish() to already have been called. // Check for that before calling finish() again. if (!this.tabbrowser._switcher) { return; } this.maybeFinishTabSwitch(); - if (numWarming > this.tabbrowser.tabWarmingMax) { + if (numWarming > gTabWarmingMax) { this.logState("Hit tabWarmingMax"); if (this.unloadTimer) { this.clearTimer(this.unloadTimer); } this.unloadNonRequiredTabs(); } if (numPending == 0) { @@ -816,17 +823,17 @@ class AsyncTabSwitcher { if (state != this.STATE_LOADING && state != this.STATE_LOADED) { this.setTabState(tab, this.STATE_LOADING); this.logState("Activated browser " + this.tinfo(tab) + " for print preview"); } } canWarmTab(tab) { - if (!this.tabbrowser.tabWarmingEnabled) { + if (!gTabWarmingEnabled) { return false; } if (!tab) { return false; } // If the tab is not yet inserted, closing, not remote, @@ -865,27 +872,26 @@ class AsyncTabSwitcher { if (!this.shouldWarmTab(tab)) { return; } this.logState("warmupTab " + this.tinfo(tab)); this.warmingTabs.add(tab); this.setTabState(tab, this.STATE_LOADING); - this.suppressDisplayPortAndQueueUnload(tab, - this.tabbrowser.tabWarmingUnloadDelay); + this.suppressDisplayPortAndQueueUnload(tab, gTabWarmingUnloadDelayMs); } // Called when the user asks to switch to a given tab. requestTab(tab) { if (tab === this.requestedTab) { return; } - if (this.tabbrowser.tabWarmingEnabled) { + if (gTabWarmingEnabled) { let warmingState = "disqualified"; if (this.canWarmTab(tab)) { let tabState = this.getTabState(tab); if (tabState == this.STATE_LOADING) { warmingState = "stillLoading"; } else if (tabState == this.STATE_LOADED) { warmingState = "loaded";
--- a/browser/modules/WindowsJumpLists.jsm +++ b/browser/modules/WindowsJumpLists.jsm @@ -397,17 +397,17 @@ var WinTaskbarJumpList = function WTBLJL__getHistoryResults(aSortingMode, aLimit, aCallback, aScope) { var options = PlacesUtils.history.getNewQueryOptions(); options.maxResults = aLimit; options.sortingMode = aSortingMode; var query = PlacesUtils.history.getNewQuery(); // Return the pending statement to the caller, to allow cancelation. return PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase) - .asyncExecuteLegacyQueries([query], 1, options, { + .asyncExecuteLegacyQuery(query, options, { handleResult(aResultSet) { for (let row; (row = aResultSet.getNextRow());) { try { aCallback.call(aScope, { uri: row.getResultByIndex(1), title: row.getResultByIndex(2) }); } catch (e) {}
--- a/config/mozunit.py +++ b/config/mozunit.py @@ -227,14 +227,14 @@ def main(*args, **kwargs): unittest.main(testRunner=MozTestRunner(), *args, **kwargs) else: args = list(args) if os.environ.get('MACH_STDOUT_ISATTY') and not any(a.startswith('--color') for a in args): args.append('--color=yes') module = __import__('__main__') args.extend([ - '--verbose', + '-vv', '-p', 'mozlog.pytest_mozlog.plugin', '-p', 'no:cacheprovider', module.__file__, ]) sys.exit(pytest.main(args))
--- a/devtools/client/debugger/content/views/sources-view.js +++ b/devtools/client/debugger/content/views/sources-view.js @@ -1093,17 +1093,17 @@ SourcesView.prototype = extend(WidgetMet _onStopBlackBoxing: Task.async(function* () { this.actions.blackbox(getSelectedSource(this.getState()), false); }), /** * The source editor's contextmenu handler. * - Toggles "Add Conditional Breakpoint" and "Edit Conditional Breakpoint" items */ - _onEditorContextMenuOpen: function (message, ev, popup) { + _onEditorContextMenuOpen: function (ev, popup) { let actor = this.selectedValue; let line = this.DebuggerView.editor.getCursor().line + 1; let location = { actor, line }; let breakpoint = getBreakpoint(this.getState(), location); let addConditionalBreakpointMenuItem = popup.querySelector("#se-dbg-cMenu-addConditionalBreakpoint"); let editConditionalBreakpointMenuItem = popup.querySelector("#se-dbg-cMenu-editConditionalBreakpoint");
--- a/devtools/client/debugger/debugger-view.js +++ b/devtools/client/debugger/debugger-view.js @@ -269,17 +269,17 @@ var DebuggerView = { }); this.editor.appendTo(document.getElementById("editor")).then(() => { this.editor.extend(DebuggerEditor); this._loadingText = L10N.getStr("loadingText"); callback(); }); - this.editor.on("gutterClick", (ev, line, button) => { + this.editor.on("gutterClick", (line, button) => { // A right-click shouldn't do anything but keep track of where // it was clicked. if (button == 2) { this.clickedLine = line; } else { const source = queries.getSelectedSource(this.controller.getState()); if (source) {
--- a/devtools/client/debugger/test/mochitest/browser_dbg_breakpoints-editor.js +++ b/devtools/client/debugger/test/mochitest/browser_dbg_breakpoints-editor.js @@ -62,33 +62,31 @@ function test() { }); callInTab(gTab, "firstCall"); let breakpointsAdded = 0; let breakpointsRemoved = 0; let editorBreakpointChanges = 0; - function onEditorBreakpointAddFirst(aEvent, aLine) { + function onEditorBreakpointAddFirst(aLine) { editorBreakpointChanges++; - ok(aEvent, - "breakpoint1 added to the editor."); + info("breakpoint1 added to the editor."); is(aLine, 5, "Editor breakpoint line is correct."); is(gEditor.getBreakpoints().length, 1, "editor.getBreakpoints().length is correct."); } - function onEditorBreakpointRemoveFirst(aEvent, aLine) { + function onEditorBreakpointRemoveFirst(aLine) { editorBreakpointChanges++; - ok(aEvent, - "breakpoint1 removed from the editor."); + info("breakpoint1 removed from the editor."); is(aLine, 5, "Editor breakpoint line is correct."); is(gEditor.getBreakpoints().length, 0, "editor.getBreakpoints().length is correct."); } function checkFirstBreakpoint(location) { @@ -154,21 +152,20 @@ function test() { is(queries.getSelectedSource(getState()).actor, gSources.values[1], "The second source should be currently selected."); // Remove the trap listener. gEditor.off("breakpointAdded", onEditorBreakpointAddBackgroundTrap); } - function onEditorBreakpointAddSwitch(aEvent, aLine) { + function onEditorBreakpointAddSwitch(aLine) { editorBreakpointChanges++; - ok(aEvent, - "breakpoint2 added to the editor."); + info("breakpoint2 added to the editor."); is(aLine, 4, "Editor breakpoint line is correct."); is(gEditor.getBreakpoints().length, 1, "editor.getBreakpoints().length is correct"); } function onEditorTextChanged() { @@ -202,21 +199,20 @@ function test() { let coords = gEditor.getCoordsFromPosition({ line: 4, ch: 0 }); let rect = iframe.getBoundingClientRect(); let left = rect.left + 10; let top = rect.top + coords.top + 4; utils.sendMouseEventToWindow("mousedown", left, top, 0, 1, 0, false, 0, 0); utils.sendMouseEventToWindow("mouseup", left, top, 0, 1, 0, false, 0, 0); } - function onEditorBreakpointRemoveSecond(aEvent, aLine) { + function onEditorBreakpointRemoveSecond(aLine) { editorBreakpointChanges++; - ok(aEvent, - "breakpoint2 removed from the editor."); + info("breakpoint2 removed from the editor."); is(aLine, 4, "Editor breakpoint line is correct."); is(gEditor.getBreakpoints().length, 0, "editor.getBreakpoints().length is correct."); waitForDebuggerEvents(gPanel, gDebugger.EVENTS.AFTER_FRAMES_CLEARED).then(() => { finalCheck();
--- a/devtools/client/netmonitor/src/connector/firefox-data-provider.js +++ b/devtools/client/netmonitor/src/connector/firefox-data-provider.js @@ -179,18 +179,20 @@ class FirefoxDataProvider { // Calculate total header size and don't forget to include // two new-line characters at the end. const headersSize = headers.reduce((acc, { name, value }) => { return acc + name.length + value.length + 2; }, 0); requestPostData.postData.text = postData; - payload.requestPostData = Object.assign({}, requestPostData); - payload.requestHeadersFromUploadStream = { headers, headersSize }; + payload.requestPostData = { + ...requestPostData, + uploadHeaders: { headers, headersSize } + }; } return payload; } async fetchRequestCookies(requestCookies) { let payload = {}; if (requestCookies) { let reqCookies = []; @@ -535,17 +537,17 @@ class FirefoxDataProvider { * * @param {object} response the message received from the server. */ async onRequestPostData(response) { let payload = await this.updateRequest(response.from, { requestPostData: response }); emit(EVENTS.RECEIVED_REQUEST_POST_DATA, response.from); - return payload; + return payload.requestPostData; } /** * Handles additional information received for a "securityInfo" packet. * * @param {object} response the message received from the server. */ async onSecurityInfo(response) {
--- a/devtools/client/netmonitor/src/har/har-builder.js +++ b/devtools/client/netmonitor/src/har/har-builder.js @@ -263,19 +263,18 @@ HarBuilder.prototype = { // When using HarAutomation, HarCollector will automatically fetch requestPostData // and requestHeaders, but when we use it from netmonitor, FirefoxDataProvider // should fetch it itself lazily, via requestData. let requestPostData = file.requestPostData; let requestHeaders = file.requestHeaders; let requestHeadersFromUploadStream; if (!requestPostData && this._options.requestData) { - let payload = await this._options.requestData(file.id, "requestPostData"); - requestPostData = payload.requestPostData; - requestHeadersFromUploadStream = payload.requestHeadersFromUploadStream; + requestPostData = await this._options.requestData(file.id, "requestPostData"); + requestHeadersFromUploadStream = requestPostData.uploadHeaders; } if (!requestPostData.postData.text) { return undefined; } if (!requestHeaders && this._options.requestData) { requestHeaders = await this._options.requestData(file.id, "requestHeaders");
--- a/devtools/client/netmonitor/src/utils/request-utils.js +++ b/devtools/client/netmonitor/src/utils/request-utils.js @@ -471,20 +471,17 @@ function processNetworkUpdates(request = switch (key) { case "securityInfo": result.securityState = value.state; break; case "totalTime": result.totalTime = request.totalTime; break; case "requestPostData": - result.requestHeadersFromUploadStream = { - headers: [], - headersSize: 0, - }; + result.requestHeadersFromUploadStream = value.uploadHeaders; break; } } } return result; } module.exports = {
--- a/devtools/client/netmonitor/src/widgets/RequestListContextMenu.js +++ b/devtools/client/netmonitor/src/widgets/RequestListContextMenu.js @@ -266,32 +266,35 @@ class RequestListContextMenu { } /** * Copy the request form data parameters (or raw payload) from * the currently selected item. */ async copyPostData(id, formDataSections, requestPostData) { let params = []; - // Try to extract any form data parameters. - formDataSections.forEach(section => { - let paramsArray = parseQueryString(section); - if (paramsArray) { - params = [...params, ...paramsArray]; - } - }); + // Try to extract any form data parameters if formDataSections is already + // available, which is only true if ParamsPanel has ever been mounted before. + if (formDataSections) { + formDataSections.forEach(section => { + let paramsArray = parseQueryString(section); + if (paramsArray) { + params = [...params, ...paramsArray]; + } + }); + } let string = params .map(param => param.name + (param.value ? "=" + param.value : "")) .join(Services.appinfo.OS === "WINNT" ? "\r\n" : "\n"); // Fall back to raw payload. if (!string) { requestPostData = requestPostData || - await this.props.connector.requestData(id, "requestPostData").requestPostData; + await this.props.connector.requestData(id, "requestPostData"); string = requestPostData.postData.text; if (Services.appinfo.OS !== "WINNT") { string = string.replace(/\r/g, ""); } } copyString(string); } @@ -299,17 +302,17 @@ class RequestListContextMenu { /** * Copy a cURL command from the currently selected item. */ async copyAsCurl(id, url, method, httpVersion, requestHeaders, requestPostData) { requestHeaders = requestHeaders || await this.props.connector.requestData(id, "requestHeaders"); requestPostData = requestPostData || - await this.props.connector.requestData(id, "requestPostData").requestPostData; + await this.props.connector.requestData(id, "requestPostData"); // Create a sanitized object for the Curl command generator. let data = { url, method, headers: requestHeaders.headers, httpVersion, postDataText: requestPostData ? requestPostData.postData.text : "",
--- a/devtools/client/netmonitor/test/browser_net_copy_as_curl.js +++ b/devtools/client/netmonitor/test/browser_net_copy_as_curl.js @@ -20,70 +20,104 @@ add_task(async function() { } // Header param is formatted as -H "Header: value" or -H 'Header: value' function header(h) { return "-H " + quote(h); } // Construct the expected command - const EXPECTED_RESULT = [ + const BASE_RESULT = [ "curl " + quote(SIMPLE_SJS), "--compressed", header("Host: example.com"), header("User-Agent: " + navigator.userAgent), header("Accept: */*"), header("Accept-Language: " + navigator.language), header("X-Custom-Header-1: Custom value"), header("X-Custom-Header-2: 8.8.8.8"), header("X-Custom-Header-3: Mon, 3 Mar 2014 11:11:11 GMT"), header("Referer: " + CURL_URL), header("Connection: keep-alive"), header("Pragma: no-cache"), header("Cache-Control: no-cache") ]; - let { document } = monitor.panelWin; - - let wait = waitForNetworkEvents(monitor, 1); - await ContentTask.spawn(tab.linkedBrowser, SIMPLE_SJS, async function(url) { - content.wrappedJSObject.performRequest(url); - }); - await wait; + const COOKIE_PARTIAL_RESULT = [ + header("Cookie: bob=true; tom=cool") + ]; - EventUtils.sendMouseEvent({ type: "mousedown" }, - document.querySelectorAll(".request-list-item")[0]); - EventUtils.sendMouseEvent({ type: "contextmenu" }, - document.querySelectorAll(".request-list-item")[0]); + const POST_PAYLOAD = "Plaintext value as a payload"; + const POST_PARTIAL_RESULT = [ + "--data " + quote(POST_PAYLOAD), + header("Content-Type: text/plain;charset=UTF-8") + ]; - await waitForClipboardPromise(function setup() { - monitor.panelWin.parent.document - .querySelector("#request-list-context-copy-as-curl").click(); - }, function validate(result) { - if (typeof result !== "string") { - return false; - } + // GET request, no cookies (first request) + await performRequest(null); + await testClipboardContent(BASE_RESULT); - // Different setups may produce the same command, but with the - // parameters in a different order in the commandline (which is fine). - // Here we confirm that the commands are the same even in that case. - - // This monster regexp parses the command line into an array of arguments, - // recognizing quoted args with matching quotes and escaped quotes inside: - // [ "curl 'url'", "--standalone-arg", "-arg-with-quoted-string 'value\'s'" ] - let matchRe = /[-A-Za-z1-9]+(?: ([\"'])(?:\\\1|.)*?\1)?/g; - - let actual = result.match(matchRe); + // GET request, cookies set by previous response + await performRequest(null); + await testClipboardContent([ + ...BASE_RESULT, + ...COOKIE_PARTIAL_RESULT + ]); - // Must begin with the same "curl 'URL'" segment - if (!actual || EXPECTED_RESULT[0] != actual[0]) { - return false; - } - - // Must match each of the params in the middle (headers and --compressed) - return EXPECTED_RESULT.length === actual.length && - EXPECTED_RESULT.every(param => actual.includes(param)); - }); - - info("Clipboard contains a cURL command for the currently selected item's url."); + // POST request + await performRequest(POST_PAYLOAD); + await testClipboardContent([ + ...BASE_RESULT, + ...COOKIE_PARTIAL_RESULT, + ...POST_PARTIAL_RESULT + ]); await teardown(monitor); + + async function performRequest(payload) { + let wait = waitForNetworkEvents(monitor, 1); + await ContentTask.spawn(tab.linkedBrowser, { + url: SIMPLE_SJS, payload_: payload + }, async function({url, payload_}) { + content.wrappedJSObject.performRequest(url, payload_); + }); + await wait; + } + + async function testClipboardContent(expectedResult) { + let { document } = monitor.panelWin; + + const items = document.querySelectorAll(".request-list-item"); + EventUtils.sendMouseEvent({ type: "mousedown" }, items[items.length - 1]); + EventUtils.sendMouseEvent({ type: "contextmenu" }, + document.querySelectorAll(".request-list-item")[0]); + + await waitForClipboardPromise(function setup() { + monitor.panelWin.parent.document + .querySelector("#request-list-context-copy-as-curl").click(); + }, function validate(result) { + if (typeof result !== "string") { + return false; + } + + // Different setups may produce the same command, but with the + // parameters in a different order in the commandline (which is fine). + // Here we confirm that the commands are the same even in that case. + + // This monster regexp parses the command line into an array of arguments, + // recognizing quoted args with matching quotes and escaped quotes inside: + // [ "curl 'url'", "--standalone-arg", "-arg-with-quoted-string 'value\'s'" ] + let matchRe = /[-A-Za-z1-9]+(?: ([\"'])(?:\\\1|.)*?\1)?/g; + + let actual = result.match(matchRe); + // Must begin with the same "curl 'URL'" segment + if (!actual || expectedResult[0] != actual[0]) { + return false; + } + + // Must match each of the params in the middle (headers and --compressed) + return expectedResult.length === actual.length && + expectedResult.every(param => actual.includes(param)); + }); + + info("Clipboard contains a cURL command for the currently selected item's url."); + } });
--- a/devtools/client/netmonitor/test/browser_net_curl-utils.js +++ b/devtools/client/netmonitor/test/browser_net_curl-utils.js @@ -253,17 +253,17 @@ async function createCurlData(selected, let requestHeaders = await requestData(id, "requestHeaders"); // Fetch header values. for (let { name, value } of requestHeaders.headers) { let text = await getLongString(value); data.headers.push({ name: name, value: text }); } - let { requestPostData } = await requestData(id, "requestPostData"); + let requestPostData = await requestData(id, "requestPostData"); // Fetch the request payload. if (requestPostData) { let postData = requestPostData.postData.text; data.postDataText = await getLongString(postData); } return data; }
--- a/devtools/client/netmonitor/test/html_copy-as-curl.html +++ b/devtools/client/netmonitor/test/html_copy-as-curl.html @@ -7,27 +7,28 @@ <meta charset="utf-8"/> <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" /> <meta http-equiv="Pragma" content="no-cache" /> <meta http-equiv="Expires" content="0" /> <title>Network Monitor test page</title> </head> <body> - <p>Performing a GET request</p> + <p>Performing a GET or POST request</p> <script type="text/javascript"> /* exported performRequest */ "use strict"; - function performRequest(url) { + function performRequest(url, payload) { let xhr = new XMLHttpRequest(); - xhr.open("GET", url, true); + let method = payload ? "POST" : "GET"; + xhr.open(method, url, true); xhr.setRequestHeader("Accept-Language", window.navigator.language); xhr.setRequestHeader("X-Custom-Header-1", "Custom value"); xhr.setRequestHeader("X-Custom-Header-2", "8.8.8.8"); xhr.setRequestHeader("X-Custom-Header-3", "Mon, 3 Mar 2014 11:11:11 GMT"); - xhr.send(null); + xhr.send(payload); } </script> </body> </html>
--- a/devtools/client/sourceeditor/editor.js +++ b/devtools/client/sourceeditor/editor.js @@ -25,17 +25,17 @@ const VALID_KEYMAPS = new Set(["emacs", const MAX_VERTICAL_OFFSET = 3; // Match @Scratchpad/N:LINE[:COLUMN] or (LINE[:COLUMN]) anywhere at an end of // line in text selection. const RE_SCRATCHPAD_ERROR = /(?:@Scratchpad\/\d+:|\()(\d+):?(\d+)?(?:\)|\n)/; const RE_JUMP_TO_LINE = /^(\d+):?(\d+)?/; const Services = require("Services"); -const events = require("devtools/shared/old-event-emitter"); +const EventEmitter = require("devtools/shared/event-emitter"); const { PrefObserver } = require("devtools/client/shared/prefs"); const { getClientCssProperties } = require("devtools/shared/fronts/css-properties"); const KeyShortcuts = require("devtools/client/shared/key-shortcuts"); const {LocalizationHelper} = require("devtools/shared/l10n"); const L10N = new LocalizationHelper("devtools/client/locales/sourceeditor.properties"); const { @@ -203,17 +203,17 @@ function Editor(config) { if (this.config.cssProperties) { // Ensure that autocompletion has cssProperties if it's passed in via the options. this.config.autocompleteOpts.cssProperties = this.config.cssProperties; } else { // Use a static client-side database of CSS values if none is provided. this.config.cssProperties = getClientCssProperties(); } - events.decorate(this); + EventEmitter.decorate(this); } Editor.prototype = { container: null, version: null, config: null, Doc: null,
--- a/devtools/server/actors/highlighters/css-grid.js +++ b/devtools/server/actors/highlighters/css-grid.js @@ -1062,16 +1062,23 @@ class CssGridHighlighter extends AutoRef } else { endPos = this._winDimensions.width; startPos = -endPos; } drawRect(this.ctx, startPos, linePos, endPos, linePos + breadth, this.currentMatrix); } + // Find current angle of grid by measuring the angle of two arbitrary points, + // then rotate canvas, so the hash pattern stays 45deg to the gridlines. + let p1 = apply(this.currentMatrix, [0, 0]); + let p2 = apply(this.currentMatrix, [1, 0]); + let angleRad = Math.atan2(p2[1] - p1[1], p2[0] - p1[0]); + this.ctx.rotate(angleRad); + this.ctx.fill(); this.ctx.restore(); } /** * Render the grid line name highlight for the given grid fragment index, lineNumber, * and dimensionType. *
--- a/devtools/server/actors/highlighters/flexbox.js +++ b/devtools/server/actors/highlighters/flexbox.js @@ -1,15 +1,16 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; const { AutoRefreshHighlighter } = require("./auto-refresh"); +const { apply } = require("devtools/shared/layout/dom-matrix-2d"); const { CANVAS_SIZE, DEFAULT_COLOR, clearRect, drawLine, drawRect, getCurrentMatrix, updateCanvasElement, @@ -359,16 +360,23 @@ class FlexboxHighlighter extends AutoRef this.ctx.setLineDash(FLEXBOX_LINES_PROPERTIES.edge.lineDash); this.ctx.lineWidth = 0; this.ctx.strokeStyle = DEFAULT_COLOR; this.ctx.fillStyle = this.getFlexContainerPattern(devicePixelRatio); let { bounds } = this.currentQuads.content[0]; drawRect(this.ctx, 0, 0, bounds.width, bounds.height, this.currentMatrix); + // Find current angle of outer flex element by measuring the angle of two arbitrary + // points, then rotate canvas, so the hash pattern stays 45deg to the boundary. + let p1 = apply(this.currentMatrix, [0, 0]); + let p2 = apply(this.currentMatrix, [1, 0]); + let angleRad = Math.atan2(p2[1] - p1[1], p2[0] - p1[0]); + this.ctx.rotate(angleRad); + this.ctx.fill(); this.ctx.stroke(); this.ctx.restore(); } /** * Renders the flex basis for a given flex item. */
--- a/dom/animation/EffectCompositor.cpp +++ b/dom/animation/EffectCompositor.cpp @@ -12,33 +12,33 @@ #include "mozilla/dom/Animation.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/KeyframeEffectReadOnly.h" #include "mozilla/AnimationComparator.h" #include "mozilla/AnimationPerformanceWarning.h" #include "mozilla/AnimationTarget.h" #include "mozilla/AnimationUtils.h" #include "mozilla/AutoRestore.h" +#include "mozilla/ComputedStyleInlines.h" #include "mozilla/EffectSet.h" #include "mozilla/LayerAnimationInfo.h" #include "mozilla/RestyleManager.h" #include "mozilla/RestyleManagerInlines.h" #include "mozilla/ServoBindings.h" // Servo_GetProperties_Overriding_Animation #include "mozilla/ServoStyleSet.h" #include "mozilla/StyleAnimationValue.h" #include "mozilla/TypeTraits.h" // For Forward<> #include "nsContentUtils.h" #include "nsCSSPseudoElements.h" #include "nsCSSPropertyIDSet.h" #include "nsCSSProps.h" #include "nsAtom.h" #include "nsIPresShell.h" #include "nsIPresShellInlines.h" #include "nsLayoutUtils.h" -#include "nsStyleContextInlines.h" #include "nsTArray.h" #include "PendingAnimationTracker.h" using mozilla::dom::Animation; using mozilla::dom::Element; using mozilla::dom::KeyframeEffectReadOnly; namespace mozilla { @@ -162,24 +162,21 @@ FindAnimationsForCompositor(const nsIFra // from test control after seeking where it might not be the case. // // Those cases are probably not important but just to be safe, let's make // sure the cascade is up to date since if it *is* up to date, this is // basically a no-op. Maybe<NonOwningAnimationTarget> pseudoElement = EffectCompositor::GetAnimationElementAndPseudoForFrame(aFrame); if (pseudoElement) { - StyleBackendType backend = - aFrame->StyleContext()->IsServo() - ? StyleBackendType::Servo - : StyleBackendType::Gecko; + StyleBackendType backend = StyleBackendType::Servo; EffectCompositor::MaybeUpdateCascadeResults(backend, pseudoElement->mElement, pseudoElement->mPseudoType, - aFrame->StyleContext()); + aFrame->Style()); } if (!nsLayoutUtils::AreAsyncAnimationsEnabled()) { if (nsLayoutUtils::IsAnimationLoggingEnabled()) { nsCString message; message.AppendLiteral("Performance warning: Async animations are " "disabled"); AnimationUtils::LogAsyncAnimationFailure(message); @@ -545,37 +542,37 @@ EffectCompositor::ClearIsRunningOnCompos effect->SetIsRunningOnCompositor(aProperty, false); } } /* static */ void EffectCompositor::MaybeUpdateCascadeResults(StyleBackendType aBackendType, Element* aElement, CSSPseudoElementType aPseudoType, - nsStyleContext* aStyleContext) + ComputedStyle* aComputedStyle) { EffectSet* effects = EffectSet::GetEffectSet(aElement, aPseudoType); if (!effects || !effects->CascadeNeedsUpdate()) { return; } UpdateCascadeResults(aBackendType, *effects, aElement, aPseudoType, - aStyleContext); + aComputedStyle); MOZ_ASSERT(!effects->CascadeNeedsUpdate(), "Failed to update cascade state"); } /* static */ Maybe<NonOwningAnimationTarget> EffectCompositor::GetAnimationElementAndPseudoForFrame(const nsIFrame* aFrame) { // Always return the same object to benefit from return-value optimization. Maybe<NonOwningAnimationTarget> result; CSSPseudoElementType pseudoType = - aFrame->StyleContext()->GetPseudoType(); + aFrame->Style()->GetPseudoType(); if (pseudoType != CSSPseudoElementType::NotPseudo && pseudoType != CSSPseudoElementType::before && pseudoType != CSSPseudoElementType::after) { return result; } nsIContent* content = aFrame->GetContent(); @@ -601,26 +598,26 @@ EffectCompositor::GetAnimationElementAnd } /* static */ nsCSSPropertyIDSet EffectCompositor::GetOverriddenProperties(StyleBackendType aBackendType, EffectSet& aEffectSet, Element* aElement, CSSPseudoElementType aPseudoType, - nsStyleContext* aStyleContext) + ComputedStyle* aComputedStyle) { MOZ_ASSERT(aBackendType != StyleBackendType::Servo || aElement, "Should have an element to get style data from if we are using" " the Servo backend"); nsCSSPropertyIDSet result; Element* elementToRestyle = GetElementToRestyle(aElement, aPseudoType); - if (aBackendType == StyleBackendType::Gecko && !aStyleContext) { + if (aBackendType == StyleBackendType::Gecko && !aComputedStyle) { MOZ_CRASH("old style system disabled"); } else if (aBackendType == StyleBackendType::Servo && !elementToRestyle) { return result; } AutoTArray<nsCSSPropertyID, LayerAnimationInfo::kRecords> propertiesToTrack; { nsCSSPropertyIDSet propertiesToTrackAsSet; @@ -662,17 +659,17 @@ EffectCompositor::GetOverriddenPropertie return result; } /* static */ void EffectCompositor::UpdateCascadeResults(StyleBackendType aBackendType, EffectSet& aEffectSet, Element* aElement, CSSPseudoElementType aPseudoType, - nsStyleContext* aStyleContext) + ComputedStyle* aComputedStyle) { MOZ_ASSERT(EffectSet::GetEffectSet(aElement, aPseudoType) == &aEffectSet, "Effect set should correspond to the specified (pseudo-)element"); if (aEffectSet.IsEmpty()) { aEffectSet.MarkCascadeUpdated(); return; } @@ -687,17 +684,17 @@ EffectCompositor::UpdateCascadeResults(S // // We only do this for properties that we can animate on the compositor // since we will apply other properties on the main thread where the usual // cascade applies. nsCSSPropertyIDSet overriddenProperties = GetOverriddenProperties(aBackendType, aEffectSet, aElement, aPseudoType, - aStyleContext); + aComputedStyle); // Returns a bitset the represents which properties from // LayerAnimationInfo::sRecords are present in |aPropertySet|. auto compositorPropertiesInSet = [](nsCSSPropertyIDSet& aPropertySet) -> std::bitset<LayerAnimationInfo::kRecords> { std::bitset<LayerAnimationInfo::kRecords> result; for (size_t i = 0; i < LayerAnimationInfo::kRecords; i++) { @@ -1027,13 +1024,13 @@ EffectCompositor::PreTraverse(dom::Eleme } return found; } template void EffectCompositor::UpdateEffectProperties( - const ServoStyleContext* aStyleContext, + const ComputedStyle* aComputedStyle, Element* aElement, CSSPseudoElementType aPseudoType); } // namespace mozilla
--- a/dom/animation/EffectCompositor.h +++ b/dom/animation/EffectCompositor.h @@ -17,22 +17,22 @@ #include "nsCycleCollectionParticipant.h" #include "nsDataHashtable.h" #include "nsTArray.h" class nsCSSPropertyIDSet; class nsAtom; class nsIFrame; class nsPresContext; -class nsStyleContext; struct RawServoAnimationValueMap; typedef RawServoAnimationValueMap* RawServoAnimationValueMapBorrowedMut; namespace mozilla { +class ComputedStyle; class EffectSet; class RestyleTracker; class StyleAnimationValue; struct AnimationPerformanceWarning; struct AnimationProperty; struct NonOwningAnimationTarget; namespace dom { @@ -148,53 +148,53 @@ public: static void ClearIsRunningOnCompositor(const nsIFrame* aFrame, nsCSSPropertyID aProperty); // Update animation cascade results for the specified (pseudo-)element // but only if we have marked the cascade as needing an update due a // the change in the set of effects or a change in one of the effects' // "in effect" state. // - // When |aBackendType| is StyleBackendType::Gecko, |aStyleContext| is used to - // find overridden properties. If it is nullptr, the nsStyleContext of the + // When |aBackendType| is StyleBackendType::Gecko, |aComputedStyle| is used to + // find overridden properties. If it is nullptr, the ComputedStyle of the // primary frame of the specified (pseudo-)element, if available, is used. // // When |aBackendType| is StyleBackendType::Servo, we fetch the rule node - // from the |aElement| (i.e. |aStyleContext| is ignored). + // from the |aElement| (i.e. |aComputedStyle| is ignored). // // This method does NOT detect if other styles that apply above the // animation level of the cascade have changed. static void MaybeUpdateCascadeResults(StyleBackendType aBackendType, dom::Element* aElement, CSSPseudoElementType aPseudoType, - nsStyleContext* aStyleContext); + ComputedStyle* aComputedStyle); // Update the mPropertiesWithImportantRules and // mPropertiesForAnimationsLevel members of the given EffectSet, and also // request any restyles required by changes to the cascade result. // // NOTE: This can be expensive so we should only call it if styles that apply // above the animation level of the cascade might have changed. For all // other cases we should call MaybeUpdateCascadeResults. // // This is typically reserved for internal callers but is public here since // when we detect changes to the cascade on the Servo side we can't call // MarkCascadeNeedsUpdate during the traversal so instead we call this as part // of a follow-up sequential task. // - // As with MaybeUpdateCascadeResults, |aStyleContext| is only used + // As with MaybeUpdateCascadeResults, |aComputedStyle| is only used // when |aBackendType| is StyleBackendType::Gecko. When |aBackendType| is // StyleBackendType::Servo, it is ignored. static void UpdateCascadeResults(StyleBackendType aBackendType, EffectSet& aEffectSet, dom::Element* aElement, CSSPseudoElementType aPseudoType, - nsStyleContext* aStyleContext); + ComputedStyle* aComputedStyle); // Helper to fetch the corresponding element and pseudo-type from a frame. // // For frames corresponding to pseudo-elements, the returned element is the // element on which we store the animations (i.e. the EffectSet and/or // AnimationCollection), *not* the generated content. // // Returns an empty result when a suitable element cannot be found including @@ -237,29 +237,29 @@ private: ~EffectCompositor() = default; // Get the properties in |aEffectSet| that we are able to animate on the // compositor but which are also specified at a higher level in the cascade // than the animations level. // // When |aBackendType| is StyleBackendType::Gecko, we determine which - // properties are specified using the provided |aStyleContext| and - // |aElement| and |aPseudoType| are ignored. If |aStyleContext| is nullptr, + // properties are specified using the provided |aComputedStyle| and + // |aElement| and |aPseudoType| are ignored. If |aComputedStyle| is nullptr, // we automatically look up the style context of primary frame of the // (pseudo-)element. // // When |aBackendType| is StyleBackendType::Servo, we use the |StrongRuleNode| // stored on the (pseudo-)element indicated by |aElement| and |aPseudoType|. static nsCSSPropertyIDSet GetOverriddenProperties(StyleBackendType aBackendType, EffectSet& aEffectSet, dom::Element* aElement, CSSPseudoElementType aPseudoType, - nsStyleContext* aStyleContext); + ComputedStyle* aComputedStyle); static nsPresContext* GetPresContext(dom::Element* aElement); nsPresContext* mPresContext; // Elements with a pending animation restyle. The associated bool value is // true if a pending animation restyle has also been dispatched. For // animations that can be throttled, we will add an entry to the hashtable to
--- a/dom/animation/KeyframeEffect.cpp +++ b/dom/animation/KeyframeEffect.cpp @@ -1,23 +1,23 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/dom/KeyframeEffect.h" +#include "mozilla/ComputedStyle.h" #include "mozilla/dom/KeyframeAnimationOptionsBinding.h" // For UnrestrictedDoubleOrKeyframeAnimationOptions #include "mozilla/dom/AnimationEffectTiming.h" #include "mozilla/dom/KeyframeEffectBinding.h" #include "nsDocument.h" // For nsDocument::IsWebAnimationsEnabled #include "nsDOMMutationObserver.h" // For nsAutoAnimationMutationBatch -#include "nsStyleContext.h" namespace mozilla { namespace dom { KeyframeEffect::KeyframeEffect(nsIDocument* aDocument, const Maybe<OwningAnimationTarget>& aTarget, const TimingParams& aTiming, const KeyframeEffectParams& aOptions) @@ -105,17 +105,17 @@ KeyframeEffect::SetTarget(const Nullable nsNodeUtils::AnimationRemoved(mAnimation); } } mTarget = newTarget; if (mTarget) { UpdateTargetRegistration(); - RefPtr<nsStyleContext> styleContext = GetTargetStyleContext(); + RefPtr<ComputedStyle> styleContext = GetTargetComputedStyle(); if (styleContext) { UpdateProperties(styleContext); } MaybeUpdateFrameForCompositor(); RequestRestyle(EffectCompositor::RestyleType::Layer); @@ -158,17 +158,17 @@ KeyframeEffect::SetComposite(const Compo mEffectOptions.mComposite = aComposite; if (mAnimation && mAnimation->IsRelevant()) { nsNodeUtils::AnimationChanged(mAnimation); } if (mTarget) { - RefPtr<nsStyleContext> styleContext = GetTargetStyleContext(); + RefPtr<ComputedStyle> styleContext = GetTargetComputedStyle(); if (styleContext) { UpdateProperties(styleContext); } } } } // namespace dom } // namespace mozilla
--- a/dom/animation/KeyframeEffect.h +++ b/dom/animation/KeyframeEffect.h @@ -60,21 +60,21 @@ public: Constructor(const GlobalObject& aGlobal, const Nullable<ElementOrCSSPseudoElement>& aTarget, JS::Handle<JSObject*> aKeyframes, const UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions, ErrorResult& aRv); void NotifySpecifiedTimingUpdated(); - // This method calls GetTargetStyleContext which is not safe to use when + // This method calls GetTargetComputedStyle which is not safe to use when // we are in the middle of updating style. If we need to use this when - // updating style, we should pass the nsStyleContext into this method and use + // updating style, we should pass the ComputedStyle into this method and use // that to update the properties rather than calling - // GetStyleContext. + // GetComputedStyle. void SetTarget(const Nullable<ElementOrCSSPseudoElement>& aTarget); IterationCompositeOperation IterationComposite(CallerType aCallerType) { return KeyframeEffectReadOnly::IterationComposite(); } void SetIterationComposite( const IterationCompositeOperation& aIterationComposite,
--- a/dom/animation/KeyframeEffectReadOnly.cpp +++ b/dom/animation/KeyframeEffectReadOnly.cpp @@ -9,35 +9,35 @@ #include "FrameLayerBuilder.h" #include "mozilla/dom/Animation.h" #include "mozilla/dom/KeyframeAnimationOptionsBinding.h" // For UnrestrictedDoubleOrKeyframeAnimationOptions; #include "mozilla/dom/CSSPseudoElement.h" #include "mozilla/dom/KeyframeEffectBinding.h" #include "mozilla/AnimationUtils.h" #include "mozilla/AutoRestore.h" +#include "mozilla/ComputedStyleInlines.h" #include "mozilla/EffectSet.h" #include "mozilla/FloatingPoint.h" // For IsFinite #include "mozilla/LayerAnimationInfo.h" #include "mozilla/LookAndFeel.h" // For LookAndFeel::GetInt #include "mozilla/KeyframeUtils.h" #include "mozilla/ServoBindings.h" #include "mozilla/TypeTraits.h" #include "Layers.h" // For Layer -#include "nsComputedDOMStyle.h" // nsComputedDOMStyle::GetStyleContext +#include "nsComputedDOMStyle.h" // nsComputedDOMStyle::GetComputedStyle #include "nsContentUtils.h" #include "nsCSSPropertyIDSet.h" #include "nsCSSProps.h" // For nsCSSProps::PropHasFlags #include "nsCSSPseudoElements.h" // For CSSPseudoElementType #include "nsDocument.h" // For nsDocument::IsWebAnimationsEnabled #include "nsIFrame.h" #include "nsIPresShell.h" #include "nsIScriptError.h" #include "nsRefreshDriver.h" -#include "nsStyleContextInlines.h" namespace mozilla { bool PropertyValuePair::operator==(const PropertyValuePair& aOther) const { if (mProperty != aOther.mProperty || mValue != aOther.mValue) { return false; @@ -185,35 +185,31 @@ KeyframeEffectReadOnly::SetKeyframes(JSC ErrorResult& aRv) { nsTArray<Keyframe> keyframes = KeyframeUtils::GetKeyframesFromObject(aContext, mDocument, aKeyframes, aRv); if (aRv.Failed()) { return; } - RefPtr<nsStyleContext> styleContext = GetTargetStyleContext(); - if (styleContext) { - if (styleContext->IsGecko()) { - MOZ_CRASH("old style system disabled"); - } else { - SetKeyframes(Move(keyframes), styleContext->AsServo()); - } + RefPtr<ComputedStyle> style = GetTargetComputedStyle(); + if (style) { + SetKeyframes(Move(keyframes), style); } else { // SetKeyframes has the same behavior for null StyleType* for // both backends, just pick one and use it. - SetKeyframes(Move(keyframes), (ServoStyleContext*) nullptr); + SetKeyframes(Move(keyframes), (ComputedStyle*) nullptr); } } void KeyframeEffectReadOnly::SetKeyframes( nsTArray<Keyframe>&& aKeyframes, - const ServoStyleContext* aComputedValues) + const ComputedStyle* aComputedValues) { DoSetKeyframes(Move(aKeyframes), aComputedValues); } template<typename StyleType> void KeyframeEffectReadOnly::DoSetKeyframes(nsTArray<Keyframe>&& aKeyframes, StyleType* aStyle) @@ -292,43 +288,30 @@ SpecifiedKeyframeArraysAreEqual(const ns } } return true; } #endif void -KeyframeEffectReadOnly::UpdateProperties(nsStyleContext* aStyleContext) +KeyframeEffectReadOnly::UpdateProperties(const ComputedStyle* aComputedStyle) { - MOZ_ASSERT(aStyleContext); - - if (aStyleContext->IsGecko()) { - MOZ_CRASH("old style system disabled"); - } - - UpdateProperties(aStyleContext->AsServo()); -} - -void -KeyframeEffectReadOnly::UpdateProperties( - const ServoStyleContext* aStyleContext) -{ - DoUpdateProperties(aStyleContext); + DoUpdateProperties(aComputedStyle); } template<typename StyleType> void KeyframeEffectReadOnly::DoUpdateProperties(StyleType* aStyle) { MOZ_ASSERT(aStyle); // Skip updating properties when we are composing style. // FIXME: Bug 1324966. Drop this check once we have a function to get - // nsStyleContext without resolving animating style. + // ComputedStyle without resolving animating style. MOZ_DIAGNOSTIC_ASSERT(!mIsComposingStyle, "Should not be called while processing ComposeStyle()"); if (mIsComposingStyle) { return; } nsTArray<AnimationProperty> properties = BuildProperties(aStyle); @@ -362,17 +345,17 @@ KeyframeEffectReadOnly::DoUpdateProperti MarkCascadeNeedsUpdate(); RequestRestyle(EffectCompositor::RestyleType::Layer); } void KeyframeEffectReadOnly::EnsureBaseStyles( - const ServoStyleContext* aComputedValues, + const ComputedStyle* aComputedValues, const nsTArray<AnimationProperty>& aProperties) { if (!mTarget) { return; } mBaseStyleValuesForServo.Clear(); @@ -387,57 +370,57 @@ KeyframeEffectReadOnly::EnsureBaseStyles // case where |presContext| is nullptr is so rare (we've only ever seen in // fuzzing, and even then we've never been able to reproduce it reliably) // it's not worth the runtime cost of an extra branch. MOZ_ASSERT(presContext || aProperties.IsEmpty(), "Typically presContext should not be nullptr but if it is" " we should have also failed to calculate the computed values" " passed-in as aProperties"); - RefPtr<ServoStyleContext> baseStyleContext; + RefPtr<ComputedStyle> baseComputedStyle; for (const AnimationProperty& property : aProperties) { EnsureBaseStyle(property, presContext, aComputedValues, - baseStyleContext); + baseComputedStyle); } } void KeyframeEffectReadOnly::EnsureBaseStyle( const AnimationProperty& aProperty, nsPresContext* aPresContext, - const ServoStyleContext* aComputedStyle, - RefPtr<ServoStyleContext>& aBaseStyleContext) + const ComputedStyle* aComputedStyle, + RefPtr<ComputedStyle>& aBaseComputedStyle) { bool hasAdditiveValues = false; for (const AnimationPropertySegment& segment : aProperty.mSegments) { if (!segment.HasReplaceableValues()) { hasAdditiveValues = true; break; } } if (!hasAdditiveValues) { return; } - if (!aBaseStyleContext) { + if (!aBaseComputedStyle) { Element* animatingElement = EffectCompositor::GetElementToRestyle(mTarget->mElement, mTarget->mPseudoType); - aBaseStyleContext = + aBaseComputedStyle = aPresContext->StyleSet()->AsServo()->GetBaseContextForElement( animatingElement, aPresContext, aComputedStyle); } RefPtr<RawServoAnimationValue> baseValue = - Servo_ComputedValues_ExtractAnimationValue(aBaseStyleContext, + Servo_ComputedValues_ExtractAnimationValue(aBaseComputedStyle, aProperty.mProperty).Consume(); mBaseStyleValuesForServo.Put(aProperty.mProperty, baseValue); } void KeyframeEffectReadOnly::WillComposeStyle() { ComputedTiming computedTiming = GetComputedTiming(); @@ -834,31 +817,31 @@ KeyframeEffectReadOnly::RequestRestyle( nsPresContext* presContext = nsContentUtils::GetContextForContent(mTarget->mElement); if (presContext && mAnimation) { presContext->EffectCompositor()-> RequestRestyle(mTarget->mElement, mTarget->mPseudoType, aRestyleType, mAnimation->CascadeLevel()); } } -already_AddRefed<nsStyleContext> -KeyframeEffectReadOnly::GetTargetStyleContext() +already_AddRefed<ComputedStyle> +KeyframeEffectReadOnly::GetTargetComputedStyle() { if (!GetRenderedDocument()) { return nullptr; } MOZ_ASSERT(mTarget, "Should only have a document when we have a target element"); nsAtom* pseudo = mTarget->mPseudoType < CSSPseudoElementType::Count ? nsCSSPseudoElements::GetPseudoAtom(mTarget->mPseudoType) : nullptr; - return nsComputedDOMStyle::GetStyleContext(mTarget->mElement, pseudo); + return nsComputedDOMStyle::GetComputedStyle(mTarget->mElement, pseudo); } #ifdef DEBUG void DumpAnimationProperties(nsTArray<AnimationProperty>& aAnimationProperties) { for (auto& p : aAnimationProperties) { printf("%s\n", nsCSSProps::GetStringValue(p.mProperty).get()); @@ -1035,27 +1018,27 @@ KeyframeEffectReadOnly::GetKeyframes(JSC // a longhand that comes from a variable reference in a shorthand? Servo says, // "an empty string" which is not particularly helpful. // // We should just store shorthands as-is (bug 1391537) and then return the // variable references, but for now, since we don't do that, and in order to // be consistent with Gecko, we just expand the variables (assuming we have // enough context to do so). For that we need to grab the style context so we // know what custom property values to provide. - RefPtr<nsStyleContext> styleContext; + RefPtr<ComputedStyle> styleContext; if (isServo && isCSSAnimation) { // The following will flush style but that's ok since if you update // a variable's computed value, you expect to see that updated value in the // result of getKeyframes(). // // If we don't have a target, the following will return null. In that case // we might end up returning variables as-is or empty string. That should be // acceptable however, since such a case is rare and this is only // short-term (and unshipped) behavior until bug 1391537 is fixed. - styleContext = GetTargetStyleContext(); + styleContext = GetTargetComputedStyle(); } for (const Keyframe& keyframe : mKeyframes) { // Set up a dictionary object for the explicit members BaseComputedKeyframe keyframeDict; if (keyframe.mOffset) { keyframeDict.mOffset.SetValue(keyframe.mOffset.value()); } @@ -1097,23 +1080,23 @@ KeyframeEffectReadOnly::GetKeyframes(JSC nsAutoString stringValue; if (isServo) { // Don't serialize the custom properties for this keyframe. if (propertyValue.mProperty == nsCSSPropertyID::eCSSPropertyExtra_variable) { continue; } if (propertyValue.mServoDeclarationBlock) { - const ServoStyleContext* servoStyleContext = + const ComputedStyle* servoComputedStyle = styleContext ? styleContext->AsServo() : nullptr; Servo_DeclarationBlock_SerializeOneValue( propertyValue.mServoDeclarationBlock, propertyValue.mProperty, &stringValue, - servoStyleContext, + servoComputedStyle, customProperties); } else { RawServoAnimationValue* value = mBaseStyleValuesForServo.GetWeak(propertyValue.mProperty); if (value) { Servo_AnimationValue_Serialize(value, propertyValue.mProperty, @@ -1498,40 +1481,40 @@ KeyframeEffectReadOnly::SetPerformanceWa AnimationUtils::LogAsyncAnimationFailure(logMessage, mTarget->mElement); } return; } } } -already_AddRefed<nsStyleContext> -KeyframeEffectReadOnly::CreateStyleContextForAnimationValue( +already_AddRefed<ComputedStyle> +KeyframeEffectReadOnly::CreateComputedStyleForAnimationValue( nsCSSPropertyID aProperty, const AnimationValue& aValue, - const ServoStyleContext* aBaseStyleContext) + const ComputedStyle* aBaseComputedStyle) { - MOZ_ASSERT(aBaseStyleContext, - "CreateStyleContextForAnimationValue needs to be called " - "with a valid ServoStyleContext"); + MOZ_ASSERT(aBaseComputedStyle, + "CreateComputedStyleForAnimationValue needs to be called " + "with a valid ComputedStyle"); ServoStyleSet* styleSet = - aBaseStyleContext->PresContext()->StyleSet()->AsServo(); + aBaseComputedStyle->PresContext()->StyleSet()->AsServo(); Element* elementForResolve = EffectCompositor::GetElementToRestyle(mTarget->mElement, mTarget->mPseudoType); MOZ_ASSERT(elementForResolve, "The target element shouldn't be null"); return styleSet->ResolveServoStyleByAddingAnimation(elementForResolve, - aBaseStyleContext, + aBaseComputedStyle, aValue.mServo); } template<typename StyleType> void -KeyframeEffectReadOnly::CalculateCumulativeChangeHint(StyleType* aStyleContext) +KeyframeEffectReadOnly::CalculateCumulativeChangeHint(StyleType* aComputedStyle) { mCumulativeChangeHint = nsChangeHint(0); for (const AnimationProperty& property : mProperties) { // For opacity property we don't produce any change hints that are not // included in nsChangeHint_Hints_CanIgnoreIfNotVisible so we can throttle // opacity animations regardless of the change they produce. This // optimization is particularly important since it allows us to throttle @@ -1544,29 +1527,29 @@ KeyframeEffectReadOnly::CalculateCumulat // In case composite operation is not 'replace' or value is null, // we can't throttle animations which will not cause any layout changes // on invisible elements because we can't calculate the change hint for // such properties until we compose it. if (!segment.HasReplaceableValues()) { mCumulativeChangeHint = ~nsChangeHint_Hints_CanIgnoreIfNotVisible; return; } - RefPtr<nsStyleContext> fromContext = - CreateStyleContextForAnimationValue(property.mProperty, + RefPtr<ComputedStyle> fromContext = + CreateComputedStyleForAnimationValue(property.mProperty, segment.mFromValue, - aStyleContext); + aComputedStyle); if (!fromContext) { mCumulativeChangeHint = ~nsChangeHint_Hints_CanIgnoreIfNotVisible; return; } - RefPtr<nsStyleContext> toContext = - CreateStyleContextForAnimationValue(property.mProperty, + RefPtr<ComputedStyle> toContext = + CreateComputedStyleForAnimationValue(property.mProperty, segment.mToValue, - aStyleContext); + aComputedStyle); if (!toContext) { mCumulativeChangeHint = ~nsChangeHint_Hints_CanIgnoreIfNotVisible; return; } uint32_t equalStructs = 0; uint32_t samePointerStructs = 0; nsChangeHint changeHint =
--- a/dom/animation/KeyframeEffectReadOnly.h +++ b/dom/animation/KeyframeEffectReadOnly.h @@ -40,18 +40,18 @@ class nsIPresShell; namespace mozilla { class AnimValuesStyleRule; enum class CSSPseudoElementType : uint8_t; class ErrorResult; struct AnimationRule; struct TimingParams; class EffectSet; -class ServoStyleContext; -class GeckoStyleContext; +class ComputedStyle; +class GeckoComputedStyle; namespace dom { class ElementOrCSSPseudoElement; class GlobalObject; class OwningElementOrCSSPseudoElement; class UnrestrictedDoubleOrKeyframeAnimationOptions; class UnrestrictedDoubleOrKeyframeEffectOptions; enum class IterationCompositeOperation : uint8_t; @@ -161,17 +161,17 @@ public: IterationCompositeOperation IterationComposite() const; CompositeOperation Composite() const; void NotifyAnimationTimingUpdated(); void RequestRestyle(EffectCompositor::RestyleType aRestyleType); void SetAnimation(Animation* aAnimation) override; void SetKeyframes(JSContext* aContext, JS::Handle<JSObject*> aKeyframes, ErrorResult& aRv); void SetKeyframes(nsTArray<Keyframe>&& aKeyframes, - const ServoStyleContext* aComputedValues); + const ComputedStyle* aComputedValues); // Returns true if the effect includes |aProperty| regardless of whether the // property is overridden by !important rule. bool HasAnimationOfProperty(nsCSSPropertyID aProperty) const; // GetEffectiveAnimationOfProperty returns AnimationProperty corresponding // to a given CSS property if the effect includes the property and the // property is not overridden by !important rules. @@ -187,20 +187,18 @@ public: nsCSSPropertyID aProperty) const; const InfallibleTArray<AnimationProperty>& Properties() const { return mProperties; } // Update |mProperties| by recalculating from |mKeyframes| using - // |aStyleContext| to resolve specified values. - void UpdateProperties(nsStyleContext* aStyleContext); - // Servo version of the above function. - void UpdateProperties(const ServoStyleContext* aComputedValues); + // |aComputedStyle| to resolve specified values. + void UpdateProperties(const ComputedStyle* aComputedValues); // Update various bits of state related to running ComposeStyle(). // We need to update this outside ComposeStyle() because we should avoid // mutating any state in ComposeStyle() since it might be called during // parallel traversal. void WillComposeStyle(); // Updates |aComposeResult| with the animation values produced by this @@ -242,17 +240,17 @@ public: // will be used to generate a localized message for devtools. void SetPerformanceWarning( nsCSSPropertyID aProperty, const AnimationPerformanceWarning& aWarning); // Cumulative change hint on each segment for each property. // This is used for deciding the animation is paint-only. template<typename StyleType> - void CalculateCumulativeChangeHint(StyleType* aStyleContext); + void CalculateCumulativeChangeHint(StyleType* aComputedStyle); // Returns true if all of animation properties' change hints // can ignore painting if the animation is not visible. // See nsChangeHint_Hints_CanIgnoreIfNotVisible in nsChangeHint.h // in detail which change hint can be ignored. bool CanIgnoreIfNotVisible() const; // Returns true if the effect is current state and has scale animation. @@ -295,17 +293,17 @@ protected: ErrorResult& aRv); template<class KeyframeEffectType> static already_AddRefed<KeyframeEffectType> ConstructKeyframeEffect(const GlobalObject& aGlobal, KeyframeEffectReadOnly& aSource, ErrorResult& aRv); - // Build properties by recalculating from |mKeyframes| using |aStyleContext| + // Build properties by recalculating from |mKeyframes| using |aComputedStyle| // to resolve specified values. This function also applies paced spacing if // needed. template<typename StyleType> nsTArray<AnimationProperty> BuildProperties(StyleType* aStyle); // This effect is registered with its target element so long as: // // (a) It has a target element, and @@ -323,34 +321,34 @@ protected: // Update the associated frame state bits so that, if necessary, a stacking // context will be created and the effect sent to the compositor. We // typically need to do this when the properties referenced by the keyframe // have changed, or when the target frame might have changed. void MaybeUpdateFrameForCompositor(); // Looks up the style context associated with the target element, if any. // We need to be careful to *not* call this when we are updating the style - // context. That's because calling GetStyleContext when we are in the process + // context. That's because calling GetComputedStyle when we are in the process // of building a style context may trigger various forms of infinite // recursion. - already_AddRefed<nsStyleContext> GetTargetStyleContext(); + already_AddRefed<ComputedStyle> GetTargetComputedStyle(); // A wrapper for marking cascade update according to the current // target and its effectSet. void MarkCascadeNeedsUpdate(); - void EnsureBaseStyles(const ServoStyleContext* aComputedValues, + void EnsureBaseStyles(const ComputedStyle* aComputedValues, const nsTArray<AnimationProperty>& aProperties); // Stylo version of the above function that also first checks for an additive // value in |aProperty|'s list of segments. void EnsureBaseStyle(const AnimationProperty& aProperty, nsPresContext* aPresContext, - const ServoStyleContext* aComputedValues, - RefPtr<mozilla::ServoStyleContext>& aBaseComputedValues); + const ComputedStyle* aComputedValues, + RefPtr<ComputedStyle>& aBaseComputedValues); Maybe<OwningAnimationTarget> mTarget; KeyframeEffectParams mEffectOptions; // The specified keyframes. nsTArray<Keyframe> mKeyframes; @@ -393,20 +391,20 @@ private: void ComposeStyleRule(RawServoAnimationValueMap& aAnimationValues, const AnimationProperty& aProperty, const AnimationPropertySegment& aSegment, const ComputedTiming& aComputedTiming); - already_AddRefed<nsStyleContext> CreateStyleContextForAnimationValue( + already_AddRefed<ComputedStyle> CreateComputedStyleForAnimationValue( nsCSSPropertyID aProperty, const AnimationValue& aValue, - const ServoStyleContext* aBaseStyleContext); + const ComputedStyle* aBaseComputedStyle); nsIFrame* GetAnimationFrame() const; bool CanThrottle() const; bool CanThrottleTransformChanges(const nsIFrame& aFrame) const; bool CanThrottleTransformChangesInScrollable(nsIFrame& aFrame) const; // Returns true if the computedTiming has changed since the last
--- a/dom/animation/KeyframeUtils.cpp +++ b/dom/animation/KeyframeUtils.cpp @@ -1,16 +1,17 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/KeyframeUtils.h" +#include "mozilla/ComputedStyle.h" #include "mozilla/ErrorResult.h" #include "mozilla/Move.h" #include "mozilla/RangedArray.h" #include "mozilla/ServoBindings.h" #include "mozilla/ServoBindingTypes.h" #include "mozilla/ServoCSSParser.h" #include "mozilla/StyleAnimationValue.h" #include "mozilla/TimingParams.h" @@ -23,17 +24,16 @@ #include "nsContentUtils.h" // For GetContextForContent, and // AnimationsAPICoreEnabled #include "nsCSSParser.h" #include "nsCSSPropertyIDSet.h" #include "nsCSSProps.h" #include "nsCSSPseudoElements.h" // For CSSPseudoElementType #include "nsDocument.h" // For nsDocument::IsWebAnimationsEnabled #include "nsIScriptError.h" -#include "nsStyleContext.h" #include "nsTArray.h" #include <algorithm> // For std::stable_sort, std::min namespace mozilla { // ------------------------------------------------------------------ // // Internal data types @@ -365,17 +365,17 @@ static void MarkAsComputeValuesFailureKey(PropertyValuePair& aPair); #endif static nsTArray<ComputedKeyframeValues> GetComputedKeyframeValues(const nsTArray<Keyframe>& aKeyframes, dom::Element* aElement, - const ServoStyleContext* aComputedValues); + const ComputedStyle* aComputedValues); static void BuildSegmentsFromValueEntries(nsTArray<KeyframeValueEntry>& aEntries, nsTArray<AnimationProperty>& aResult); static void GetKeyframeListFromPropertyIndexedKeyframe(JSContext* aCx, nsIDocument* aDocument, @@ -940,34 +940,34 @@ MarkAsComputeValuesFailureKey(PropertyVa /** * The variation of the above function. This is for Servo backend. */ static nsTArray<ComputedKeyframeValues> GetComputedKeyframeValues(const nsTArray<Keyframe>& aKeyframes, dom::Element* aElement, - const ServoStyleContext* aStyleContext) + const ComputedStyle* aComputedStyle) { MOZ_ASSERT(aElement); MOZ_ASSERT(aElement->IsStyledByServo()); nsTArray<ComputedKeyframeValues> result; nsPresContext* presContext = nsContentUtils::GetContextForContent(aElement); if (!presContext) { // This has been reported to happen with some combinations of content // (particularly involving resize events and layout flushes? See bug 1407898 // and bug 1408420) but no reproducible steps have been found. // For now we just return an empty array. return result; } result = presContext->StyleSet()->AsServo() - ->GetComputedKeyframeValuesFor(aKeyframes, aElement, aStyleContext); + ->GetComputedKeyframeValuesFor(aKeyframes, aElement, aComputedStyle); return result; } static void AppendInitialSegment(AnimationProperty* aAnimationProperty, const KeyframeValueEntry& aFirstEntry) { AnimationPropertySegment* segment = @@ -1528,12 +1528,12 @@ DistributeRange(const Range<Keyframe>& a } template nsTArray<AnimationProperty> KeyframeUtils::GetAnimationPropertiesFromKeyframes( const nsTArray<Keyframe>& aKeyframes, dom::Element* aElement, - const ServoStyleContext* aStyle, + const ComputedStyle* aStyle, dom::CompositeOperation aEffectComposite); } // namespace mozilla
--- a/dom/animation/KeyframeUtils.h +++ b/dom/animation/KeyframeUtils.h @@ -10,17 +10,17 @@ #include "mozilla/KeyframeEffectParams.h" // For CompositeOperation #include "nsCSSPropertyID.h" #include "nsTArrayForwardDeclare.h" // For nsTArray #include "js/RootingAPI.h" // For JS::Handle struct JSContext; class JSObject; class nsIDocument; -class nsStyleContext; +class ComputedStyle; struct RawServoDeclarationBlock; namespace mozilla { struct AnimationProperty; enum class CSSPseudoElementType : uint8_t; class ErrorResult; struct Keyframe; struct PropertyStyleAnimationValuePair; @@ -76,17 +76,17 @@ public: /** * Converts an array of Keyframe objects into an array of AnimationProperty * objects. This involves creating an array of computed values for each * longhand property and determining the offset and timing function to use * for each value. * * @param aKeyframes The input keyframes. * @param aElement The context element. - * @param aStyleType The |ServoStyleContext| or |GeckoStyleContext| to use + * @param aStyleType The |ComputedStyle| or |GeckoComputedStyle| to use * when computing values. * @param aEffectComposite The composite operation specified on the effect. * For any keyframes in |aKeyframes| that do not specify a composite * operation, this value will be used. * @return The set of animation properties. If an error occurs, the returned * array will be empty. */ template<typename StyleType>
--- a/dom/base/Element.cpp +++ b/dom/base/Element.cpp @@ -539,18 +539,18 @@ Element::GetBindingURL(nsIDocument *aDoc IsHTMLElement(nsGkAtoms::object) || IsHTMLElement(nsGkAtoms::embed)); if (!aDocument->GetShell() || GetPrimaryFrame() || !isXULorPluginElement) { *aResult = nullptr; return true; } // Get the computed -moz-binding directly from the style context - RefPtr<nsStyleContext> sc = - nsComputedDOMStyle::GetStyleContextNoFlush(this, nullptr); + RefPtr<ComputedStyle> sc = + nsComputedDOMStyle::GetComputedStyleNoFlush(this, nullptr); NS_ENSURE_TRUE(sc, false); NS_IF_ADDREF(*aResult = sc->StyleDisplay()->mBinding); return true; } JSObject* Element::WrapObject(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) @@ -1500,18 +1500,18 @@ Element::GetElementsByClassName(const ns void Element::GetElementsWithGrid(nsTArray<RefPtr<Element>>& aElements) { // This helper function is passed to GetElementsByMatching() // to identify elements with styling which will cause them to // generate a nsGridContainerFrame during layout. auto IsDisplayGrid = [](Element* aElement) -> bool { - RefPtr<nsStyleContext> styleContext = - nsComputedDOMStyle::GetStyleContext(aElement, nullptr); + RefPtr<ComputedStyle> styleContext = + nsComputedDOMStyle::GetComputedStyle(aElement, nullptr); if (styleContext) { const nsStyleDisplay* display = styleContext->StyleDisplay(); return (display->mDisplay == StyleDisplay::Grid || display->mDisplay == StyleDisplay::InlineGrid); } return false; }; @@ -4380,17 +4380,17 @@ Element::AddSizeOfExcludingThis(nsWindow // code. *aNodeSize += Servo_Element_SizeOfExcludingThisAndCVs(ServoElementMallocSizeOf, ServoElementMallocEnclosingSizeOf, &aSizes.mState.mSeenPtrs, this); // Now measure just the ComputedValues (and style structs) under // mServoData. This counts towards the relevant fields in |aSizes|. - RefPtr<ServoStyleContext> sc; + RefPtr<ComputedStyle> sc; if (Servo_Element_HasPrimaryComputedValues(this)) { sc = Servo_Element_GetPrimaryComputedValues(this).Consume(); if (!aSizes.mState.HaveSeenPtr(sc.get())) { sc->AddSizeOfIncludingThis(aSizes, &aSizes.mLayoutComputedValuesDom); } for (size_t i = 0; i < nsCSSPseudoElements::kEagerPseudoCount; i++) { if (Servo_Element_HasPseudoComputedValues(this, i)) {
--- a/dom/base/nsDOMWindowUtils.cpp +++ b/dom/base/nsDOMWindowUtils.cpp @@ -2721,18 +2721,18 @@ nsDOMWindowUtils::ComputeAnimationDistan Element* element = content->AsElement(); AnimationValue v1 = AnimationValue::FromString(property, aValue1, element); AnimationValue v2 = AnimationValue::FromString(property, aValue2, element); if (v1.IsNull() || v2.IsNull()) { return NS_ERROR_ILLEGAL_VALUE; } - RefPtr<nsStyleContext> styleContext = - nsComputedDOMStyle::GetStyleContext(element, nullptr); + RefPtr<ComputedStyle> styleContext = + nsComputedDOMStyle::GetComputedStyle(element, nullptr); *aResult = v1.ComputeDistance(property, v2, styleContext); return NS_OK; } NS_IMETHODIMP nsDOMWindowUtils::GetAnimationTypeForLonghand(const nsAString& aProperty, nsAString& aResult) { @@ -2819,34 +2819,30 @@ nsDOMWindowUtils::GetUnanimatedComputedS } nsIPresShell* shell = GetPresShell(); if (!shell) { return NS_ERROR_FAILURE; } RefPtr<nsAtom> pseudo = nsCSSPseudoElements::GetPseudoAtom(aPseudoElement); - RefPtr<nsStyleContext> styleContext = - nsComputedDOMStyle::GetUnanimatedStyleContextNoFlush(element, pseudo); + RefPtr<ComputedStyle> styleContext = + nsComputedDOMStyle::GetUnanimatedComputedStyleNoFlush(element, pseudo); if (!styleContext) { return NS_ERROR_FAILURE; } - if (styleContext->IsServo()) { - RefPtr<RawServoAnimationValue> value = - Servo_ComputedValues_ExtractAnimationValue(styleContext->AsServo(), - propertyID).Consume(); - if (!value) { - return NS_ERROR_FAILURE; - } - Servo_AnimationValue_Serialize(value, propertyID, &aResult); - return NS_OK; + RefPtr<RawServoAnimationValue> value = + Servo_ComputedValues_ExtractAnimationValue(styleContext->AsServo(), + propertyID).Consume(); + if (!value) { + return NS_ERROR_FAILURE; } - - MOZ_CRASH("old style system disabled"); + Servo_AnimationValue_Serialize(value, propertyID, &aResult); + return NS_OK; } nsresult nsDOMWindowUtils::RenderDocument(const nsRect& aRect, uint32_t aFlags, nscolor aBackgroundColor, gfxContext* aThebesContext) {
--- a/dom/base/nsPlainTextSerializer.cpp +++ b/dom/base/nsPlainTextSerializer.cpp @@ -1846,31 +1846,31 @@ bool nsPlainTextSerializer::IsInPre() { return !mPreformatStack.empty() && mPreformatStack.top(); } bool nsPlainTextSerializer::IsElementPreformatted(Element* aElement) { - RefPtr<nsStyleContext> styleContext = - nsComputedDOMStyle::GetStyleContextNoFlush(aElement, nullptr); + RefPtr<ComputedStyle> styleContext = + nsComputedDOMStyle::GetComputedStyleNoFlush(aElement, nullptr); if (styleContext) { const nsStyleText* textStyle = styleContext->StyleText(); return textStyle->WhiteSpaceOrNewlineIsSignificant(); } // Fall back to looking at the tag, in case there is no style information. return GetIdForContent(aElement) == nsGkAtoms::pre; } bool nsPlainTextSerializer::IsElementBlock(Element* aElement) { - RefPtr<nsStyleContext> styleContext = - nsComputedDOMStyle::GetStyleContextNoFlush(aElement, nullptr); + RefPtr<ComputedStyle> styleContext = + nsComputedDOMStyle::GetComputedStyleNoFlush(aElement, nullptr); if (styleContext) { const nsStyleDisplay* displayStyle = styleContext->StyleDisplay(); return displayStyle->IsBlockOutsideStyle(); } // Fall back to looking at the tag, in case there is no style information. return nsContentUtils::IsHTMLBlock(aElement); }
--- a/dom/base/nsRange.cpp +++ b/dom/base/nsRange.cpp @@ -3736,18 +3736,18 @@ IsVisibleAndNotInReplacedElement(nsIFram } static bool ElementIsVisibleNoFlush(Element* aElement) { if (!aElement) { return false; } - RefPtr<nsStyleContext> sc = - nsComputedDOMStyle::GetStyleContextNoFlush(aElement, nullptr); + RefPtr<ComputedStyle> sc = + nsComputedDOMStyle::GetComputedStyleNoFlush(aElement, nullptr); return sc && sc->StyleVisibility()->IsVisible(); } static void AppendTransformedText(InnerTextAccumulator& aResult, nsIContent* aContainer) { auto textNode = static_cast<CharacterData*>(aContainer);
--- a/dom/base/nsWindowMemoryReporter.cpp +++ b/dom/base/nsWindowMemoryReporter.cpp @@ -437,17 +437,17 @@ CollectWindowReports(nsGlobalWindowInner "listeners on nodes and other event targets."); REPORT_SIZE("/layout/line-boxes", mArenaSizes.mLineBoxes, "Memory used by line boxes within a window."); REPORT_SIZE("/layout/rule-nodes", mArenaSizes.mRuleNodes, "Memory used by CSS rule nodes within a window."); - REPORT_SIZE("/layout/style-contexts", mArenaSizes.mStyleContexts, + REPORT_SIZE("/layout/style-contexts", mArenaSizes.mComputedStyles, "Memory used by style contexts within a window."); // There are many different kinds of style structs, but it is likely that // only a few matter. Implement a cutoff so we don't bloat about:memory with // many uninteresting entries. const size_t STYLE_SUNDRIES_THRESHOLD = js::MemoryReportingSundriesThreshold(); @@ -703,17 +703,17 @@ nsWindowMemoryReporter::CollectReports(n windowTotalSizes.mArenaSizes.mLineBoxes, "This is the sum of all windows' 'layout/line-boxes' numbers."); REPORT("window-objects/layout/rule-nodes", windowTotalSizes.mArenaSizes.mRuleNodes, "This is the sum of all windows' 'layout/rule-nodes' numbers."); REPORT("window-objects/layout/style-contexts", - windowTotalSizes.mArenaSizes.mStyleContexts, + windowTotalSizes.mArenaSizes.mComputedStyles, "This is the sum of all windows' 'layout/style-contexts' numbers."); size_t geckoStyleTotal = 0; #define STYLE_STRUCT(name_, cb_) \ geckoStyleTotal += \ windowTotalSizes.mArenaSizes.mGeckoStyleSizes.NS_STYLE_SIZES_FIELD(name_); #define STYLE_STRUCT_LIST_IGNORE_VARIABLES #include "nsStyleStructList.h"
--- a/dom/base/nsWindowSizes.h +++ b/dom/base/nsWindowSizes.h @@ -98,17 +98,17 @@ struct nsStyleSizes }; #define NS_ARENA_SIZES_FIELD(classname) mArena##classname struct nsArenaSizes { #define FOR_EACH_SIZE(macro) \ macro(Other, mLineBoxes) \ macro(Style, mRuleNodes) \ - macro(Style, mStyleContexts) + macro(Style, mComputedStyles) nsArenaSizes() : FOR_EACH_SIZE(ZERO_SIZE) #define FRAME_ID(classname, ...) \ NS_ARENA_SIZES_FIELD(classname)(0), #define ABSTRACT_FRAME_ID(...)
--- a/dom/base/nsXHTMLContentSerializer.cpp +++ b/dom/base/nsXHTMLContentSerializer.cpp @@ -715,18 +715,18 @@ nsXHTMLContentSerializer::MaybeLeaveFrom bool nsXHTMLContentSerializer::IsElementPreformatted(nsIContent* aNode) { MOZ_ASSERT(ShouldMaintainPreLevel(), "We should not be calling this needlessly"); if (!aNode->IsElement()) { return false; } - RefPtr<nsStyleContext> styleContext = - nsComputedDOMStyle::GetStyleContextNoFlush(aNode->AsElement(), nullptr); + RefPtr<ComputedStyle> styleContext = + nsComputedDOMStyle::GetComputedStyleNoFlush(aNode->AsElement(), nullptr); if (styleContext) { const nsStyleText* textStyle = styleContext->StyleText(); return textStyle->WhiteSpaceOrNewlineIsSignificant(); } return false; } bool
--- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -1170,18 +1170,18 @@ CanvasRenderingContext2D::ParseColor(con if (!ServoCSSParser::ComputeColor(set, NS_RGB(0, 0, 0), aString, aColor, &wasCurrentColor, loader)) { return false; } if (wasCurrentColor && mCanvasElement) { // Otherwise, get the value of the color property, flushing style // if necessary. - RefPtr<nsStyleContext> canvasStyle = - nsComputedDOMStyle::GetStyleContext(mCanvasElement, nullptr); + RefPtr<ComputedStyle> canvasStyle = + nsComputedDOMStyle::GetComputedStyle(mCanvasElement, nullptr); if (canvasStyle) { *aColor = canvasStyle->StyleColor()->mColor; } // Beware that the presShell could be gone here. } return true; } @@ -1950,18 +1950,18 @@ CanvasRenderingContext2D::ClearTarget() SetInitialState(); if (!mCanvasElement || !mCanvasElement->IsInComposedDoc()) { return; } // For vertical writing-mode, unless text-orientation is sideways, // we'll modify the initial value of textBaseline to 'middle'. - RefPtr<nsStyleContext> canvasStyle = - nsComputedDOMStyle::GetStyleContext(mCanvasElement, nullptr); + RefPtr<ComputedStyle> canvasStyle = + nsComputedDOMStyle::GetComputedStyle(mCanvasElement, nullptr); if (canvasStyle) { WritingMode wm(canvasStyle); if (wm.IsVertical() && !wm.IsSideways()) { CurrentState().textBaseline = TextBaseline::MIDDLE; } } } @@ -2678,17 +2678,17 @@ CreateDeclarationForServo(nsCSSPropertyI static already_AddRefed<RawServoDeclarationBlock> CreateFontDeclarationForServo(const nsAString& aFont, nsIDocument* aDocument) { return CreateDeclarationForServo(eCSSProperty_font, aFont, aDocument); } -static already_AddRefed<ServoStyleContext> +static already_AddRefed<ComputedStyle> GetFontStyleForServo(Element* aElement, const nsAString& aFont, nsIPresShell* aPresShell, nsAString& aOutUsedFont, ErrorResult& aError) { MOZ_ASSERT(aPresShell->StyleSet()->IsServo()); RefPtr<RawServoDeclarationBlock> declarations = @@ -2703,21 +2703,21 @@ GetFontStyleForServo(Element* aElement, // at font-size-adjust, which the font shorthand resets to 'none'. if (Servo_DeclarationBlock_HasCSSWideKeyword(declarations, eCSSProperty_font_size_adjust)) { return nullptr; } ServoStyleSet* styleSet = aPresShell->StyleSet()->AsServo(); - RefPtr<nsStyleContext> parentStyle; + RefPtr<ComputedStyle> parentStyle; // have to get a parent style context for inherit-like relative // values (2em, bolder, etc.) if (aElement && aElement->IsInComposedDoc()) { - parentStyle = nsComputedDOMStyle::GetStyleContext(aElement, nullptr); + parentStyle = nsComputedDOMStyle::GetComputedStyle(aElement, nullptr); if (!parentStyle) { // The flush killed the shell, so we couldn't get any meaningful style // back. aError.Throw(NS_ERROR_FAILURE); return nullptr; } } else { RefPtr<RawServoDeclarationBlock> declarations = @@ -2730,17 +2730,17 @@ GetFontStyleForServo(Element* aElement, } MOZ_RELEASE_ASSERT(parentStyle, "Should have a valid parent style"); MOZ_ASSERT(!aPresShell->IsDestroying(), "We should have returned an error above if the presshell is " "being destroyed."); - RefPtr<ServoStyleContext> sc = + RefPtr<ComputedStyle> sc = styleSet->ResolveForDeclarations(parentStyle->AsServo(), declarations); // The font getter is required to be reserialized based on what we // parsed (including having line-height removed). (Older drafts of // the spec required font sizes be converted to pixels, but that no // longer seems to be required.) Servo_SerializeFontValueForCanvas(declarations, &aOutUsedFont); return sc.forget(); @@ -2749,19 +2749,19 @@ GetFontStyleForServo(Element* aElement, static already_AddRefed<RawServoDeclarationBlock> CreateFilterDeclarationForServo(const nsAString& aFilter, nsIDocument* aDocument) { return CreateDeclarationForServo(eCSSProperty_filter, aFilter, aDocument); } -static already_AddRefed<ServoStyleContext> +static already_AddRefed<ComputedStyle> ResolveFilterStyleForServo(const nsAString& aFilterString, - const ServoStyleContext* aParentStyle, + const ComputedStyle* aParentStyle, nsIPresShell* aPresShell, ErrorResult& aError) { MOZ_ASSERT(aPresShell->StyleSet()->IsServo()); RefPtr<RawServoDeclarationBlock> declarations = CreateFilterDeclarationForServo(aFilterString, aPresShell->GetDocument()); if (!declarations) { @@ -2772,17 +2772,17 @@ ResolveFilterStyleForServo(const nsAStri // In addition to unparseable values, the spec says we need to reject // 'inherit' and 'initial'. if (Servo_DeclarationBlock_HasCSSWideKeyword(declarations, eCSSProperty_filter)) { return nullptr; } ServoStyleSet* styleSet = aPresShell->StyleSet()->AsServo(); - RefPtr<ServoStyleContext> computedValues = + RefPtr<ComputedStyle> computedValues = styleSet->ResolveForDeclarations(aParentStyle, declarations); return computedValues.forget(); } bool CanvasRenderingContext2D::ParseFilter(const nsAString& aString, nsTArray<nsStyleFilter>& aFilterChain, @@ -2804,27 +2804,27 @@ CanvasRenderingContext2D::ParseFilter(co if (presShell->StyleSet()->IsGecko()) { MOZ_CRASH("old style system disabled"); return false; } // For stylo MOZ_ASSERT(presShell->StyleSet()->IsServo()); - RefPtr<ServoStyleContext> parentStyle = + RefPtr<ComputedStyle> parentStyle = GetFontStyleForServo(mCanvasElement, GetFont(), presShell, usedFont, aError); if (!parentStyle) { return false; } - RefPtr<ServoStyleContext> computedValues = + RefPtr<ComputedStyle> computedValues = ResolveFilterStyleForServo(aString, parentStyle, presShell, aError); if (!computedValues) { return false; } @@ -3730,17 +3730,17 @@ CanvasRenderingContext2D::SetFontInterna } nsCOMPtr<nsIPresShell> presShell = GetPresShell(); if (!presShell) { aError.Throw(NS_ERROR_FAILURE); return false; } - RefPtr<nsStyleContext> sc; + RefPtr<ComputedStyle> sc; nsString usedFont; if (presShell->StyleSet()->IsServo()) { sc = GetFontStyleForServo(mCanvasElement, aFont, presShell, usedFont, aError); } else { MOZ_CRASH("old style system disabled"); } if (!sc) { @@ -4300,21 +4300,21 @@ CanvasRenderingContext2D::DrawOrMeasureT // but is less than or equal to zero or equal to NaN. if (aMaxWidth.WasPassed() && (aMaxWidth.Value() <= 0 || IsNaN(aMaxWidth.Value()))) { textToDraw.Truncate(); } // for now, default to ltr if not in doc bool isRTL = false; - RefPtr<nsStyleContext> canvasStyle; + RefPtr<ComputedStyle> canvasStyle; if (mCanvasElement && mCanvasElement->IsInComposedDoc()) { // try to find the closest context canvasStyle = - nsComputedDOMStyle::GetStyleContext(mCanvasElement, nullptr); + nsComputedDOMStyle::GetComputedStyle(mCanvasElement, nullptr); if (!canvasStyle) { return NS_ERROR_FAILURE; } isRTL = canvasStyle->StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL; } else { isRTL = GET_BIDI_OPTION_DIRECTION(document->GetBidiOptions()) == IBMBIDI_TEXTDIRECTION_RTL;
--- a/dom/events/test/test_all_synthetic_events.html +++ b/dom/events/test/test_all_synthetic_events.html @@ -284,16 +284,18 @@ const kEventConstructors = { return new PopupBlockedEvent(aName, aProps); }, }, ProgressEvent: { create: function (aName, aProps) { return new ProgressEvent(aName, aProps); }, }, RTCDataChannelEvent: { create: function (aName, aProps) { + let pc = new RTCPeerConnection(); + aProps.channel = pc.createDataChannel("foo"); return new RTCDataChannelEvent(aName, aProps); }, }, RTCDTMFToneChangeEvent: { create: function (aName, aProps) { return new RTCDTMFToneChangeEvent(aName, aProps); }, }, RTCPeerConnectionIceEvent: { create: function (aName, aProps) {
--- a/dom/html/ImageDocument.cpp +++ b/dom/html/ImageDocument.cpp @@ -1,15 +1,16 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "ImageDocument.h" +#include "mozilla/ComputedStyle.h" #include "mozilla/dom/DOMPrefs.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/ImageDocumentBinding.h" #include "mozilla/dom/HTMLImageElement.h" #include "mozilla/dom/MouseEvent.h" #include "nsRect.h" #include "nsIImageLoadingContent.h" #include "nsGenericHTMLElement.h" @@ -21,17 +22,16 @@ #include "nsIFrame.h" #include "nsGkAtoms.h" #include "imgIRequest.h" #include "imgILoader.h" #include "imgIContainer.h" #include "imgINotificationObserver.h" #include "nsIPresShell.h" #include "nsPresContext.h" -#include "nsStyleContext.h" #include "nsIChannel.h" #include "nsIContentPolicy.h" #include "nsContentPolicyUtils.h" #include "nsPIDOMWindow.h" #include "nsIDOMElement.h" #include "nsError.h" #include "nsURILoader.h" #include "nsIDocShell.h"
--- a/dom/html/reftests/reftest.list +++ b/dom/html/reftests/reftest.list @@ -39,17 +39,17 @@ skip-if(Android) == 649134-2.html 649134 == image-load-shortcircuit-1.html image-load-shortcircuit-ref.html == image-load-shortcircuit-2.html image-load-shortcircuit-ref.html # Test that image documents taken into account CSS properties like # image-orientation when determining the size of the image. # (Fuzzy necessary due to pixel-wise comparison of different JPEGs. # The vast majority of the fuzziness comes from Linux and WinXP.) fuzzy(1,149) == bug917595-iframe-1.html bug917595-1-ref.html -fuzzy(3,640) fuzzy-if(skiaContent,3,7544) fuzzy-if(webrender,10-10,10916-10916) == bug917595-exif-rotated.jpg bug917595-pixel-rotated.jpg # bug 1060869 +fuzzy(3,640) fuzzy-if(skiaContent,3,7544) fuzzy-if(webrender,3-3,7544-7544) == bug917595-exif-rotated.jpg bug917595-pixel-rotated.jpg # bug 1060869 # Test support for SVG-as-image in <picture> elements. == bug1106522-1.html bug1106522-ref.html == bug1106522-2.html bug1106522-ref.html == href-attr-change-restyles.html href-attr-change-restyles-ref.html == figure.html figure-ref.html == pre-1.html pre-1-ref.html
--- a/dom/smil/nsSMILCSSProperty.cpp +++ b/dom/smil/nsSMILCSSProperty.cpp @@ -18,20 +18,20 @@ #include "nsCSSProps.h" using namespace mozilla; using namespace mozilla::dom; // Class Methods nsSMILCSSProperty::nsSMILCSSProperty(nsCSSPropertyID aPropID, Element* aElement, - nsStyleContext* aBaseStyleContext) + ComputedStyle* aBaseComputedStyle) : mPropID(aPropID) , mElement(aElement) - , mBaseStyleContext(aBaseStyleContext) + , mBaseComputedStyle(aBaseComputedStyle) { MOZ_ASSERT(IsPropertyAnimatable(mPropID, aElement->OwnerDoc()->GetStyleBackendType()), "Creating a nsSMILCSSProperty for a property " "that's not supported for animation"); } nsSMILValue @@ -42,17 +42,17 @@ nsSMILCSSProperty::GetBaseValue() const // from ALL return points. This function must only return THIS variable: nsSMILValue baseValue; // SPECIAL CASE: (a) Shorthands // (b) 'display' // (c) No base style context if (nsCSSProps::IsShorthand(mPropID) || mPropID == eCSSProperty_display || - !mBaseStyleContext) { + !mBaseComputedStyle) { // We can't look up the base (computed-style) value of shorthand // properties because they aren't guaranteed to have a consistent computed // value. // // Also, although we can look up the base value of the display property, // doing so involves clearing and resetting the property which can cause // frames to be recreated which we'd like to avoid. // @@ -64,17 +64,17 @@ nsSMILCSSProperty::GetBaseValue() const nsSMILValue tmpVal(&nsSMILCSSValueType::sSingleton); Swap(baseValue, tmpVal); return baseValue; } AnimationValue computedValue; if (mElement->IsStyledByServo()) { computedValue.mServo = - Servo_ComputedValues_ExtractAnimationValue(mBaseStyleContext->AsServo(), mPropID) + Servo_ComputedValues_ExtractAnimationValue(mBaseComputedStyle->AsServo(), mPropID) .Consume(); if (!computedValue.mServo) { return baseValue; } } else { MOZ_CRASH("old style system disabled"); }
--- a/dom/smil/nsSMILCSSProperty.h +++ b/dom/smil/nsSMILCSSProperty.h @@ -11,19 +11,18 @@ #include "mozilla/Attributes.h" #include "mozilla/StyleBackendType.h" #include "nsISMILAttr.h" #include "nsAtom.h" #include "nsCSSPropertyID.h" #include "nsCSSValue.h" -class nsStyleContext; - namespace mozilla { +class ComputedStyle; namespace dom { class Element; } // namespace dom } // namespace mozilla /** * nsSMILCSSProperty: Implements the nsISMILAttr interface for SMIL animations * that target CSS properties. Represents a particular animation-targeted CSS @@ -31,24 +30,24 @@ class Element; */ class nsSMILCSSProperty : public nsISMILAttr { public: /** * Constructs a new nsSMILCSSProperty. * @param aPropID The CSS property we're interested in animating. * @param aElement The element whose CSS property is being animated. - * @param aBaseStyleContext The style context to use when getting the base - * value. If this is nullptr and GetBaseValue is - * called, an empty nsSMILValue initialized with - * the nsSMILCSSValueType will be returned. + * @param aBaseComputedStyle The style context to use when getting the base + * value. If this is nullptr and GetBaseValue is + * called, an empty nsSMILValue initialized with + * the nsSMILCSSValueType will be returned. */ nsSMILCSSProperty(nsCSSPropertyID aPropID, mozilla::dom::Element* aElement, - nsStyleContext* aBaseStyleContext); + mozilla::ComputedStyle* aBaseComputedStyle); // nsISMILAttr methods virtual nsresult ValueFromString(const nsAString& aStr, const mozilla::dom::SVGAnimationElement* aSrcElement, nsSMILValue& aValue, bool& aPreventCachingOfSandwich) const override; virtual nsSMILValue GetBaseValue() const override; virtual nsresult SetAnimValue(const nsSMILValue& aValue) override; @@ -71,16 +70,17 @@ public: protected: nsCSSPropertyID mPropID; // Using non-refcounted pointer for mElement -- we know mElement will stay // alive for my lifetime because a nsISMILAttr (like me) only lives as long // as the Compositing step, and DOM elements don't get a chance to die during // that time. mozilla::dom::Element* mElement; - // The style context to use when fetching base styles. + // The style to use when fetching base styles. + // // As with mElement, since an nsISMILAttr only lives as long as the // compositing step and since ComposeAttribute holds an owning reference to // the base style context, we can use a non-owning reference here. - nsStyleContext* mBaseStyleContext; + mozilla::ComputedStyle* mBaseComputedStyle; }; #endif // NS_SMILCSSPROPERTY_H_
--- a/dom/smil/nsSMILCSSValueType.cpp +++ b/dom/smil/nsSMILCSSValueType.cpp @@ -21,16 +21,17 @@ #include "mozilla/ServoCSSParser.h" #include "mozilla/StyleSetHandleInlines.h" #include "mozilla/dom/BaseKeyframeTypesBinding.h" // For CompositeOperation #include "mozilla/dom/Element.h" #include "nsDebug.h" #include "nsStyleUtil.h" #include "nsIDocument.h" +using namespace mozilla; using namespace mozilla::dom; using mozilla::StyleAnimationValue; typedef AutoTArray<RefPtr<RawServoAnimationValue>, 1> ServoAnimationValues; /*static*/ nsSMILCSSValueType nsSMILCSSValueType::sSingleton; struct ValueWrapper { @@ -490,17 +491,17 @@ GetPresContextForElement(Element* aElem) return doc->GetPresContext(); } static ServoAnimationValues ValueFromStringHelper(nsCSSPropertyID aPropID, Element* aTargetElement, nsPresContext* aPresContext, - nsStyleContext* aStyleContext, + ComputedStyle* aComputedStyle, const nsAString& aString) { ServoAnimationValues result; nsIDocument* doc = aTargetElement->GetUncomposedDoc(); if (!doc) { return result; } @@ -514,17 +515,17 @@ ValueFromStringHelper(nsCSSPropertyID aP ParsingMode::AllowAllNumericValues); if (!servoDeclarationBlock) { return result; } // Compute value aPresContext->StyleSet()->AsServo()->GetAnimationValues(servoDeclarationBlock, aTargetElement, - aStyleContext->AsServo(), + aComputedStyle->AsServo(), result); return result; } // static void nsSMILCSSValueType::ValueFromString(nsCSSPropertyID aPropID, @@ -544,40 +545,35 @@ nsSMILCSSValueType::ValueFromString(nsCS if (doc && !nsStyleUtil::CSPAllowsInlineStyle(nullptr, doc->NodePrincipal(), nullptr, doc->GetDocumentURI(), 0, aString, nullptr)) { return; } - RefPtr<nsStyleContext> styleContext = - nsComputedDOMStyle::GetStyleContext(aTargetElement, nullptr); + RefPtr<ComputedStyle> styleContext = + nsComputedDOMStyle::GetComputedStyle(aTargetElement, nullptr); if (!styleContext) { return; } - if (styleContext->IsServo()) { - ServoAnimationValues parsedValues = - ValueFromStringHelper(aPropID, aTargetElement, presContext, - styleContext, aString); - if (aIsContextSensitive) { - // FIXME: Bug 1358955 - detect context-sensitive values and set this value - // appropriately. - *aIsContextSensitive = false; - } - - if (!parsedValues.IsEmpty()) { - sSingleton.Init(aValue); - aValue.mU.mPtr = new ValueWrapper(aPropID, Move(parsedValues)); - } - return; + ServoAnimationValues parsedValues = + ValueFromStringHelper(aPropID, aTargetElement, presContext, + styleContext, aString); + if (aIsContextSensitive) { + // FIXME: Bug 1358955 - detect context-sensitive values and set this value + // appropriately. + *aIsContextSensitive = false; } - MOZ_CRASH("old style system disabled"); + if (!parsedValues.IsEmpty()) { + sSingleton.Init(aValue); + aValue.mU.mPtr = new ValueWrapper(aPropID, Move(parsedValues)); + } } // static nsSMILValue nsSMILCSSValueType::ValueFromAnimationValue(nsCSSPropertyID aPropID, Element* aTargetElement, const AnimationValue& aValue) {
--- a/dom/smil/nsSMILCompositor.cpp +++ b/dom/smil/nsSMILCompositor.cpp @@ -52,26 +52,26 @@ nsSMILCompositor::AddAnimationFunction(n void nsSMILCompositor::ComposeAttribute(bool& aMightHavePendingStyleUpdates) { if (!mKey.mElement) return; // If we might need to resolve base styles, grab a suitable style context // for initializing our nsISMILAttr with. - RefPtr<nsStyleContext> baseStyleContext; + RefPtr<ComputedStyle> baseComputedStyle; if (MightNeedBaseStyle()) { - baseStyleContext = - nsComputedDOMStyle::GetUnanimatedStyleContextNoFlush(mKey.mElement, - nullptr); + baseComputedStyle = + nsComputedDOMStyle::GetUnanimatedComputedStyleNoFlush(mKey.mElement, + nullptr); } // FIRST: Get the nsISMILAttr (to grab base value from, and to eventually // give animated value to) - UniquePtr<nsISMILAttr> smilAttr = CreateSMILAttr(baseStyleContext); + UniquePtr<nsISMILAttr> smilAttr = CreateSMILAttr(baseComputedStyle); if (!smilAttr) { // Target attribute not found (or, out of memory) return; } if (mAnimationFunctions.IsEmpty()) { // No active animation functions. (We can still have a nsSMILCompositor in // that case if an animation function has *just* become inactive) smilAttr->ClearAnimValue(); @@ -129,23 +129,23 @@ nsSMILCompositor::ClearAnimationEffects( return; } smilAttr->ClearAnimValue(); } // Protected Helper Functions // -------------------------- UniquePtr<nsISMILAttr> -nsSMILCompositor::CreateSMILAttr(nsStyleContext* aBaseStyleContext) +nsSMILCompositor::CreateSMILAttr(ComputedStyle* aBaseComputedStyle) { nsCSSPropertyID propID = GetCSSPropertyToAnimate(); if (propID != eCSSProperty_UNKNOWN) { return MakeUnique<nsSMILCSSProperty>(propID, mKey.mElement.get(), - aBaseStyleContext); + aBaseComputedStyle); } return mKey.mElement->GetAnimatedAttr(mKey.mAttributeNamespaceID, mKey.mAttributeName); } nsCSSPropertyID nsSMILCompositor::GetCSSPropertyToAnimate() const
--- a/dom/smil/nsSMILCompositor.h +++ b/dom/smil/nsSMILCompositor.h @@ -70,20 +70,20 @@ public: // Transfers |aOther|'s mCachedBaseValue to |this| void StealCachedBaseValue(nsSMILCompositor* aOther) { mCachedBaseValue = mozilla::Move(aOther->mCachedBaseValue); } private: // Create a nsISMILAttr for my target, on the heap. // - // @param aBaseStyleContext An optional style context which, if set, will be + // @param aBaseComputedStyle An optional style context which, if set, will be // used when fetching the base style. mozilla::UniquePtr<nsISMILAttr> - CreateSMILAttr(nsStyleContext* aBaseStyleContext); + CreateSMILAttr(mozilla::ComputedStyle* aBaseComputedStyle); // Returns the CSS property this compositor should animate, or // eCSSProperty_UNKNOWN if this compositor does not animate a CSS property. nsCSSPropertyID GetCSSPropertyToAnimate() const; // Returns true if we might need to refer to base styles (i.e. we are // targeting a CSS property and have one or more animation functions that // don't just replace the underlying value).
--- a/dom/svg/SVGContentUtils.cpp +++ b/dom/svg/SVGContentUtils.cpp @@ -23,17 +23,17 @@ #include "nsLayoutUtils.h" #include "nsMathUtils.h" #include "SVGAnimationElement.h" #include "SVGAnimatedPreserveAspectRatio.h" #include "nsContentUtils.h" #include "mozilla/gfx/2D.h" #include "mozilla/gfx/Types.h" #include "mozilla/FloatingPoint.h" -#include "nsStyleContext.h" +#include "mozilla/ComputedStyle.h" #include "nsSVGPathDataParser.h" #include "SVGPathData.h" #include "SVGPathElement.h" using namespace mozilla; using namespace mozilla::dom; using namespace mozilla::dom::SVGPreserveAspectRatioBinding; using namespace mozilla::gfx; @@ -166,26 +166,26 @@ GetStrokeDashData(SVGContentUtils::AutoS } return eDashedStroke; } void SVGContentUtils::GetStrokeOptions(AutoStrokeOptions* aStrokeOptions, nsSVGElement* aElement, - nsStyleContext* aStyleContext, + ComputedStyle* aComputedStyle, SVGContextPaint* aContextPaint, StrokeOptionFlags aFlags) { - RefPtr<nsStyleContext> styleContext; - if (aStyleContext) { - styleContext = aStyleContext; + RefPtr<ComputedStyle> styleContext; + if (aComputedStyle) { + styleContext = aComputedStyle; } else { styleContext = - nsComputedDOMStyle::GetStyleContextNoFlush(aElement, nullptr); + nsComputedDOMStyle::GetComputedStyleNoFlush(aElement, nullptr); } if (!styleContext) { return; } const nsStyleSVG* styleSVG = styleContext->StyleSVG(); @@ -240,25 +240,25 @@ SVGContentUtils::GetStrokeOptions(AutoSt aStrokeOptions->mLineCap = CapStyle::SQUARE; break; } } } Float SVGContentUtils::GetStrokeWidth(nsSVGElement* aElement, - nsStyleContext* aStyleContext, + ComputedStyle* aComputedStyle, SVGContextPaint* aContextPaint) { - RefPtr<nsStyleContext> styleContext; - if (aStyleContext) { - styleContext = aStyleContext; + RefPtr<ComputedStyle> styleContext; + if (aComputedStyle) { + styleContext = aComputedStyle; } else { styleContext = - nsComputedDOMStyle::GetStyleContextNoFlush(aElement, nullptr); + nsComputedDOMStyle::GetComputedStyleNoFlush(aElement, nullptr); } if (!styleContext) { return 0.0f; } const nsStyleSVG* styleSVG = styleContext->StyleSVG(); @@ -270,81 +270,81 @@ SVGContentUtils::GetStrokeWidth(nsSVGEle } float SVGContentUtils::GetFontSize(Element *aElement) { if (!aElement) return 1.0f; - RefPtr<nsStyleContext> styleContext = - nsComputedDOMStyle::GetStyleContextNoFlush(aElement, nullptr); + RefPtr<ComputedStyle> styleContext = + nsComputedDOMStyle::GetComputedStyleNoFlush(aElement, nullptr); if (!styleContext) { // ReportToConsole NS_WARNING("Couldn't get style context for content in GetFontStyle"); return 1.0f; } return GetFontSize(styleContext); } float SVGContentUtils::GetFontSize(nsIFrame *aFrame) { MOZ_ASSERT(aFrame, "NULL frame in GetFontSize"); - return GetFontSize(aFrame->StyleContext()); + return GetFontSize(aFrame->Style()); } float -SVGContentUtils::GetFontSize(nsStyleContext *aStyleContext) +SVGContentUtils::GetFontSize(ComputedStyle *aComputedStyle) { - MOZ_ASSERT(aStyleContext, "NULL style context in GetFontSize"); + MOZ_ASSERT(aComputedStyle, "NULL style context in GetFontSize"); - nsPresContext *presContext = aStyleContext->PresContext(); + nsPresContext *presContext = aComputedStyle->PresContext(); MOZ_ASSERT(presContext, "NULL pres context in GetFontSize"); - nscoord fontSize = aStyleContext->StyleFont()->mSize; + nscoord fontSize = aComputedStyle->StyleFont()->mSize; return nsPresContext::AppUnitsToFloatCSSPixels(fontSize) / presContext->EffectiveTextZoom(); } float SVGContentUtils::GetFontXHeight(Element *aElement) { if (!aElement) return 1.0f; - RefPtr<nsStyleContext> styleContext = - nsComputedDOMStyle::GetStyleContextNoFlush(aElement, nullptr); + RefPtr<ComputedStyle> styleContext = + nsComputedDOMStyle::GetComputedStyleNoFlush(aElement, nullptr); if (!styleContext) { // ReportToConsole NS_WARNING("Couldn't get style context for content in GetFontStyle"); return 1.0f; } return GetFontXHeight(styleContext); } float SVGContentUtils::GetFontXHeight(nsIFrame *aFrame) { MOZ_ASSERT(aFrame, "NULL frame in GetFontXHeight"); - return GetFontXHeight(aFrame->StyleContext()); + return GetFontXHeight(aFrame->Style()); } float -SVGContentUtils::GetFontXHeight(nsStyleContext *aStyleContext) +SVGContentUtils::GetFontXHeight(ComputedStyle *aComputedStyle) { - MOZ_ASSERT(aStyleContext, "NULL style context in GetFontXHeight"); + MOZ_ASSERT(aComputedStyle, "NULL style context in GetFontXHeight"); - nsPresContext *presContext = aStyleContext->PresContext(); + nsPresContext *presContext = aComputedStyle->PresContext(); MOZ_ASSERT(presContext, "NULL pres context in GetFontXHeight"); RefPtr<nsFontMetrics> fontMetrics = - nsLayoutUtils::GetFontMetricsForStyleContext(aStyleContext); + nsLayoutUtils::GetFontMetricsForComputedStyle(aComputedStyle); if (!fontMetrics) { // ReportToConsole NS_WARNING("no FontMetrics in GetFontXHeight()"); return 1.0f; } nscoord xHeight = fontMetrics->XHeight();
--- a/dom/svg/SVGContentUtils.h +++ b/dom/svg/SVGContentUtils.h @@ -15,21 +15,21 @@ #include "mozilla/RangedPtr.h" #include "nsError.h" #include "nsStringFwd.h" #include "gfx2DGlue.h" class nsIContent; class nsIDocument; class nsIFrame; -class nsStyleContext; class nsStyleCoord; class nsSVGElement; namespace mozilla { +class ComputedStyle; class nsSVGAnimatedTransformList; class SVGAnimatedPreserveAspectRatio; class SVGContextPaint; class SVGPreserveAspectRatio; namespace dom { class Element; class SVGSVGElement; class SVGViewportElement; @@ -70,16 +70,17 @@ enum SVGTransformTypes { /** * Functions generally used by SVG Content classes. Functions here * should not generally depend on layout methods/classes e.g. nsSVGUtils */ class SVGContentUtils { public: + typedef mozilla::ComputedStyle ComputedStyle; typedef mozilla::gfx::Float Float; typedef mozilla::gfx::Matrix Matrix; typedef mozilla::gfx::Rect Rect; typedef mozilla::gfx::StrokeOptions StrokeOptions; typedef mozilla::SVGAnimatedPreserveAspectRatio SVGAnimatedPreserveAspectRatio; typedef mozilla::SVGPreserveAspectRatio SVGPreserveAspectRatio; /* @@ -150,53 +151,53 @@ public: /** * Note: the linecap style returned in aStrokeOptions is not valid when * ShapeTypeHasNoCorners(aElement) == true && aFlags == eIgnoreStrokeDashing, * since when aElement has no corners the rendered linecap style depends on * whether or not the stroke is dashed. */ static void GetStrokeOptions(AutoStrokeOptions* aStrokeOptions, nsSVGElement* aElement, - nsStyleContext* aStyleContext, + ComputedStyle* aComputedStyle, mozilla::SVGContextPaint* aContextPaint, StrokeOptionFlags aFlags = eAllStrokeOptions); /** * Returns the current computed value of the CSS property 'stroke-width' for - * the given element. aStyleContext may be provided as an optimization. + * the given element. aComputedStyle may be provided as an optimization. * aContextPaint is also optional. * * Note that this function does NOT take account of the value of the 'stroke' * and 'stroke-opacity' properties to, say, return zero if they are "none" or * "0", respectively. */ static Float GetStrokeWidth(nsSVGElement* aElement, - nsStyleContext* aStyleContext, + ComputedStyle* aComputedStyle, mozilla::SVGContextPaint* aContextPaint); /* * Get the number of CSS px (user units) per em (i.e. the em-height in user * units) for an nsIContent * * XXX document the conditions under which these may fail, and what they * return in those cases. */ static float GetFontSize(mozilla::dom::Element *aElement); static float GetFontSize(nsIFrame *aFrame); - static float GetFontSize(nsStyleContext *aStyleContext); + static float GetFontSize(ComputedStyle *aComputedStyle); /* * Get the number of CSS px (user units) per ex (i.e. the x-height in user * units) for an nsIContent * * XXX document the conditions under which these may fail, and what they * return in those cases. */ static float GetFontXHeight(mozilla::dom::Element *aElement); static float GetFontXHeight(nsIFrame *aFrame); - static float GetFontXHeight(nsStyleContext *aStyleContext); + static float GetFontXHeight(ComputedStyle *aComputedStyle); /* * Report a localized error message to the error console. */ static nsresult ReportToConsole(nsIDocument* doc, const char* aWarning, const char16_t **aParams, uint32_t aParamsLength);
--- a/dom/svg/SVGFEDropShadowElement.cpp +++ b/dom/svg/SVGFEDropShadowElement.cpp @@ -104,17 +104,17 @@ SVGFEDropShadowElement::GetPrimitiveDesc SVGContentUtils::Y, &mNumberAttributes[DY]))); FilterPrimitiveDescription descr(PrimitiveType::DropShadow); descr.Attributes().Set(eDropShadowStdDeviation, Size(stdX, stdY)); descr.Attributes().Set(eDropShadowOffset, offset); nsIFrame* frame = GetPrimaryFrame(); if (frame) { - nsStyleContext* style = frame->StyleContext(); + ComputedStyle* style = frame->Style(); Color color(Color::FromABGR(style->StyleSVGReset()->mFloodColor)); color.a *= style->StyleSVGReset()->mFloodOpacity; descr.Attributes().Set(eDropShadowColor, color); } else { descr.Attributes().Set(eDropShadowColor, Color()); } return descr; }
--- a/dom/svg/SVGFEFloodElement.cpp +++ b/dom/svg/SVGFEFloodElement.cpp @@ -38,17 +38,17 @@ FilterPrimitiveDescription SVGFEFloodElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstance, const IntRect& aFilterSubregion, const nsTArray<bool>& aInputsAreTainted, nsTArray<RefPtr<SourceSurface>>& aInputImages) { FilterPrimitiveDescription descr(PrimitiveType::Flood); nsIFrame* frame = GetPrimaryFrame(); if (frame) { - nsStyleContext* style = frame->StyleContext(); + ComputedStyle* style = frame->Style(); Color color(Color::FromABGR(style->StyleSVGReset()->mFloodColor)); color.a *= style->StyleSVGReset()->mFloodOpacity; descr.Attributes().Set(eFloodColor, color); } else { descr.Attributes().Set(eFloodColor, Color()); } return descr; }
--- a/dom/svg/SVGGeometryElement.cpp +++ b/dom/svg/SVGGeometryElement.cpp @@ -133,18 +133,18 @@ SVGGeometryElement::GetOrBuildPathForMea return GetOrBuildPath(drawTarget, fillRule); } FillRule SVGGeometryElement::GetFillRule() { FillRule fillRule = FillRule::FILL_WINDING; // Equivalent to StyleFillRule::Nonzero - RefPtr<nsStyleContext> styleContext = - nsComputedDOMStyle::GetStyleContextNoFlush(this, nullptr); + RefPtr<ComputedStyle> styleContext = + nsComputedDOMStyle::GetComputedStyleNoFlush(this, nullptr); if (styleContext) { MOZ_ASSERT(styleContext->StyleSVG()->mFillRule == StyleFillRule::Nonzero || styleContext->StyleSVG()->mFillRule == StyleFillRule::Evenodd); if (styleContext->StyleSVG()->mFillRule == StyleFillRule::Evenodd) { fillRule = FillRule::FILL_EVEN_ODD; }
--- a/dom/svg/SVGPathElement.cpp +++ b/dom/svg/SVGPathElement.cpp @@ -293,18 +293,18 @@ SVGPathElement::BuildPath(PathBuilder* a // spec regarding zero length sub-paths when square line caps are in use, // SVGPathData needs to know our stroke-linecap style and, if "square", then // also our stroke width. See the comment for // ApproximateZeroLengthSubpathSquareCaps for more info. uint8_t strokeLineCap = NS_STYLE_STROKE_LINECAP_BUTT; Float strokeWidth = 0; - RefPtr<nsStyleContext> styleContext = - nsComputedDOMStyle::GetStyleContextNoFlush(this, nullptr); + RefPtr<ComputedStyle> styleContext = + nsComputedDOMStyle::GetComputedStyleNoFlush(this, nullptr); if (styleContext) { const nsStyleSVG* style = styleContext->StyleSVG(); // Note: the path that we return may be used for hit-testing, and SVG // exposes hit-testing of strokes that are not actually painted. For that // reason we do not check for eStyleSVGPaintType_None or check the stroke // opacity here. if (style->mStrokeLinecap != NS_STYLE_STROKE_LINECAP_BUTT) { strokeLineCap = style->mStrokeLinecap;
--- a/dom/svg/nsSVGFilters.cpp +++ b/dom/svg/nsSVGFilters.cpp @@ -17,17 +17,17 @@ #include "nsSVGFilterInstance.h" #include "nsSVGEnum.h" #include "SVGNumberList.h" #include "SVGAnimatedNumberList.h" #include "DOMSVGAnimatedNumberList.h" #include "nsSVGFilters.h" #include "nsLayoutUtils.h" #include "nsSVGUtils.h" -#include "nsStyleContext.h" +#include "mozilla/ComputedStyle.h" #include "nsIFrame.h" #include "imgIContainer.h" #include "mozilla/dom/SVGFilterElement.h" #include "nsSVGString.h" #include "SVGContentUtils.h" #include <algorithm> #include "mozilla/dom/SVGAnimatedLength.h" #include "mozilla/dom/SVGComponentTransferFunctionElement.h" @@ -156,17 +156,17 @@ nsSVGFE::IsAttributeMapped(const nsAtom* bool nsSVGFE::StyleIsSetToSRGB() { nsIFrame* frame = GetPrimaryFrame(); if (!frame) return false; - nsStyleContext* style = frame->StyleContext(); + ComputedStyle* style = frame->Style(); return style->StyleSVG()->mColorInterpolationFilters == NS_STYLE_COLOR_INTERPOLATION_SRGB; } /* virtual */ bool nsSVGFE::HasValidDimensions() const { return (!mLengthAttributes[ATTR_WIDTH].IsExplicitlySet() || @@ -497,17 +497,17 @@ FilterPrimitiveDescription nsSVGFELightingElement::AddLightingAttributes(const FilterPrimitiveDescription& aDescription, nsSVGFilterInstance* aInstance) { nsIFrame* frame = GetPrimaryFrame(); if (!frame) { return FilterPrimitiveDescription(PrimitiveType::Empty); } - nsStyleContext* style = frame->StyleContext(); + ComputedStyle* style = frame->Style(); Color color(Color::FromABGR(style->StyleSVGReset()->mLightingColor)); color.a = 1.f; float surfaceScale = mNumberAttributes[SURFACE_SCALE].GetAnimValue(); Size kernelUnitLength = GetKernelUnitLength(aInstance, &mNumberPairAttributes[KERNEL_UNIT_LENGTH]); if (kernelUnitLength.width <= 0 || kernelUnitLength.height <= 0) { // According to spec, A negative or zero value is an error. See link below for details.
--- a/dom/webidl/RTCDataChannelEvent.webidl +++ b/dom/webidl/RTCDataChannelEvent.webidl @@ -3,16 +3,16 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. * * The origin of this IDL file is * http://dev.w3.org/2011/webrtc/editor/webrtc.html#idl-def-RTCDataChannelEvent */ dictionary RTCDataChannelEventInit : EventInit { - RTCDataChannel? channel = null; + required RTCDataChannel channel; }; [Pref="media.peerconnection.enabled", - Constructor(DOMString type, optional RTCDataChannelEventInit eventInitDict)] + Constructor(DOMString type, RTCDataChannelEventInit eventInitDict)] interface RTCDataChannelEvent : Event { - readonly attribute RTCDataChannel? channel; + readonly attribute RTCDataChannel channel; };
--- a/dom/xbl/nsXBLResourceLoader.cpp +++ b/dom/xbl/nsXBLResourceLoader.cpp @@ -12,23 +12,23 @@ #include "nsIPresShell.h" #include "nsXBLService.h" #include "nsIServiceManager.h" #include "nsXBLResourceLoader.h" #include "nsXBLPrototypeResources.h" #include "nsIDocumentObserver.h" #include "imgILoader.h" #include "imgRequestProxy.h" +#include "mozilla/ComputedStyle.h" #include "mozilla/StyleSheet.h" #include "mozilla/StyleSheetInlines.h" #include "mozilla/css/Loader.h" #include "nsIURI.h" #include "nsNetUtil.h" #include "nsGkAtoms.h" -#include "nsStyleContext.h" #include "nsXBLPrototypeBinding.h" #include "nsContentUtils.h" #include "nsIScriptSecurityManager.h" using namespace mozilla; NS_IMPL_CYCLE_COLLECTION(nsXBLResourceLoader, mBoundElements) @@ -253,17 +253,17 @@ nsXBLResourceLoader::NotifyBoundElements // has a primary frame and whether it's in the undisplayed map // before sending a ContentInserted notification, or bad things // will happen. nsIPresShell *shell = doc->GetShell(); if (shell) { nsIFrame* childFrame = content->GetPrimaryFrame(); if (!childFrame) { // Check if it's in the display:none or display:contents maps. - nsStyleContext* sc = + ComputedStyle* sc = shell->FrameConstructor()->GetDisplayNoneStyleFor(content); if (!sc) { sc = shell->FrameConstructor()->GetDisplayContentsStyleFor(content); } if (!sc) { shell->PostRecreateFramesFor(content->AsElement());
--- a/dom/xbl/nsXBLService.cpp +++ b/dom/xbl/nsXBLService.cpp @@ -1,15 +1,16 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/ArrayUtils.h" +#include "mozilla/ComputedStyle.h" #include "nsCOMPtr.h" #include "nsNetUtil.h" #include "nsXBLService.h" #include "nsXBLWindowKeyHandler.h" #include "nsIInputStream.h" #include "nsNameSpaceManager.h" #include "nsIURI.h" @@ -36,17 +37,16 @@ #include "nsSyncLoadService.h" #include "nsContentPolicyUtils.h" #include "nsTArray.h" #include "nsError.h" #include "nsIPresShell.h" #include "nsIDocumentObserver.h" #include "nsFrameManager.h" -#include "nsStyleContext.h" #include "nsIScriptSecurityManager.h" #include "nsIScriptError.h" #include "nsXBLSerialize.h" #ifdef MOZ_XUL #include "nsXULPrototypeCache.h" #endif #include "nsIDOMEventListener.h"
--- a/dom/xul/nsXULElement.cpp +++ b/dom/xul/nsXULElement.cpp @@ -666,54 +666,35 @@ nsXULElement::UpdateEditableState(bool a // Don't call through to Element here because the things // it does don't work for cases when we're an editable control. nsIContent *parent = GetParent(); SetEditableFlag(parent && parent->HasFlag(NODE_IS_EDITABLE)); UpdateState(aNotify); } +#ifdef DEBUG /** * Returns true if the user-agent style sheet rules for this XUL element are * in minimal-xul.css instead of xul.css. */ static inline bool XULElementsRulesInMinimalXULSheet(nsAtom* aTag) { return // scrollbar parts: aTag == nsGkAtoms::scrollbar || aTag == nsGkAtoms::scrollbarbutton || aTag == nsGkAtoms::scrollcorner || aTag == nsGkAtoms::slider || aTag == nsGkAtoms::thumb || - aTag == nsGkAtoms::scale || // other aTag == nsGkAtoms::datetimebox || aTag == nsGkAtoms::resizer || aTag == nsGkAtoms::label || aTag == nsGkAtoms::videocontrols; } - -#ifdef DEBUG -/** - * Returns true if aElement is a XUL element created by the video controls - * binding. HTML <video> and <audio> bindings pull in this binding. This - * binding creates lots of different types of XUL elements. - */ -static inline bool -IsInVideoControls(nsXULElement* aElement) -{ - nsIContent* ancestor = aElement->GetParent(); - while (ancestor) { - if (ancestor->NodeInfo()->Equals(nsGkAtoms::videocontrols, kNameSpaceID_XUL)) { - return true; - } - ancestor = ancestor->GetParent(); - } - return false; -} #endif class XULInContentErrorReporter : public Runnable { public: explicit XULInContentErrorReporter(nsIDocument* aDocument) : mozilla::Runnable("XULInContentErrorReporter") , mDocument(aDocument) @@ -758,47 +739,33 @@ nsXULElement::BindToTree(nsIDocument* aD } nsresult rv = nsStyledElement::BindToTree(aDocument, aParent, aBindingParent, aCompileEventHandlers); NS_ENSURE_SUCCESS(rv, rv); nsIDocument* doc = GetComposedDoc(); +#ifdef DEBUG if (doc && !doc->LoadsFullXULStyleSheetUpFront() && !doc->IsUnstyledDocument()) { // To save CPU cycles and memory, non-XUL documents only load the user // agent style sheet rules for a minimal set of XUL elements such as // 'scrollbar' that may be created implicitly for their content (those - // rules being in minimal-xul.css). This is where we make sure that all - // the other XUL UA style sheet rules (xul.css) have been loaded if the - // minimal set is not sufficient. + // rules being in minimal-xul.css). // - // We do this during binding, not element construction, because elements - // can be moved from the document that creates them to another document. - + // This assertion makes sure no other XUL element than the ones in the + // minimal XUL sheet is used in the bindings. if (!XULElementsRulesInMinimalXULSheet(NodeInfo()->NameAtom())) { - auto cache = nsLayoutStylesheetCache::For(doc->GetStyleBackendType()); - doc->EnsureOnDemandBuiltInUASheet(cache->XULSheet()); - // To keep memory usage down it is important that we try and avoid - // pulling xul.css into non-XUL documents. That should be very rare, and - // for HTML we currently should only pull it in if the document contains - // an <audio> or <video> element. This assertion is here to make sure - // that we don't fail to notice if a change to bindings causes us to - // start pulling in xul.css much more frequently. If this assertion - // fails then we need to figure out why, and how we can continue to avoid - // pulling in xul.css. - // Note that add-ons may introduce bindings that cause this assertion to - // fire. - NS_ASSERTION(IsInVideoControls(this), - "Unexpected XUL element in non-XUL doc"); + NS_ERROR("Unexpected XUL element in non-XUL doc"); } } +#endif if (doc && NeedTooltipSupport(*this)) { AddTooltipSupport(); } if (aDocument) { NS_ASSERTION(!nsContentUtils::IsSafeToRunScript(), "Missing a script blocker!");
--- a/editor/libeditor/EditorBase.cpp +++ b/editor/libeditor/EditorBase.cpp @@ -23,16 +23,17 @@ #include "InsertNodeTransaction.h" // for InsertNodeTransaction #include "InsertTextTransaction.h" // for InsertTextTransaction #include "JoinNodeTransaction.h" // for JoinNodeTransaction #include "PlaceholderTransaction.h" // for PlaceholderTransaction #include "SplitNodeTransaction.h" // for SplitNodeTransaction #include "StyleSheetTransactions.h" // for AddStyleSheetTransaction, etc. #include "TextEditUtils.h" // for TextEditUtils #include "mozilla/CheckedInt.h" // for CheckedInt +#include "mozilla/ComputedStyle.h" // for ComputedStyle #include "mozilla/EditAction.h" // for EditAction #include "mozilla/EditorDOMPoint.h" // for EditorDOMPoint #include "mozilla/EditorSpellCheck.h" // for EditorSpellCheck #include "mozilla/EditorUtils.h" // for AutoRules, etc. #include "mozilla/EditTransactionBase.h" // for EditTransactionBase #include "mozilla/FlushType.h" // for FlushType::Frames #include "mozilla/IMEContentObserver.h" // for IMEContentObserver #include "mozilla/IMEStateManager.h" // for IMEStateManager @@ -98,17 +99,16 @@ #include "nsIWidget.h" // for nsIWidget, IMEState, etc. #include "nsPIDOMWindow.h" // for nsPIDOMWindow #include "nsPresContext.h" // for nsPresContext #include "nsRange.h" // for nsRange #include "nsReadableUtils.h" // for EmptyString, ToNewCString #include "nsString.h" // for nsAutoString, nsString, etc. #include "nsStringFwd.h" // for nsString #include "nsStyleConsts.h" // for NS_STYLE_DIRECTION_RTL, etc. -#include "nsStyleContext.h" // for nsStyleContext #include "nsStyleStruct.h" // for nsStyleDisplay, nsStyleText, etc. #include "nsStyleStructFwd.h" // for nsIFrame::StyleUIReset, etc. #include "nsTextNode.h" // for nsTextNode #include "nsThreadUtils.h" // for nsRunnable #include "nsTransactionManager.h" // for nsTransactionManager #include "prtime.h" // for PR_Now class nsIOutputStream; @@ -4104,23 +4104,23 @@ EditorBase::IsPreformatted(nsIDOMNode* a nsCOMPtr<nsIContent> content = do_QueryInterface(aNode); NS_ENSURE_TRUE(aResult && content, NS_ERROR_NULL_POINTER); nsCOMPtr<nsIPresShell> ps = GetPresShell(); NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED); // Look at the node (and its parent if it's not an element), and grab its style context - RefPtr<nsStyleContext> elementStyle; + RefPtr<ComputedStyle> elementStyle; if (!content->IsElement()) { content = content->GetParent(); } if (content && content->IsElement()) { elementStyle = - nsComputedDOMStyle::GetStyleContextNoFlush(content->AsElement(), nullptr); + nsComputedDOMStyle::GetComputedStyleNoFlush(content->AsElement(), nullptr); } if (!elementStyle) { // Consider nodes without a style context to be NOT preformatted: // For instance, this is true of JS tags inside the body (which show // up as #text nodes but have no style context). *aResult = false; return NS_OK;
--- a/editor/libeditor/HTMLAbsPositionEditor.cpp +++ b/editor/libeditor/HTMLAbsPositionEditor.cpp @@ -616,18 +616,18 @@ HTMLEditor::GetTemporaryStyleForFocusedP rv = CSSEditUtils::GetComputedProperty(aElement, *nsGkAtoms::backgroundColor, bgColorStr); NS_ENSURE_SUCCESS(rv, rv); if (!bgColorStr.EqualsLiteral("rgba(0, 0, 0, 0)")) { return NS_OK; } - RefPtr<nsStyleContext> style = - nsComputedDOMStyle::GetStyleContext(&aElement, nullptr); + RefPtr<ComputedStyle> style = + nsComputedDOMStyle::GetComputedStyle(&aElement, nullptr); NS_ENSURE_STATE(style); const uint8_t kBlackBgTrigger = 0xd0; nscolor color = style->StyleColor()->mColor; if (NS_GET_R(color) >= kBlackBgTrigger && NS_GET_G(color) >= kBlackBgTrigger && NS_GET_B(color) >= kBlackBgTrigger) {
--- a/gfx/webrender/Cargo.toml +++ b/gfx/webrender/Cargo.toml @@ -11,18 +11,18 @@ default = ["freetype-lib"] freetype-lib = ["freetype/servo-freetype-sys"] profiler = ["thread_profiler/thread_profiler"] debugger = ["ws", "serde_json", "serde", "image", "base64"] capture = ["webrender_api/serialize", "ron", "serde"] replay = ["webrender_api/deserialize", "ron", "serde"] [dependencies] app_units = "0.6" -bincode = "0.9" byteorder = "1.0" +bincode = "1.0" euclid = "0.17" fxhash = "0.2.1" gleam = "0.4.20" lazy_static = "1" log = "0.4" num-traits = "0.1.32" time = "0.1" rayon = "1"
--- a/gfx/webrender/examples/basic.rs +++ b/gfx/webrender/examples/basic.rs @@ -197,17 +197,17 @@ impl Example for App { None, MixBlendMode::Normal, Vec::new(), ); let image_mask_key = api.generate_image_key(); resources.add_image( image_mask_key, - ImageDescriptor::new(2, 2, ImageFormat::R8, true), + ImageDescriptor::new(2, 2, ImageFormat::R8, true, false), ImageData::new(vec![0, 80, 180, 255]), None, ); let mask = ImageMask { image: image_mask_key, rect: (75, 75).by(100, 100), repeat: false, };
--- a/gfx/webrender/examples/blob.rs +++ b/gfx/webrender/examples/blob.rs @@ -227,25 +227,25 @@ impl Example for App { resources: &mut ResourceUpdates, _framebuffer_size: api::DeviceUintSize, _pipeline_id: PipelineId, _document_id: DocumentId, ) { let blob_img1 = api.generate_image_key(); resources.add_image( blob_img1, - api::ImageDescriptor::new(500, 500, api::ImageFormat::BGRA8, true), + api::ImageDescriptor::new(500, 500, api::ImageFormat::BGRA8, true, false), api::ImageData::new_blob_image(serialize_blob(api::ColorU::new(50, 50, 150, 255))), Some(128), ); let blob_img2 = api.generate_image_key(); resources.add_image( blob_img2, - api::ImageDescriptor::new(200, 200, api::ImageFormat::BGRA8, true), + api::ImageDescriptor::new(200, 200, api::ImageFormat::BGRA8, true, false), api::ImageData::new_blob_image(serialize_blob(api::ColorU::new(50, 150, 50, 255))), None, ); let bounds = api::LayoutRect::new(api::LayoutPoint::zero(), builder.content_size()); let info = api::LayoutPrimitiveInfo::new(bounds); builder.push_stacking_context( &info,
--- a/gfx/webrender/examples/common/boilerplate.rs +++ b/gfx/webrender/examples/common/boilerplate.rs @@ -133,17 +133,16 @@ pub fn main_wrapper<E: Example>( println!("OpenGL version {}", gl.get_string(gl::VERSION)); println!("Shader resource path: {:?}", res_path); let device_pixel_ratio = window.hidpi_factor(); println!("Device pixel ratio: {}", device_pixel_ratio); println!("Loading shaders..."); let opts = webrender::RendererOptions { resource_override_path: res_path, - debug: true, precache_shaders: E::PRECACHE_SHADERS, device_pixel_ratio, clear_color: Some(ColorF::new(0.3, 0.0, 0.0, 1.0)), //scatter_gpu_cache_updates: false, ..options.unwrap_or(webrender::RendererOptions::default()) }; let framebuffer_size = {
--- a/gfx/webrender/examples/common/image_helper.rs +++ b/gfx/webrender/examples/common/image_helper.rs @@ -7,10 +7,10 @@ use webrender::api::{ImageData, ImageDes pub fn make_checkerboard(width: u32, height: u32) -> (ImageDescriptor, ImageData) { let mut image_data = Vec::new(); for y in 0 .. height { for x in 0 .. width { let lum = 255 * (((x & 8) == 0) ^ ((y & 8) == 0)) as u8; image_data.extend_from_slice(&[lum, lum, lum, 0xff]); } } - (ImageDescriptor::new(width, height, ImageFormat::BGRA8, true), ImageData::new(image_data)) + (ImageDescriptor::new(width, height, ImageFormat::BGRA8, true, false), ImageData::new(image_data)) }
--- a/gfx/webrender/examples/frame_output.rs +++ b/gfx/webrender/examples/frame_output.rs @@ -65,17 +65,17 @@ impl App { framebuffer_size: DeviceUintSize, device_pixel_ratio: f32, ) { // Generate the external image key that will be used to render the output document to the root document. self.external_image_key = Some(api.generate_image_key()); let mut resources = ResourceUpdates::new(); resources.add_image( self.external_image_key.unwrap(), - ImageDescriptor::new(100, 100, ImageFormat::BGRA8, true), + ImageDescriptor::new(100, 100, ImageFormat::BGRA8, true, false), ImageData::External(ExternalImageData { id: ExternalImageId(0), channel_index: 0, image_type: ExternalImageType::TextureHandle(TextureTarget::Default), }), None, );
--- a/gfx/webrender/examples/image_resize.rs +++ b/gfx/webrender/examples/image_resize.rs @@ -96,17 +96,17 @@ impl Example for App { let g = 255 * ((x & 32) == 0) as u8; image_data.extend_from_slice(&[0, g, r, 0xff]); } } let mut updates = ResourceUpdates::new(); updates.update_image( self.image_key, - ImageDescriptor::new(64, 64, ImageFormat::BGRA8, true), + ImageDescriptor::new(64, 64, ImageFormat::BGRA8, true, false), ImageData::new(image_data), None, ); let mut txn = Transaction::new(); txn.update_resources(updates); txn.generate_frame(); api.send_transaction(document_id, txn); }
--- a/gfx/webrender/examples/multiwindow.rs +++ b/gfx/webrender/examples/multiwindow.rs @@ -81,17 +81,16 @@ impl Window { gl::GlesFns::load_with(|symbol| window.get_proc_address(symbol) as *const _) }, glutin::Api::WebGl => unimplemented!(), }; let device_pixel_ratio = window.hidpi_factor(); let opts = webrender::RendererOptions { - debug: true, device_pixel_ratio, clear_color: Some(clear_color), ..webrender::RendererOptions::default() }; let framebuffer_size = { let (width, height) = window.get_inner_size().unwrap(); DeviceUintSize::new(width, height)
--- a/gfx/webrender/examples/texture_cache_stress.rs +++ b/gfx/webrender/examples/texture_cache_stress.rs @@ -106,25 +106,25 @@ impl Example for App { if self.swap_keys.is_empty() { let key0 = api.generate_image_key(); let key1 = api.generate_image_key(); self.image_generator.generate_image(128); resources.add_image( key0, - ImageDescriptor::new(128, 128, ImageFormat::BGRA8, true), + ImageDescriptor::new(128, 128, ImageFormat::BGRA8, true, false), ImageData::new(self.image_generator.take()), None, ); self.image_generator.generate_image(128); resources.add_image( key1, - ImageDescriptor::new(128, 128, ImageFormat::BGRA8, true), + ImageDescriptor::new(128, 128, ImageFormat::BGRA8, true, false), ImageData::new(self.image_generator.take()), None, ); self.swap_keys.push(key0); self.swap_keys.push(key1); } @@ -210,17 +210,17 @@ impl Example for App { let size = 4; let image_key = api.generate_image_key(); self.image_generator.generate_image(size); updates.add_image( image_key, - ImageDescriptor::new(size, size, ImageFormat::BGRA8, true), + ImageDescriptor::new(size, size, ImageFormat::BGRA8, true, false), ImageData::new(self.image_generator.take()), None, ); self.stress_keys.push(image_key); } } } @@ -228,17 +228,17 @@ impl Example for App { updates.delete_image(image_key); }, glutin::VirtualKeyCode::U => if let Some(image_key) = self.image_key { let size = 128; self.image_generator.generate_image(size); updates.update_image( image_key, - ImageDescriptor::new(size, size, ImageFormat::BGRA8, true), + ImageDescriptor::new(size, size, ImageFormat::BGRA8, true, false), ImageData::new(self.image_generator.take()), None, ); }, glutin::VirtualKeyCode::E => { if let Some(image_key) = self.image_key.take() { updates.delete_image(image_key); } @@ -249,17 +249,17 @@ impl Example for App { let image_data = ExternalImageData { id: ExternalImageId(0), channel_index: size as u8, image_type: ExternalImageType::Buffer, }; updates.add_image( image_key, - ImageDescriptor::new(size, size, ImageFormat::BGRA8, true), + ImageDescriptor::new(size, size, ImageFormat::BGRA8, true, false), ImageData::External(image_data), None, ); self.image_key = Some(image_key); } glutin::VirtualKeyCode::R => { if let Some(image_key) = self.image_key.take() { @@ -267,17 +267,17 @@ impl Example for App { } let image_key = api.generate_image_key(); let size = 32; self.image_generator.generate_image(size); updates.add_image( image_key, - ImageDescriptor::new(size, size, ImageFormat::BGRA8, true), + ImageDescriptor::new(size, size, ImageFormat::BGRA8, true, false), ImageData::new(self.image_generator.take()), None, ); self.image_key = Some(image_key); } _ => {} }
--- a/gfx/webrender/examples/yuv.rs +++ b/gfx/webrender/examples/yuv.rs @@ -96,53 +96,53 @@ impl Example for App { ); let yuv_chanel1 = api.generate_image_key(); let yuv_chanel2 = api.generate_image_key(); let yuv_chanel2_1 = api.generate_image_key(); let yuv_chanel3 = api.generate_image_key(); resources.add_image( yuv_chanel1, - ImageDescriptor::new(100, 100, ImageFormat::R8, true), + ImageDescriptor::new(100, 100, ImageFormat::R8, true, false), ImageData::External(ExternalImageData { id: ExternalImageId(0), channel_index: 0, image_type: ExternalImageType::TextureHandle( TextureTarget::Default, ), }), None, ); resources.add_image( yuv_chanel2, - ImageDescriptor::new(100, 100, ImageFormat::RG8, true), + ImageDescriptor::new(100, 100, ImageFormat::RG8, true, false), ImageData::External(ExternalImageData { id: ExternalImageId(1), channel_index: 0, image_type: ExternalImageType::TextureHandle( TextureTarget::Default, ), }), None, ); resources.add_image( yuv_chanel2_1, - ImageDescriptor::new(100, 100, ImageFormat::R8, true), + ImageDescriptor::new(100, 100, ImageFormat::R8, true, false), ImageData::External(ExternalImageData { id: ExternalImageId(2), channel_index: 0, image_type: ExternalImageType::TextureHandle( TextureTarget::Default, ), }), None, ); resources.add_image( yuv_chanel3, - ImageDescriptor::new(100, 100, ImageFormat::R8, true), + ImageDescriptor::new(100, 100, ImageFormat::R8, true, false), ImageData::External(ExternalImageData { id: ExternalImageId(3), channel_index: 0, image_type: ExternalImageType::TextureHandle( TextureTarget::Default, ), }), None,
--- a/gfx/webrender/res/brush.glsl +++ b/gfx/webrender/res/brush.glsl @@ -84,94 +84,66 @@ void main(void) { RectWithSize local_segment_rect = RectWithSize(segment_data[0].xy, segment_data[0].zw); VertexInfo vi; // Fetch the dynamic picture that we are drawing on. PictureTask pic_task = fetch_picture_task(brush.picture_address); ClipArea clip_area = fetch_clip_area(brush.clip_address); - if (pic_task.pic_kind_and_raster_mode > 0.0) { - vec2 local_pos = local_segment_rect.p0 + aPosition.xy * local_segment_rect.size; - vec2 clamped_local_pos = clamp_rect(local_pos, brush_prim.local_clip_rect); - - vec2 device_pos = uDevicePixelRatio * clamped_local_pos; - - vec2 final_pos = device_pos + - pic_task.common_data.task_rect.p0 - - uDevicePixelRatio * pic_task.content_origin; + ClipScrollNode scroll_node = fetch_clip_scroll_node(brush.scroll_node_id); -#ifdef WR_FEATURE_ALPHA_PASS - write_clip( - vec2(0.0), - clip_area - ); -#endif - - vi = VertexInfo( - local_pos, - device_pos, - 1.0, - device_pos + // Write the normal vertex information out. + if (scroll_node.is_axis_aligned) { + vi = write_vertex( + local_segment_rect, + brush_prim.local_clip_rect, + float(brush.z), + scroll_node, + pic_task, + brush_prim.local_rect ); - // Write the final position transformed by the orthographic device-pixel projection. - gl_Position = uTransform * vec4(final_pos, 0.0, 1.0); - } else { - ClipScrollNode scroll_node = fetch_clip_scroll_node(brush.scroll_node_id); - - // Write the normal vertex information out. - if (scroll_node.is_axis_aligned) { - vi = write_vertex( - local_segment_rect, - brush_prim.local_clip_rect, - float(brush.z), - scroll_node, - pic_task, - brush_prim.local_rect - ); - - // TODO(gw): vLocalBounds may be referenced by - // the fragment shader when running in - // the alpha pass, even on non-transformed - // items. For now, just ensure it has no - // effect. We can tidy this up as we move - // more items to be brush shaders. + // TODO(gw): vLocalBounds may be referenced by + // the fragment shader when running in + // the alpha pass, even on non-transformed + // items. For now, just ensure it has no + // effect. We can tidy this up as we move + // more items to be brush shaders. #ifdef WR_FEATURE_ALPHA_PASS - vLocalBounds = vec4(vec2(-1000000.0), vec2(1000000.0)); + vLocalBounds = vec4(vec2(-1000000.0), vec2(1000000.0)); #endif - } else { - bvec4 edge_mask = notEqual(brush.edge_mask & ivec4(1, 2, 4, 8), ivec4(0)); - bool do_perspective_interpolation = (brush.flags & BRUSH_FLAG_PERSPECTIVE_INTERPOLATION) != 0; + } else { + bvec4 edge_mask = notEqual(brush.edge_mask & ivec4(1, 2, 4, 8), ivec4(0)); + bool do_perspective_interpolation = (brush.flags & BRUSH_FLAG_PERSPECTIVE_INTERPOLATION) != 0; - vi = write_transform_vertex( - local_segment_rect, - brush_prim.local_rect, - brush_prim.local_clip_rect, - mix(vec4(0.0), vec4(1.0), edge_mask), - float(brush.z), - scroll_node, - pic_task, - do_perspective_interpolation - ); - } + vi = write_transform_vertex( + local_segment_rect, + brush_prim.local_rect, + brush_prim.local_clip_rect, + mix(vec4(0.0), vec4(1.0), edge_mask), + float(brush.z), + scroll_node, + pic_task, + do_perspective_interpolation + ); + } - // For brush instances in the alpha pass, always write - // out clip information. - // TODO(gw): It's possible that we might want alpha - // shaders that don't clip in the future, - // but it's reasonable to assume that one - // implies the other, for now. + // For brush instances in the alpha pass, always write + // out clip information. + // TODO(gw): It's possible that we might want alpha + // shaders that don't clip in the future, + // but it's reasonable to assume that one + // implies the other, for now. #ifdef WR_FEATURE_ALPHA_PASS - write_clip( - vi.screen_pos, - clip_area - ); + write_clip( + vi.screen_pos, + clip_area + ); #endif - } // Run the specific brush VS code to write interpolators. brush_vs( vi, brush.prim_address + VECS_PER_BRUSH_PRIM, brush_prim.local_rect, brush.user_data, pic_task
--- a/gfx/webrender/res/brush_image.glsl +++ b/gfx/webrender/res/brush_image.glsl @@ -89,17 +89,21 @@ void brush_vs( ) / texture_size.xyxy; break; case RASTER_LOCAL: default: { f = (vi.local_pos - local_rect.p0) / local_rect.size; // Set the clip bounds to a value that won't have any // effect for local space images. +#ifdef WR_FEATURE_TEXTURE_RECT + vUvClipBounds = vec4(0.0, 0.0, vec2(textureSize(sColor0))); +#else vUvClipBounds = vec4(0.0, 0.0, 1.0, 1.0); +#endif break; } } #else f = (vi.local_pos - local_rect.p0) / local_rect.size; #endif vUv.xy = mix(uv0, uv1, f);
deleted file mode 100644 --- a/gfx/webrender/res/cs_text_run.glsl +++ /dev/null @@ -1,68 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include shared,prim_shared - -varying vec3 vUv; -flat varying vec4 vColor; -flat varying vec4 vStRect; - -#ifdef WR_VERTEX_SHADER -// Draw a text run to a cache target. These are always -// drawn un-transformed. These are used for effects such -// as text-shadow. - -void main(void) { - Primitive prim = load_primitive(); - TextRun text = fetch_text_run(prim.specific_prim_address); - - int glyph_index = prim.user_data0; - int resource_address = prim.user_data1; - int subpx_dir = prim.user_data2; - - Glyph glyph = fetch_glyph(prim.specific_prim_address, - glyph_index, - subpx_dir); - - GlyphResource res = fetch_glyph_resource(resource_address); - - // Scale from glyph space to local space. - float scale = res.scale / uDevicePixelRatio; - - // Compute the glyph rect in local space. - RectWithSize glyph_rect = RectWithSize(scale * res.offset + text.offset + glyph.offset, - scale * (res.uv_rect.zw - res.uv_rect.xy)); - - // Select the corner of the glyph rect that we are processing. - vec2 local_pos = (glyph_rect.p0 + glyph_rect.size * aPosition.xy); - - // Clamp the local position to the text run's local clipping rectangle. - local_pos = clamp_rect(local_pos, prim.local_clip_rect); - - // Move the point into device pixel space. - local_pos = (local_pos - prim.task.content_origin) * uDevicePixelRatio; - local_pos += prim.task.common_data.task_rect.p0; - gl_Position = uTransform * vec4(local_pos, 0.0, 1.0); - - vec2 texture_size = vec2(textureSize(sColor0, 0)); - vec2 st0 = res.uv_rect.xy / texture_size; - vec2 st1 = res.uv_rect.zw / texture_size; - - vUv = vec3(mix(st0, st1, aPosition.xy), res.layer); - vColor = prim.task.color; - - // We clamp the texture coordinates to the half-pixel offset from the borders - // in order to avoid sampling outside of the texture area. - vec2 half_texel = vec2(0.5) / texture_size; - vStRect = vec4(min(st0, st1) + half_texel, max(st0, st1) - half_texel); -} -#endif - -#ifdef WR_FRAGMENT_SHADER -void main(void) { - vec2 uv = clamp(vUv.xy, vStRect.xy, vStRect.zw); - float a = texture(sColor0, vec3(uv, vUv.z)).a; - oFragColor = vColor * a; -} -#endif
--- a/gfx/webrender/src/batch.rs +++ b/gfx/webrender/src/batch.rs @@ -1,27 +1,27 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use api::{AlphaType, DeviceIntRect, DeviceIntSize, LayerToWorldScale}; use api::{DeviceUintRect, DeviceUintPoint, DeviceUintSize, ExternalImageType, FilterOp, ImageRendering, LayerRect}; -use api::{DeviceIntPoint, LayerPoint, SubpixelDirection, YuvColorSpace, YuvFormat}; +use api::{DeviceIntPoint, SubpixelDirection, YuvColorSpace, YuvFormat}; use api::{LayerToWorldTransform, WorldPixel}; use border::{BorderCornerInstance, BorderCornerSide, BorderEdgeKind}; use clip::{ClipSource, ClipStore, ClipWorkItem}; use clip_scroll_tree::{CoordinateSystemId}; use euclid::{TypedTransform3D, vec3}; use glyph_rasterizer::GlyphFormat; use gpu_cache::{GpuCache, GpuCacheAddress}; use gpu_types::{BrushFlags, BrushInstance, ClipChainRectIndex}; use gpu_types::{ClipMaskInstance, ClipScrollNodeIndex, RasterizationSpace}; use gpu_types::{CompositePrimitiveInstance, PrimitiveInstance, SimplePrimitiveInstance}; use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture}; -use picture::{ContentOrigin, PictureCompositeMode, PictureKind, PicturePrimitive}; +use picture::{PictureCompositeMode, PictureKind, PicturePrimitive}; use plane_split::{BspSplitter, Polygon, Splitter}; use prim_store::{CachedGradient, ImageSource, PrimitiveIndex, PrimitiveKind, PrimitiveMetadata, PrimitiveStore}; use prim_store::{BrushPrimitive, BrushKind, DeferredResolve, EdgeAaSegmentMask, PictureIndex, PrimitiveRun}; use render_task::{RenderTaskAddress, RenderTaskId, RenderTaskKind, RenderTaskTree}; use renderer::{BlendMode, ImageBufferKind}; use renderer::BLOCKS_PER_UV_RECT; use resource_cache::{CacheItem, GlyphFetchResult, ImageRequest, ResourceCache}; use std::{usize, f32, i32}; @@ -351,40 +351,31 @@ impl PrimitiveBatch { instances: Vec::new(), } } } #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct AlphaBatchContainer { - pub text_run_cache_prims: FastHashMap<SourceTexture, Vec<PrimitiveInstance>>, pub opaque_batches: Vec<PrimitiveBatch>, pub alpha_batches: Vec<PrimitiveBatch>, pub target_rect: Option<DeviceIntRect>, } impl AlphaBatchContainer { pub fn new(target_rect: Option<DeviceIntRect>) -> AlphaBatchContainer { AlphaBatchContainer { - text_run_cache_prims: FastHashMap::default(), opaque_batches: Vec::new(), alpha_batches: Vec::new(), target_rect, } } fn merge(&mut self, builder: AlphaBatchBuilder) { - for (key, value) in builder.text_run_cache_prims { - self.text_run_cache_prims - .entry(key) - .or_insert(vec![]) - .extend(value); - } - for other_batch in builder.batch_list.opaque_batch_list.batches { let batch_index = self.opaque_batches.iter().position(|batch| { batch.key.is_compatible_with(&other_batch.key) }); match batch_index { Some(batch_index) => { self.opaque_batches[batch_index].instances.extend(other_batch.instances); @@ -415,30 +406,28 @@ impl AlphaBatchContainer { } } } } /// Encapsulates the logic of building batches for items that are blended. pub struct AlphaBatchBuilder { pub batch_list: BatchList, - pub text_run_cache_prims: FastHashMap<SourceTexture, Vec<PrimitiveInstance>>, glyph_fetch_buffer: Vec<GlyphFetchResult>, target_rect: DeviceIntRect, } impl AlphaBatchBuilder { pub fn new( screen_size: DeviceIntSize, target_rect: DeviceIntRect, ) -> Self { AlphaBatchBuilder { batch_list: BatchList::new(screen_size), glyph_fetch_buffer: Vec::new(), - text_run_cache_prims: FastHashMap::default(), target_rect, } } pub fn build(mut self, merged_batches: &mut AlphaBatchContainer) -> Option<AlphaBatchContainer> { self.batch_list.finalize(); let task_relative_target_rect = DeviceIntRect::new( @@ -451,17 +440,16 @@ impl AlphaBatchBuilder { if can_merge { merged_batches.merge(self); None } else { Some(AlphaBatchContainer { alpha_batches: self.batch_list.alpha_batch_list.batches, opaque_batches: self.batch_list.opaque_batch_list.batches, target_rect: Some(self.target_rect), - text_run_cache_prims: self.text_run_cache_prims, }) } } pub fn add_pic_to_batch( &mut self, pic: &PicturePrimitive, task_id: RenderTaskId, @@ -495,17 +483,16 @@ impl AlphaBatchBuilder { scroll_id, ctx, gpu_cache, render_tasks, task_id, task_address, deferred_resolves, &mut splitter, - pic, content_origin, ); } // Flush the accumulated plane splits onto the task tree. // Z axis is directed at the screen, `sort` is ascending, and we need back-to-front order. for poly in splitter.sort(vec3(0.0, 0.0, 1.0)) { let prim_index = PrimitiveIndex(poly.anchor); @@ -555,49 +542,35 @@ impl AlphaBatchBuilder { scroll_id: ClipScrollNodeIndex, ctx: &RenderTargetContext, gpu_cache: &mut GpuCache, render_tasks: &RenderTaskTree, task_id: RenderTaskId, task_address: RenderTaskAddress, deferred_resolves: &mut Vec<DeferredResolve>, splitter: &mut BspSplitter<f64, WorldPixel>, - pic: &PicturePrimitive, - content_origin: ContentOrigin, + content_origin: DeviceIntPoint, ) { for i in 0 .. run.count { let prim_index = PrimitiveIndex(run.base_prim_index.0 + i); - let metadata = &ctx.prim_store.cpu_metadata[prim_index.0]; - // Now that we walk the primitive runs in order to add - // items to batches, we need to check if they are - // visible here. - // We currently only support culling on normal (Image) - // picture types. - // TODO(gw): Support culling on shadow image types. - let is_image = match pic.kind { - PictureKind::Image { .. } => true, - PictureKind::TextShadow { .. } => false, - }; - - if !is_image || metadata.screen_rect.is_some() { + if metadata.screen_rect.is_some() { self.add_prim_to_batch( metadata.clip_chain_rect_index, scroll_id, prim_index, ctx, gpu_cache, render_tasks, task_id, task_address, deferred_resolves, splitter, content_origin, - pic, ); } } } // Adds a primitive to a batch. // It can recursively call itself in some situations, for // example if it encounters a picture where the items @@ -609,51 +582,34 @@ impl AlphaBatchBuilder { prim_index: PrimitiveIndex, ctx: &RenderTargetContext, gpu_cache: &mut GpuCache, render_tasks: &RenderTaskTree, task_id: RenderTaskId, task_address: RenderTaskAddress, deferred_resolves: &mut Vec<DeferredResolve>, splitter: &mut BspSplitter<f64, WorldPixel>, - content_origin: ContentOrigin, - pic: &PicturePrimitive, + content_origin: DeviceIntPoint, ) { let z = prim_index.0 as i32; let prim_metadata = ctx.prim_store.get_metadata(prim_index); let scroll_node = &ctx.node_data[scroll_id.0 as usize]; // TODO(gw): Calculating this for every primitive is a bit // wasteful. We should probably cache this in // the scroll node... let transform_kind = scroll_node.transform.transform_kind(); - let task_relative_bounding_rect = match content_origin { - ContentOrigin::Screen(point) => { - // translate by content-origin - let screen_rect = prim_metadata.screen_rect.expect("bug"); - DeviceIntRect::new( - DeviceIntPoint::new( - screen_rect.unclipped.origin.x - point.x, - screen_rect.unclipped.origin.y - point.y, - ), - screen_rect.unclipped.size, - ) - } - ContentOrigin::Local(point) => { - // scale local rect by device pixel ratio - let content_rect = LayerRect::new( - LayerPoint::new( - prim_metadata.local_rect.origin.x - point.x, - prim_metadata.local_rect.origin.y - point.y, - ), - prim_metadata.local_rect.size, - ); - (content_rect * LayerToWorldScale::new(1.0) * ctx.device_pixel_scale).round().to_i32() - } - }; + let screen_rect = prim_metadata.screen_rect.expect("bug"); + let task_relative_bounding_rect = DeviceIntRect::new( + DeviceIntPoint::new( + screen_rect.unclipped.origin.x - content_origin.x, + screen_rect.unclipped.origin.y - content_origin.y, + ), + screen_rect.unclipped.size, + ); let prim_cache_address = gpu_cache.get_address(&prim_metadata.gpu_location); let no_textures = BatchTextures::no_texture(); let clip_task_address = prim_metadata .clip_task_id .map_or(OPAQUE_TASK_ADDRESS, |id| render_tasks.get_task_address(id)); let base_instance = SimplePrimitiveInstance::new( prim_cache_address, @@ -704,21 +660,21 @@ impl AlphaBatchBuilder { picture_address: task_address, prim_address: prim_cache_address, clip_chain_rect_index, scroll_id, clip_task_address, z, segment_index: 0, edge_flags: EdgeAaSegmentMask::empty(), - brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION, + brush_flags: BrushFlags::empty(), user_data: [ uv_rect_address, BrushImageSourceKind::Color as i32, - RasterizationSpace::Local as i32, + RasterizationSpace::Screen as i32, ], }; batch.push(PrimitiveInstance::from(instance)); } PictureKind::Image { composite_mode, secondary_render_task_id, is_in_3d_context, @@ -1131,37 +1087,24 @@ impl AlphaBatchBuilder { }, ); let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect); batch.push(base_instance.build(cache_item.uv_rect_handle.as_int(gpu_cache), 0, 0)); } PrimitiveKind::TextRun => { let text_cpu = &ctx.prim_store.cpu_text_runs[prim_metadata.cpu_prim_index.0]; - let is_shadow = match pic.kind { - PictureKind::TextShadow { .. } => true, - PictureKind::Image { .. } => false, - }; - - // TODO(gw): It probably makes sense to base this decision on the content - // origin field in the future (once that's configurable). - let font_transform = if is_shadow { - None - } else { - Some(scroll_node.transform) - }; let font = text_cpu.get_font( ctx.device_pixel_scale, - font_transform, + Some(scroll_node.transform), ); let glyph_fetch_buffer = &mut self.glyph_fetch_buffer; let batch_list = &mut self.batch_list; - let text_run_cache_prims = &mut self.text_run_cache_prims; ctx.resource_cache.fetch_glyphs( font, &text_cpu.glyph_keys, glyph_fetch_buffer, gpu_cache, |texture_id, mut glyph_format, glyphs| { debug_assert_ne!(texture_id, SourceTexture::Invalid); @@ -1172,54 +1115,48 @@ impl AlphaBatchBuilder { } let subpx_dir = match glyph_format { GlyphFormat::Bitmap | GlyphFormat::ColorBitmap => SubpixelDirection::None, _ => text_cpu.font.subpx_dir.limit_by(text_cpu.font.render_mode), }; - let batch = if is_shadow { - text_run_cache_prims - .entry(texture_id) - .or_insert(Vec::new()) - } else { - let textures = BatchTextures { - colors: [ - texture_id, - SourceTexture::Invalid, - SourceTexture::Invalid, - ], - }; + let textures = BatchTextures { + colors: [ + texture_id, + SourceTexture::Invalid, + SourceTexture::Invalid, + ], + }; - let kind = BatchKind::Transformable( - transform_kind, - TransformBatchKind::TextRun(glyph_format), - ); + let kind = BatchKind::Transformable( + transform_kind, + TransformBatchKind::TextRun(glyph_format), + ); - let blend_mode = match glyph_format { - GlyphFormat::Subpixel | - GlyphFormat::TransformedSubpixel => { - if text_cpu.font.bg_color.a != 0 { - BlendMode::SubpixelWithBgColor - } else if ctx.use_dual_source_blending { - BlendMode::SubpixelDualSource - } else { - BlendMode::SubpixelConstantTextColor(text_cpu.font.color.into()) - } + let blend_mode = match glyph_format { + GlyphFormat::Subpixel | + GlyphFormat::TransformedSubpixel => { + if text_cpu.font.bg_color.a != 0 { + BlendMode::SubpixelWithBgColor + } else if ctx.use_dual_source_blending { + BlendMode::SubpixelDualSource + } else { + BlendMode::SubpixelConstantTextColor(text_cpu.font.color.into()) } - GlyphFormat::Alpha | - GlyphFormat::TransformedAlpha | - GlyphFormat::Bitmap | - GlyphFormat::ColorBitmap => BlendMode::PremultipliedAlpha, - }; + } + GlyphFormat::Alpha | + GlyphFormat::TransformedAlpha | + GlyphFormat::Bitmap | + GlyphFormat::ColorBitmap => BlendMode::PremultipliedAlpha, + }; - let key = BatchKey::new(kind, blend_mode, textures); - batch_list.get_suitable_batch(key, &task_relative_bounding_rect) - }; + let key = BatchKey::new(kind, blend_mode, textures); + let batch = batch_list.get_suitable_batch(key, &task_relative_bounding_rect); for glyph in glyphs { batch.push(base_instance.build( glyph.index_in_text_run, glyph.uv_rect_address.as_int(), subpx_dir as u32 as i32, )); }
--- a/gfx/webrender/src/display_list_flattener.rs +++ b/gfx/webrender/src/display_list_flattener.rs @@ -10,29 +10,30 @@ use api::{FilterOp, FontInstanceKey, Fon use api::{IframeDisplayItem, ImageKey, ImageRendering, ItemRange, LayerPoint, LayerPrimitiveInfo}; use api::{LayerRect, LayerSize, LayerVector2D, LayoutRect, LayoutSize, LayoutTransform}; use api::{LayoutVector2D, LineOrientation, LineStyle, LocalClip, PipelineId, PropertyBinding}; use api::{RepeatMode, ScrollFrameDisplayItem, ScrollPolicy, ScrollSensitivity, Shadow}; use api::{SpecificDisplayItem, StackingContext, StickyFrameDisplayItem, TexelRect, TileOffset}; use api::{TransformStyle, YuvColorSpace, YuvData}; use app_units::Au; use border::ImageBorderSegment; +use box_shadow::{BLUR_SAMPLE_SCALE}; use clip::{ClipRegion, ClipSource, ClipSources, ClipStore}; use clip_scroll_node::{ClipScrollNode, NodeType, StickyFrameInfo}; use clip_scroll_tree::{ClipChainIndex, ClipScrollNodeIndex, ClipScrollTree}; use euclid::{SideOffsets2D, vec2}; use frame_builder::{FrameBuilder, FrameBuilderConfig}; use glyph_rasterizer::FontInstance; use hit_test::{HitTestingItem, HitTestingRun}; use image::{decompose_image, TiledImageInfo}; use internal_types::{FastHashMap, FastHashSet}; use picture::{PictureCompositeMode, PictureKind}; use prim_store::{BrushKind, BrushPrimitive, BrushSegmentDescriptor, CachedGradient}; use prim_store::{CachedGradientIndex, ImageCacheKey, ImagePrimitiveCpu, ImageSource}; -use prim_store::{PictureIndex, PrimitiveContainer, PrimitiveIndex, PrimitiveKind, PrimitiveStore}; +use prim_store::{PictureIndex, PrimitiveContainer, PrimitiveIndex, PrimitiveStore}; use prim_store::{ScrollNodeAndClipChain, TextRunPrimitiveCpu}; use render_backend::{DocumentView}; use resource_cache::{FontInstanceMap, ImageRequest, TiledImageMap}; use scene::{Scene, ScenePipeline, StackingContextHelpers}; use scene_builder::{BuiltScene, SceneRequest}; use std::{f32, mem, usize}; use tiling::{CompositeOps, ScrollbarPrimitive}; use util::{MaxRect, RectHelpers, recycle_vec}; @@ -734,18 +735,18 @@ impl<'a> DisplayListFlattener<'a> { info.tile_spacing, ); } SpecificDisplayItem::RadialGradient(ref info) => { self.add_radial_gradient( clip_and_scroll, &prim_info, info.gradient.center, - info.gradient.start_radius, - info.gradient.end_radius, + info.gradient.start_offset * info.gradient.radius.width, + info.gradient.end_offset * info.gradient.radius.width, info.gradient.radius.width / info.gradient.radius.height, item.gradient_stops(), info.gradient.extend_mode, info.tile_size, info.tile_spacing, ); } SpecificDisplayItem::BoxShadow(ref box_shadow_info) => { @@ -1514,23 +1515,29 @@ impl<'a> DisplayListFlattener<'a> { color: line_color.premultiplied(), style, orientation, }, None, ); let mut fast_shadow_prims = Vec::new(); + let mut slow_shadow_prims = Vec::new(); for (idx, &(shadow_prim_index, _)) in self.shadow_prim_stack.iter().enumerate() { let shadow_metadata = &self.prim_store.cpu_metadata[shadow_prim_index.0]; let brush = &self.prim_store.cpu_brushes[shadow_metadata.cpu_prim_index.0]; - let picture = &self.prim_store.pictures[brush.get_picture_index().0]; + let pic_index = brush.get_picture_index(); + let picture = &self.prim_store.pictures[pic_index.0]; match picture.kind { - PictureKind::TextShadow { offset, color, blur_radius, .. } if blur_radius == 0.0 => { - fast_shadow_prims.push((idx, offset, color)); + PictureKind::TextShadow { offset, color, blur_radius, .. } => { + if blur_radius == 0.0 { + fast_shadow_prims.push((idx, offset, color)); + } else { + slow_shadow_prims.push((pic_index, offset, color)); + } } _ => {} } } for (idx, shadow_offset, shadow_color) in fast_shadow_prims { let line = BrushPrimitive::new( BrushKind::Line { @@ -1547,47 +1554,56 @@ impl<'a> DisplayListFlattener<'a> { let prim_index = self.create_primitive( &info, Vec::new(), PrimitiveContainer::Brush(line), ); self.shadow_prim_stack[idx].1.push((prim_index, clip_and_scroll)); } - let prim_index = self.create_primitive( - &info, - Vec::new(), - PrimitiveContainer::Brush(line), - ); + if line_color.a > 0.0 { + let prim_index = self.create_primitive( + &info, + Vec::new(), + PrimitiveContainer::Brush(line), + ); - if line_color.a > 0.0 { if self.shadow_prim_stack.is_empty() { self.add_primitive_to_hit_testing_list(&info, clip_and_scroll); self.add_primitive_to_draw_list(prim_index, clip_and_scroll); } else { self.pending_shadow_contents.push((prim_index, clip_and_scroll, *info)); } } - for &(shadow_prim_index, _) in &self.shadow_prim_stack { - let shadow_metadata = &mut self.prim_store.cpu_metadata[shadow_prim_index.0]; - debug_assert_eq!(shadow_metadata.prim_kind, PrimitiveKind::Brush); - let brush = &self.prim_store.cpu_brushes[shadow_metadata.cpu_prim_index.0]; - let picture = &mut self.prim_store.pictures[brush.get_picture_index().0]; + for (pic_index, shadow_offset, shadow_color) in slow_shadow_prims { + let line = BrushPrimitive::new( + BrushKind::Line { + wavy_line_thickness, + color: shadow_color.premultiplied(), + style, + orientation, + }, + None, + ); + let mut info = info.clone(); + info.rect = info.rect.translate(&shadow_offset); + info.clip_rect = info.clip_rect.translate(&shadow_offset); + let prim_index = self.create_primitive( + &info, + Vec::new(), + PrimitiveContainer::Brush(line), + ); - match picture.kind { - // Only run real blurs here (fast path zero blurs are handled above). - PictureKind::TextShadow { blur_radius, .. } if blur_radius > 0.0 => { - picture.add_primitive( - prim_index, - clip_and_scroll, - ); - } - _ => {} - } + let picture = &mut self.prim_store.pictures[pic_index.0]; + + picture.add_primitive( + prim_index, + clip_and_scroll, + ); } } pub fn add_border( &mut self, clip_and_scroll: ScrollNodeAndClipChain, info: &LayerPrimitiveInfo, border_item: &BorderDisplayItem, @@ -1819,18 +1835,18 @@ impl<'a> DisplayListFlattener<'a> { let segment_rel = segment.origin - rect.origin; let mut info = info.clone(); info.rect = segment; self.add_radial_gradient( clip_and_scroll, &info, border.gradient.center - segment_rel, - border.gradient.start_radius, - border.gradient.end_radius, + border.gradient.start_offset * border.gradient.radius.width, + border.gradient.end_offset * border.gradient.radius.width, border.gradient.radius.width / border.gradient.radius.height, gradient_stops, border.gradient.extend_mode, segment.size, LayerSize::zero(), ); } } @@ -2015,17 +2031,17 @@ impl<'a> DisplayListFlattener<'a> { } } } pub fn add_text( &mut self, clip_and_scroll: ScrollNodeAndClipChain, run_offset: LayoutVector2D, - info: &LayerPrimitiveInfo, + prim_info: &LayerPrimitiveInfo, font_instance_key: &FontInstanceKey, text_color: &ColorF, glyph_range: ItemRange<GlyphInstance>, glyph_count: usize, glyph_options: Option<GlyphOptions>, ) { let prim = { let instance_map = self.font_instances.read().unwrap(); @@ -2106,86 +2122,102 @@ impl<'a> DisplayListFlattener<'a> { // text elements to get pixel perfect results for reftests. It's also a big // performance win to avoid blurs and render target allocations where // possible. For any text shadows that have zero blur, create a normal text // primitive with the shadow's color and offset. These need to be added // *before* the visual text primitive in order to get the correct paint // order. Store them in a Vec first to work around borrowck issues. // TODO(gw): Refactor to avoid having to store them in a Vec first. let mut fast_shadow_prims = Vec::new(); + let mut slow_shadow_prims = Vec::new(); for (idx, &(shadow_prim_index, _)) in self.shadow_prim_stack.iter().enumerate() { let shadow_metadata = &self.prim_store.cpu_metadata[shadow_prim_index.0]; let brush = &self.prim_store.cpu_brushes[shadow_metadata.cpu_prim_index.0]; - let picture_prim = &self.prim_store.pictures[brush.get_picture_index().0]; + let pic_index = brush.get_picture_index(); + let picture_prim = &self.prim_store.pictures[pic_index.0]; match picture_prim.kind { - PictureKind::TextShadow { offset, color, blur_radius, .. } if blur_radius == 0.0 => { + PictureKind::TextShadow { offset, color, blur_radius, .. } => { let mut text_prim = prim.clone(); text_prim.font.color = color.into(); text_prim.shadow = true; text_prim.offset += offset; - fast_shadow_prims.push((idx, text_prim)); + + if blur_radius == 0.0 { + fast_shadow_prims.push((idx, text_prim, offset)); + } else { + text_prim.font.render_mode = text_prim + .font + .render_mode + .limit_by(FontRenderMode::Alpha); + + slow_shadow_prims.push((pic_index, text_prim, offset, blur_radius)); + } } _ => {} } } - for (idx, text_prim) in fast_shadow_prims { - let rect = info.rect; - let mut info = info.clone(); - info.rect = rect.translate(&text_prim.offset); - info.clip_rect = info.clip_rect.translate(&text_prim.offset); + for (idx, text_prim, offset) in fast_shadow_prims { + let rect = prim_info.rect; + let mut info = prim_info.clone(); + info.rect = rect.translate(&offset); + info.clip_rect = info.clip_rect.translate(&offset); let prim_index = self.create_primitive( &info, Vec::new(), PrimitiveContainer::TextRun(text_prim), ); self.shadow_prim_stack[idx].1.push((prim_index, clip_and_scroll)); } - // Create (and add to primitive store) the primitive that will be - // used for both the visual element and also the shadow(s). - let prim_index = self.create_primitive( - info, - Vec::new(), - PrimitiveContainer::TextRun(prim), - ); - // Only add a visual element if it can contribute to the scene. if text_color.a > 0.0 { + // Create (and add to primitive store) the primitive that will be + // used for both the visual element and also the shadow(s). + let prim_index = self.create_primitive( + prim_info, + Vec::new(), + PrimitiveContainer::TextRun(prim), + ); + if self.shadow_prim_stack.is_empty() { - self.add_primitive_to_hit_testing_list(info, clip_and_scroll); + self.add_primitive_to_hit_testing_list(prim_info, clip_and_scroll); self.add_primitive_to_draw_list(prim_index, clip_and_scroll); } else { - self.pending_shadow_contents.push((prim_index, clip_and_scroll, *info)); + self.pending_shadow_contents.push((prim_index, clip_and_scroll, *prim_info)); } } // Now add this primitive index to all the currently active text shadow // primitives. Although we're adding the indices *after* the visual // primitive here, they will still draw before the visual text, since // the shadow primitive itself has been added to the draw cmd // list *before* the visual element, during push_shadow. We need // the primitive index of the visual element here before we can add // the indices as sub-primitives to the shadow primitives. - for &(shadow_prim_index, _) in &self.shadow_prim_stack { - let shadow_metadata = &mut self.prim_store.cpu_metadata[shadow_prim_index.0]; - debug_assert_eq!(shadow_metadata.prim_kind, PrimitiveKind::Brush); - let brush = &self.prim_store.cpu_brushes[shadow_metadata.cpu_prim_index.0]; - let picture = &mut self.prim_store.pictures[brush.get_picture_index().0]; + for (pic_index, shadow_prim, offset, blur_radius) in slow_shadow_prims { + let blur_region = blur_radius * BLUR_SAMPLE_SCALE; + + let rect = prim_info.rect; + let mut info = prim_info.clone(); + info.rect = rect.translate(&offset).inflate(blur_region, blur_region); + info.clip_rect = info.clip_rect.translate(&offset); - match picture.kind { - // Only run real blurs here (fast path zero blurs are handled above). - PictureKind::TextShadow { blur_radius, .. } if blur_radius > 0.0 => { - picture.add_primitive( - prim_index, - clip_and_scroll, - ); - } - _ => {} - } + let prim_index = self.create_primitive( + &info, + Vec::new(), + PrimitiveContainer::TextRun(shadow_prim), + ); + + let picture = &mut self.prim_store.pictures[pic_index.0]; + + picture.add_primitive( + prim_index, + clip_and_scroll, + ); } } pub fn add_image( &mut self, clip_and_scroll: ScrollNodeAndClipChain, info: &LayerPrimitiveInfo, stretch_size: LayerSize,
--- a/gfx/webrender/src/frame_builder.rs +++ b/gfx/webrender/src/frame_builder.rs @@ -8,17 +8,16 @@ use api::{LayerRect, LayerSize, Pipeline use clip::{ClipChain, ClipStore}; use clip_scroll_node::{ClipScrollNode}; use clip_scroll_tree::{ClipScrollNodeIndex, ClipScrollTree}; use display_list_flattener::{DisplayListFlattener}; use gpu_cache::GpuCache; use gpu_types::{ClipChainRectIndex, ClipScrollNodeData, PictureType}; use hit_test::{HitTester, HitTestingRun}; use internal_types::{FastHashMap}; -use picture::{ContentOrigin}; use prim_store::{CachedGradient, PrimitiveIndex, PrimitiveRun, PrimitiveStore}; use profiler::{FrameProfileCounters, GpuCacheProfileCounters, TextureCacheProfileCounters}; use render_backend::FrameId; use render_task::{ClearMode, RenderTask, RenderTaskId, RenderTaskLocation, RenderTaskTree}; use resource_cache::{ResourceCache}; use scene::{ScenePipeline, SceneProperties}; use std::{mem, f32}; use std::sync::Arc; @@ -27,17 +26,16 @@ use tiling::ScrollbarPrimitive; use util::{self, MaxRect, WorldToLayerFastTransform}; #[derive(Clone, Copy)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct FrameBuilderConfig { pub enable_scrollbars: bool, pub default_font_render_mode: FontRenderMode, - pub debug: bool, pub dual_source_blending_is_supported: bool, pub dual_source_blending_is_enabled: bool, } /// A builder structure for `tiling::Frame` pub struct FrameBuilder { screen_rect: DeviceUintRect, background_color: Option<ColorF>, @@ -66,22 +64,21 @@ pub struct FrameBuildingState<'a> { pub local_clip_rects: &'a mut Vec<LayerRect>, pub resource_cache: &'a mut ResourceCache, pub gpu_cache: &'a mut GpuCache, pub cached_gradients: &'a mut [CachedGradient], } pub struct PictureContext<'a> { pub pipeline_id: PipelineId, - pub perform_culling: bool, pub prim_runs: Vec<PrimitiveRun>, pub original_reference_frame_index: Option<ClipScrollNodeIndex>, pub display_list: &'a BuiltDisplayList, - pub draw_text_transformed: bool, pub inv_world_transform: Option<WorldToLayerFastTransform>, + pub apply_local_clip_rect: bool, } pub struct PictureState { pub tasks: Vec<RenderTaskId>, } impl PictureState { pub fn new() -> PictureState { @@ -120,17 +117,16 @@ impl FrameBuilder { prim_store: PrimitiveStore::new(), clip_store: ClipStore::new(), screen_rect: DeviceUintRect::zero(), window_size: DeviceUintSize::zero(), background_color: None, config: FrameBuilderConfig { enable_scrollbars: false, default_font_render_mode: FontRenderMode::Mono, - debug: false, dual_source_blending_is_enabled: true, dual_source_blending_is_supported: false, }, } } pub fn with_display_list_flattener( screen_rect: DeviceUintRect, @@ -197,22 +193,21 @@ impl FrameBuilder { local_clip_rects, resource_cache, gpu_cache, cached_gradients: &mut self.cached_gradients, }; let pic_context = PictureContext { pipeline_id: root_clip_scroll_node.pipeline_id, - perform_culling: true, prim_runs: mem::replace(&mut self.prim_store.pictures[0].runs, Vec::new()), original_reference_frame_index: None, display_list, - draw_text_transformed: true, inv_world_transform: None, + apply_local_clip_rect: true, }; let mut pic_state = PictureState::new(); self.prim_store.reset_prim_visibility(); self.prim_store.prepare_prim_runs( &pic_context, &mut pic_state, @@ -222,17 +217,17 @@ impl FrameBuilder { let pic = &mut self.prim_store.pictures[0]; pic.runs = pic_context.prim_runs; let root_render_task = RenderTask::new_picture( RenderTaskLocation::Fixed(frame_context.screen_rect), PrimitiveIndex(0), RenderTargetKind::Color, - ContentOrigin::Screen(DeviceIntPoint::zero()), + DeviceIntPoint::zero(), PremultipliedColorF::TRANSPARENT, ClearMode::Transparent, pic_state.tasks, PictureType::Image, ); let render_task_id = frame_state.render_tasks.add(root_render_task); pic.surface = Some(render_task_id);
--- a/gfx/webrender/src/freelist.rs +++ b/gfx/webrender/src/freelist.rs @@ -60,35 +60,38 @@ struct Slot<T> { value: Option<T>, } #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct FreeList<T> { slots: Vec<Slot<T>>, free_list_head: Option<u32>, + active_count: usize, } pub enum UpsertResult<T> { Updated(T), Inserted(FreeListHandle<T>), } impl<T> FreeList<T> { pub fn new() -> Self { FreeList { slots: Vec::new(), free_list_head: None, + active_count: 0, } } pub fn recycle(self) -> FreeList<T> { FreeList { slots: recycle_vec(self.slots), free_list_head: None, + active_count: 0, } } #[allow(dead_code)] pub fn get(&self, id: &FreeListHandle<T>) -> &T { self.slots[id.index as usize].value.as_ref().unwrap() } @@ -126,16 +129,18 @@ impl<T> FreeList<T> { slot.value = Some(data); result } else { UpsertResult::Inserted(self.insert(data)) } } pub fn insert(&mut self, item: T) -> FreeListHandle<T> { + self.active_count += 1; + match self.free_list_head { Some(free_index) => { let slot = &mut self.slots[free_index as usize]; // Remove from free list. self.free_list_head = slot.next; slot.next = None; slot.value = Some(item); @@ -161,15 +166,20 @@ impl<T> FreeList<T> { epoch, _marker: PhantomData, } } } } pub fn free(&mut self, id: FreeListHandle<T>) -> T { + self.active_count -= 1; let slot = &mut self.slots[id.index as usize]; slot.next = self.free_list_head; slot.epoch = Epoch(slot.epoch.0 + 1); self.free_list_head = Some(id.index); slot.value.take().unwrap() } + + pub fn len(&self) -> usize { + self.active_count + } }
--- a/gfx/webrender/src/glyph_rasterizer.rs +++ b/gfx/webrender/src/glyph_rasterizer.rs @@ -516,16 +516,17 @@ impl GlyphRasterizer { texture_cache.update( &mut texture_cache_handle, ImageDescriptor { width: glyph.width, height: glyph.height, stride: None, format: ImageFormat::BGRA8, is_opaque: false, + allow_mipmaps: false, offset: 0, }, TextureFilter::Linear, Some(ImageData::Raw(Arc::new(glyph.bytes))), [glyph.left, -glyph.top, glyph.scale], None, gpu_cache, Some(glyph_key_cache.eviction_notice()),
--- a/gfx/webrender/src/picture.rs +++ b/gfx/webrender/src/picture.rs @@ -1,25 +1,24 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use api::{DeviceIntPoint, DeviceIntRect}; -use api::{LayerPoint, LayerRect, LayerToWorldScale, LayerVector2D}; use api::{ColorF, FilterOp, MixBlendMode, PipelineId}; +use api::{DeviceIntRect, LayerRect, LayerToWorldScale, LayerVector2D}; use api::{PremultipliedColorF, Shadow}; use box_shadow::{BLUR_SAMPLE_SCALE}; use clip_scroll_tree::ClipScrollNodeIndex; use frame_builder::{FrameBuildingContext, FrameBuildingState, PictureState}; use gpu_cache::{GpuCacheHandle, GpuDataRequest}; use gpu_types::{PictureType}; use prim_store::{PrimitiveIndex, PrimitiveRun, PrimitiveRunLocalRect}; use prim_store::{PrimitiveMetadata, ScrollNodeAndClipChain}; use render_task::{ClearMode, RenderTask}; -use render_task::{RenderTaskId, RenderTaskLocation, to_cache_size}; +use render_task::{RenderTaskId, RenderTaskLocation}; use scene::{FilterOpHelpers, SceneProperties}; use tiling::RenderTargetKind; /* A picture represents a dynamically rendered image. It consists of: * A number of primitives that are drawn onto the picture. * A composite operation describing how to composite this @@ -36,33 +35,22 @@ pub enum PictureCompositeMode { MixBlend(MixBlendMode), /// Apply a CSS filter. Filter(FilterOp), /// Draw to intermediate surface, copy straight across. This /// is used for CSS isolation, and plane splitting. Blit, } -/// Configure whether the content to be drawn by a picture -/// in local space rasterization or the screen space. -#[derive(Debug, Copy, Clone, PartialEq)] -#[cfg_attr(feature = "capture", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] -pub enum ContentOrigin { - Local(LayerPoint), - Screen(DeviceIntPoint), -} - #[derive(Debug)] pub enum PictureKind { TextShadow { offset: LayerVector2D, color: ColorF, blur_radius: f32, - content_rect: LayerRect, }, Image { // If a mix-blend-mode, contains the render task for // the readback of the framebuffer that we use to sample // from in the mix-blend-mode shader. // For drop-shadow filter, this will store the original // picture task which would be rendered on screen after // blur pass. @@ -80,19 +68,16 @@ pub enum PictureKind { // It is only different if this is part of a 3D // rendering context. reference_frame_index: ClipScrollNodeIndex, real_local_rect: LayerRect, // An optional cache handle for storing extra data // in the GPU cache, depending on the type of // picture. extra_gpu_data_handle: GpuCacheHandle, - // The current screen-space rect of the rendered - // portion of this picture. - task_rect: DeviceIntRect, }, } #[derive(Debug)] pub struct PicturePrimitive { // If this picture is drawn to an intermediate surface, // the associated target information. pub surface: Option<RenderTaskId>, @@ -101,35 +86,33 @@ pub struct PicturePrimitive { pub kind: PictureKind, // List of primitive runs that make up this picture. pub runs: Vec<PrimitiveRun>, // The pipeline that the primitives on this picture belong to. pub pipeline_id: PipelineId, - // If true, apply visibility culling to primitives on this - // picture. For text shadows and box shadows, we want to - // unconditionally draw them. - pub cull_children: bool, + // The current screen-space rect of the rendered + // portion of this picture. + task_rect: DeviceIntRect, } impl PicturePrimitive { pub fn new_text_shadow(shadow: Shadow, pipeline_id: PipelineId) -> Self { PicturePrimitive { runs: Vec::new(), surface: None, kind: PictureKind::TextShadow { offset: shadow.offset, color: shadow.color, blur_radius: shadow.blur_radius, - content_rect: LayerRect::zero(), }, pipeline_id, - cull_children: false, + task_rect: DeviceIntRect::zero(), } } pub fn resolve_scene_properties(&mut self, properties: &SceneProperties) -> bool { match self.kind { PictureKind::Image { ref mut composite_mode, .. } => { match composite_mode { &mut Some(PictureCompositeMode::Filter(ref mut filter)) => { @@ -162,20 +145,19 @@ impl PicturePrimitive { kind: PictureKind::Image { secondary_render_task_id: None, composite_mode, is_in_3d_context, frame_output_pipeline_id, reference_frame_index, real_local_rect: LayerRect::zero(), extra_gpu_data_handle: GpuCacheHandle::new(), - task_rect: DeviceIntRect::zero(), }, pipeline_id, - cull_children: true, + task_rect: DeviceIntRect::zero(), } } pub fn add_primitive( &mut self, prim_index: PrimitiveIndex, clip_and_scroll: ScrollNodeAndClipChain ) { @@ -214,25 +196,23 @@ impl PicturePrimitive { local_content_rect.inflate(inflate_size, inflate_size) .translate(&offset) } _ => { local_content_rect } } } - PictureKind::TextShadow { offset, blur_radius, ref mut content_rect, .. } => { + PictureKind::TextShadow { blur_radius, .. } => { let blur_offset = blur_radius * BLUR_SAMPLE_SCALE; - *content_rect = local_content_rect.inflate( + local_content_rect.inflate( blur_offset, blur_offset, - ); - - content_rect.translate(&offset) + ) } } } pub fn prepare_for_render( &mut self, prim_index: PrimitiveIndex, prim_metadata: &mut PrimitiveMetadata, @@ -241,26 +221,26 @@ impl PicturePrimitive { frame_context: &FrameBuildingContext, frame_state: &mut FrameBuildingState, ) { let content_scale = LayerToWorldScale::new(1.0) * frame_context.device_pixel_scale; let prim_screen_rect = prim_metadata .screen_rect .as_ref() .expect("bug: trying to draw an off-screen picture!?"); + let device_rect; match self.kind { PictureKind::Image { ref mut secondary_render_task_id, ref mut extra_gpu_data_handle, - ref mut task_rect, composite_mode, .. } => { - let device_rect = match composite_mode { + device_rect = match composite_mode { Some(PictureCompositeMode::Filter(FilterOp::Blur(blur_radius))) => { // If blur radius is 0, we can skip drawing this an an // intermediate surface. if blur_radius == 0.0 { pic_state.tasks.extend(pic_state_for_children.tasks); self.surface = None; DeviceIntRect::zero() @@ -277,23 +257,21 @@ impl PicturePrimitive { // then intersect with the total screen rect, to minimize the // allocation size. let device_rect = prim_screen_rect .clipped .inflate(blur_range, blur_range) .intersection(&prim_screen_rect.unclipped) .unwrap(); - let content_origin = ContentOrigin::Screen(device_rect.origin); - let picture_task = RenderTask::new_picture( RenderTaskLocation::Dynamic(None, device_rect.size), prim_index, RenderTargetKind::Color, - content_origin, + device_rect.origin, PremultipliedColorF::TRANSPARENT, ClearMode::Transparent, pic_state_for_children.tasks, PictureType::Image, ); let picture_task_id = frame_state.render_tasks.add(picture_task); @@ -315,17 +293,17 @@ impl PicturePrimitive { Some(PictureCompositeMode::Filter(FilterOp::DropShadow(offset, blur_radius, _))) => { // TODO(gw): This is totally wrong and can never work with // transformed drop-shadow elements. Fix me! let rect = (prim_metadata.local_rect.translate(&-offset) * content_scale).round().to_i32(); let mut picture_task = RenderTask::new_picture( RenderTaskLocation::Dynamic(None, rect.size), prim_index, RenderTargetKind::Color, - ContentOrigin::Screen(rect.origin), + rect.origin, PremultipliedColorF::TRANSPARENT, ClearMode::Transparent, pic_state_for_children.tasks, PictureType::Image, ); picture_task.mark_for_saving(); let blur_std_deviation = blur_radius * frame_context.device_pixel_scale.0; @@ -343,23 +321,21 @@ impl PicturePrimitive { let render_task_id = frame_state.render_tasks.add(blur_render_task); pic_state.tasks.push(render_task_id); self.surface = Some(render_task_id); rect } Some(PictureCompositeMode::MixBlend(..)) => { - let content_origin = ContentOrigin::Screen(prim_screen_rect.clipped.origin); - let picture_task = RenderTask::new_picture( RenderTaskLocation::Dynamic(None, prim_screen_rect.clipped.size), prim_index, RenderTargetKind::Color, - content_origin, + prim_screen_rect.clipped.origin, PremultipliedColorF::TRANSPARENT, ClearMode::Transparent, pic_state_for_children.tasks, PictureType::Image, ); let readback_task_id = frame_state.render_tasks.add( RenderTask::new_readback(prim_screen_rect.clipped) @@ -370,18 +346,16 @@ impl PicturePrimitive { let render_task_id = frame_state.render_tasks.add(picture_task); pic_state.tasks.push(render_task_id); self.surface = Some(render_task_id); prim_screen_rect.clipped } Some(PictureCompositeMode::Filter(filter)) => { - let content_origin = ContentOrigin::Screen(prim_screen_rect.clipped.origin); - // If this filter is not currently going to affect // the picture, just collapse this picture into the // current render task. This most commonly occurs // when opacity == 1.0, but can also occur on other // filters and be a significant performance win. if filter.is_noop() { pic_state.tasks.extend(pic_state_for_children.tasks); self.surface = None; @@ -394,38 +368,36 @@ impl PicturePrimitive { } } } let picture_task = RenderTask::new_picture( RenderTaskLocation::Dynamic(None, prim_screen_rect.clipped.size), prim_index, RenderTargetKind::Color, - content_origin, + prim_screen_rect.clipped.origin, PremultipliedColorF::TRANSPARENT, ClearMode::Transparent, pic_state_for_children.tasks, PictureType::Image, ); let render_task_id = frame_state.render_tasks.add(picture_task); pic_state.tasks.push(render_task_id); self.surface = Some(render_task_id); } prim_screen_rect.clipped } Some(PictureCompositeMode::Blit) => { - let content_origin = ContentOrigin::Screen(prim_screen_rect.clipped.origin); - let picture_task = RenderTask::new_picture( RenderTaskLocation::Dynamic(None, prim_screen_rect.clipped.size), prim_index, RenderTargetKind::Color, - content_origin, + prim_screen_rect.clipped.origin, PremultipliedColorF::TRANSPARENT, ClearMode::Transparent, pic_state_for_children.tasks, PictureType::Image, ); let render_task_id = frame_state.render_tasks.add(picture_task); pic_state.tasks.push(render_task_id); @@ -435,44 +407,42 @@ impl PicturePrimitive { } None => { pic_state.tasks.extend(pic_state_for_children.tasks); self.surface = None; DeviceIntRect::zero() } }; - - // If scrolling or property animation has resulted in the task - // rect being different than last time, invalidate the GPU - // cache entry for this picture to ensure that the correct - // task rect is provided to the image shader. - if *task_rect != device_rect { - frame_state.gpu_cache.invalidate(&prim_metadata.gpu_location); - *task_rect = device_rect; - } } - PictureKind::TextShadow { blur_radius, color, content_rect, .. } => { + PictureKind::TextShadow { blur_radius, color, .. } => { // This is a shadow element. Create a render task that will // render the text run to a target, and then apply a gaussian // blur to that text run in order to build the actual primitive // which will be blitted to the framebuffer. - let cache_size = to_cache_size(content_rect.size * content_scale); // Quote from https://drafts.csswg.org/css-backgrounds-3/#shadow-blur // "the image that would be generated by applying to the shadow a // Gaussian blur with a standard deviation equal to half the blur radius." let device_radius = (blur_radius * frame_context.device_pixel_scale.0).round(); let blur_std_deviation = device_radius * 0.5; + let blur_range = (blur_std_deviation * BLUR_SAMPLE_SCALE).ceil() as i32; + + device_rect = prim_screen_rect + .clipped + .inflate(blur_range, blur_range) + .intersection(&prim_screen_rect.unclipped) + .unwrap(); + let picture_task = RenderTask::new_picture( - RenderTaskLocation::Dynamic(None, cache_size), + RenderTaskLocation::Dynamic(None, device_rect.size), prim_index, RenderTargetKind::Color, - ContentOrigin::Local(content_rect.origin), + device_rect.origin, color.premultiplied(), ClearMode::Transparent, Vec::new(), PictureType::TextShadow, ); let picture_task_id = frame_state.render_tasks.add(picture_task); @@ -484,32 +454,41 @@ impl PicturePrimitive { ClearMode::Transparent, ); let render_task_id = frame_state.render_tasks.add(blur_render_task); pic_state.tasks.push(render_task_id); self.surface = Some(render_task_id); } } + + // If scrolling or property animation has resulted in the task + // rect being different than last time, invalidate the GPU + // cache entry for this picture to ensure that the correct + // task rect is provided to the image shader. + if self.task_rect != device_rect { + frame_state.gpu_cache.invalidate(&prim_metadata.gpu_location); + self.task_rect = device_rect; + } } pub fn write_gpu_blocks(&self, request: &mut GpuDataRequest) { + request.push(self.task_rect.to_f32()); + match self.kind { PictureKind::TextShadow { .. } => { - request.push([0.0; 4]); request.push(PremultipliedColorF::WHITE); } - PictureKind::Image { task_rect, composite_mode, .. } => { + PictureKind::Image { composite_mode, .. } => { let color = match composite_mode { Some(PictureCompositeMode::Filter(FilterOp::DropShadow(_, _, color))) => { color.premultiplied() } _ => { PremultipliedColorF::WHITE } }; - request.push(task_rect.to_f32()); request.push(color); } } } }
--- a/gfx/webrender/src/prim_store.rs +++ b/gfx/webrender/src/prim_store.rs @@ -1102,21 +1102,17 @@ impl PrimitiveStore { frame_state: &mut FrameBuildingState, ) { let metadata = &mut self.cpu_metadata[prim_index.0]; match metadata.prim_kind { PrimitiveKind::Border => {} PrimitiveKind::TextRun => { let text = &mut self.cpu_text_runs[metadata.cpu_prim_index.0]; // The transform only makes sense for screen space rasterization - let transform = if pic_context.draw_text_transformed { - Some(prim_run_context.scroll_node.world_content_transform.into()) - } else { - None - }; + let transform = Some(prim_run_context.scroll_node.world_content_transform.into()); text.prepare_for_render( frame_state.resource_cache, frame_context.device_pixel_scale, transform, pic_context.display_list, frame_state.gpu_cache, ); } @@ -1710,18 +1706,17 @@ impl PrimitiveStore { let mut may_need_clip_mask = true; let mut pic_state_for_children = PictureState::new(); // Do some basic checks first, that can early out // without even knowing the local rect. let (prim_kind, cpu_prim_index) = { let metadata = &self.cpu_metadata[prim_index.0]; - if pic_context.perform_culling && - !metadata.is_backface_visible && + if !metadata.is_backface_visible && prim_run_context.scroll_node.world_content_transform.is_backface_visible() { return None; } (metadata.prim_kind, metadata.cpu_prim_index) }; // If we have dependencies, we need to prepare them first, in order @@ -1733,17 +1728,17 @@ impl PrimitiveStore { if let BrushKind::Picture { pic_index } = self.cpu_brushes[cpu_prim_index.0].kind { let pic_context_for_children = { let pic = &mut self.pictures[pic_index.0]; if !pic.resolve_scene_properties(frame_context.scene_properties) { return None; } - let (draw_text_transformed, original_reference_frame_index) = match pic.kind { + let (apply_local_clip_rect, original_reference_frame_index) = match pic.kind { PictureKind::Image { reference_frame_index, composite_mode, .. } => { may_need_clip_mask = composite_mode.is_some(); (true, Some(reference_frame_index)) } PictureKind::TextShadow { .. } => { (false, None) } }; @@ -1756,22 +1751,21 @@ impl PrimitiveStore { let inv_world_transform = prim_run_context .scroll_node .world_content_transform .inverse(); PictureContext { pipeline_id: pic.pipeline_id, - perform_culling: pic.cull_children, prim_runs: mem::replace(&mut pic.runs, Vec::new()), original_reference_frame_index, display_list, - draw_text_transformed, inv_world_transform, + apply_local_clip_rect, } }; let result = self.prepare_prim_runs( &pic_context_for_children, &mut pic_state_for_children, frame_context, frame_state, @@ -1792,18 +1786,17 @@ impl PrimitiveStore { metadata.local_rect.size.height <= 0.0 { //warn!("invalid primitive rect {:?}", metadata.local_rect); return None; } let local_rect = metadata.local_clip_rect.intersection(&metadata.local_rect); let local_rect = match local_rect { Some(local_rect) => local_rect, - None if pic_context.perform_culling => return None, - None => LayerRect::zero(), + None => return None, }; let screen_bounding_rect = calculate_screen_bounding_rect( &prim_run_context.scroll_node.world_content_transform, &local_rect, frame_context.device_pixel_scale, ); @@ -1811,26 +1804,26 @@ impl PrimitiveStore { .intersection(&prim_run_context.clip_chain.combined_outer_screen_rect) .map(|clipped| { ScreenRect { clipped, unclipped: screen_bounding_rect, } }); - if metadata.screen_rect.is_none() && pic_context.perform_culling { + if metadata.screen_rect.is_none() { return None; } metadata.clip_chain_rect_index = prim_run_context.clip_chain_rect_index; (local_rect, screen_bounding_rect) }; - if pic_context.perform_culling && may_need_clip_mask && !self.update_clip_task( + if may_need_clip_mask && !self.update_clip_task( prim_index, prim_run_context, &unclipped_device_rect, pic_state, frame_context, frame_state, ) { return None; @@ -1875,26 +1868,24 @@ impl PrimitiveStore { // lookups ever show up in a profile). let scroll_node = &frame_context .clip_scroll_tree .nodes[run.clip_and_scroll.scroll_node_id.0]; let clip_chain = frame_context .clip_scroll_tree .get_clip_chain(run.clip_and_scroll.clip_chain_index); - if pic_context.perform_culling { - if !scroll_node.invertible { - debug!("{:?} {:?}: position not invertible", run.base_prim_index, pic_context.pipeline_id); - continue; - } + if !scroll_node.invertible { + debug!("{:?} {:?}: position not invertible", run.base_prim_index, pic_context.pipeline_id); + continue; + } - if clip_chain.combined_outer_screen_rect.is_empty() { - debug!("{:?} {:?}: clipped out", run.base_prim_index, pic_context.pipeline_id); - continue; - } + if clip_chain.combined_outer_screen_rect.is_empty() { + debug!("{:?} {:?}: clipped out", run.base_prim_index, pic_context.pipeline_id); + continue; } let parent_relative_transform = pic_context .inv_world_transform .map(|inv_parent| { inv_parent.pre_mul(&scroll_node.world_content_transform) }); @@ -1905,19 +1896,20 @@ impl PrimitiveStore { .nodes[original_reference_frame_index.0] .world_content_transform; parent.inverse() .map(|inv_parent| { inv_parent.pre_mul(&scroll_node.world_content_transform) }) }); - let clip_chain_rect = match pic_context.perform_culling { - true => get_local_clip_rect_for_nodes(scroll_node, clip_chain), - false => None, + let clip_chain_rect = if pic_context.apply_local_clip_rect { + get_local_clip_rect_for_nodes(scroll_node, clip_chain) + } else { + None }; let clip_chain_rect_index = match clip_chain_rect { Some(rect) if rect.is_empty() => continue, Some(rect) => { frame_state.local_clip_rects.push(rect); ClipChainRectIndex(frame_state.local_clip_rects.len() - 1) }
--- a/gfx/webrender/src/record.rs +++ b/gfx/webrender/src/record.rs @@ -1,14 +1,14 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use api::{ApiMsg, FrameMsg, SceneMsg}; -use bincode::{serialize, Infinite}; +use bincode::serialize; use byteorder::{LittleEndian, WriteBytesExt}; use std::any::TypeId; use std::fmt::Debug; use std::fs::File; use std::io::Write; use std::mem; use std::path::PathBuf; @@ -44,17 +44,17 @@ impl BinaryRecorder { self.file.write_u32::<LittleEndian>(data.len() as u32).ok(); self.file.write(data).ok(); } } impl ApiRecordingReceiver for BinaryRecorder { fn write_msg(&mut self, _: u32, msg: &ApiMsg) { if should_record_msg(msg) { - let buf = serialize(msg, Infinite).unwrap(); + let buf = serialize(msg).unwrap(); self.write_length_and_data(&buf); } } fn write_payload(&mut self, _: u32, data: &[u8]) { // signal payload with a 0 length self.file.write_u32::<LittleEndian>(0).ok(); self.write_length_and_data(data);
--- a/gfx/webrender/src/render_task.rs +++ b/gfx/webrender/src/render_task.rs @@ -6,17 +6,16 @@ use api::{DeviceIntPoint, DeviceIntRect, use api::{DeviceSize, PremultipliedColorF}; use box_shadow::{BoxShadowCacheKey}; use clip::{ClipSource, ClipStore, ClipWorkItem}; use clip_scroll_tree::CoordinateSystemId; use device::TextureFilter; use gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle}; use gpu_types::{ImageSource, PictureType, RasterizationSpace}; use internal_types::{FastHashMap, SavedTargetIndex, SourceTexture}; -use picture::ContentOrigin; use prim_store::{PrimitiveIndex, ImageCacheKey}; #[cfg(feature = "debugger")] use print_tree::{PrintTreePrinter}; use resource_cache::{CacheItem, ResourceCache}; use std::{cmp, ops, usize, f32, i32}; use texture_cache::{TextureCache, TextureCacheHandle}; use tiling::{RenderPass, RenderTargetIndex}; use tiling::{RenderTargetKind}; @@ -162,17 +161,17 @@ pub struct ClipRegionTask { } #[derive(Debug)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct PictureTask { pub prim_index: PrimitiveIndex, pub target_kind: RenderTargetKind, - pub content_origin: ContentOrigin, + pub content_origin: DeviceIntPoint, pub color: PremultipliedColorF, pub pic_type: PictureType, pub uv_rect_handle: GpuCacheHandle, } #[derive(Debug)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] @@ -254,17 +253,17 @@ pub struct RenderTask { pub saved_index: Option<SavedTargetIndex>, } impl RenderTask { pub fn new_picture( location: RenderTaskLocation, prim_index: PrimitiveIndex, target_kind: RenderTargetKind, - content_origin: ContentOrigin, + content_origin: DeviceIntPoint, color: PremultipliedColorF, clear_mode: ClearMode, children: Vec<RenderTaskId>, pic_type: PictureType, ) -> Self { RenderTask { children, location, @@ -523,29 +522,21 @@ impl RenderTask { // TODO(gw): Maybe there's a way to make this stuff a bit // more type-safe. Although, it will always need // to be kept in sync with the GLSL code anyway. let (data1, data2) = match self.kind { RenderTaskKind::Picture(ref task) => { ( // Note: has to match `PICTURE_TYPE_*` in shaders - // TODO(gw): Instead of using the sign of the picture - // type here, we should consider encoding it - // as a set of flags that get casted here - // and in the shader. This is a bit tidier - // and allows for future expansion of flags. - match task.content_origin { - ContentOrigin::Local(point) => [ - point.x, point.y, task.pic_type as u32 as f32, - ], - ContentOrigin::Screen(point) => [ - point.x as f32, point.y as f32, -(task.pic_type as u32 as f32), - ], - }, + [ + task.content_origin.x as f32, + task.content_origin.y as f32, + task.pic_type as u32 as f32, + ], task.color.to_array() ) } RenderTaskKind::CacheMask(ref task) => { ( [ task.actual_rect.origin.x as f32, task.actual_rect.origin.y as f32, @@ -916,16 +907,17 @@ impl RenderTaskCache { // TODO(gw): Support color tasks in the texture cache, // and perhaps consider if we can determine // if some tasks are opaque as an optimization. let descriptor = ImageDescriptor::new( size.width as u32, size.height as u32, image_format, is_opaque, + false, ); // Allocate space in the texture cache, but don't supply // and CPU-side data to be uploaded. texture_cache.update( &mut cache_entry.handle, descriptor, TextureFilter::Linear,
--- a/gfx/webrender/src/renderer.rs +++ b/gfx/webrender/src/renderer.rs @@ -37,17 +37,16 @@ use frame_builder::FrameBuilderConfig; use gleam::gl; use glyph_rasterizer::{GlyphFormat, GlyphRasterizer}; use gpu_cache::{GpuBlockData, GpuCacheUpdate, GpuCacheUpdateList}; use gpu_types::PrimitiveInstance; use internal_types::{SourceTexture, ORTHO_FAR_PLANE, ORTHO_NEAR_PLANE, ResourceCacheError}; use internal_types::{CacheTextureId, DebugOutput, FastHashMap, RenderedDocument, ResultMsg}; use internal_types::{TextureUpdateList, TextureUpdateOp, TextureUpdateSource}; use internal_types::{RenderTargetInfo, SavedTargetIndex}; -use picture::ContentOrigin; use prim_store::DeferredResolve; use profiler::{BackendProfileCounters, FrameProfileCounters, Profiler}; use profiler::{GpuProfileTag, RendererProfileCounters, RendererProfileTimers}; use query::{GpuProfiler, GpuTimer}; use rayon::{ThreadPool, ThreadPoolBuilder}; use record::ApiRecordingReceiver; use render_backend::RenderBackend; use scene_builder::SceneBuilder; @@ -116,20 +115,16 @@ const GPU_TAG_BRUSH_SOLID: GpuProfileTag const GPU_TAG_BRUSH_LINE: GpuProfileTag = GpuProfileTag { label: "Line", color: debug_colors::DARKRED, }; const GPU_TAG_CACHE_CLIP: GpuProfileTag = GpuProfileTag { label: "C_Clip", color: debug_colors::PURPLE, }; -const GPU_TAG_CACHE_TEXT_RUN: GpuProfileTag = GpuProfileTag { - label: "C_TextRun", - color: debug_colors::MISTYROSE, -}; const GPU_TAG_SETUP_TARGET: GpuProfileTag = GpuProfileTag { label: "target init", color: debug_colors::SLATEGREY, }; const GPU_TAG_SETUP_DATA: GpuProfileTag = GpuProfileTag { label: "data init", color: debug_colors::LIGHTGREY, }; @@ -1440,17 +1435,16 @@ impl Renderer { (true, true) => FontRenderMode::Subpixel, (true, false) => FontRenderMode::Alpha, (false, _) => FontRenderMode::Mono, }; let config = FrameBuilderConfig { enable_scrollbars: options.enable_scrollbars, default_font_render_mode, - debug: options.debug, dual_source_blending_is_enabled: true, dual_source_blending_is_supported: ext_dual_source_blending, }; let device_pixel_ratio = options.device_pixel_ratio; // First set the flags to default and later call set_debug_flags to ensure any // potential transition when enabling a flag is run. let debug_flags = DebugFlags::default(); @@ -1479,16 +1473,17 @@ impl Renderer { .build(); Arc::new(worker.unwrap()) }); let enable_render_on_scroll = options.enable_render_on_scroll; let blob_image_renderer = options.blob_image_renderer.take(); let thread_listener_for_render_backend = thread_listener.clone(); let thread_listener_for_scene_builder = thread_listener.clone(); + let renderer_id_for_render_backend = options.renderer_id.clone(); let rb_thread_name = format!("WRRenderBackend#{}", options.renderer_id.unwrap_or(0)); let scene_thread_name = format!("WRSceneBuilder#{}", options.renderer_id.unwrap_or(0)); let glyph_rasterizer = GlyphRasterizer::new(workers)?; let (scene_builder, scene_tx, scene_rx) = SceneBuilder::new(config, api_tx.clone()); thread::Builder::new().name(scene_thread_name.clone()).spawn(move || { register_thread_with_profiler(scene_thread_name.clone()); if let Some(ref thread_listener) = *thread_listener_for_scene_builder { @@ -1501,16 +1496,17 @@ impl Renderer { if let Some(ref thread_listener) = *thread_listener_for_scene_builder { thread_listener.thread_stopped(&scene_thread_name); } })?; thread::Builder::new().name(rb_thread_name.clone()).spawn(move || { register_thread_with_profiler(rb_thread_name.clone()); if let Some(ref thread_listener) = *thread_listener_for_render_backend { + thread_listener.new_render_backend_thread(renderer_id_for_render_backend); thread_listener.thread_started(&rb_thread_name); } let texture_cache = TextureCache::new(max_device_size); let resource_cache = ResourceCache::new( texture_cache, glyph_rasterizer, blob_image_renderer, @@ -1718,17 +1714,17 @@ impl Renderer { String::new() } #[cfg(feature = "debugger")] fn get_screenshot_for_debugger(&mut self) -> String { use api::ImageDescriptor; - let desc = ImageDescriptor::new(1024, 768, ImageFormat::BGRA8, true); + let desc = ImageDescriptor::new(1024, 768, ImageFormat::BGRA8, true, false); let data = self.device.read_pixels(&desc); let screenshot = debug_server::Screenshot::new(desc.width, desc.height, data); serde_json::to_string(&screenshot).unwrap() } #[cfg(not(feature = "debugger"))] fn get_passes_for_debugger(&self) -> String { @@ -1809,24 +1805,16 @@ impl Renderer { ); debug_target.add( debug_server::BatchKind::Cache, "Horizontal Blur", target.horizontal_blurs.len(), ); for alpha_batch_container in &target.alpha_batch_containers { - for (_, batch) in &alpha_batch_container.text_run_cache_prims { - debug_target.add( - debug_server::BatchKind::Cache, - "Text Shadow", - batch.len(), - ); - } - for batch in alpha_batch_container .opaque_batches .iter() .rev() { debug_target.add( debug_server::BatchKind::Opaque, batch.key.kind.debug_name(), batch.instances.len(), @@ -2420,27 +2408,21 @@ impl Renderer { .unwrap(); // Before submitting the composite batch, do the // framebuffer readbacks that are needed for each // composite operation in this batch. let (readback_rect, readback_layer) = readback.get_target_rect(); let (backdrop_rect, _) = backdrop.get_target_rect(); let backdrop_screen_origin = match backdrop.kind { - RenderTaskKind::Picture(ref task_info) => match task_info.content_origin { - ContentOrigin::Local(_) => panic!("bug: composite from a local-space rasterized picture?"), - ContentOrigin::Screen(p) => p, - }, + RenderTaskKind::Picture(ref task_info) => task_info.content_origin, _ => panic!("bug: composite on non-picture?"), }; let source_screen_origin = match source.kind { - RenderTaskKind::Picture(ref task_info) => match task_info.content_origin { - ContentOrigin::Local(_) => panic!("bug: composite from a local-space rasterized picture?"), - ContentOrigin::Screen(p) => p, - }, + RenderTaskKind::Picture(ref task_info) => task_info.content_origin, _ => panic!("bug: composite on non-picture?"), }; // Bind the FBO to blit the backdrop to. // Called per-instance in case the layer (and therefore FBO) // changes. The device will skip the GL call if the requested // target is already bound. let cache_draw_target = (cache_texture, readback_layer.0 as i32); @@ -2679,41 +2661,16 @@ impl Renderer { &BatchTextures::no_texture(), stats, ); } } self.handle_scaling(render_tasks, &target.scalings, SourceTexture::CacheRGBA8); - // Draw any textrun caches for this target. For now, this - // is only used to cache text runs that are to be blurred - // for shadow support. In the future it may be worth - // considering using this for (some) other text runs, since - // it removes the overhead of submitting many small glyphs - // to multiple tiles in the normal text run case. - for alpha_batch_container in &target.alpha_batch_containers { - if !alpha_batch_container.text_run_cache_prims.is_empty() { - self.device.set_blend(true); - self.device.set_blend_mode_premultiplied_alpha(); - - let _timer = self.gpu_profile.start_timer(GPU_TAG_CACHE_TEXT_RUN); - self.shaders.cs_text_run - .bind(&mut self.device, projection, &mut self.renderer_errors); - for (texture_id, instances) in &alpha_batch_container.text_run_cache_prims { - self.draw_instanced_batch( - instances, - VertexArrayKind::Primitive, - &BatchTextures::color(*texture_id), - stats, - ); - } - } - } - //TODO: record the pixel count for cached primitives if target.needs_depth() { let _gl = self.gpu_profile.start_marker("opaque batches"); let opaque_sampler = self.gpu_profile.start_sampler(GPU_SAMPLER_TAG_OPAQUE); self.device.set_blend(false); //Note: depth equality is needed for split planes self.device.set_depth_func(DepthFunction::LessEqual); @@ -3816,25 +3773,25 @@ pub trait ExternalImageHandler { pub trait OutputImageHandler { fn lock(&mut self, pipeline_id: PipelineId) -> Option<(u32, DeviceIntSize)>; fn unlock(&mut self, pipeline_id: PipelineId); } pub trait ThreadListener { fn thread_started(&self, thread_name: &str); fn thread_stopped(&self, thread_name: &str); + fn new_render_backend_thread(&self, renderer_id: Option<u64>); } pub struct RendererOptions { pub device_pixel_ratio: f32, pub resource_override_path: Option<PathBuf>, pub enable_aa: bool, pub enable_dithering: bool, pub max_recorded_profiles: usize, - pub debug: bool, pub enable_scrollbars: bool, pub precache_shaders: bool, pub renderer_kind: RendererKind, pub enable_subpixel_aa: bool, pub clear_color: Option<ColorF>, pub enable_clear_scissor: bool, pub max_texture_size: Option<u32>, pub scatter_gpu_cache_updates: bool, @@ -3854,17 +3811,16 @@ impl Default for RendererOptions { fn default() -> Self { RendererOptions { device_pixel_ratio: 1.0, resource_override_path: None, enable_aa: true, enable_dithering: true, debug_flags: DebugFlags::empty(), max_recorded_profiles: 0, - debug: false, enable_scrollbars: false, precache_shaders: false, renderer_kind: RendererKind::Native, enable_subpixel_aa: false, clear_color: Some(ColorF::new(1.0, 1.0, 1.0, 1.0)), enable_clear_scissor: true, max_texture_size: None, // Scattered GPU cache updates haven't met a test that would show their superiority yet.
--- a/gfx/webrender/src/resource_cache.rs +++ b/gfx/webrender/src/resource_cache.rs @@ -884,18 +884,17 @@ impl ResourceCache { (Some(stride), offset) }; ImageDescriptor { width: actual_width, height: actual_height, stride, offset, - format: image_descriptor.format, - is_opaque: image_descriptor.is_opaque, + ..*image_descriptor } } else { image_template.descriptor.clone() }; let filter = match request.rendering { ImageRendering::Pixelated => { TextureFilter::Nearest @@ -903,17 +902,18 @@ impl ResourceCache { ImageRendering::Auto | ImageRendering::CrispEdges => { // If the texture uses linear filtering, enable mipmaps and // trilinear filtering, for better image quality. We only // support this for now on textures that are not placed // into the shared cache. This accounts for any image // that is > 512 in either dimension, so it should cover // the most important use cases. We may want to support // mip-maps on shared cache items in the future. - if descriptor.width > 512 && + if descriptor.allow_mipmaps && + descriptor.width > 512 && descriptor.height > 512 && !self.texture_cache.is_allowed_in_shared_cache( TextureFilter::Linear, &descriptor, ) { TextureFilter::Trilinear } else { TextureFilter::Linear @@ -949,16 +949,19 @@ impl ResourceCache { self.cached_glyphs.clear(); } if what.contains(ClearCache::GLYPH_DIMENSIONS) { self.cached_glyph_dimensions.clear(); } if what.contains(ClearCache::RENDER_TASKS) { self.cached_render_tasks.clear(); } + if what.contains(ClearCache::TEXTURE_CACHE) { + self.texture_cache.clear(); + } } pub fn clear_namespace(&mut self, namespace: IdNamespace) { self.resources .image_templates .images .retain(|key, _| key.0 != namespace); self.cached_images
--- a/gfx/webrender/src/shade.rs +++ b/gfx/webrender/src/shade.rs @@ -408,17 +408,16 @@ fn create_clip_shader(name: &'static str program } pub struct Shaders { // These are "cache shaders". These shaders are used to // draw intermediate results to cache targets. The results // of these shaders are then used by the primitive shaders. - pub cs_text_run: LazilyCompiledShader, pub cs_blur_a8: LazilyCompiledShader, pub cs_blur_rgba8: LazilyCompiledShader, // Brush shaders brush_solid: BrushShader, brush_line: BrushShader, brush_image: Vec<Option<BrushShader>>, brush_blend: BrushShader, @@ -453,24 +452,16 @@ pub struct Shaders { } impl Shaders { pub fn new( device: &mut Device, gl_type: GlType, options: &RendererOptions, ) -> Result<Self, ShaderError> { - let cs_text_run = LazilyCompiledShader::new( - ShaderKind::Cache(VertexArrayKind::Primitive), - "cs_text_run", - &[], - device, - options.precache_shaders, - )?; - let brush_solid = BrushShader::new( "brush_solid", device, &[], options.precache_shaders, )?; let brush_line = BrushShader::new( @@ -677,17 +668,16 @@ impl Shaders { ShaderKind::Primitive, "ps_split_composite", &[], device, options.precache_shaders, )?; Ok(Shaders { - cs_text_run, cs_blur_a8, cs_blur_rgba8, brush_solid, brush_line, brush_image, brush_blend, brush_mix_blend, brush_yuv_image, @@ -777,17 +767,16 @@ impl Shaders { } }; prim_shader.get(transform_kind) } } } pub fn deinit(self, device: &mut Device) { - self.cs_text_run.deinit(device); self.cs_blur_a8.deinit(device); self.cs_blur_rgba8.deinit(device); self.brush_solid.deinit(device); self.brush_line.deinit(device); self.brush_blend.deinit(device); self.brush_mix_blend.deinit(device); self.brush_radial_gradient.deinit(device); self.brush_linear_gradient.deinit(device);
--- a/gfx/webrender/src/texture_cache.rs +++ b/gfx/webrender/src/texture_cache.rs @@ -276,16 +276,66 @@ impl TextureCache { pending_updates: TextureUpdateList::new(), frame_id: FrameId(0), entries: FreeList::new(), standalone_entry_handles: Vec::new(), shared_entry_handles: Vec::new(), } } + pub fn clear(&mut self) { + let standalone_entry_handles = mem::replace( + &mut self.standalone_entry_handles, + Vec::new(), + ); + + for handle in standalone_entry_handles { + let entry = self.entries.free(handle); + entry.evict(); + self.free(entry); + } + + let shared_entry_handles = mem::replace( + &mut self.shared_entry_handles, + Vec::new(), + ); + + for handle in shared_entry_handles { + let entry = self.entries.free(handle); + entry.evict(); + self.free(entry); + } + + assert!(self.entries.len() == 0); + + if let Some(texture_id) = self.array_a8_linear.clear() { + self.pending_updates.push(TextureUpdate { + id: texture_id, + op: TextureUpdateOp::Free, + }); + self.cache_textures.free(texture_id, self.array_a8_linear.format); + } + + if let Some(texture_id) = self.array_rgba8_linear.clear() { + self.pending_updates.push(TextureUpdate { + id: texture_id, + op: TextureUpdateOp::Free, + }); + self.cache_textures.free(texture_id, self.array_rgba8_linear.format); + } + + if let Some(texture_id) = self.array_rgba8_nearest.clear() { + self.pending_updates.push(TextureUpdate { + id: texture_id, + op: TextureUpdateOp::Free, + }); + self.cache_textures.free(texture_id, self.array_rgba8_nearest.format); + } + } + pub fn begin_frame(&mut self, frame_id: FrameId) { self.frame_id = frame_id; } pub fn end_frame(&mut self, texture_cache_profile: &mut TextureCacheProfileCounters) { self.expire_old_standalone_entries(); self.array_a8_linear @@ -1008,16 +1058,22 @@ impl TextureArray { filter, layer_count, is_allocated: false, regions: Vec::new(), texture_id: None, } } + fn clear(&mut self) -> Option<CacheTextureId> { + self.is_allocated = false; + self.regions.clear(); + self.texture_id.take() + } + fn update_profile(&self, counter: &mut ResourceProfileCounter) { if self.is_allocated { let size = self.layer_count as u32 * TEXTURE_LAYER_DIMENSIONS * TEXTURE_LAYER_DIMENSIONS * self.format.bytes_per_pixel(); counter.set(self.layer_count as usize, size as usize); } else { counter.set(0, 0); }
--- a/gfx/webrender/tests/angle_shader_validation.rs +++ b/gfx/webrender/tests/angle_shader_validation.rs @@ -40,20 +40,16 @@ const SHADERS: &[Shader] = &[ name: "cs_clip_border", features: CLIP_FEATURES, }, // Cache shaders Shader { name: "cs_blur", features: CACHE_FEATURES, }, - Shader { - name: "cs_text_run", - features: CACHE_FEATURES, - }, // Prim shaders Shader { name: "ps_border_corner", features: PRIM_FEATURES, }, Shader { name: "ps_border_edge", features: PRIM_FEATURES,
--- a/gfx/webrender_api/Cargo.toml +++ b/gfx/webrender_api/Cargo.toml @@ -8,21 +8,21 @@ repository = "https://github.com/servo/w [features] nightly = ["euclid/unstable", "serde/unstable"] ipc = ["ipc-channel"] serialize = [] deserialize = [] [dependencies] app_units = "0.6" +bincode = "1.0" bitflags = "1.0" -bincode = "0.9" byteorder = "1.2.1" +ipc-channel = {version = "0.10.0", optional = true} euclid = { version = "0.17", features = ["serde"] } -ipc-channel = {version = "0.9", optional = true} serde = { version = "=1.0.27", features = ["rc"] } serde_derive = { version = "=1.0.27", features = ["deserialize_in_place"] } time = "0.1" [target.'cfg(target_os = "macos")'.dependencies] core-foundation = "0.5" core-graphics = "0.13"
--- a/gfx/webrender_api/src/api.rs +++ b/gfx/webrender_api/src/api.rs @@ -531,16 +531,17 @@ bitflags!{ bitflags!{ /// Mask for clearing caches in debug commands. #[derive(Deserialize, Serialize)] pub struct ClearCache: u8 { const IMAGES = 0x1; const GLYPHS = 0x2; const GLYPH_DIMENSIONS = 0x4; const RENDER_TASKS = 0x8; + const TEXTURE_CACHE = 0x16; } } /// Information about a loaded capture of each document /// that is returned by `RenderBackend`. #[derive(Clone, Debug, Deserialize, Serialize)] pub struct CapturedDocument { pub document_id: DocumentId,
--- a/gfx/webrender_api/src/display_item.rs +++ b/gfx/webrender_api/src/display_item.rs @@ -415,18 +415,18 @@ pub struct GradientStop { pub offset: f32, pub color: ColorF, } #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] pub struct RadialGradient { pub center: LayoutPoint, pub radius: LayoutSize, - pub start_radius: f32, - pub end_radius: f32, + pub start_offset: f32, + pub end_offset: f32, pub extend_mode: ExtendMode, } // IMPLICIT stops: Vec<GradientStop> #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] pub struct ClipChainItem { pub id: ClipChainId, pub parent: Option<ClipChainId>, } // IMPLICIT stops: Vec<ClipId>
--- a/gfx/webrender_api/src/display_list.rs +++ b/gfx/webrender_api/src/display_list.rs @@ -157,24 +157,24 @@ impl BuiltDisplayList { AuxIter::new(&self.data[range.start .. range.start + range.length]) } } /// Returns the byte-range the slice occupied, and the number of elements /// in the slice. fn skip_slice<T: for<'de> Deserialize<'de>>( list: &BuiltDisplayList, - data: &mut &[u8], + mut data: &mut &[u8], ) -> (ItemRange<T>, usize) { let base = list.data.as_ptr() as usize; - let byte_size: usize = bincode::deserialize_from(data, bincode::Infinite) + let byte_size: usize = bincode::deserialize_from(&mut data) .expect("MEH: malicious input?"); let start = data.as_ptr() as usize; - let item_count: usize = bincode::deserialize_from(data, bincode::Infinite) + let item_count: usize = bincode::deserialize_from(&mut data) .expect("MEH: malicious input?"); // Remember how many bytes item_count occupied let item_count_size = data.as_ptr() as usize - start; let range = ItemRange { start: start - base, // byte offset to item_count length: byte_size + item_count_size, // number of bytes for item_count + payload @@ -236,19 +236,18 @@ impl<'a> BuiltDisplayListIter<'a> { self.cur_clip_chain_items = ItemRange::default(); loop { if self.data.len() == 0 { return None; } { - let reader = bincode::read_types::IoReader::new(UnsafeReader::new(&mut self.data)); - let mut deserializer = bincode::Deserializer::new(reader, bincode::Infinite); - Deserialize::deserialize_in_place(&mut deserializer, &mut self.cur_item) + let reader = bincode::IoReader::new(UnsafeReader::new(&mut self.data)); + bincode::deserialize_in_place(reader, &mut self.cur_item) .expect("MEH: malicious process?"); } match self.cur_item.item { SetGradientStops => { self.cur_stops = skip_slice::<GradientStop>(self.list, &mut self.data).0; // This is a dummy item, skip over it @@ -388,18 +387,17 @@ impl<'a, 'b> DisplayItemRef<'a, 'b> { } } impl<'de, 'a, T: Deserialize<'de>> AuxIter<'a, T> { pub fn new(mut data: &'a [u8]) -> Self { let size: usize = if data.len() == 0 { 0 // Accept empty ItemRanges pointing anywhere } else { - bincode::deserialize_from(&mut UnsafeReader::new(&mut data), bincode::Infinite) - .expect("MEH: malicious input?") + bincode::deserialize_from(&mut UnsafeReader::new(&mut data)).expect("MEH: malicious input?") }; AuxIter { data, size, _boo: PhantomData, } } @@ -409,17 +407,17 @@ impl<'a, T: for<'de> Deserialize<'de>> I type Item = T; fn next(&mut self) -> Option<T> { if self.size == 0 { None } else { self.size -= 1; Some( - bincode::deserialize_from(&mut UnsafeReader::new(&mut self.data), bincode::Infinite) + bincode::deserialize_from(&mut UnsafeReader::new(&mut self.data)) .expect("MEH: malicious input?"), ) } } fn size_hint(&self) -> (usize, Option<usize>) { (self.size, Some(self.size)) } @@ -660,23 +658,23 @@ impl<'a> Write for SizeCounter { /// invocations. /// /// If this assumption is incorrect, the result will be Undefined Behaviour. This /// assumption should hold for all derived Serialize impls, which is all we currently /// use. fn serialize_fast<T: Serialize>(vec: &mut Vec<u8>, e: &T) { // manually counting the size is faster than vec.reserve(bincode::serialized_size(&e) as usize) for some reason let mut size = SizeCounter(0); - bincode::serialize_into(&mut size, e, bincode::Infinite).unwrap(); + bincode::serialize_into(&mut size, e).unwrap(); vec.reserve(size.0); let old_len = vec.len(); let ptr = unsafe { vec.as_mut_ptr().offset(old_len as isize) }; let mut w = UnsafeVecWriter(ptr); - bincode::serialize_into(&mut w, e, bincode::Infinite).unwrap(); + bincode::serialize_into(&mut w, e).unwrap(); // fix up the length unsafe { vec.set_len(old_len + size.0); } // make sure we wrote the right amount debug_assert_eq!(((w.0 as usize) - (vec.as_ptr() as usize)), vec.len()); } @@ -697,29 +695,29 @@ fn serialize_iter_fast<I>(vec: &mut Vec< where I: ExactSizeIterator + Clone, I::Item: Serialize, { // manually counting the size is faster than vec.reserve(bincode::serialized_size(&e) as usize) for some reason let mut size = SizeCounter(0); let mut count1 = 0; for e in iter.clone() { - bincode::serialize_into(&mut size, &e, bincode::Infinite).unwrap(); + bincode::serialize_into(&mut size, &e).unwrap(); count1 += 1; } vec.reserve(size.0); let old_len = vec.len(); let ptr = unsafe { vec.as_mut_ptr().offset(old_len as isize) }; let mut w = UnsafeVecWriter(ptr); let mut count2 = 0; for e in iter { - bincode::serialize_into(&mut w, &e, bincode::Infinite).unwrap(); + bincode::serialize_into(&mut w, &e).unwrap(); count2 += 1; } // fix up the length unsafe { vec.set_len(old_len + size.0); } // make sure we wrote the right amount debug_assert_eq!(((w.0 as usize) - (vec.as_ptr() as usize)), vec.len()); @@ -957,17 +955,16 @@ impl DisplayListBuilder { // Now write the actual byte_size let final_offset = data.len(); let byte_size = final_offset - payload_offset; // Note we don't use serialize_fast because we don't want to change the Vec's len bincode::serialize_into( &mut &mut data[byte_size_offset..], &byte_size, - bincode::Infinite, ).unwrap(); debug_assert_eq!(len, count); } fn push_iter<I>(&mut self, iter: I) where I: IntoIterator, @@ -1070,70 +1067,51 @@ impl DisplayListBuilder { fn normalize_stops(stops: &mut Vec<GradientStop>, extend_mode: ExtendMode) -> (f32, f32) { assert!(stops.len() >= 2); let first = *stops.first().unwrap(); let last = *stops.last().unwrap(); assert!(first.offset <= last.offset); - let stops_origin = first.offset; let stops_delta = last.offset - first.offset; if stops_delta > 0.000001 { for stop in stops { - stop.offset = (stop.offset - stops_origin) / stops_delta; + stop.offset = (stop.offset - first.offset) / stops_delta; } (first.offset, last.offset) } else { // We have a degenerate gradient and can't accurately transform the stops // what happens here depends on the repeat behavior, but in any case // we reconstruct the gradient stops to something simpler and equivalent stops.clear(); match extend_mode { ExtendMode::Clamp => { // This gradient is two colors split at the offset of the stops, // so create a gradient with two colors split at 0.5 and adjust // the gradient line so 0.5 is at the offset of the stops - stops.push(GradientStop { - color: first.color, - offset: 0.0, - }); - stops.push(GradientStop { - color: first.color, - offset: 0.5, - }); - stops.push(GradientStop { - color: last.color, - offset: 0.5, - }); - stops.push(GradientStop { - color: last.color, - offset: 1.0, - }); + stops.push(GradientStop { color: first.color, offset: 0.0, }); + stops.push(GradientStop { color: first.color, offset: 0.5, }); + stops.push(GradientStop { color: last.color, offset: 0.5, }); + stops.push(GradientStop { color: last.color, offset: 1.0, }); let offset = last.offset; (offset - 0.5, offset + 0.5) } ExtendMode::Repeat => { // A repeating gradient with stops that are all in the same // position should just display the last color. I believe the // spec says that it should be the average color of the gradient, // but this matches what Gecko and Blink does - stops.push(GradientStop { - color: last.color, - offset: 0.0, - }); - stops.push(GradientStop { - color: last.color, - offset: 1.0, - }); + stops.push(GradientStop { color: last.color, offset: 0.0, }); + stops.push(GradientStop { color: last.color, offset: 1.0, }); (0.0, 1.0) } } } } // NOTE: gradients must be pushed in the order they're created @@ -1170,69 +1148,41 @@ impl DisplayListBuilder { ) -> RadialGradient { if radius.width <= 0.0 || radius.height <= 0.0 { // The shader cannot handle a non positive radius. So // reuse the stops vector and construct an equivalent // gradient. let last_color = stops.last().unwrap().color; let stops = [ - GradientStop { - offset: 0.0, - color: last_color, - }, - GradientStop { - offset: 1.0, - color: last_color, - }, + GradientStop { offset: 0.0, color: last_color, }, + GradientStop { offset: 1.0, color: last_color, }, ]; self.push_stops(&stops); return RadialGradient { center, radius: LayoutSize::new(1.0, 1.0), - start_radius: 0.0, - end_radius: 1.0, + start_offset: 0.0, + end_offset: 1.0, extend_mode, }; } let (start_offset, end_offset) = DisplayListBuilder::normalize_stops(&mut stops, extend_mode); self.push_stops(&stops); RadialGradient { center, radius, - start_radius: radius.width * start_offset, - end_radius: radius.width * end_offset, - extend_mode, - } - } - - // NOTE: gradients must be pushed in the order they're created - // because create_gradient stores the stops in anticipation - pub fn create_complex_radial_gradient( - &mut self, - center: LayoutPoint, - radius: LayoutSize, - start_radius: f32, - end_radius: f32, - stops: Vec<GradientStop>, - extend_mode: ExtendMode, - ) -> RadialGradient { - self.push_stops(&stops); - - RadialGradient { - center, - radius, - start_radius, - end_radius, + start_offset: start_offset, + end_offset: end_offset, extend_mode, } } pub fn push_border( &mut self, info: &LayoutPrimitiveInfo, widths: BorderWidths,
--- a/gfx/webrender_api/src/image.rs +++ b/gfx/webrender_api/src/image.rs @@ -71,27 +71,35 @@ impl ImageFormat { #[derive(Copy, Clone, Debug, Deserialize, PartialEq, Serialize)] pub struct ImageDescriptor { pub format: ImageFormat, pub width: u32, pub height: u32, pub stride: Option<u32>, pub offset: u32, pub is_opaque: bool, + pub allow_mipmaps: bool, } impl ImageDescriptor { - pub fn new(width: u32, height: u32, format: ImageFormat, is_opaque: bool) -> Self { + pub fn new( + width: u32, + height: u32, + format: ImageFormat, + is_opaque: bool, + allow_mipmaps: bool, + ) -> Self { ImageDescriptor { width, height, format, stride: None, offset: 0, is_opaque, + allow_mipmaps, } } pub fn compute_stride(&self) -> u32 { self.stride .unwrap_or(self.width * self.format.bytes_per_pixel()) }
--- a/gfx/webrender_bindings/revision.txt +++ b/gfx/webrender_bindings/revision.txt @@ -1,1 +1,1 @@ -2083e83d958dd4a230ccae5c518e4bc8fbf88009 +30cfecc343e407ce277d07cf09f27ad9dd1917a1
--- a/gfx/webrender_bindings/src/bindings.rs +++ b/gfx/webrender_bindings/src/bindings.rs @@ -262,16 +262,17 @@ impl<'a> Into<ImageDescriptor> for &'a W stride: if self.stride != 0 { Some(self.stride) } else { None }, format: self.format, is_opaque: self.is_opaque, offset: 0, + allow_mipmaps: false, } } } /// cbindgen:field-names=[mHandle] #[repr(C)] #[derive(Copy, Clone)] pub struct WrExternalImageId(pub u64); @@ -666,16 +667,19 @@ impl ThreadListener for GeckoProfilerThr } } fn thread_stopped(&self, _: &str) { unsafe { gecko_profiler_unregister_thread(); } } + + fn new_render_backend_thread(&self, _renderer_id: Option<u64>) { + } } pub struct WrThreadPool(Arc<rayon::ThreadPool>); #[no_mangle] pub unsafe extern "C" fn wr_thread_pool_new() -> *mut WrThreadPool { let worker = rayon::ThreadPoolBuilder::new() .thread_name(|idx|{ format!("WRWorker#{}", idx) })
--- a/gfx/wrench/Cargo.toml +++ b/gfx/wrench/Cargo.toml @@ -2,17 +2,17 @@ name = "wrench" version = "0.3.0" authors = ["Vladimir Vukicevic <vladimir@pobox.com>"] build = "build.rs" license = "MPL-2.0" [dependencies] base64 = "0.6" -bincode = "0.9" +bincode = "1.0" byteorder = "1.0" env_logger = { version = "0.5", optional = true } euclid = "0.17" gleam = "0.4" glutin = "0.12" app_units = "0.6" image = "0.18" clap = { version = "2", features = ["yaml"] }
--- a/gfx/wrench/src/args.yaml +++ b/gfx/wrench/src/args.yaml @@ -12,20 +12,16 @@ args: short: v long: verbose help: Enable verbose display - zoom: short: z long: zoom help: Set zoom factor takes_value: true - - debug: - short: d - long: debug - help: Enable debug renderer - shaders: long: shaders help: Override path for shaders takes_value: true - rebuild: short: r long: rebuild help: Rebuild display list from scratch every frame
--- a/gfx/wrench/src/main.rs +++ b/gfx/wrench/src/main.rs @@ -424,17 +424,16 @@ fn main() { &mut window, events_loop.as_mut().map(|el| el.create_proxy()), res_path, dp_ratio, save_type, dim, args.is_present("rebuild"), args.is_present("no_subpixel_aa"), - args.is_present("debug"), args.is_present("verbose"), args.is_present("no_scissor"), args.is_present("no_batch"), args.is_present("precache"), args.is_present("slow_subpixel"), zoom_factor.unwrap_or(1.0), notifier, );
--- a/gfx/wrench/src/rawtest.rs +++ b/gfx/wrench/src/rawtest.rs @@ -83,17 +83,17 @@ impl<'a> RawtestHarness<'a> { println!("\ttile decomposition..."); // This exposes a crash in tile decomposition let layout_size = LayoutSize::new(800., 800.); let mut resources = ResourceUpdates::new(); let blob_img = self.wrench.api.generate_image_key(); resources.add_image( blob_img, - ImageDescriptor::new(151, 56, ImageFormat::BGRA8, true), + ImageDescriptor::new(151, 56, ImageFormat::BGRA8, true, false), ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 50, 150, 255))), Some(128), ); let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size); let info = LayoutPrimitiveInfo::new(rect(448.899994, 74.0, 151.000031, 56.)); @@ -135,17 +135,17 @@ impl<'a> RawtestHarness<'a> { let layout_size = LayoutSize::new(400., 400.); let mut resources = ResourceUpdates::new(); { let api = &self.wrench.api; blob_img = api.generate_image_key(); resources.add_image( blob_img, - ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true), + ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true, false), ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 50, 150, 255))), None, ); } // draw the blob the first time let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size); let info = LayoutPrimitiveInfo::new(rect(0.0, 60.0, 200.0, 200.0)); @@ -215,24 +215,24 @@ impl<'a> RawtestHarness<'a> { let layout_size = LayoutSize::new(400., 400.); let mut resources = ResourceUpdates::new(); let (blob_img, blob_img2) = { let api = &self.wrench.api; blob_img = api.generate_image_key(); resources.add_image( blob_img, - ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true), + ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true, false), ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 50, 150, 255))), None, ); blob_img2 = api.generate_image_key(); resources.add_image( blob_img2, - ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true), + ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true, false), ImageData::new_blob_image(blob::serialize_blob(ColorU::new(80, 50, 150, 255))), None, ); (blob_img, blob_img2) }; // setup some counters to count how many times each image is requested let img1_requested = Arc::new(AtomicIsize::new(0)); @@ -280,38 +280,38 @@ impl<'a> RawtestHarness<'a> { self.submit_dl(&mut epoch, layout_size, builder, Some(resources)); let _pixels_first = self.render_and_get_pixels(window_rect); // update and redraw both images let mut resources = ResourceUpdates::new(); resources.update_image( blob_img, - ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true), + ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true, false), ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 50, 150, 255))), Some(rect(100, 100, 100, 100)), ); resources.update_image( blob_img2, - ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true), + ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true, false), ImageData::new_blob_image(blob::serialize_blob(ColorU::new(59, 50, 150, 255))), Some(rect(100, 100, 100, 100)), ); let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size); push_images(&mut builder); self.submit_dl(&mut epoch, layout_size, builder, Some(resources)); let _pixels_second = self.render_and_get_pixels(window_rect); // only update the first image let mut resources = ResourceUpdates::new(); resources.update_image( blob_img, - ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true), + ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true, false), ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 150, 150, 255))), Some(rect(200, 200, 100, 100)), ); let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size); push_images(&mut builder); self.submit_dl(&mut epoch, layout_size, builder, Some(resources)); let _pixels_third = self.render_and_get_pixels(window_rect); @@ -334,17 +334,17 @@ impl<'a> RawtestHarness<'a> { ); let layout_size = LayoutSize::new(400., 400.); let mut resources = ResourceUpdates::new(); let blob_img = { let img = self.wrench.api.generate_image_key(); resources.add_image( img, - ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true), + ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true, false), ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 50, 150, 255))), None, ); img }; // draw the blobs the first time let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size); @@ -363,17 +363,17 @@ impl<'a> RawtestHarness<'a> { self.submit_dl(&mut epoch, layout_size, builder, Some(resources)); let pixels_first = self.render_and_get_pixels(window_rect); // draw the blob image a second time after updating it with the same color let mut resources = ResourceUpdates::new(); resources.update_image( blob_img, - ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true), + ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true, false), ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 50, 150, 255))), Some(rect(100, 100, 100, 100)), ); // make a new display list that refers to the first image let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size); let info = LayoutPrimitiveInfo::new(rect(0.0, 60.0, 200.0, 200.0)); builder.push_image( @@ -387,17 +387,17 @@ impl<'a> RawtestHarness<'a> { self.submit_dl(&mut epoch, layout_size, builder, Some(resources)); let pixels_second = self.render_and_get_pixels(window_rect); // draw the blob image a third time after updating it with a different color let mut resources = ResourceUpdates::new(); resources.update_image( blob_img, - ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true), + ImageDescriptor::new(500, 500, ImageFormat::BGRA8, true, false), ImageData::new_blob_image(blob::serialize_blob(ColorU::new(50, 150, 150, 255))), Some(rect(200, 200, 100, 100)), ); // make a new display list that refers to the first image let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size); let info = LayoutPrimitiveInfo::new(rect(0.0, 60.0, 200.0, 200.0)); builder.push_image( @@ -502,17 +502,17 @@ impl<'a> RawtestHarness<'a> { ); // 1. render some scene let mut resources = ResourceUpdates::new(); let image = self.wrench.api.generate_image_key(); resources.add_image( image, - ImageDescriptor::new(1, 1, ImageFormat::BGRA8, true), + ImageDescriptor::new(1, 1, ImageFormat::BGRA8, true, false), ImageData::new(vec![0xFF, 0, 0, 0xFF]), None, ); let mut builder = DisplayListBuilder::new(self.wrench.root_pipeline_id, layout_size); builder.push_image( &LayoutPrimitiveInfo::new(rect(300.0, 70.0, 150.0, 50.0)),
--- a/gfx/wrench/src/reftest.rs +++ b/gfx/wrench/src/reftest.rs @@ -27,16 +27,17 @@ const PLATFORM: &str = "linux"; #[cfg(target_os = "macos")] const PLATFORM: &str = "mac"; #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))] const PLATFORM: &str = "other"; const OPTION_DISABLE_SUBPX: &str = "disable-subpixel"; const OPTION_DISABLE_AA: &str = "disable-aa"; const OPTION_DISABLE_DUAL_SOURCE_BLENDING: &str = "disable-dual-source-blending"; +const OPTION_ALLOW_MIPMAPS: &str = "allow-mipmaps"; pub struct ReftestOptions { // These override values that are lower. pub allow_max_difference: usize, pub allow_num_differences: usize, } impl ReftestOptions { @@ -72,16 +73,17 @@ pub struct Reftest { reference: PathBuf, font_render_mode: Option<FontRenderMode>, max_difference: usize, num_differences: usize, expected_draw_calls: Option<usize>, expected_alpha_targets: Option<usize>, expected_color_targets: Option<usize>, disable_dual_source_blending: bool, + allow_mipmaps: bool, zoom_factor: f32, } impl Display for Reftest { fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { write!( f, "{} {} {}", @@ -191,16 +193,17 @@ impl ReftestManifest { let mut max_count = 0; let mut op = ReftestOp::Equal; let mut font_render_mode = None; let mut expected_color_targets = None; let mut expected_alpha_targets = None; let mut expected_draw_calls = None; let mut disable_dual_source_blending = false; let mut zoom_factor = 1.0; + let mut allow_mipmaps = false; for (i, token) in tokens.iter().enumerate() { match *token { "include" => { assert!(i == 0, "include must be by itself"); let include = dir.join(tokens[1]); reftests.append( @@ -243,16 +246,19 @@ impl ReftestManifest { font_render_mode = Some(FontRenderMode::Alpha); } if args.iter().any(|arg| arg == &OPTION_DISABLE_AA) { font_render_mode = Some(FontRenderMode::Mono); } if args.iter().any(|arg| arg == &OPTION_DISABLE_DUAL_SOURCE_BLENDING) { disable_dual_source_blending = true; } + if args.iter().any(|arg| arg == &OPTION_ALLOW_MIPMAPS) { + allow_mipmaps = true; + } } "==" => { op = ReftestOp::Equal; } "!=" => { op = ReftestOp::NotEqual; } _ => { @@ -262,16 +268,17 @@ impl ReftestManifest { reference: dir.join(tokens[i + 1]), font_render_mode, max_difference: cmp::max(max_difference, options.allow_max_difference), num_differences: cmp::max(max_count, options.allow_num_differences), expected_draw_calls, expected_alpha_targets, expected_color_targets, disable_dual_source_blending, + allow_mipmaps, zoom_factor, }); break; } } } } @@ -329,16 +336,22 @@ impl<'a> ReftestHarness<'a> { } failing.len() } fn run_reftest(&mut self, t: &Reftest) -> bool { println!("REFTEST {}", t); + self.wrench + .api + .send_debug_cmd( + DebugCommand::ClearCaches(ClearCache::all()) + ); + self.wrench.set_page_zoom(ZoomFactor::new(t.zoom_factor)); if t.disable_dual_source_blending { self.wrench .api .send_debug_cmd( DebugCommand::EnableDualSourceBlending(false) ); @@ -346,31 +359,33 @@ impl<'a> ReftestHarness<'a> { let window_size = self.window.get_inner_size(); let reference = match t.reference.extension().unwrap().to_str().unwrap() { "yaml" => { let (reference, _) = self.render_yaml( t.reference.as_path(), window_size, t.font_render_mode, + t.allow_mipmaps, ); reference } "png" => { self.load_image(t.reference.as_path(), ImageFormat::PNG) } other => panic!("Unknown reftest extension: {}", other), }; // the reference can be smaller than the window size, // in which case we only compare the intersection let (test, stats) = self.render_yaml( t.test.as_path(), reference.size, t.font_render_mode, + t.allow_mipmaps, ); if t.disable_dual_source_blending { self.wrench .api .send_debug_cmd( DebugCommand::EnableDualSourceBlending(true) ); @@ -459,19 +474,21 @@ impl<'a> ReftestHarness<'a> { } } fn render_yaml( &mut self, filename: &Path, size: DeviceUintSize, font_render_mode: Option<FontRenderMode>, + allow_mipmaps: bool, ) -> (ReftestImage, RendererStats) { let mut reader = YamlFrameReader::new(filename); reader.set_font_render_mode(font_render_mode); + reader.allow_mipmaps(allow_mipmaps); reader.do_frame(self.wrench); // wait for the frame self.rx.recv().unwrap(); let stats = self.wrench.render(); let window_size = self.window.get_inner_size(); assert!(size.width <= window_size.width && size.height <= window_size.height);
--- a/gfx/wrench/src/wrench.rs +++ b/gfx/wrench/src/wrench.rs @@ -169,17 +169,16 @@ impl Wrench { window: &mut WindowWrapper, proxy: Option<EventsLoopProxy>, shader_override_path: Option<PathBuf>, dp_ratio: f32, save_type: Option<SaveType>, size: DeviceUintSize, do_rebuild: bool, no_subpixel_aa: bool, - debug: bool, verbose: bool, no_scissor: bool, no_batch: bool, precache_shaders: bool, disable_dual_source_blending: bool, zoom_factor: f32, notifier: Option<Box<RenderNotifier>>, ) -> Self { @@ -202,17 +201,16 @@ impl Wrench { debug_flags.set(DebugFlags::DISABLE_BATCHING, no_batch); let callbacks = Arc::new(Mutex::new(blob::BlobCallbacks::new())); let opts = webrender::RendererOptions { device_pixel_ratio: dp_ratio, resource_override_path: shader_override_path, recorder, enable_subpixel_aa: !no_subpixel_aa, - debug, debug_flags, enable_clear_scissor: !no_scissor, max_recorded_profiles: 16, precache_shaders, blob_image_renderer: Some(Box::new(blob::CheckerboardRenderer::new(callbacks.clone()))), disable_dual_source_blending, ..Default::default() };
--- a/gfx/wrench/src/yaml_frame_reader.rs +++ b/gfx/wrench/src/yaml_frame_reader.rs @@ -99,17 +99,17 @@ fn generate_checkerboard_image( pixels.push(value); pixels.push(value); pixels.push(0xff); } } } ( - ImageDescriptor::new(width, height, ImageFormat::BGRA8, true), + ImageDescriptor::new(width, height, ImageFormat::BGRA8, true, false), ImageData::new(pixels), ) } fn generate_xy_gradient_image(w: u32, h: u32) -> (ImageDescriptor, ImageData) { let mut pixels = Vec::with_capacity((w * h * 4) as usize); for y in 0 .. h { for x in 0 .. w { @@ -117,17 +117,17 @@ fn generate_xy_gradient_image(w: u32, h: pixels.push((y as f32 / h as f32 * 255.0 * grid) as u8); pixels.push(0); pixels.push((x as f32 / w as f32 * 255.0 * grid) as u8); pixels.push(255); } } ( - ImageDescriptor::new(w, h, ImageFormat::BGRA8, true), + ImageDescriptor::new(w, h, ImageFormat::BGRA8, true, false), ImageData::new(pixels), ) } fn generate_solid_color_image( r: u8, g: u8, b: u8, @@ -147,17 +147,17 @@ fn generate_solid_color_image( let end = ptr.offset((w * h) as isize); while ptr < end { *ptr = color; ptr = ptr.offset(1); } } ( - ImageDescriptor::new(w, h, ImageFormat::BGRA8, a == 255), + ImageDescriptor::new(w, h, ImageFormat::BGRA8, a == 255, false), ImageData::new(pixels), ) } fn is_image_opaque(format: ImageFormat, bytes: &[u8]) -> bool { match format { @@ -195,16 +195,17 @@ pub struct YamlFrameReader { /// scroll layers should be initialized with. scroll_offsets: HashMap<ExternalScrollId, LayerPoint>, image_map: HashMap<(PathBuf, Option<i64>), (ImageKey, LayoutSize)>, fonts: HashMap<FontDescriptor, FontKey>, font_instances: HashMap<(FontKey, Au, FontInstanceFlags), FontInstanceKey>, font_render_mode: Option<FontRenderMode>, + allow_mipmaps: bool, /// A HashMap that allows specifying a numeric id for clip and clip chains in YAML /// and having each of those ids correspond to a unique ClipId. clip_id_map: HashMap<u64, ClipId>, } impl YamlFrameReader { pub fn new(yaml_path: &Path) -> YamlFrameReader { @@ -219,16 +220,17 @@ impl YamlFrameReader { queue_depth: 1, include_only: vec![], scroll_offsets: HashMap::new(), fonts: HashMap::new(), font_instances: HashMap::new(), font_render_mode: None, image_map: HashMap::new(), clip_id_map: HashMap::new(), + allow_mipmaps: false, } } pub fn deinit(mut self, wrench: &mut Wrench) { let mut updates = ResourceUpdates::new(); for (_, font_instance) in self.font_instances.drain() { updates.delete_font_instance(font_instance); @@ -410,16 +412,17 @@ impl YamlFrameReader { } _ => panic!("We don't support whatever your crazy image type is, come on"), }; let descriptor = ImageDescriptor::new( image_dims.0, image_dims.1, format, is_image_opaque(format, &bytes[..]), + self.allow_mipmaps, ); let data = ImageData::new(bytes);