Merge mozilla-central to mozilla-inbound. r=merge a=merge CLOSED TREE

This commit is contained in:
Margareta Eliza Balazs 2017-11-08 00:09:29 +02:00
Родитель 25f3d350f0 4164a3a53d
Коммит 130574a8e2
263 изменённых файлов: 3431 добавлений и 2362 удалений

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

@ -3346,12 +3346,18 @@
<certItem issuerName="MCgxCzAJBgNVBAYTAkJFMRkwFwYDVQQDExBCZWxnaXVtIFJvb3QgQ0Ey">
<serialNumber>frj5jTuqBnQ4fljPvVU3KA==</serialNumber>
</certItem>
<certItem issuerName="MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQDExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMw==">
<serialNumber>AzL4tLuklekJ8lSh6VnRMSrk</serialNumber>
</certItem>
<certItem issuerName="MIGFMQswCQYDVQQGEwJVUzEgMB4GA1UECgwXV2VsbHMgRmFyZ28gV2VsbHNTZWN1cmUxHDAaBgNVBAsME1dlbGxzIEZhcmdvIEJhbmsgTkExNjA0BgNVBAMMLVdlbGxzU2VjdXJlIFB1YmxpYyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eQ==">
<serialNumber>AMs=</serialNumber>
</certItem>
<certItem issuerName="MHExKDAmBgNVBAMTH0dsb2JhbFNpZ24gUm9vdFNpZ24gUGFydG5lcnMgQ0ExHTAbBgNVBAsTFFJvb3RTaWduIFBhcnRuZXJzIENBMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMQswCQYDVQQGEwJCRQ==">
<serialNumber>BAAAAAABFqoAZoI=</serialNumber>
</certItem>
<certItem issuerName="MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQDExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMw==">
<serialNumber>A+ly3y1rVP59k/MKfcE3DoEq</serialNumber>
</certItem>
<certItem issuerName="MIGVMQswCQYDVQQGEwJHUjFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIwMTE=">
<serialNumber>GN2Hrh9LtnM=</serialNumber>
</certItem>
@ -3364,6 +3370,9 @@
<certItem issuerName="MIGBMQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTElMCMGA1UECxMcUHJpbWFyeSBPYmplY3QgUHVibGlzaGluZyBDQTEwMC4GA1UEAxMnR2xvYmFsU2lnbiBQcmltYXJ5IE9iamVjdCBQdWJsaXNoaW5nIENB">
<serialNumber>BAAAAAABI54PryQ=</serialNumber>
</certItem>
<certItem issuerName="MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQDExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMw==">
<serialNumber>BJDHnthjoDRutxFRJPFnixbU</serialNumber>
</certItem>
<certItem issuerName="MFoxCzAJBgNVBAYTAkRFMRMwEQYDVQQKEwpERk4tVmVyZWluMRAwDgYDVQQLEwdERk4tUEtJMSQwIgYDVQQDExtERk4tVmVyZWluIFBDQSBHbG9iYWwgLSBHMDE=">
<serialNumber>CeFU2w==</serialNumber>
</certItem>
@ -3376,9 +3385,15 @@
<certItem issuerName="MFkxCzAJBgNVBAYTAk5MMR4wHAYDVQQKExVTdGFhdCBkZXIgTmVkZXJsYW5kZW4xKjAoBgNVBAMTIVN0YWF0IGRlciBOZWRlcmxhbmRlbiBPdmVyaGVpZCBDQQ==">
<serialNumber>ATFEdg==</serialNumber>
</certItem>
<certItem issuerName="MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQDExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMw==">
<serialNumber>A5oET6WBWx72ColKf0txoWyR</serialNumber>
</certItem>
<certItem issuerName="MFAxJDAiBgNVBAsTG0dsb2JhbFNpZ24gRUNDIFJvb3QgQ0EgLSBSNDETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbg==">
<serialNumber>RnQ3dg5KdDZs0nyFZk4=</serialNumber>
</certItem>
<certItem issuerName="MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQDExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMw==">
<serialNumber>BONHqLIx/ibQE08IQIyoGaXg</serialNumber>
</certItem>
<certItem issuerName="MHsxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazEyMDAGA1UEAxMpVmVyaVNpZ24gQ2xhc3MgMyBTU1AgSW50ZXJtZWRpYXRlIENBIC0gRzI=">
<serialNumber>NpsJHyt3o1U47AAgw3UNXA==</serialNumber>
</certItem>
@ -3418,6 +3433,9 @@
<certItem issuerName="MIG8MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBhdCBodHRwczovL3d3dy52ZXJpc2lnbi5jb20vcnBhIChjKTEwMTYwNAYDVQQDEy1WZXJpU2lnbiBDbGFzcyAzIEludGVybmF0aW9uYWwgU2VydmVyIENBIC0gRzM=">
<serialNumber>BYyEX2b5+K+myAIR7eXaRQ==</serialNumber>
</certItem>
<certItem issuerName="MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQDExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMw==">
<serialNumber>A7RCxMe1S9Hb7ENzRxl0mxGP</serialNumber>
</certItem>
<certItem issuerName="MFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxTaWduIFJvb3QgQ0E=">
<serialNumber>BAAAAAABLF5/Gog=</serialNumber>
</certItem>
@ -3430,6 +3448,9 @@
<certItem issuerName="MEwxIDAeBgNVBAsTF0dsb2JhbFNpZ24gUm9vdCBDQSAtIFIzMRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu">
<serialNumber>BAAAAAABMYnGRuw=</serialNumber>
</certItem>
<certItem issuerName="MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQDExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMw==">
<serialNumber>A/99bZCzSpexYL5y6dSryDn3</serialNumber>
</certItem>
<certItem issuerName="MIGKMQswCQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEmMCQGA1UECxMdQ29weXJpZ2h0IChjKSAyMDA1IFdJU2VLZXkgU0ExFjAUBgNVBAsTDUludGVybmF0aW9uYWwxKTAnBgNVBAMTIFdJU2VLZXkgQ2VydGlmeUlEIEFkdmFuY2VkIEcxIENB">
<serialNumber>WD1AyQAAAAAAJQ==</serialNumber>
</certItem>
@ -3490,6 +3511,9 @@
<certItem issuerName="MDsxCzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBGTk1ULVJDTQ==">
<serialNumber>Eg==</serialNumber>
</certItem>
<certItem issuerName="MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQDExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMw==">
<serialNumber>AyjNQ4dnGD3FD6WL5gYrYru7</serialNumber>
</certItem>
<certItem issuerName="MEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDM=">
<serialNumber>Cj0=</serialNumber>
</certItem>
@ -3541,6 +3565,9 @@
<certItem issuerName="MDwxHjAcBgNVBAMMFUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsGA1UECgwEQXRvczELMAkGA1UEBhMCREU=">
<serialNumber>a12RvBNhznU=</serialNumber>
</certItem>
<certItem issuerName="MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQDExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMw==">
<serialNumber>A7uy+rmTav6tDH4dRrsnvXGH</serialNumber>
</certItem>
<certItem issuerName="MIGFMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01PRE8gQ0EgTGltaXRlZDErMCkGA1UEAxMiQ09NT0RPIFJTQSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eQ==">
<serialNumber>AKrMYlJmUUin8FOM/0TJrmk=</serialNumber>
</certItem>
@ -3688,9 +3715,15 @@
<certItem issuerName="MEIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9iYWwgQ0E=">
<serialNumber>AjpW</serialNumber>
</certItem>
<certItem issuerName="MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQDExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMw==">
<serialNumber>A8wZnhfuY6VIV1SwGsTGNR7L</serialNumber>
</certItem>
<certItem issuerName="MF8xCzAJBgNVBAYTAlRXMRIwEAYDVQQKDAlUQUlXQU4tQ0ExEDAOBgNVBAsMB1Jvb3QgQ0ExKjAoBgNVBAMMIVRXQ0EgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eQ==">
<serialNumber>DL8=</serialNumber>
</certItem>
<certItem issuerName="MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQDExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMw==">
<serialNumber>A+RCQYwhofmXM+/hxdyoUzkI</serialNumber>
</certItem>
<certItem issuerName="MEYxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMR8wHQYDVQQDExZHZW9UcnVzdCBTSEEyNTYgU1NMIENB">
<serialNumber>OUvvVscW0/NltofkmV9qmg==</serialNumber>
</certItem>
@ -3718,6 +3751,9 @@
<certItem issuerName="MIG8MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBhdCBodHRwczovL3d3dy52ZXJpc2lnbi5jb20vcnBhIChjKTEwMTYwNAYDVQQDEy1WZXJpU2lnbiBDbGFzcyAzIEludGVybmF0aW9uYWwgU2VydmVyIENBIC0gRzM=">
<serialNumber>NMpMcEnex3eXx4ohk9glcQ==</serialNumber>
</certItem>
<certItem issuerName="MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQDExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMw==">
<serialNumber>A7T0V6o47rgCKl3oUb7jF2Ph</serialNumber>
</certItem>
<certItem issuerName="MFoxCzAJBgNVBAYTAkRFMRMwEQYDVQQKEwpERk4tVmVyZWluMRAwDgYDVQQLEwdERk4tUEtJMSQwIgYDVQQDExtERk4tVmVyZWluIFBDQSBHbG9iYWwgLSBHMDE=">
<serialNumber>F6QlB/yX+A==</serialNumber>
</certItem>
@ -3766,6 +3802,9 @@
<certItem issuerName="MEoxCzAJBgNVBAYTAlVTMSAwHgYDVQQKExdTZWN1cmVUcnVzdCBDb3Jwb3JhdGlvbjEZMBcGA1UEAxMQU2VjdXJlIEdsb2JhbCBDQQ==">
<serialNumber>QAAnEQ==</serialNumber>
</certItem>
<certItem issuerName="MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQDExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMw==">
<serialNumber>A3ZQibPGSZ8nPVbuccaCvUfa</serialNumber>
</certItem>
<certItem issuerName="MFwxCzAJBgNVBAYTAlVTMRkwFwYDVQQKDBBWZXJpem9uIEJ1c2luZXNzMREwDwYDVQQLDAhPbW5pUm9vdDEfMB0GA1UEAwwWVmVyaXpvbiBHbG9iYWwgUm9vdCBDQQ==">
<serialNumber>A4g=</serialNumber>
</certItem>
@ -3775,6 +3814,9 @@
<certItem issuerName="MFoxCzAJBgNVBAYTAklFMRIwEAYDVQQKEwlCYWx0aW1vcmUxEzARBgNVBAsTCkN5YmVyVHJ1c3QxIjAgBgNVBAMTGUJhbHRpbW9yZSBDeWJlclRydXN0IFJvb3Q=">
<serialNumber>BycfpA==</serialNumber>
</certItem>
<certItem issuerName="MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQDExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMw==">
<serialNumber>BHT6CK6B569m/dd5dEluBOEd</serialNumber>
</certItem>
<certItem issuerName="MIGTMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRydXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dD">
<serialNumber>Ew1ee9Jq7Q/Dig3ACF4V6Q==</serialNumber>
</certItem>
@ -3835,6 +3877,9 @@
<certItem issuerName="MD8xCzAJBgNVBAYTAlRXMTAwLgYDVQQKDCdHb3Zlcm5tZW50IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHk=">
<serialNumber>APdCebq8ZyZr/T0luxlicNw=</serialNumber>
</certItem>
<certItem issuerName="MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQDExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMw==">
<serialNumber>A7GX+szdK8/7Kf0xUuarfyIN</serialNumber>
</certItem>
<certItem issuerName="MFwxCzAJBgNVBAYTAkJFMRUwEwYDVQQLEwxUcnVzdGVkIFJvb3QxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExGzAZBgNVBAMTElRydXN0ZWQgUm9vdCBDQSBHMg==">
<serialNumber>YUlF+VXF2FWFqCo472HfZlw=</serialNumber>
</certItem>
@ -3913,24 +3958,12 @@
<certItem issuerName="MIG9MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNhbCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5">
<serialNumber>QOu0a5Z9rCkw6Nk7Rg1/AQ==</serialNumber>
</certItem>
<certItem issuerName="MH4xCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRTeW1hbnRlYyBDb3Jwb3JhdGlvbjEfMB0GA1UECxMWU3ltYW50ZWMgVHJ1c3QgTmV0d29yazEvMC0GA1UEAxMmU3ltYW50ZWMgQ2xhc3MgMyBTZWN1cmUgU2VydmVyIENBIC0gRzQ=">
<serialNumber>PAdKZPiaac2CvPxbOrsHOw==</serialNumber>
</certItem>
<certItem issuerName="MF8xCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRQwEgYDVQQLEwtQYXJ0bmVycyBDQTEfMB0GA1UEAxMWR2xvYmFsU2lnbiBQYXJ0bmVycyBDQQ==">
<serialNumber>BAAAAAABCFiEp9s=</serialNumber>
</certItem>
<certItem issuerName="MHYxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazEtMCsGA1UEAxMkVmVyaVNpZ24gQ2xhc3MgMyBTU1AgSW50ZXJtZWRpYXRlIENB">
<serialNumber>GuJ0aGBYhChXAOljooJZ3A==</serialNumber>
</certItem>
<certItem issuerName="MFwxCzAJBgNVBAYTAkJFMRUwEwYDVQQLEwxUcnVzdGVkIFJvb3QxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExGzAZBgNVBAMTElRydXN0ZWQgUm9vdCBDQSBHMg==">
<serialNumber>QM1zZ4GZ4gfwpQtUYye3Ne0=</serialNumber>
</certItem>
<certItem issuerName="MIGVMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRydXN0LmNvbTEdMBsGA1UEAxMUVVROLVVTRVJGaXJzdC1PYmplY3Q=">
<serialNumber>a9rf7/BmG9JkKvRuy7J5QA==</serialNumber>
</certItem>
<certItem issuerName="MFcxCzAJBgNVBAYTAlRXMQ4wDAYDVQQKEwVUYWlDQTESMBAGA1UECxMJUG9saWN5IENBMSQwIgYDVQQDExtUYWlDQSBJbmZvcm1hdGlvbiBQb2xpY3kgQ0E=">
<serialNumber>UbQGvw==</serialNumber>
</certItem>
<certItem issuerName="MDwxHjAcBgNVBAMMFUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsGA1UECgwEQXRvczELMAkGA1UEBhMCREU=">
<serialNumber>M0VSOewW3WI=</serialNumber>
</certItem>
@ -3943,17 +3976,11 @@
<certItem issuerName="MFoxCzAJBgNVBAYTAkRFMRMwEQYDVQQKEwpERk4tVmVyZWluMRAwDgYDVQQLEwdERk4tUEtJMSQwIgYDVQQDExtERk4tVmVyZWluIFBDQSBHbG9iYWwgLSBHMDE=">
<serialNumber>CcHC/g==</serialNumber>
</certItem>
<certItem issuerName="MIGVMQswCQYDVQQGEwJHUjFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIwMTE=">
<serialNumber>AQAAAAU=</serialNumber>
<certItem issuerName="MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQDExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMw==">
<serialNumber>A3TWA5Aylxw0x8bVvrmUSNJd</serialNumber>
</certItem>
<certItem issuerName="MFoxCzAJBgNVBAYTAkRFMRMwEQYDVQQKEwpERk4tVmVyZWluMRAwDgYDVQQLEwdERk4tUEtJMSQwIgYDVQQDExtERk4tVmVyZWluIFBDQSBHbG9iYWwgLSBHMDE=">
<serialNumber>Cfk9lw==</serialNumber>
</certItem>
<certItem issuerName="MGQxCzAJBgNVBAYTAmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGlnaXRhbCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAy">
<serialNumber>AIChpbGNqu4XKp9J70syKEs=</serialNumber>
</certItem>
<certItem issuerName="MHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlBUyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRyZSBSb290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWU=">
<serialNumber>cJ+vg4742XhNgJW2ot9eIg==</serialNumber>
<certItem issuerName="MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQDExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMw==">
<serialNumber>A3UNTBOHUkbq+k999nJeSJdF</serialNumber>
</certItem>
<certItem issuerName="MIG9MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNhbCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5">
<serialNumber>fMTRbGCp280pnyE/u53zbA==</serialNumber>
@ -3970,12 +3997,6 @@
<certItem issuerName="MCgxCzAJBgNVBAYTAkJFMRkwFwYDVQQDExBCZWxnaXVtIFJvb3QgQ0Ey">
<serialNumber>RFlmmjulj6Ve7PfBi44nnw==</serialNumber>
</certItem>
<certItem issuerName="MFoxCzAJBgNVBAYTAkRFMRMwEQYDVQQKEwpERk4tVmVyZWluMRAwDgYDVQQLEwdERk4tUEtJMSQwIgYDVQQDExtERk4tVmVyZWluIFBDQSBHbG9iYWwgLSBHMDE=">
<serialNumber>Cyr1PA==</serialNumber>
</certItem>
<certItem issuerName="MDQxCzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25h">
<serialNumber>Gg==</serialNumber>
</certItem>
<certItem issuerName="MFoxCzAJBgNVBAYTAkRFMRMwEQYDVQQKEwpERk4tVmVyZWluMRAwDgYDVQQLEwdERk4tUEtJMSQwIgYDVQQDExtERk4tVmVyZWluIFBDQSBHbG9iYWwgLSBHMDE=">
<serialNumber>CqL7CA==</serialNumber>
</certItem>
@ -3985,30 +4006,12 @@
<certItem issuerName="MEMxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwx0aGF3dGUsIEluYy4xHTAbBgNVBAMTFHRoYXd0ZSBTSEEyNTYgU1NMIENB">
<serialNumber>UKKK5ol/rKBZchAAOnZjaA==</serialNumber>
</certItem>
<certItem issuerName="MGYxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMR0wGwYDVQQLExREb21haW4gVmFsaWRhdGVkIFNTTDEgMB4GA1UEAxMXR2VvVHJ1c3QgRFYgU1NMIENBIC0gRzQ=">
<serialNumber>H08=</serialNumber>
</certItem>
<certItem issuerName="MHExKDAmBgNVBAMTH0dsb2JhbFNpZ24gUm9vdFNpZ24gUGFydG5lcnMgQ0ExHTAbBgNVBAsTFFJvb3RTaWduIFBhcnRuZXJzIENBMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMQswCQYDVQQGEwJCRQ==">
<serialNumber>BAAAAAABLM/7qjk=</serialNumber>
</certItem>
<certItem issuerName="MHExKDAmBgNVBAMTH0dsb2JhbFNpZ24gUm9vdFNpZ24gUGFydG5lcnMgQ0ExHTAbBgNVBAsTFFJvb3RTaWduIFBhcnRuZXJzIENBMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMQswCQYDVQQGEwJCRQ==">
<serialNumber>BAAAAAABKB/OGqI=</serialNumber>
</certItem>
<certItem issuerName="MGMxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwx0aGF3dGUsIEluYy4xHTAbBgNVBAsTFERvbWFpbiBWYWxpZGF0ZWQgU1NMMR4wHAYDVQQDExV0aGF3dGUgRFYgU1NMIENBIC0gRzI=">
<serialNumber>Rvm2CEw2IC2Mu/ax0A46QQ==</serialNumber>
</certItem>
<certItem issuerName="MGYxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMR0wGwYDVQQLExREb21haW4gVmFsaWRhdGVkIFNTTDEgMB4GA1UEAxMXR2VvVHJ1c3QgRFYgU1NMIENBIC0gRzM=">
<serialNumber>HNo1DR4XCe4mS1iUMsY6Wg==</serialNumber>
</certItem>
<certItem issuerName="MFoxCzAJBgNVBAYTAklFMRIwEAYDVQQKEwlCYWx0aW1vcmUxEzARBgNVBAsTCkN5YmVyVHJ1c3QxIjAgBgNVBAMTGUJhbHRpbW9yZSBDeWJlclRydXN0IFJvb3Q=">
<serialNumber>ByfFnw==</serialNumber>
</certItem>
<certItem issuerName="MFoxCzAJBgNVBAYTAkRFMRMwEQYDVQQKEwpERk4tVmVyZWluMRAwDgYDVQQLEwdERk4tUEtJMSQwIgYDVQQDExtERk4tVmVyZWluIFBDQSBHbG9iYWwgLSBHMDE=">
<serialNumber>F5BhENPfVw==</serialNumber>
</certItem>
<certItem issuerName="MIGVMQswCQYDVQQGEwJHUjFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIwMTE=">
<serialNumber>GN2Hrh9Ltm4=</serialNumber>
</certItem>
<certItem issuerName="MGQxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMTowOAYDVQQDEzFHbG9iYWxTaWduIFBlcnNvbmFsU2lnbiBQYXJ0bmVycyBDQSAtIFNIQTI1NiAtIEcy">
<serialNumber>AeNmeF8oVpDp/4GPvA==</serialNumber>
</certItem>
@ -4021,9 +4024,6 @@
<certItem issuerName="MH8xCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRTeW1hbnRlYyBDb3Jwb3JhdGlvbjEfMB0GA1UECxMWU3ltYW50ZWMgVHJ1c3QgTmV0d29yazEwMC4GA1UEAxMnU3ltYW50ZWMgQ2xhc3MgMyBFQ0MgMjU2IGJpdCBFViBDQSAtIEcy">
<serialNumber>OhrtngFwotLcm4i+z00SjA==</serialNumber>
</certItem>
<certItem issuerName="MD0xCzAJBgNVBAYTAkZSMREwDwYDVQQKEwhDZXJ0cGx1czEbMBkGA1UEAxMSQ2xhc3MgMiBQcmltYXJ5IENB">
<serialNumber>ESJJweWBPhoXAaB9c8SHwI4O</serialNumber>
</certItem>
<certItem issuerName="MIGFMQswCQYDVQQGEwJVUzEgMB4GA1UECgwXV2VsbHMgRmFyZ28gV2VsbHNTZWN1cmUxHDAaBgNVBAsME1dlbGxzIEZhcmdvIEJhbmsgTkExNjA0BgNVBAMMLVdlbGxzU2VjdXJlIFB1YmxpYyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eQ==">
<serialNumber>ANU=</serialNumber>
</certItem>
@ -4036,36 +4036,21 @@
<certItem issuerName="MEwxIDAeBgNVBAsTF0dsb2JhbFNpZ24gUm9vdCBDQSAtIFIzMRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu">
<serialNumber>BAAAAAABJQcQRNU=</serialNumber>
</certItem>
<certItem issuerName="MIG8MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBhdCBodHRwczovL3d3dy52ZXJpc2lnbi5jb20vcnBhIChjKTEwMTYwNAYDVQQDEy1WZXJpU2lnbiBDbGFzcyAzIEludGVybmF0aW9uYWwgU2VydmVyIENBIC0gRzM=">
<serialNumber>VOcIuNbTqkpOMUyI108FOg==</serialNumber>
</certItem>
<certItem issuerName="MF8xCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xhc3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eQ==">
<serialNumber>HVRikKXRQ1ouhOpYcOna/A==</serialNumber>
</certItem>
<certItem issuerName="MIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp">
<serialNumber>TA5iEg==</serialNumber>
</certItem>
<certItem issuerName="MFAxJDAiBgNVBAsTG0dsb2JhbFNpZ24gRUNDIFJvb3QgQ0EgLSBSNDETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbg==">
<serialNumber>RnQ3dYovwvB0D5q2YGY=</serialNumber>
</certItem>
<certItem issuerName="MEExCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxUaGF3dGUsIEluYy4xGzAZBgNVBAMTElRoYXd0ZSBTR0MgQ0EgLSBHMg==">
<serialNumber>e0bEFhI16xx9U1yvlI56rA==</serialNumber>
</certItem>
<certItem issuerName="MFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUgQ2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjg=">
<serialNumber>JGKKnm00uOQ=</serialNumber>
</certItem>
<certItem issuerName="MGMxCzAJBgNVBAYTAkZSMRMwEQYDVQQKEwpDZXJ0aW5vbWlzMRcwFQYDVQQLEw4wMDAyIDQzMzk5ODkwMzEmMCQGA1UEAwwdQ2VydGlub21pcyAtIEF1dG9yaXTDqSBSYWNpbmU=">
<serialNumber>Eg==</serialNumber>
</certItem>
<certItem issuerName="MCgxCzAJBgNVBAYTAkJFMRkwFwYDVQQDExBCZWxnaXVtIFJvb3QgQ0Ey">
<serialNumber>L1fHogsVxmfMBka5q4uzaQ==</serialNumber>
</certItem>
<certItem issuerName="MH4xCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRTeW1hbnRlYyBDb3Jwb3JhdGlvbjEfMB0GA1UECxMWU3ltYW50ZWMgVHJ1c3QgTmV0d29yazEvMC0GA1UEAxMmU3ltYW50ZWMgQ2xhc3MgMyBTZWN1cmUgU2VydmVyIENBIC0gRzQ=">
<serialNumber>ezdAeCxKH7BFs7vn3byYaw==</serialNumber>
</certItem>
<certItem issuerName="MIGFMQswCQYDVQQGEwJVUzEgMB4GA1UECgwXV2VsbHMgRmFyZ28gV2VsbHNTZWN1cmUxHDAaBgNVBAsME1dlbGxzIEZhcmdvIEJhbmsgTkExNjA0BgNVBAMMLVdlbGxzU2VjdXJlIFB1YmxpYyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eQ==">
<serialNumber>AZ0=</serialNumber>
</certItem>
<certItem issuerName="MD8xJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjEXMBUGA1UEAxMORFNUIFJvb3QgQ0EgWDM=">
<serialNumber>AJiU+bpWh2Uc4xFRf8GM9yA=</serialNumber>
</certItem>
@ -4075,33 +4060,18 @@
<certItem issuerName="MFwxCzAJBgNVBAYTAkJFMRUwEwYDVQQLEwxUcnVzdGVkIFJvb3QxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExGzAZBgNVBAMTElRydXN0ZWQgUm9vdCBDQSBHMg==">
<serialNumber>UV9aaDeNRNtQuXjRYk4Skhg=</serialNumber>
</certItem>
<certItem issuerName="MFoxCzAJBgNVBAYTAkRFMRMwEQYDVQQKEwpERk4tVmVyZWluMRAwDgYDVQQLEwdERk4tUEtJMSQwIgYDVQQDExtERk4tVmVyZWluIFBDQSBHbG9iYWwgLSBHMDE=">
<serialNumber>CcHC1w==</serialNumber>
</certItem>
<certItem issuerName="MGMxCzAJBgNVBAYTAkJFMRUwEwYDVQQLEwxUcnVzdGVkIFJvb3QxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExIjAgBgNVBAMTGVRydXN0ZWQgUm9vdCBDQSBTSEEyNTYgRzI=">
<serialNumber>RdHgEmEIjdyRFWDRRlk=</serialNumber>
</certItem>
<certItem issuerName="MFoxCzAJBgNVBAYTAklFMRIwEAYDVQQKEwlCYWx0aW1vcmUxEzARBgNVBAsTCkN5YmVyVHJ1c3QxIjAgBgNVBAMTGUJhbHRpbW9yZSBDeWJlclRydXN0IFJvb3Q=">
<serialNumber>BEeJFwO0nu759EPo9tKluw==</serialNumber>
</certItem>
<certItem issuerName="MHExCzAJBgNVBAYTAkRFMRwwGgYDVQQKExNEZXV0c2NoZSBUZWxla29tIEFHMR8wHQYDVQQLExZULVRlbGVTZWMgVHJ1c3QgQ2VudGVyMSMwIQYDVQQDExpEZXV0c2NoZSBUZWxla29tIFJvb3QgQ0EgMg==">
<serialNumber>AQw=</serialNumber>
</certItem>
<certItem issuerName="MFYxCzAJBgNVBAYTAkpQMQ8wDQYDVQQKEwZKSVBERUMxGjAYBgNVBAsTEUpDQU4gU3ViIFJvb3QgQ0EwMRowGAYDVQQDExFKQ0FOIFN1YiBSb290IENBMA==">
<serialNumber>BAAAAAABK84yjs8=</serialNumber>
</certItem>
<certItem issuerName="MIGVMQswCQYDVQQGEwJHUjFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIwMTE=">
<serialNumber>FJl6tXgNpSk=</serialNumber>
</certItem>
<certItem issuerName="MHExKDAmBgNVBAMTH0dsb2JhbFNpZ24gUm9vdFNpZ24gUGFydG5lcnMgQ0ExHTAbBgNVBAsTFFJvb3RTaWduIFBhcnRuZXJzIENBMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMQswCQYDVQQGEwJCRQ==">
<serialNumber>BAAAAAAA+X/GIyk=</serialNumber>
</certItem>
<certItem issuerName="MD0xCzAJBgNVBAYTAkZSMREwDwYDVQQKEwhDZXJ0cGx1czEbMBkGA1UEAxMSQ2xhc3MgMiBQcmltYXJ5IENB">
<serialNumber>ESCC9oPNcRdPOox+SjWm9dTX</serialNumber>
</certItem>
<certItem issuerName="MD0xCzAJBgNVBAYTAkZSMREwDwYDVQQKEwhDZXJ0cGx1czEbMBkGA1UEAxMSQ2xhc3MgMiBQcmltYXJ5IENB">
<serialNumber>DjIvBkX+ECVbB/C3i6w2Gg==</serialNumber>
</certItem>
<certItem issuerName="MIHBMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0NsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yaw==">
<serialNumber>O2Qh+qhbBRuZA11yDhcLGQ==</serialNumber>
</certItem>
@ -4123,6 +4093,9 @@
<certItem issuerName="MHExKDAmBgNVBAMTH0dsb2JhbFNpZ24gUm9vdFNpZ24gUGFydG5lcnMgQ0ExHTAbBgNVBAsTFFJvb3RTaWduIFBhcnRuZXJzIENBMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMQswCQYDVQQGEwJCRQ==">
<serialNumber>BAAAAAABJ/ufQg8=</serialNumber>
</certItem>
<certItem issuerName="MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQDExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMw==">
<serialNumber>A8LV4zckxcwdttbQSk0EPnoA</serialNumber>
</certItem>
<certItem issuerName="MIGCMQswCQYDVQQGEwJVUzEeMBwGA1UECxMVd3d3LnhyYW1wc2VjdXJpdHkuY29tMSQwIgYDVQQKExtYUmFtcCBTZWN1cml0eSBTZXJ2aWNlcyBJbmMxLTArBgNVBAMTJFhSYW1wIEdsb2JhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eQ==">
<serialNumber>QZCrvQ==</serialNumber>
</certItem>
@ -4156,6 +4129,9 @@
<certItem issuerName="MIGVMQswCQYDVQQGEwJHUjFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIwMTE=">
<serialNumber>GN2Hrh9Ltms=</serialNumber>
</certItem>
<certItem issuerName="MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQDExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMw==">
<serialNumber>AyYMguSo1my449OZq51C3s3Z</serialNumber>
</certItem>
<certItem issuerName="MH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5">
<serialNumber>Qh/QbQ==</serialNumber>
</certItem>
@ -4231,12 +4207,18 @@
<certItem issuerName="MIG8MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBhdCBodHRwczovL3d3dy52ZXJpc2lnbi5jb20vcnBhIChjKTEwMTYwNAYDVQQDEy1WZXJpU2lnbiBDbGFzcyAzIEludGVybmF0aW9uYWwgU2VydmVyIENBIC0gRzM=">
<serialNumber>A9GPKQ8jv9oIxfwiOy7qxQ==</serialNumber>
</certItem>
<certItem issuerName="MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQDExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMw==">
<serialNumber>BOPwjyn5eqfeoxs7Z0y3vqNN</serialNumber>
</certItem>
<certItem issuerName="MFoxCzAJBgNVBAYTAklFMRIwEAYDVQQKEwlCYWx0aW1vcmUxEzARBgNVBAsTCkN5YmVyVHJ1c3QxIjAgBgNVBAMTGUJhbHRpbW9yZSBDeWJlclRydXN0IFJvb3Q=">
<serialNumber>Byd/Ug==</serialNumber>
</certItem>
<certItem issuerName="MEwxIDAeBgNVBAsTF0dsb2JhbFNpZ24gUm9vdCBDQSAtIFIyMRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu">
<serialNumber>BAAAAAABIg08FMU=</serialNumber>
</certItem>
<certItem issuerName="MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQDExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMw==">
<serialNumber>BKobzjrOxa/6kCR0ImKoqaQW</serialNumber>
</certItem>
<certItem issuerName="MIGVMQswCQYDVQQGEwJHUjFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIwMTE=">
<serialNumber>AQAAAAA=</serialNumber>
</certItem>
@ -4309,6 +4291,9 @@
<certItem issuerName="MEgxCzAJBgNVBAYTAlVTMSAwHgYDVQQKExdTZWN1cmVUcnVzdCBDb3Jwb3JhdGlvbjEXMBUGA1UEAxMOU2VjdXJlVHJ1c3QgQ0E=">
<serialNumber>MABJTA==</serialNumber>
</certItem>
<certItem issuerName="MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQDExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMw==">
<serialNumber>BOc11keA9WJ9R20XQY8hO7yi</serialNumber>
</certItem>
<certItem issuerName="MFoxCzAJBgNVBAYTAklFMRIwEAYDVQQKEwlCYWx0aW1vcmUxEzARBgNVBAsTCkN5YmVyVHJ1c3QxIjAgBgNVBAMTGUJhbHRpbW9yZSBDeWJlclRydXN0IFJvb3Q=">
<serialNumber>BydCwg==</serialNumber>
</certItem>
@ -4378,6 +4363,9 @@
<certItem issuerName="MEgxCzAJBgNVBAYTAlVTMSAwHgYDVQQKExdTZWN1cmVUcnVzdCBDb3Jwb3JhdGlvbjEXMBUGA1UEAxMOU2VjdXJlVHJ1c3QgQ0E=">
<serialNumber>R/j2qA==</serialNumber>
</certItem>
<certItem issuerName="MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQDExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMw==">
<serialNumber>A/7DHCczBnP5qUVh0jF2pvwB</serialNumber>
</certItem>
<certItem issuerName="MFoxCzAJBgNVBAYTAkRFMRMwEQYDVQQKEwpERk4tVmVyZWluMRAwDgYDVQQLEwdERk4tUEtJMSQwIgYDVQQDExtERk4tVmVyZWluIFBDQSBHbG9iYWwgLSBHMDE=">
<serialNumber>CdWFNw==</serialNumber>
</certItem>
@ -4420,6 +4408,9 @@
<certItem issuerName="MDsxGDAWBgNVBAoTD0N5YmVydHJ1c3QsIEluYzEfMB0GA1UEAxMWQ3liZXJ0cnVzdCBHbG9iYWwgUm9vdA==">
<serialNumber>BAAAAAABQaHhNLo=</serialNumber>
</certItem>
<certItem issuerName="MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQDExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMw==">
<serialNumber>AwBGo0Zmp6KRryAguuMvXATI</serialNumber>
</certItem>
<certItem issuerName="MEQxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMR0wGwYDVQQDExRHZW9UcnVzdCBTU0wgQ0EgLSBHMw==">
<serialNumber>bx/XHJqcwxDOptxJ2lh5vw==</serialNumber>
</certItem>
@ -4447,6 +4438,9 @@
<certItem issuerName="MGgxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMR0wGwYDVQQLExREb21haW4gVmFsaWRhdGVkIFNTTDEiMCAGA1UEAxMZR2VvVHJ1c3QgRFYgU1NMIFNIQTI1NiBDQQ==">
<serialNumber>ZgwfEqZnBsUNvNuZ77FbQA==</serialNumber>
</certItem>
<certItem issuerName="MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQDExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMw==">
<serialNumber>BOIIipysxAz5xHIMmFRvYchY</serialNumber>
</certItem>
<certItem issuerName="MIHKMQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMw==">
<serialNumber>OgxXyntHYBXnPAHDxY0OXg==</serialNumber>
</certItem>
@ -4501,6 +4495,9 @@
<certItem issuerName="MIG9MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNhbCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5">
<serialNumber>MWzraR3LLhU9m/qKEhvVLQ==</serialNumber>
</certItem>
<certItem issuerName="MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQDExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMw==">
<serialNumber>Ax6Jm7ajV49tqHgf9nYnzRCI</serialNumber>
</certItem>
<certItem issuerName="MEcxCzAJBgNVBAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxITAfBgNVBAMTGFN3aXNzU2lnbiBTaWx2ZXIgQ0EgLSBHMg==">
<serialNumber>APiyCXmwAUq+95DYa3DmGw==</serialNumber>
</certItem>
@ -4531,6 +4528,9 @@
<certItem issuerName="MH4xCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRTeW1hbnRlYyBDb3Jwb3JhdGlvbjEfMB0GA1UECxMWU3ltYW50ZWMgVHJ1c3QgTmV0d29yazEvMC0GA1UEAxMmU3ltYW50ZWMgQ2xhc3MgMyBTZWN1cmUgU2VydmVyIENBIC0gRzQ=">
<serialNumber>E77H6yvyFQjO0PcN3x0H+Q==</serialNumber>
</certItem>
<certItem issuerName="MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQDExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMw==">
<serialNumber>A3WVy2V+2VFkWtMvA6HFwnhq</serialNumber>
</certItem>
<certItem issuerName="MEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDM=">
<serialNumber>B+U=</serialNumber>
</certItem>
@ -4543,6 +4543,12 @@
<certItem issuerName="MIGVMQswCQYDVQQGEwJHUjFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIwMTE=">
<serialNumber>GN2Hrh9LtnA=</serialNumber>
</certItem>
<certItem issuerName="MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQDExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMw==">
<serialNumber>BOncXh7IZp1SNydhtUdyh2O2</serialNumber>
</certItem>
<certItem issuerName="MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQDExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMw==">
<serialNumber>A8aDg1/IA4O8gjMPZHVqPI+w</serialNumber>
</certItem>
<certItem issuerName="MDMxCzAJBgNVBAYTAlBUMQ0wCwYDVQQKDARTQ0VFMRUwEwYDVQQDDAxFQ1JhaXpFc3RhZG8=">
<serialNumber>cx0HrIEQg8JHWTP7DzOxSQ==</serialNumber>
</certItem>
@ -4603,6 +4609,9 @@
<certItem issuerName="MFoxCzAJBgNVBAYTAkRFMRMwEQYDVQQKEwpERk4tVmVyZWluMRAwDgYDVQQLEwdERk4tUEtJMSQwIgYDVQQDExtERk4tVmVyZWluIFBDQSBHbG9iYWwgLSBHMDE=">
<serialNumber>EAdmaA==</serialNumber>
</certItem>
<certItem issuerName="MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQDExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMw==">
<serialNumber>BLlQHJ611eOZuedFrFgVAfAs</serialNumber>
</certItem>
<certItem issuerName="MD8xJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjEXMBUGA1UEAxMORFNUIFJvb3QgQ0EgWDM=">
<serialNumber>CgFBQQAAATjtdPY5AAAAAg==</serialNumber>
</certItem>
@ -4612,6 +4621,9 @@
<certItem issuerName="MHExKDAmBgNVBAMTH0dsb2JhbFNpZ24gUm9vdFNpZ24gUGFydG5lcnMgQ0ExHTAbBgNVBAsTFFJvb3RTaWduIFBhcnRuZXJzIENBMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMQswCQYDVQQGEwJCRQ==">
<serialNumber>BAAAAAABGMGjftY=</serialNumber>
</certItem>
<certItem issuerName="MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQDExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMw==">
<serialNumber>A1V4dX0tTb1rdTZxdWcuZ7YR</serialNumber>
</certItem>
<certItem issuerName="MGMxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwx0aGF3dGUsIEluYy4xHTAbBgNVBAsTFERvbWFpbiBWYWxpZGF0ZWQgU1NMMR4wHAYDVQQDExV0aGF3dGUgRFYgU1NMIENBIC0gRzI=">
<serialNumber>BUrYjru5px1ym4QUN33TOQ==</serialNumber>
</certItem>
@ -4627,6 +4639,12 @@
<certItem issuerName="MEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDM=">
<serialNumber>SurdtfsuPcXXDpY2LkBpYO6BT7o=</serialNumber>
</certItem>
<certItem issuerName="MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQDExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMw==">
<serialNumber>AxW0+uDsfyCSfhECdsGGpVD8</serialNumber>
</certItem>
<certItem issuerName="MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQDExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMw==">
<serialNumber>A9BRwOwbXRRhCe+kcmglgW3z</serialNumber>
</certItem>
<certItem issuerName="MHsxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazEyMDAGA1UEAxMpVmVyaVNpZ24gQ2xhc3MgMyBTU1AgSW50ZXJtZWRpYXRlIENBIC0gRzI=">
<serialNumber>dhjnNtYx6cojdAE55TgIBA==</serialNumber>
</certItem>
@ -4660,6 +4678,9 @@
<certItem issuerName="MIGCMQswCQYDVQQGEwJVUzEeMBwGA1UECxMVd3d3LnhyYW1wc2VjdXJpdHkuY29tMSQwIgYDVQQKExtYUmFtcCBTZWN1cml0eSBTZXJ2aWNlcyBJbmMxLTArBgNVBAMTJFhSYW1wIEdsb2JhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eQ==">
<serialNumber>QZCrvA==</serialNumber>
</certItem>
<certItem issuerName="MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQDExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMw==">
<serialNumber>A0BOaf9UbJxzqBudSyes/cEM</serialNumber>
</certItem>
<certItem issuerName="MEUxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9WYWRpcyBSb290IENBIDM=">
<serialNumber>NTgf4iwIfeyJPIomw2dwSXEwtxQ=</serialNumber>
</certItem>
@ -4690,8 +4711,98 @@
<certItem issuerName="MFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxTaWduIFJvb3QgQ0E=">
<serialNumber>BAAAAAABKUXDqA8=</serialNumber>
</certItem>
<certItem issuerName="MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQDExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMw==">
<serialNumber>BDV89QWZE9MJYlCpFQUv5Y2W</serialNumber>
</certItem>
<certItem issuerName="MIGXMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRydXN0LmNvbTEfMB0GA1UEAxMWVVROLVVTRVJGaXJzdC1IYXJkd2FyZQ==">
<serialNumber>Xrr31RF0DoIzMKXS6XtD+g==</serialNumber>
</certItem>
<certItem issuerName="MH4xCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRTeW1hbnRlYyBDb3Jwb3JhdGlvbjEfMB0GA1UECxMWU3ltYW50ZWMgVHJ1c3QgTmV0d29yazEvMC0GA1UEAxMmU3ltYW50ZWMgQ2xhc3MgMyBTZWN1cmUgU2VydmVyIENBIC0gRzQ=">
<serialNumber>PAdKZPiaac2CvPxbOrsHOw==</serialNumber>
</certItem>
<certItem issuerName="MF8xCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRQwEgYDVQQLEwtQYXJ0bmVycyBDQTEfMB0GA1UEAxMWR2xvYmFsU2lnbiBQYXJ0bmVycyBDQQ==">
<serialNumber>BAAAAAABCFiEp9s=</serialNumber>
</certItem>
<certItem issuerName="MHYxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazEtMCsGA1UEAxMkVmVyaVNpZ24gQ2xhc3MgMyBTU1AgSW50ZXJtZWRpYXRlIENB">
<serialNumber>GuJ0aGBYhChXAOljooJZ3A==</serialNumber>
</certItem>
<certItem issuerName="MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQDExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMw==">
<serialNumber>BPVqx4UbKVAbJSFTKwrcFryU</serialNumber>
</certItem>
<certItem issuerName="MFcxCzAJBgNVBAYTAlRXMQ4wDAYDVQQKEwVUYWlDQTESMBAGA1UECxMJUG9saWN5IENBMSQwIgYDVQQDExtUYWlDQSBJbmZvcm1hdGlvbiBQb2xpY3kgQ0E=">
<serialNumber>UbQGvw==</serialNumber>
</certItem>
<certItem issuerName="MIGVMQswCQYDVQQGEwJHUjFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIwMTE=">
<serialNumber>AQAAAAU=</serialNumber>
</certItem>
<certItem issuerName="MFoxCzAJBgNVBAYTAkRFMRMwEQYDVQQKEwpERk4tVmVyZWluMRAwDgYDVQQLEwdERk4tUEtJMSQwIgYDVQQDExtERk4tVmVyZWluIFBDQSBHbG9iYWwgLSBHMDE=">
<serialNumber>Cfk9lw==</serialNumber>
</certItem>
<certItem issuerName="MGQxCzAJBgNVBAYTAmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGlnaXRhbCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAy">
<serialNumber>AIChpbGNqu4XKp9J70syKEs=</serialNumber>
</certItem>
<certItem issuerName="MHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlBUyBTZXJ0aWZpdHNlZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRyZSBSb290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWU=">
<serialNumber>cJ+vg4742XhNgJW2ot9eIg==</serialNumber>
</certItem>
<certItem issuerName="MFoxCzAJBgNVBAYTAkRFMRMwEQYDVQQKEwpERk4tVmVyZWluMRAwDgYDVQQLEwdERk4tUEtJMSQwIgYDVQQDExtERk4tVmVyZWluIFBDQSBHbG9iYWwgLSBHMDE=">
<serialNumber>Cyr1PA==</serialNumber>
</certItem>
<certItem issuerName="MDQxCzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25h">
<serialNumber>Gg==</serialNumber>
</certItem>
<certItem issuerName="MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQDExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMw==">
<serialNumber>BKrxi2/1iFxHEFzyZvegxq5C</serialNumber>
</certItem>
<certItem issuerName="MGYxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMR0wGwYDVQQLExREb21haW4gVmFsaWRhdGVkIFNTTDEgMB4GA1UEAxMXR2VvVHJ1c3QgRFYgU1NMIENBIC0gRzQ=">
<serialNumber>H08=</serialNumber>
</certItem>
<certItem issuerName="MHExKDAmBgNVBAMTH0dsb2JhbFNpZ24gUm9vdFNpZ24gUGFydG5lcnMgQ0ExHTAbBgNVBAsTFFJvb3RTaWduIFBhcnRuZXJzIENBMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMQswCQYDVQQGEwJCRQ==">
<serialNumber>BAAAAAABKB/OGqI=</serialNumber>
</certItem>
<certItem issuerName="MGMxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwx0aGF3dGUsIEluYy4xHTAbBgNVBAsTFERvbWFpbiBWYWxpZGF0ZWQgU1NMMR4wHAYDVQQDExV0aGF3dGUgRFYgU1NMIENBIC0gRzI=">
<serialNumber>Rvm2CEw2IC2Mu/ax0A46QQ==</serialNumber>
</certItem>
<certItem issuerName="MFoxCzAJBgNVBAYTAklFMRIwEAYDVQQKEwlCYWx0aW1vcmUxEzARBgNVBAsTCkN5YmVyVHJ1c3QxIjAgBgNVBAMTGUJhbHRpbW9yZSBDeWJlclRydXN0IFJvb3Q=">
<serialNumber>ByfFnw==</serialNumber>
</certItem>
<certItem issuerName="MFoxCzAJBgNVBAYTAkRFMRMwEQYDVQQKEwpERk4tVmVyZWluMRAwDgYDVQQLEwdERk4tUEtJMSQwIgYDVQQDExtERk4tVmVyZWluIFBDQSBHbG9iYWwgLSBHMDE=">
<serialNumber>F5BhENPfVw==</serialNumber>
</certItem>
<certItem issuerName="MIGVMQswCQYDVQQGEwJHUjFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9vdENBIDIwMTE=">
<serialNumber>GN2Hrh9Ltm4=</serialNumber>
</certItem>
<certItem issuerName="MD0xCzAJBgNVBAYTAkZSMREwDwYDVQQKEwhDZXJ0cGx1czEbMBkGA1UEAxMSQ2xhc3MgMiBQcmltYXJ5IENB">
<serialNumber>ESJJweWBPhoXAaB9c8SHwI4O</serialNumber>
</certItem>
<certItem issuerName="MIG8MQswCQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxOzA5BgNVBAsTMlRlcm1zIG9mIHVzZSBhdCBodHRwczovL3d3dy52ZXJpc2lnbi5jb20vcnBhIChjKTEwMTYwNAYDVQQDEy1WZXJpU2lnbiBDbGFzcyAzIEludGVybmF0aW9uYWwgU2VydmVyIENBIC0gRzM=">
<serialNumber>VOcIuNbTqkpOMUyI108FOg==</serialNumber>
</certItem>
<certItem issuerName="MFAxJDAiBgNVBAsTG0dsb2JhbFNpZ24gRUNDIFJvb3QgQ0EgLSBSNDETMBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbg==">
<serialNumber>RnQ3dYovwvB0D5q2YGY=</serialNumber>
</certItem>
<certItem issuerName="MGMxCzAJBgNVBAYTAkZSMRMwEQYDVQQKEwpDZXJ0aW5vbWlzMRcwFQYDVQQLEw4wMDAyIDQzMzk5ODkwMzEmMCQGA1UEAwwdQ2VydGlub21pcyAtIEF1dG9yaXTDqSBSYWNpbmU=">
<serialNumber>Eg==</serialNumber>
</certItem>
<certItem issuerName="MH4xCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRTeW1hbnRlYyBDb3Jwb3JhdGlvbjEfMB0GA1UECxMWU3ltYW50ZWMgVHJ1c3QgTmV0d29yazEvMC0GA1UEAxMmU3ltYW50ZWMgQ2xhc3MgMyBTZWN1cmUgU2VydmVyIENBIC0gRzQ=">
<serialNumber>ezdAeCxKH7BFs7vn3byYaw==</serialNumber>
</certItem>
<certItem issuerName="MIGFMQswCQYDVQQGEwJVUzEgMB4GA1UECgwXV2VsbHMgRmFyZ28gV2VsbHNTZWN1cmUxHDAaBgNVBAsME1dlbGxzIEZhcmdvIEJhbmsgTkExNjA0BgNVBAMMLVdlbGxzU2VjdXJlIFB1YmxpYyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eQ==">
<serialNumber>AZ0=</serialNumber>
</certItem>
<certItem issuerName="MFoxCzAJBgNVBAYTAkRFMRMwEQYDVQQKEwpERk4tVmVyZWluMRAwDgYDVQQLEwdERk4tUEtJMSQwIgYDVQQDExtERk4tVmVyZWluIFBDQSBHbG9iYWwgLSBHMDE=">
<serialNumber>CcHC1w==</serialNumber>
</certItem>
<certItem issuerName="MFoxCzAJBgNVBAYTAklFMRIwEAYDVQQKEwlCYWx0aW1vcmUxEzARBgNVBAsTCkN5YmVyVHJ1c3QxIjAgBgNVBAMTGUJhbHRpbW9yZSBDeWJlclRydXN0IFJvb3Q=">
<serialNumber>BEeJFwO0nu759EPo9tKluw==</serialNumber>
</certItem>
<certItem issuerName="MFYxCzAJBgNVBAYTAkpQMQ8wDQYDVQQKEwZKSVBERUMxGjAYBgNVBAsTEUpDQU4gU3ViIFJvb3QgQ0EwMRowGAYDVQQDExFKQ0FOIFN1YiBSb290IENBMA==">
<serialNumber>BAAAAAABK84yjs8=</serialNumber>
</certItem>
<certItem issuerName="MD0xCzAJBgNVBAYTAkZSMREwDwYDVQQKEwhDZXJ0cGx1czEbMBkGA1UEAxMSQ2xhc3MgMiBQcmltYXJ5IENB">
<serialNumber>ESCC9oPNcRdPOox+SjWm9dTX</serialNumber>
</certItem>
<certItem issuerName="MD0xCzAJBgNVBAYTAkZSMREwDwYDVQQKEwhDZXJ0cGx1czEbMBkGA1UEAxMSQ2xhc3MgMiBQcmltYXJ5IENB">
<serialNumber>DjIvBkX+ECVbB/C3i6w2Gg==</serialNumber>
</certItem>
</certItems>
</blocklist>

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

@ -168,7 +168,7 @@ var TabsInTitlebar = {
let fullTabsHeight = rect($("TabsToolbar")).height;
// Buttons first:
let captionButtonsBoxWidth = rect($("titlebar-buttonbox-container")).width;
let captionButtonsBoxWidth = rect($("titlebar-buttonbox")).width;
let secondaryButtonsWidth, menuHeight, fullMenuHeight, menuStyles;
if (AppConstants.platform == "macosx") {

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

@ -904,6 +904,12 @@ CustomizeMode.prototype = {
let removable = aPlace == "palette" || CustomizableUI.isWidgetRemovable(aNode);
wrapper.setAttribute("removable", removable);
if (AppConstants.platform == "win") {
// Allow touch events to initiate dragging in customize mode.
// This is only supported on Windows for now.
wrapper.setAttribute("touchdownstartsdrag", "true");
}
let contextMenuAttrName = "";
if (aNode.getAttribute("context")) {
contextMenuAttrName = "context";

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

@ -38,6 +38,9 @@ add_task(async function searchbar_in_panel() {
// autocomplete panel and search for suggestions, which would
// trigger network requests. Temporarily disable suggestions.
await SpecialPowers.pushPrefEnv({set: [["browser.search.suggest.enabled", false]]});
let dontShowPopup = e => e.preventDefault();
let searchbarPopup = searchbar.textbox.popup;
searchbarPopup.addEventListener("popupshowing", dontShowPopup);
searchbar.value = "foo";
searchbar.focus();
@ -55,9 +58,6 @@ add_task(async function searchbar_in_panel() {
EventUtils.synthesizeMouseAtCenter(selectAll, {});
await contextMenuHidden;
// Hide the suggestion panel.
searchbar.textbox.popup.hidePopup();
ok(isOverflowOpen(), "Panel should still be open");
let hiddenPanelPromise = promiseOverflowHidden(window);
@ -65,6 +65,9 @@ add_task(async function searchbar_in_panel() {
await hiddenPanelPromise;
ok(!isOverflowOpen(), "Panel should no longer be open");
// Allow search bar popup to show again.
searchbarPopup.removeEventListener("popupshowing", dontShowPopup);
// We focused the search bar earlier - ensure we don't keep doing that.
gURLBar.select();

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

@ -91,7 +91,11 @@ this.pageAction = class extends ExtensionAPI {
this.tabContext.shutdown();
if (this.browserPageAction) {
// Removing the browser page action causes PageActions to forget about it
// across app restarts, so don't remove it on app shutdown, but do remove
// it on all other shutdowns since there's no guarantee the action will be
// coming back.
if (reason != "APP_SHUTDOWN" && this.browserPageAction) {
this.browserPageAction.remove();
this.browserPageAction = null;
}

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

@ -0,0 +1,79 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
Cu.import("resource:///modules/PageActions.jsm");
Cu.import("resource://testing-common/AddonTestUtils.jsm");
const {
createAppInfo,
promiseShutdownManager,
promiseStartupManager,
} = AddonTestUtils;
AddonTestUtils.init(this);
AddonTestUtils.overrideCertDB();
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "58");
// This is copied and pasted from ExtensionPopups.jsm. It's used as the
// PageActions action ID. See ext-pageAction.js.
function makeWidgetId(id) {
id = id.toLowerCase();
// FIXME: This allows for collisions.
return id.replace(/[^a-z0-9_-]/g, "_");
}
// Tests that the shownInUrlbar property of the PageActions.Action object
// backing the extension's page action persists across app restarts.
add_task(async function testAppShutdown() {
let extensionData = {
useAddonManager: "permanent",
manifest: {
page_action: {
default_title: "test_ext_pageAction_shutdown.js",
browser_style: false,
},
},
};
// Simulate starting up the app.
PageActions.init();
await promiseStartupManager();
let extension = ExtensionTestUtils.loadExtension(extensionData);
await extension.startup();
// Get the PageAction.Action object. Its shownInUrlbar should have been
// initialized to true in ext-pageAction.js, when it's created.
let actionID = makeWidgetId(extension.id);
let action = PageActions.actionForID(actionID);
Assert.equal(action.shownInUrlbar, true);
// Simulate restarting the app without first unloading the extension.
await promiseShutdownManager();
PageActions._reset();
await promiseStartupManager();
await extension.awaitStartup();
// Get the action. Its shownInUrlbar should remain true.
action = PageActions.actionForID(actionID);
Assert.equal(action.shownInUrlbar, true);
// Now set its shownInUrlbar to false.
action.shownInUrlbar = false;
// Simulate restarting the app again without first unloading the extension.
await promiseShutdownManager();
PageActions._reset();
await promiseStartupManager();
await extension.awaitStartup();
// Get the action. Its shownInUrlbar should remain false.
action = PageActions.actionForID(actionID);
Assert.equal(action.shownInUrlbar, false);
// Now unload the extension and quit the app.
await extension.unload();
await promiseShutdownManager();
});

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

@ -16,10 +16,11 @@ dupe-manifest =
# - xpcshell-remote.ini
# For tests which should only run with both remote extensions and remote content.
[test_ext_geckoProfiler_schema.js]
[test_ext_manifest_commands.js]
[test_ext_manifest_omnibox.js]
[test_ext_manifest_permissions.js]
[test_ext_geckoProfiler_schema.js]
[test_ext_pageAction_shutdown.js]
[test_ext_pkcs11_management.js]
[include:xpcshell-common.ini]

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

@ -1328,7 +1328,11 @@ PlacesController.prototype = {
transactions = [...transactions, ...newTransactions];
}
await PlacesUIUtils.batchUpdatesForNode(this._view.result, transactions.length, async () => {
// Note: this._view may be a view or the tree element.
let resultForBatching = getResultForBatching(this._view);
await PlacesUIUtils.batchUpdatesForNode(resultForBatching,
transactions.length, async () => {
await PlacesTransactions.batch(async () => {
for (let transaction of transactions) {
let guid = await transaction.transact();
@ -1609,9 +1613,8 @@ var PlacesControllerDragHelper = {
* @param {Object} insertionPoint The insertion point where the items should
* be dropped.
* @param {Object} dt The dataTransfer information for the drop.
* @param {Object} view The tree view where this object is being
* dropped to. This allows batching to take
* place.
* @param {Object} view The view or the tree element. This allows
* batching to take place.
*/
async onDrop(insertionPoint, dt, view) {
let doCopy = ["copy", "link"].includes(dt.dropEffect);
@ -1723,7 +1726,9 @@ var PlacesControllerDragHelper = {
return;
}
if (PlacesUIUtils.useAsyncTransactions) {
await PlacesUIUtils.batchUpdatesForNode(view && view.result, transactions.length, async () => {
let resultForBatching = getResultForBatching(view);
await PlacesUIUtils.batchUpdatesForNode(resultForBatching,
transactions.length, async () => {
await PlacesTransactions.batch(transactions);
});
} else {
@ -1810,6 +1815,30 @@ function goDoPlacesCommand(aCommand) {
controller.doCommand(aCommand);
}
/**
* This gets the most appropriate item for using for batching. In the case of multiple
* views being related, the method returns the most expensive result to batch.
* For example, if it detects the left-hand library pane, then it will look for
* and return the reference to the right-hand pane.
*
* @param {Object} viewOrElement The item to check.
* @return {Object} Will return the best result node to batch, or null
* if one could not be found.
*/
function getResultForBatching(viewOrElement) {
if (viewOrElement && viewOrElement instanceof Ci.nsIDOMElement &&
viewOrElement.id === "placesList") {
// Note: fall back to the existing item if we can't find the right-hane pane.
viewOrElement = document.getElementById("placeContent") || viewOrElement;
}
if (viewOrElement && viewOrElement.result) {
return viewOrElement.result;
}
return null;
}
/**
* Processes a set of transfer items and returns transactions to insert or
* move them.

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

@ -121,7 +121,6 @@
<hbox flex="1" align="center">
<textbox id="editBMPanel_tagsField"
type="autocomplete"
class="padded"
flex="1"
autocompletesearch="places-tag-autocomplete"
completedefaultindex="true"

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

@ -1453,7 +1453,7 @@ PlacesTreeView.prototype = {
// since this information is specific to the tree view.
let ip = this._getInsertionPoint(aRow, aOrientation);
if (ip) {
PlacesControllerDragHelper.onDrop(ip, aDataTransfer, this)
PlacesControllerDragHelper.onDrop(ip, aDataTransfer, this._tree.element)
.catch(Components.utils.reportError)
.then(() => {
// We should only clear the drop target once

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

@ -28,8 +28,13 @@ add_task(async function test_click_on_footer() {
// Click on the footer
const optionButton = itemsBox.querySelector(".autocomplete-richlistitem:last-child")._optionButton;
const prefTabPromise = BrowserTestUtils.waitForNewTab(gBrowser, PRIVACY_PREF_URL);
// Wait for dropdown animation finished to continue mouse synthesizing.
await sleep(1000);
await EventUtils.synthesizeMouseAtCenter(optionButton, {});
await BrowserTestUtils.removeTab(await prefTabPromise);
info(`expecting tab: about:preferences#privacy opened`);
const prefTab = await prefTabPromise;
info(`expecting tab: about:preferences#privacy removed`);
await BrowserTestUtils.removeTab(prefTab);
ok(true, "Tab: preferences#privacy was successfully opened by clicking on the footer");
await closePopup(browser);
@ -48,7 +53,10 @@ add_task(async function test_press_enter_on_footer() {
await BrowserTestUtils.synthesizeKey("VK_DOWN", {}, browser);
}
await BrowserTestUtils.synthesizeKey("VK_RETURN", {}, browser);
await BrowserTestUtils.removeTab(await prefTabPromise);
info(`expecting tab: about:preferences#privacy opened`);
const prefTab = await prefTabPromise;
info(`expecting tab: about:preferences#privacy removed`);
await BrowserTestUtils.removeTab(prefTab);
ok(true, "Tab: preferences#privacy was successfully opened by pressing enter on the footer");
await closePopup(browser);

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

@ -31,6 +31,7 @@ add_task(async function test_back_forward() {
// Now navigate forward and make sure autofill autocomplete results are still attached
let loadPromise = BrowserTestUtils.browserLoaded(browser);
await BrowserTestUtils.loadURI(browser, `${URL}?load=2`);
info("expecting browser loaded");
await loadPromise;
// Check the second page
@ -40,6 +41,7 @@ add_task(async function test_back_forward() {
// Check after hitting back to the first page
let stoppedPromise = BrowserTestUtils.browserStopped(browser);
browser.goBack();
info("expecting browser stopped");
await stoppedPromise;
await openPopupOn(browser, "#street-address");
checkPopup(autoCompletePopup);
@ -47,6 +49,7 @@ add_task(async function test_back_forward() {
// Check after hitting forward to the second page
stoppedPromise = BrowserTestUtils.browserStopped(browser);
browser.goForward();
info("expecting browser stopped");
await stoppedPromise;
await openPopupOn(browser, "#street-address");
checkPopup(autoCompletePopup);

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

@ -30,6 +30,7 @@ add_task(async function test_detach_tab_marked() {
await closePopup(browser);
// Detach the tab to a new window
info("expecting tab replaced with new window");
let newWin = gBrowser.replaceTabWithWindow(gBrowser.getTabForBrowser(browser));
await TestUtils.topicObserved("browser-delayed-startup-finished", subject => {
return subject == newWin;

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

@ -53,10 +53,9 @@ add_task(async function test_insecure_form() {
expectedResultLength: 1,
}];
await runTest(testSets[0]);
await runTest(testSets[1]);
await runTest(testSets[2]);
await runTest(testSets[3]);
for (const test of testSets) {
await runTest(test);
}
});
add_task(async function test_click_on_insecure_warning() {

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

@ -102,6 +102,7 @@ async function sleep(ms = 500) {
}
async function focusAndWaitForFieldsIdentified(browser, selector) {
info("expecting the target input being focused and indentified");
/* eslint no-shadow: ["error", { "allow": ["selector", "previouslyFocused", "previouslyIdentified"] }] */
const {previouslyFocused, previouslyIdentified} = await ContentTask.spawn(browser, {selector}, async function({selector}) {
Components.utils.import("resource://gre/modules/FormLikeFactory.jsm");
@ -176,6 +177,7 @@ async function closePopup(browser) {
}
function getRecords(data) {
info(`expecting record retrievals: ${data.collectionName}`);
return new Promise(resolve => {
Services.cpmm.addMessageListener("FormAutofill:Records", function getResult(result) {
Services.cpmm.removeMessageListener("FormAutofill:Records", getResult);
@ -194,11 +196,13 @@ function getCreditCards() {
}
function saveAddress(address) {
info("expecting address saved");
Services.cpmm.sendAsyncMessage("FormAutofill:SaveAddress", {address});
return TestUtils.topicObserved("formautofill-storage-changed");
}
function saveCreditCard(creditcard) {
info("expecting credit card saved");
let creditcardClone = Object.assign({}, creditcard);
Services.cpmm.sendAsyncMessage("FormAutofill:SaveCreditCard", {
creditcard: creditcardClone,
@ -207,11 +211,13 @@ function saveCreditCard(creditcard) {
}
function removeAddresses(guids) {
info("expecting address removed");
Services.cpmm.sendAsyncMessage("FormAutofill:RemoveAddresses", {guids});
return TestUtils.topicObserved("formautofill-storage-changed");
}
function removeCreditCards(guids) {
info("expecting credit card removed");
Services.cpmm.sendAsyncMessage("FormAutofill:RemoveCreditCards", {guids});
return TestUtils.topicObserved("formautofill-storage-changed");
}
@ -236,6 +242,7 @@ async function clickDoorhangerButton(button, index) {
EventUtils.synthesizeMouseAtCenter(getNotification()[button], {});
} else if (button == MENU_BUTTON) {
// Click the dropmarker arrow and wait for the menu to show up.
info("expecting notification menu button present");
await BrowserTestUtils.waitForCondition(() => getNotification().menubutton);
await sleep(2000); // menubutton needs extra time for binding
let notification = getNotification();
@ -243,11 +250,13 @@ async function clickDoorhangerButton(button, index) {
let dropdownPromise =
BrowserTestUtils.waitForEvent(notification.menupopup, "popupshown");
await EventUtils.synthesizeMouseAtCenter(notification.menubutton, {});
info("expecting notification popup show up");
await dropdownPromise;
let actionMenuItem = notification.querySelectorAll("menuitem")[index];
await EventUtils.synthesizeMouseAtCenter(actionMenuItem, {});
}
info("expecting notification popup hidden");
await popuphidden;
}
@ -264,6 +273,7 @@ function getDoorhangerButton(button) {
// Wait for the master password dialog to popup and enter the password to log in
// if "login" is "true" or dismiss it directly if otherwise.
function waitForMasterPasswordDialog(login = false) {
info("expecting master password dialog loaded");
let dialogShown = TestUtils.topicObserved("common-dialog-loaded");
return dialogShown.then(([subject]) => {
let dialog = subject.Dialog;

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

@ -15,6 +15,7 @@ async function sleep(ms = 500, reason = "Intentionally wait for UI ready") {
}
async function focusAndWaitForFieldsIdentified(input, mustBeIdentified = false) {
info("expecting the target input being focused and indentified");
if (typeof input === "string") {
input = document.querySelector(input);
}
@ -66,6 +67,7 @@ function clickOnElement(selector) {
}
async function onStorageChanged(type) {
info(`expecting the storage changed: ${type}`);
return new Promise(resolve => {
formFillChromeScript.addMessageListener("formautofill-storage-changed", function onChanged(data) {
formFillChromeScript.removeMessageListener("formautofill-storage-changed", onChanged);
@ -87,6 +89,7 @@ function checkMenuEntries(expectedValues, isFormAutofillResult = true) {
}
function invokeAsyncChromeTask(message, response, payload = {}) {
info(`expecting the chrome task finished: ${message}`);
return new Promise(resolve => {
formFillChromeScript.sendAsyncMessage(message, payload);
formFillChromeScript.addMessageListener(response, function onReceived(data) {
@ -192,6 +195,7 @@ function formAutoFillCommonSetup() {
SimpleTest.registerCleanupFunction(async () => {
formFillChromeScript.sendAsyncMessage("cleanup");
info(`expecting the storage cleanup`);
await formFillChromeScript.promiseOneMessage("cleanup-finished");
formFillChromeScript.destroy();

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

@ -61,6 +61,7 @@ function checkAutoCompleteInputFilled(element, expectedvalue) {
}
function checkFormFilled(address) {
info("expecting form filled");
let promises = [];
for (let prop in address) {
let element = document.getElementById(prop);

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

@ -62,6 +62,7 @@ function checkElementFilled(element, expectedvalue) {
}
function checkFormFilled(creditCard) {
info("expecting form filled");
let promises = [];
for (let prop in creditCard) {
let element = document.getElementById(prop);

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

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

@ -47,6 +47,7 @@ function addInputField(form, className) {
}
async function checkFormChangeHappened(formId) {
info("expecting form changed");
await focusAndWaitForFieldsIdentified(`#${formId} input[name=tel]`);
doKey("down");
await expectPopup();

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

@ -73,6 +73,7 @@ function checkFormFilledFields(address) {
}
function confirmAllFieldsFilled(address) {
info("expecting form filled");
const pendingPromises = [];
for (const prop in address) {

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

@ -391,6 +391,14 @@ this.PageActions = {
}
},
// For tests. See Bug 1413692.
_reset() {
PageActions._purgeUnregisteredPersistedActions();
PageActions._builtInActions = [];
PageActions._nonBuiltInActions = [];
PageActions._actionsByID = new Map();
},
_storePersistedActions() {
let json = JSON.stringify(this._persistedActions);
Services.prefs.setStringPref(PREF_PERSISTED_ACTIONS, json);

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

@ -166,10 +166,6 @@ menuitem.bookmark-item {
border-color: Highlight;
}
.urlbar-textbox-container {
-moz-box-align: stretch;
}
/* ::::: URL Bar Zoom Reset Button ::::: */
@keyframes urlbar-zoom-reset-pulse {
0% {
@ -707,3 +703,80 @@ html|span.ac-emphasize-text-url {
.restore-tabs-button:hover:active:not([disabled="true"]) {
padding: 3px;
}
/* Hide the titlebar explicitly on versions of GTK+ where
* it's rendered by window manager. */
@media (-moz-gtk-csd-available: 0) {
#titlebar {
display: none;
}
}
/* We draw to titlebar when Gkt+ CSD is available */
@media (-moz-gtk-csd-available) {
:root[tabsintitlebar] > #titlebar:-moz-lwtheme {
visibility: hidden;
}
:root[tabsintitlebar] > #titlebar-content:-moz-lwtheme {
visibility: visible;
}
:root[tabsintitlebar][sizemode="normal"] > #titlebar {
-moz-appearance: -moz-window-titlebar;
}
:root[tabsintitlebar][sizemode="maximized"] > #titlebar {
-moz-appearance: -moz-window-titlebar-maximized;
}
/* The button box must appear on top of the navigator-toolbox in order for
* click and hover mouse events to work properly for the button in the restored
* window state. Otherwise, elements in the navigator-toolbox, like the menubar,
* can swallow those events.
*/
#titlebar-buttonbox {
z-index: 1;
}
/* Render titlebar command buttons according to system config.
* Use full scale icons here as the Gtk+ does.
*/
@media (-moz-gtk-csd-minimize-button) {
#titlebar-min {
list-style-image: url("moz-icon://stock/window-minimize-symbolic");
-moz-appearance: -moz-window-button-minimize;
}
}
@media (-moz-gtk-csd-minimize-button: 0) {
#titlebar-min {
display: none;
}
}
@media (-moz-gtk-csd-maximize-button) {
#titlebar-max {
list-style-image: url("moz-icon://stock/window-maximize-symbolic");
-moz-appearance: -moz-window-button-maximize;
}
:root[sizemode="maximized"] #titlebar-max {
list-style-image: url("moz-icon://stock/window-restore-symbolic");
-moz-appearance: -moz-window-button-restore;
}
}
@media (-moz-gtk-csd-maximize-button: 0) {
#titlebar-max {
display: none;
}
}
@media (-moz-gtk-csd-close-button) {
#titlebar-close {
list-style-image: url("moz-icon://stock/window-close-symbolic");
-moz-appearance: -moz-window-button-close;
}
}
@media (-moz-gtk-csd-close-button: 0) {
#titlebar-close {
display: none;
}
}
}

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

@ -29,6 +29,7 @@
padding: 0;
margin: 3px 5px;
min-height: 30px;
cursor: default;
overflow: -moz-hidden-unscrollable;
}
@ -72,11 +73,6 @@
-moz-box-align: center;
}
.urlbar-input-box,
.searchbar-textbox > .autocomplete-textbox-container > .textbox-input-box {
margin: 0;
}
#urlbar-search-splitter {
/* The splitter width should equal the location and search bars' combined
neighboring margin and border width. */

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

@ -529,10 +529,6 @@ html|*.urlbar-input:-moz-lwtheme::placeholder,
color: #777;
}
.urlbar-textbox-container {
-moz-box-align: stretch;
}
/* ::::: URL Bar Zoom Reset Button ::::: */
@keyframes urlbar-zoom-reset-pulse {
0% {

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

@ -57,12 +57,12 @@ def yasm_version(yasm):
return Version(version)
@depends(yasm_version)
@depends_if(yasm_version)
def yasm_major_version(yasm_version):
return str(yasm_version.major)
@depends(yasm_version)
@depends_if(yasm_version)
def yasm_minor_version(yasm_version):
return str(yasm_version.minor)

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

@ -43,6 +43,7 @@ skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32
[browser_jsonview_nojs.js]
[browser_jsonview_nul.js]
[browser_jsonview_object-type.js]
[browser_jsonview_row_selection.js]
[browser_jsonview_save_json.js]
support-files =
!/toolkit/content/tests/browser/common/mockTransfer.js

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

@ -0,0 +1,44 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
add_task(function* () {
info("Test JSON row selection started");
// Create a tall JSON so that there is a scrollbar.
let numRows = 1e3;
let json = JSON.stringify(Array(numRows).fill().map((_, i) => i));
let tab = yield addJsonViewTab("data:application/json," + json);
is(yield getElementCount(".treeRow"), numRows, "Got the expected number of rows.");
yield assertRowSelected(null);
yield evalInContent("var scroller = $('.jsonPanelBox .panelContent')");
ok(yield evalInContent("scroller.clientHeight < scroller.scrollHeight"),
"There is a scrollbar.");
is(yield evalInContent("scroller.scrollTop"), 0, "Initially scrolled to the top.");
// Click to select last row.
yield evalInContent("$('.treeRow:last-child').click()");
yield assertRowSelected(numRows);
is(yield evalInContent("scroller.scrollTop + scroller.clientHeight"),
yield evalInContent("scroller.scrollHeight"), "Scrolled to the bottom.");
// Click to select 2nd row.
yield evalInContent("$('.treeRow:nth-child(2)').click()");
yield assertRowSelected(2);
ok(yield evalInContent("scroller.scrollTop > 0"), "Not scrolled to the top.");
// Synthetize up arrow key to select first row.
yield evalInContent("$('.treeTable').focus()");
yield BrowserTestUtils.synthesizeKey("VK_UP", {}, tab.linkedBrowser);
yield assertRowSelected(1);
is(yield evalInContent("scroller.scrollTop"), 0, "Scrolled to the top.");
});
async function assertRowSelected(rowNum) {
let idx = evalInContent("[].indexOf.call($$('.treeRow'), $('.treeRow.selected'))");
is(await idx + 1, +rowNum, `${rowNum ? "The row #" + rowNum : "No row"} is selected.`);
}

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

@ -119,3 +119,8 @@ addMessageListener("Test:JsonView:Eval", function (msg) {
let result = content.eval(msg.data.code);
sendAsyncMessage(msg.name, {result});
});
Components.utils.exportFunction(content.document.querySelector.bind(content.document),
content, {defineAs: "$"});
Components.utils.exportFunction(content.document.querySelectorAll.bind(content.document),
content, {defineAs: "$$"});

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

@ -208,19 +208,16 @@ class StatisticsPanel extends Component {
} else if (Filters.media(request)) {
// "media"
type = 6;
} else if (Filters.flash(request)) {
// "flash"
type = 7;
} else if (Filters.ws(request)) {
// "ws"
type = 8;
type = 7;
} else if (Filters.xhr(request)) {
// Verify XHR last, to categorize other mime types in their own blobs.
// "xhr"
type = 3;
} else {
// "other"
type = 9;
type = 8;
}
if (emptyCache || !this.responseIsFresh(request)) {

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

@ -275,7 +275,6 @@ const FILTER_TAGS = [
"fonts",
"images",
"media",
"flash",
"ws",
"other",
];

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

@ -61,15 +61,6 @@ function isMedia({ mimeType }) {
mimeType.includes("model/"));
}
function isFlash({ url, mimeType }) {
// Flash is a mess.
return (mimeType && (
mimeType.includes("/x-flv") ||
mimeType.includes("/x-shockwave-flash"))) ||
url.includes(".swf") ||
url.includes(".flv");
}
function isWS({ requestHeaders, responseHeaders }) {
// Detect a websocket upgrade if request has an Upgrade header with value 'websocket'
if (!requestHeaders || !Array.isArray(requestHeaders.headers)) {
@ -100,7 +91,7 @@ function isWS({ requestHeaders, responseHeaders }) {
}
function isOther(item) {
let tests = [isHtml, isCss, isJs, isXHR, isFont, isImage, isMedia, isFlash, isWS];
let tests = [isHtml, isCss, isJs, isXHR, isFont, isImage, isMedia, isWS];
return tests.every(is => !is(item));
}
@ -114,7 +105,6 @@ module.exports = {
fonts: isFont,
images: isImage,
media: isMedia,
flash: isFlash,
ws: isWS,
other: isOther,
},

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

@ -213,13 +213,6 @@ add_task(function* () {
testFilterButtons(monitor, "media");
yield testContents([0, 0, 0, 0, 0, 1, 1, 0, 0]);
EventUtils.sendMouseEvent({ type: "click" },
document.querySelector(".requests-list-filter-all-button"));
EventUtils.sendMouseEvent({ type: "click" },
document.querySelector(".requests-list-filter-flash-button"));
testFilterButtons(monitor, "flash");
yield testContents([0, 0, 0, 0, 0, 0, 0, 1, 0]);
EventUtils.sendMouseEvent({ type: "click" },
document.querySelector(".requests-list-filter-all-button"));
EventUtils.sendMouseEvent({ type: "click" },
@ -265,25 +258,20 @@ add_task(function* () {
document.querySelector(".requests-list-filter-html-button"));
EventUtils.sendMouseEvent({ type: "click" },
document.querySelector(".requests-list-filter-css-button"));
testFilterButtonsCustom(monitor, [0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0]);
testFilterButtonsCustom(monitor, [0, 1, 1, 0, 0, 0, 0, 0, 0, 0]);
yield testContents([1, 1, 0, 0, 0, 0, 0, 0, 0]);
// Html and css filter enabled and text filter should show just the html and css match.
// Should not show both the items matching the button plus the items matching the text.
setFreetextFilter("sample");
yield testContents([1, 1, 0, 0, 0, 0, 0, 0, 0]);
EventUtils.sendMouseEvent({ type: "click" },
document.querySelector(".requests-list-filter-flash-button"));
setFreetextFilter("");
testFilterButtonsCustom(monitor, [0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0]);
yield testContents([1, 1, 0, 0, 0, 0, 0, 1, 0]);
testFilterButtonsCustom(monitor, [0, 1, 1, 0, 0, 0, 0, 0, 0, 0]);
yield testContents([1, 1, 0, 0, 0, 0, 0, 0, 0]);
// Disable some filters. Only one left active.
EventUtils.sendMouseEvent({ type: "click" },
document.querySelector(".requests-list-filter-css-button"));
EventUtils.sendMouseEvent({ type: "click" },
document.querySelector(".requests-list-filter-flash-button"));
testFilterButtons(monitor, "html");
yield testContents([1, 0, 0, 0, 0, 0, 0, 0, 0]);
@ -300,7 +288,7 @@ add_task(function* () {
document.querySelector(".requests-list-filter-css-button"));
EventUtils.sendMouseEvent({ type: "click" },
document.querySelector(".requests-list-filter-ws-button"));
testFilterButtonsCustom(monitor, [0, 1, 1, 0, 0, 0, 0, 0, 0, 1]);
testFilterButtonsCustom(monitor, [0, 1, 1, 0, 0, 0, 0, 0, 1, 0]);
EventUtils.sendMouseEvent({ type: "click" },
document.querySelector(".requests-list-filter-all-button"));
testFilterButtons(monitor, "all");

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

@ -38,7 +38,7 @@ add_task(function* () {
testStatus();
let buttons = ["html", "css", "js", "xhr", "fonts", "images", "media", "flash"];
let buttons = ["html", "css", "js", "xhr", "fonts", "images", "media"];
for (let button of buttons) {
let buttonEl = document.querySelector(`.requests-list-filter-${button}-button`);
EventUtils.sendMouseEvent({ type: "click" }, buttonEl);

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

@ -26,7 +26,7 @@ add_task(function* () {
document.querySelector(".requests-list-filter-ws-button"));
EventUtils.sendMouseEvent({ type: "click" },
document.querySelector(".requests-list-filter-other-button"));
testFilterButtonsCustom(monitor, [0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1]);
testFilterButtonsCustom(monitor, [0, 1, 1, 1, 0, 0, 0, 0, 1, 1]);
info("The correct filtering predicates are used before entering perf. analysis mode.");
store.dispatch(Actions.openStatistics(connector, true));

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

@ -9,6 +9,7 @@
define(function (require, exports, module) {
const { cloneElement, Component, createFactory, DOM: dom, PropTypes } =
require("devtools/client/shared/vendor/react");
const { findDOMNode } = require("devtools/client/shared/vendor/react-dom");
// Reps
const { ObjectProvider } = require("./ObjectProvider");
@ -153,7 +154,7 @@ define(function (require, exports, module) {
// TODO: Do better than just selecting the first row again. We want to
// select (in order) previous, next or parent in case when selected
// row is removed.
this.selectRow(this.rows[0].props.member.path);
this.selectRow(this.rows[0]);
}
}
@ -255,13 +256,13 @@ define(function (require, exports, module) {
case "ArrowDown":
let nextRow = this.rows[index + 1];
if (nextRow) {
this.selectRow(nextRow.props.member.path);
this.selectRow(nextRow);
}
break;
case "ArrowUp":
let previousRow = this.rows[index - 1];
if (previousRow) {
this.selectRow(previousRow.props.member.path);
this.selectRow(previousRow);
}
break;
default:
@ -277,7 +278,7 @@ define(function (require, exports, module) {
if (cell && cell.classList.contains("treeLabelCell")) {
this.toggle(nodePath);
}
this.selectRow(nodePath);
this.selectRow(event.currentTarget);
}
getSelectedRow(rows) {
@ -287,10 +288,12 @@ define(function (require, exports, module) {
return rows.find(row => this.isSelected(row.props.member.path));
}
selectRow(nodePath) {
selectRow(row) {
row = findDOMNode(row);
this.setState(Object.assign({}, this.state, {
selected: nodePath
selected: row.id
}));
row.scrollIntoView({block: "nearest"});
}
isSelected(nodePath) {

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

@ -494,7 +494,9 @@ checkbox:-moz-focusring {
top: 100%;
width: 100%;
line-height: initial !important;
z-index: 999;
/* See bug - 1414609. z-index is greater than 1000 so that searchbox's z-index
is more than z-index of requests-list-headers-wrapper in netmonitor */
z-index: 1001;
}
/* Don't add 'double spacing' for inputs that are at beginning / end

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

@ -191,7 +191,7 @@
fill: var(--theme-toolbar-selected-color);
}
.devtools-tab:not(.selected).highlighted > img {
.devtools-tab.highlighted > img {
fill: var(--theme-toolbar-highlighted-color);
}

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

@ -23,6 +23,10 @@ a {
* assertion when loading HTML page with links in XUL iframe */
*:visited { }
* {
box-sizing: border-box;
}
.message {
display: flex;
padding: 0 7px;

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

@ -95,7 +95,8 @@ support-files =
test-bug-869003-iframe.html
test-bug-869003-top-window.html
test-bug-952277-highlight-nodes-in-vview.html
test-bug-989025-iframe-parent.html
test-iframe-child.html
test-iframe-parent.html
test-certificate-messages.html
test-closure-optimized-out.html
test-closures.html
@ -198,8 +199,11 @@ skip-if = true # Bug 1403188
[browser_jsterm_add_edited_input_to_history.js]
[browser_jsterm_autocomplete_array_no_index.js]
[browser_jsterm_autocomplete_cached_results.js]
[browser_jsterm_autocomplete_crossdomain_iframe.js]
[browser_jsterm_autocomplete_escape_key.js]
[browser_jsterm_autocomplete_extraneous_closing_brackets.js]
[browser_jsterm_autocomplete_helpers.js]
[browser_jsterm_autocomplete_in_debugger_stackframe.js]
[browser_jsterm_autocomplete_inside_text.js]
[browser_jsterm_autocomplete_nav_and_tab_key.js]
[browser_jsterm_autocomplete_return_key_no_selection.js]
@ -221,17 +225,12 @@ subsuite = clipboard
tags = mcb
skip-if = true # Bug 1403452
# old console skip-if = (os == 'win' && bits == 64) # Bug 1390001
[browser_webconsole_autocomplete_crossdomain_iframe.js]
skip-if = true # Bug 1408919
[browser_webconsole_autocomplete_in_debugger_stackframe.js]
skip-if = true # Bug 1408920
[browser_webconsole_batching.js]
[browser_webconsole_block_mixedcontent_securityerrors.js]
tags = mcb
skip-if = true # Bug 1403899
# old console skip-if = (os == 'win' && bits == 64) # Bug 1390001
[browser_webconsole_cached_messages.js]
skip-if = true # Bug 1406069
[browser_webconsole_cd_iframe.js]
skip-if = true # Bug 1406030
[browser_webconsole_certificate_messages.js]
@ -246,8 +245,6 @@ skip-if = true # Bug 1406038
[browser_webconsole_clickable_urls.js]
[browser_webconsole_closing_after_completion.js]
skip-if = true # Bug 1408927
[browser_webconsole_closing_brackets.js]
skip-if = true # Bug 1408928
[browser_webconsole_closure_inspection.js]
skip-if = true # Bug 1405250
[browser_webconsole_completion.js]
@ -256,7 +253,6 @@ skip-if = true # Bug 1408929
skip-if = true # Bug 1408930
[browser_webconsole_console_dir.js]
[browser_webconsole_console_dir_uninspectable.js]
skip-if = true # Bug 1403449
[browser_webconsole_console_group.js]
[browser_webconsole_console_logging_workers_api.js]
skip-if = true # Bug 1405252
@ -271,10 +267,6 @@ skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32
subsuite = clipboard
[browser_webconsole_context_menu_open_url.js]
[browser_webconsole_context_menu_store_as_global.js]
[browser_webconsole_copy_entire_message_context_menu.js]
subsuite = clipboard
skip-if = true # Bug 1401958
# old console skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts
[browser_webconsole_copy_link_location.js]
skip-if = true # Bug 1401944
[browser_webconsole_csp_ignore_reflected_xss_message.js]

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

@ -18,7 +18,8 @@ add_task(async function () {
inputNode: input,
} = jsterm;
const jstermComplete = (value, delta) => complete(jsterm, input, value, delta);
const jstermComplete = (value, offset) =>
jstermSetValueAndComplete(jsterm, value, offset);
// Test if 'doc' gives 'document'
await jstermComplete("doc");
@ -65,16 +66,6 @@ add_task(async function () {
"autocomplete cached results do not contain docfoobar. list has not been updated");
});
function complete(jsterm, input, value, caretIndexDelta = 0) {
input.value = value;
let index = value.length + caretIndexDelta;
input.setSelectionRange(index, index);
const updated = jsterm.once("autocomplete-updated");
jsterm.complete(jsterm.COMPLETE_HINT_ONLY);
return updated;
}
function getPopupLabels(popup) {
return popup.getItems().map(item => item.label);
}

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

@ -0,0 +1,37 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Test that autocomplete doesn't break when trying to reach into objects from
// a different domain. See Bug 989025.
"use strict";
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
"new-console-output/test/mochitest/test-iframe-parent.html";
add_task(async function () {
const hud = await openNewTabAndConsole(TEST_URI);
const { jsterm } = hud;
const onParentTitle = waitForMessage(hud, "iframe parent");
jsterm.execute("document.title");
await onParentTitle;
ok(true, "root document's title is accessible");
// Make sure we don't throw when trying to autocomplete
let autocompleteUpdated = hud.jsterm.once("autocomplete-updated");
jsterm.setInputValue("window[0].document");
EventUtils.synthesizeKey(".", {});
await autocompleteUpdated;
hud.jsterm.setInputValue("window[0].document.title");
const onPermissionDeniedMessage = waitForMessage(hud, "Permission denied");
EventUtils.synthesizeKey("VK_RETURN", {});
const permissionDenied = await onPermissionDeniedMessage;
ok(permissionDenied.node.classList.contains("error"),
"A message error is shown when trying to inspect window[0]");
const onParentLocation = waitForMessage(hud, "test-iframe-parent.html");
hud.jsterm.execute("window.location");
await onParentLocation;
ok(true, "root document's location is accessible");
});

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

@ -10,20 +10,13 @@
const TEST_URI = "data:text/html;charset=utf-8,test for bug 592442";
add_task(function* () {
yield loadTab(TEST_URI);
let hud = yield openConsole();
hud.jsterm.clearOutput();
let jsterm = hud.jsterm;
add_task(async function () {
let { jsterm } = await openNewTabAndConsole(TEST_URI);
jsterm.setInputValue("document.getElementById)");
let error = false;
try {
jsterm.complete(jsterm.COMPLETE_HINT_ONLY);
await jstermSetValueAndComplete(jsterm, "document.getElementById)");
ok(true, "no error was thrown when an extraneous bracket was inserted");
} catch (ex) {
error = true;
ok(false, "an error was thrown when an extraneous bracket was inserted")
}
ok(!error, "no error was thrown when an extraneous bracket was inserted");
});

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

@ -0,0 +1,116 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Test that makes sure web console autocomplete happens in the user-selected
// stackframe from the js debugger.
"use strict";
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
"new-console-output/test/mochitest/test-autocomplete-in-stackframe.html";
add_task(async function () {
// Force the old debugger UI since it's directly used (see Bug 1301705)
await pushPref("devtools.debugger.new-debugger-frontend", false);
let { jsterm } = await openNewTabAndConsole(TEST_URI);
const {
autocompletePopup: popup,
} = jsterm;
let target = TargetFactory.forTab(gBrowser.selectedTab);
let toolbox = gDevTools.getToolbox(target);
const jstermComplete = value => jstermSetValueAndComplete(jsterm, value);
// Test that document.title gives string methods. Native getters must execute.
await jstermComplete("document.title.");
let newItemsLabels = getPopupLabels(popup);
ok(newItemsLabels.length > 0, "'document.title.' gave a list of suggestions");
ok(newItemsLabels.includes("substr"), `results do contain "substr"`);
ok(newItemsLabels.includes("toLowerCase"), `results do contain "toLowerCase"`);
ok(newItemsLabels.includes("strike"), `results do contain "strike"`);
// Test if 'foo' gives 'foo1' but not 'foo2' or 'foo3'
await jstermComplete("foo");
is(getPopupLabels(popup).join("-"), "foo1Obj-foo1",
`"foo" gave the expected suggestions`);
// Test if 'foo1Obj.' gives 'prop1' and 'prop2'
await jstermComplete("foo1Obj.");
is(getPopupLabels(popup).join("-"), "prop2-prop1",
`"foo1Obj." gave the expected suggestions`);
// Test if 'foo1Obj.prop2.' gives 'prop21'
await jstermComplete("foo1Obj.prop2.");
ok(getPopupLabels(popup).includes("prop21"),
`"foo1Obj.prop2." gave the expected suggestions`);
info("Opening Debugger");
let {panel} = await openDebugger();
info("Waiting for pause");
const stackFrames = await pauseDebugger(panel);
info("Opening Console again");
await toolbox.selectTool("webconsole");
// Test if 'foo' gives 'foo3' and 'foo1' but not 'foo2', since we are paused in
// the `secondCall` function (called by `firstCall`, which we call in `pauseDebugger`).
await jstermComplete("foo");
is(getPopupLabels(popup).join("-"), "foo3Obj-foo3-foo1Obj-foo1",
`"foo" gave the expected suggestions`);
await openDebugger();
// Select the frame for the `firstCall` function.
stackFrames.selectFrame(1);
info("openConsole");
await toolbox.selectTool("webconsole");
// Test if 'foo' gives 'foo2' and 'foo1' but not 'foo3', since we are now in the
// `firstCall` frame.
await jstermComplete("foo");
is(getPopupLabels(popup).join("-"), "foo2Obj-foo2-foo1Obj-foo1",
`"foo" gave the expected suggestions`);
// Test if 'foo2Obj.' gives 'prop1'
await jstermComplete("foo2Obj.");
ok(getPopupLabels(popup).includes("prop1"), `"foo2Obj." returns "prop1"`);
// Test if 'foo2Obj.prop1.' gives 'prop11'
await jstermComplete("foo2Obj.prop1.");
ok(getPopupLabels(popup).includes("prop11"), `"foo2Obj.prop1" returns "prop11"`);
// Test if 'foo2Obj.prop1.prop11.' gives suggestions for a string,i.e. 'length'
await jstermComplete("foo2Obj.prop1.prop11.");
ok(getPopupLabels(popup).includes("length"), `results do contain "length"`);
// Test if 'foo2Obj[0].' throws no errors.
await jstermComplete("foo2Obj[0].");
is(getPopupLabels(popup).length, 0, "no items for foo2Obj[0]");
});
function getPopupLabels(popup) {
return popup.getItems().map(item => item.label);
}
function pauseDebugger(debuggerPanel) {
const debuggerWin = debuggerPanel.panelWin;
const debuggerController = debuggerWin.DebuggerController;
const thread = debuggerController.activeThread;
return new Promise(resolve => {
thread.addOneTimeListener("framesadded", () =>
resolve(debuggerController.StackFrames));
info("firstCall()");
ContentTask.spawn(gBrowser.selectedBrowser, {}, function () {
content.wrappedJSObject.firstCall();
});
});
}

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

@ -1,64 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Test that autocomplete doesn't break when trying to reach into objects from
// a different domain, bug 989025.
"use strict";
function test() {
let hud;
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
"test/test-bug-989025-iframe-parent.html";
Task.spawn(function* () {
const {tab} = yield loadTab(TEST_URI);
hud = yield openConsole(tab);
hud.jsterm.execute("document.title");
yield waitForMessages({
webconsole: hud,
messages: [{
text: "989025 - iframe parent",
category: CATEGORY_OUTPUT,
}],
});
let autocompleteUpdated = hud.jsterm.once("autocomplete-updated");
hud.jsterm.setInputValue("window[0].document");
executeSoon(() => {
EventUtils.synthesizeKey(".", {});
});
yield autocompleteUpdated;
hud.jsterm.setInputValue("window[0].document.title");
EventUtils.synthesizeKey("VK_RETURN", {});
yield waitForMessages({
webconsole: hud,
messages: [{
text: "Permission denied",
category: CATEGORY_OUTPUT,
severity: SEVERITY_ERROR,
}],
});
hud.jsterm.execute("window.location");
yield waitForMessages({
webconsole: hud,
messages: [{
text: "test-bug-989025-iframe-parent.html",
category: CATEGORY_OUTPUT,
}],
});
yield closeConsole(tab);
}).then(finishTest);
}

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

@ -1,245 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Test that makes sure web console autocomplete happens in the user-selected
// stackframe from the js debugger.
"use strict";
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
"test/test-autocomplete-in-stackframe.html";
// Force the old debugger UI since it's directly used (see Bug 1301705)
Services.prefs.setBoolPref("devtools.debugger.new-debugger-frontend", false);
registerCleanupFunction(function* () {
Services.prefs.clearUserPref("devtools.debugger.new-debugger-frontend");
});
var gStackframes;
registerCleanupFunction(function () {
gStackframes = null;
});
requestLongerTimeout(2);
add_task(function* () {
yield loadTab(TEST_URI);
let hud = yield openConsole();
yield testCompletion(hud);
});
function* testCompletion(hud) {
let jsterm = hud.jsterm;
let input = jsterm.inputNode;
let popup = jsterm.autocompletePopup;
// Test that document.title gives string methods. Native getters must execute.
input.value = "document.title.";
input.setSelectionRange(input.value.length, input.value.length);
yield new Promise(resolve => {
jsterm.complete(jsterm.COMPLETE_HINT_ONLY, resolve);
});
let newItems = popup.getItems();
ok(newItems.length > 0, "'document.title.' gave a list of suggestions");
ok(newItems.some(function (item) {
return item.label == "substr";
}), "autocomplete results do contain substr");
ok(newItems.some(function (item) {
return item.label == "toLowerCase";
}), "autocomplete results do contain toLowerCase");
ok(newItems.some(function (item) {
return item.label == "strike";
}), "autocomplete results do contain strike");
// Test if 'f' gives 'foo1' but not 'foo2' or 'foo3'
input.value = "f";
input.setSelectionRange(1, 1);
yield new Promise(resolve => {
jsterm.complete(jsterm.COMPLETE_HINT_ONLY, resolve);
});
newItems = popup.getItems();
ok(newItems.length > 0, "'f' gave a list of suggestions");
ok(!newItems.every(function (item) {
return item.label != "foo1";
}), "autocomplete results do contain foo1");
ok(!newItems.every(function (item) {
return item.label != "foo1Obj";
}), "autocomplete results do contain foo1Obj");
ok(newItems.every(function (item) {
return item.label != "foo2";
}), "autocomplete results do not contain foo2");
ok(newItems.every(function (item) {
return item.label != "foo2Obj";
}), "autocomplete results do not contain foo2Obj");
ok(newItems.every(function (item) {
return item.label != "foo3";
}), "autocomplete results do not contain foo3");
ok(newItems.every(function (item) {
return item.label != "foo3Obj";
}), "autocomplete results do not contain foo3Obj");
// Test if 'foo1Obj.' gives 'prop1' and 'prop2'
input.value = "foo1Obj.";
input.setSelectionRange(8, 8);
yield new Promise(resolve => {
jsterm.complete(jsterm.COMPLETE_HINT_ONLY, resolve);
});
newItems = popup.getItems();
ok(!newItems.every(function (item) {
return item.label != "prop1";
}), "autocomplete results do contain prop1");
ok(!newItems.every(function (item) {
return item.label != "prop2";
}), "autocomplete results do contain prop2");
// Test if 'foo1Obj.prop2.' gives 'prop21'
input.value = "foo1Obj.prop2.";
input.setSelectionRange(14, 14);
yield new Promise(resolve => {
jsterm.complete(jsterm.COMPLETE_HINT_ONLY, resolve);
});
newItems = popup.getItems();
ok(!newItems.every(function (item) {
return item.label != "prop21";
}), "autocomplete results do contain prop21");
info("Opening Debugger");
let dbg = yield openDebugger();
info("Waiting for pause");
yield pauseDebugger(dbg);
info("Opening Console again");
yield openConsole();
// From this point on the
// Test if 'f' gives 'foo3' and 'foo1' but not 'foo2'
input.value = "f";
input.setSelectionRange(1, 1);
yield new Promise(resolve => {
jsterm.complete(jsterm.COMPLETE_HINT_ONLY, resolve);
});
newItems = popup.getItems();
ok(newItems.length > 0, "'f' gave a list of suggestions");
ok(!newItems.every(function (item) {
return item.label != "foo3";
}), "autocomplete results do contain foo3");
ok(!newItems.every(function (item) {
return item.label != "foo3Obj";
}), "autocomplete results do contain foo3Obj");
ok(!newItems.every(function (item) {
return item.label != "foo1";
}), "autocomplete results do contain foo1");
ok(!newItems.every(function (item) {
return item.label != "foo1Obj";
}), "autocomplete results do contain foo1Obj");
ok(newItems.every(function (item) {
return item.label != "foo2";
}), "autocomplete results do not contain foo2");
ok(newItems.every(function (item) {
return item.label != "foo2Obj";
}), "autocomplete results do not contain foo2Obj");
yield openDebugger();
gStackframes.selectFrame(1);
info("openConsole");
yield openConsole();
// Test if 'f' gives 'foo2' and 'foo1' but not 'foo3'
input.value = "f";
input.setSelectionRange(1, 1);
yield new Promise(resolve => {
jsterm.complete(jsterm.COMPLETE_HINT_ONLY, resolve);
});
newItems = popup.getItems();
ok(newItems.length > 0, "'f' gave a list of suggestions");
ok(!newItems.every(function (item) {
return item.label != "foo2";
}), "autocomplete results do contain foo2");
ok(!newItems.every(function (item) {
return item.label != "foo2Obj";
}), "autocomplete results do contain foo2Obj");
ok(!newItems.every(function (item) {
return item.label != "foo1";
}), "autocomplete results do contain foo1");
ok(!newItems.every(function (item) {
return item.label != "foo1Obj";
}), "autocomplete results do contain foo1Obj");
ok(newItems.every(function (item) {
return item.label != "foo3";
}), "autocomplete results do not contain foo3");
ok(newItems.every(function (item) {
return item.label != "foo3Obj";
}), "autocomplete results do not contain foo3Obj");
// Test if 'foo2Obj.' gives 'prop1'
input.value = "foo2Obj.";
input.setSelectionRange(8, 8);
yield new Promise(resolve => {
jsterm.complete(jsterm.COMPLETE_HINT_ONLY, resolve);
});
newItems = popup.getItems();
ok(!newItems.every(function (item) {
return item.label != "prop1";
}), "autocomplete results do contain prop1");
// Test if 'foo2Obj.prop1.' gives 'prop11'
input.value = "foo2Obj.prop1.";
input.setSelectionRange(14, 14);
yield new Promise(resolve => {
jsterm.complete(jsterm.COMPLETE_HINT_ONLY, resolve);
});
newItems = popup.getItems();
ok(!newItems.every(function (item) {
return item.label != "prop11";
}), "autocomplete results do contain prop11");
// Test if 'foo2Obj.prop1.prop11.' gives suggestions for a string
// i.e. 'length'
input.value = "foo2Obj.prop1.prop11.";
input.setSelectionRange(21, 21);
yield new Promise(resolve => {
jsterm.complete(jsterm.COMPLETE_HINT_ONLY, resolve);
});
newItems = popup.getItems();
ok(!newItems.every(function (item) {
return item.label != "length";
}), "autocomplete results do contain length");
// Test if 'foo1Obj[0].' throws no errors.
input.value = "foo2Obj[0].";
input.setSelectionRange(11, 11);
yield new Promise(resolve => {
jsterm.complete(jsterm.COMPLETE_HINT_ONLY, resolve);
});
newItems = popup.getItems();
is(newItems.length, 0, "no items for foo2Obj[0]");
}
function pauseDebugger(aResult) {
let debuggerWin = aResult.panelWin;
let debuggerController = debuggerWin.DebuggerController;
let thread = debuggerController.activeThread;
gStackframes = debuggerController.StackFrames;
return new Promise(resolve => {
thread.addOneTimeListener("framesadded", resolve);
info("firstCall()");
ContentTask.spawn(gBrowser.selectedBrowser, {}, function* () {
content.wrappedJSObject.firstCall();
});
});
}

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

@ -9,51 +9,41 @@
"use strict";
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
"test/test-webconsole-error-observer.html";
"new-console-output/test/mochitest/test-webconsole-error-observer.html";
add_task(async function() {
// On e10s, the exception is triggered in child process
// and is ignored by test harness
if (!Services.appinfo.browserTabsRemoteAutostart) {
expectUncaughtException();
}
// Enable CSS filter for the test.
await pushPref("devtools.webconsole.filter.css", true);
function test() {
waitForExplicitFinish();
await addTab(TEST_URI);
loadTab(TEST_URI).then(testOpenUI);
}
function testOpenUI(aTestReopen) {
openConsole().then((hud) => {
waitForMessages({
webconsole: hud,
messages: [
{
text: "log Bazzle",
category: CATEGORY_WEBDEV,
severity: SEVERITY_LOG,
},
{
text: "error Bazzle",
category: CATEGORY_WEBDEV,
severity: SEVERITY_ERROR,
},
{
text: "bazBug611032",
category: CATEGORY_JS,
severity: SEVERITY_ERROR,
},
{
text: "cssColorBug611032",
category: CATEGORY_CSS,
severity: SEVERITY_WARNING,
},
],
}).then(() => {
closeConsole(gBrowser.selectedTab).then(() => {
aTestReopen && info("will reopen the Web Console");
executeSoon(aTestReopen ? testOpenUI : finishTest);
});
});
});
info("Open the console");
let hud = await openConsole();
testMessagesVisibility(hud);
info("Close the toolbox");
await closeToolbox();
info("Open the console again");
hud = await openConsole();
testMessagesVisibility(hud);
});
function testMessagesVisibility(hud) {
let message = findMessage(hud, "log Bazzle", ".message.log");
ok(message, "console.log message is visible");
message = findMessage(hud, "error Bazzle", ".message.error");
ok(message, "console.error message is visible");
message = findMessage(hud, "bazBug611032", ".message.error");
ok(message, "exception message is visible");
message = findMessage(hud, "cssColorBug611032", ".message.warn.css");
ok(message, "css warning message is visible");
}

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

@ -8,40 +8,31 @@
"use strict";
const TEST_URI = "data:text/html;charset=utf8,test for bug 773466";
const TEST_URI = "data:text/html;charset=utf8,test console.dir on uninspectable object";
const FIRST_LOG_MESSAGE = "fooBug773466a";
const SECOND_LOG_MESSAGE = "fooBug773466b";
add_task(function* () {
yield loadTab(TEST_URI);
add_task(async function () {
const hud = await openNewTabAndConsole(TEST_URI);
const {jsterm} = hud;
let hud = yield openConsole();
info("Logging a first message to make sure everything is working");
let onLogMessage = waitForMessage(hud, FIRST_LOG_MESSAGE);
jsterm.execute(`console.log("${FIRST_LOG_MESSAGE}")`);
await onLogMessage;
hud.jsterm.clearOutput(true);
info("console.dir on an uninspectable object");
const onDirMessage = waitForMessage(hud, "Object { }");
jsterm.execute("console.dir(Object.create(null))");
await onDirMessage;
hud.jsterm.execute("console.log('fooBug773466a')");
hud.jsterm.execute("myObj = Object.create(null)");
hud.jsterm.execute("console.dir(myObj)");
yield waitForMessages({
webconsole: hud,
messages: [{
text: "fooBug773466a",
category: CATEGORY_WEBDEV,
severity: SEVERITY_LOG,
},
{
name: "console.dir output",
consoleDir: "[object Object]",
}],
info("Logging a second message to make sure the console is not broken");
onLogMessage = waitForMessage(hud, SECOND_LOG_MESSAGE);
// Logging from content to make sure the console API is working.
ContentTask.spawn(gBrowser.selectedBrowser, SECOND_LOG_MESSAGE, (string) => {
content.console.log(string);
});
await onLogMessage;
content.console.log("fooBug773466b");
yield waitForMessages({
webconsole: hud,
messages: [{
text: "fooBug773466b",
category: CATEGORY_WEBDEV,
severity: SEVERITY_LOG,
}],
});
ok(true, "The console.dir call on an uninspectable object did not break the console");
});

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

@ -1,97 +0,0 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/* globals goDoCommand */
"use strict";
// Test copying of the entire console message when right-clicked
// with no other text selected. See Bug 1100562.
add_task(function* () {
let hud;
let outputNode;
let contextMenu;
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/test/test-console.html";
const { tab, browser } = yield loadTab(TEST_URI);
hud = yield openConsole(tab);
outputNode = hud.outputNode;
contextMenu = hud.iframeWindow.document.getElementById("output-contextmenu");
registerCleanupFunction(() => {
hud = outputNode = contextMenu = null;
});
hud.jsterm.clearOutput();
yield ContentTask.spawn(browser, {}, function* () {
let button = content.document.getElementById("testTrace");
button.click();
});
let results = yield waitForMessages({
webconsole: hud,
messages: [
{
text: "bug 1100562",
category: CATEGORY_WEBDEV,
severity: SEVERITY_LOG,
lines: 1,
},
{
name: "console.trace output",
consoleTrace: true,
lines: 3,
},
]
});
outputNode.focus();
for (let result of results) {
let message = [...result.matched][0];
yield waitForContextMenu(contextMenu, message, () => {
let copyItem = contextMenu.querySelector("#cMenu_copy");
copyItem.doCommand();
let controller = top.document.commandDispatcher
.getControllerForCommand("cmd_copy");
is(controller.isCommandEnabled("cmd_copy"), true, "cmd_copy is enabled");
});
let clipboardText;
yield waitForClipboardPromise(
() => goDoCommand("cmd_copy"),
(str) => {
clipboardText = str;
return message.textContent == clipboardText;
}
);
ok(clipboardText, "Clipboard text was found and saved");
let lines = clipboardText.split("\n");
ok(lines.length > 0, "There is at least one newline in the message");
is(lines.pop(), "", "There is a newline at the end");
is(lines.length, result.lines, `There are ${result.lines} lines in the message`);
// Test the first line for "timestamp message repeat file:line"
let firstLine = lines.shift();
ok(/^[\d:.]+ .+ \d+ .+:\d+$/.test(firstLine),
"The message's first line has the right format");
// Test the remaining lines (stack trace) for "TABfunctionName sourceURL:line:col"
for (let line of lines) {
ok(/^\t.+ .+:\d+:\d+$/.test(line), "The stack trace line has the right format");
}
}
yield closeConsole(tab);
yield finishTest();
});

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

@ -3,9 +3,10 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/* import-globals-from ../../../../framework/test/shared-head.js */
/* exported WCUL10n, openNewTabAndConsole, waitForMessages, waitFor, findMessage,
openContextMenu, hideContextMenu, loadDocument, hasFocus,
waitForNodeMutation, testOpenInDebugger, checkClickOnNode */
/* exported WCUL10n, openNewTabAndConsole, waitForMessages, waitForMessage, waitFor,
findMessage, openContextMenu, hideContextMenu, loadDocument, hasFocus,
waitForNodeMutation, testOpenInDebugger, checkClickOnNode, jstermSetValueAndComplete,
openDebugger, openConsole */
"use strict";
@ -69,12 +70,12 @@ async function openNewTabAndConsole(url, clearJstermHistory = true) {
* - hud: the webconsole
* - messages: Array[Object]. An array of messages to match.
Current supported options:
* - text: Exact text match in .message-body
* - text: Partial text match in .message-body
*/
function waitForMessages({ hud, messages }) {
return new Promise(resolve => {
let numMatched = 0;
let receivedLog = hud.ui.on("new-messages",
const matchedMessages = [];
hud.ui.on("new-messages",
function messagesReceived(e, newMessages) {
for (let message of messages) {
if (message.matched) {
@ -84,17 +85,20 @@ function waitForMessages({ hud, messages }) {
for (let newMessage of newMessages) {
let messageBody = newMessage.node.querySelector(".message-body");
if (messageBody.textContent.includes(message.text)) {
numMatched++;
matchedMessages.push(newMessage);
message.matched = true;
info("Matched a message with text: " + message.text +
", still waiting for " + (messages.length - numMatched) + " messages");
const messagesLeft = messages.length - matchedMessages.length;
info(`Matched a message with text: "${message.text}", ` + (messagesLeft > 0
? `still waiting for ${messagesLeft} messages.`
: `all messages received.`)
);
break;
}
}
if (numMatched === messages.length) {
if (matchedMessages.length === messages.length) {
hud.ui.off("new-messages", messagesReceived);
resolve(receivedLog);
resolve(matchedMessages);
return;
}
}
@ -102,6 +106,17 @@ function waitForMessages({ hud, messages }) {
});
}
/**
* Wait for a single message in the web console output, resolving once it is received.
*
* @param {Object} hud : the webconsole
* @param {String} text : text included in .message-body
*/
async function waitForMessage(hud, text) {
const messages = await waitForMessages({hud, messages: [{text}]});
return messages[0];
}
/**
* Wait for a predicate to return a result.
*
@ -271,3 +286,81 @@ function hasFocus(node) {
return node.ownerDocument.activeElement == node
&& node.ownerDocument.hasFocus();
}
/**
* Set the value of the JsTerm and its caret position, and fire a completion request.
*
* @param {JsTerm} jsterm
* @param {String} value : The value to set the jsterm to.
* @param {Integer} caretIndexOffset : A number that will be added to value.length
* when setting the caret. A negative number will place the caret
* in (end - offset) position. Default to 0 (caret set at the end)
* @returns {Promise} resolves when the jsterm is completed.
*/
function jstermSetValueAndComplete(jsterm, value, caretIndexOffset = 0) {
const {inputNode} = jsterm;
inputNode.value = value;
let index = value.length + caretIndexOffset;
inputNode.setSelectionRange(index, index);
const updated = jsterm.once("autocomplete-updated");
jsterm.complete(jsterm.COMPLETE_HINT_ONLY);
return updated;
}
/**
* Open the JavaScript debugger.
*
* @param object options
* Options for opening the debugger:
* - tab: the tab you want to open the debugger for.
* @return object
* A promise that is resolved once the debugger opens, or rejected if
* the open fails. The resolution callback is given one argument, an
* object that holds the following properties:
* - target: the Target object for the Tab.
* - toolbox: the Toolbox instance.
* - panel: the jsdebugger panel instance.
*/
async function openDebugger(options = {}) {
if (!options.tab) {
options.tab = gBrowser.selectedTab;
}
let target = TargetFactory.forTab(options.tab);
let toolbox = gDevTools.getToolbox(target);
let dbgPanelAlreadyOpen = toolbox && toolbox.getPanel("jsdebugger");
if (dbgPanelAlreadyOpen) {
await toolbox.selectTool("jsdebugger");
return {
target,
toolbox,
panel: toolbox.getCurrentPanel()
};
}
toolbox = await gDevTools.showToolbox(target, "jsdebugger");
let panel = toolbox.getCurrentPanel();
// Do not clear VariableView lazily so it doesn't disturb test ending.
panel._view.Variables.lazyEmpty = false;
await panel.panelWin.DebuggerController.waitForSourcesLoaded();
return {target, toolbox, panel};
}
/**
* Open the Web Console for the given tab, or the current one if none given.
*
* @param nsIDOMElement tab
* Optional tab element for which you want open the Web Console.
* Defaults to current selected tab.
* @return Promise
* A promise that is resolved with the console hud once the web console is open.
*/
async function openConsole(tab) {
let target = TargetFactory.forTab(tab || gBrowser.selectedTab);
const toolbox = await gDevTools.showToolbox(target, "webconsole");
return toolbox.getCurrentPanel().hud;
};

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

@ -10,35 +10,33 @@
<script>
var foo1 = "globalFoo";
var foo1Obj = {
var foo1Obj = Object.assign(Object.create(null), {
prop1: "111",
prop2: {
prop21: "212121"
}
};
});
function firstCall()
{
function firstCall() {
var foo2 = "fooFirstCall";
var foo2Obj = {
prop1: {
var foo2Obj = Object.assign(Object.create(null), {
prop1: Object.assign(Object.create(null), {
prop11: "111111"
}
};
})
});
secondCall();
}
function secondCall()
{
function secondCall() {
var foo3 = "fooSecondCall";
var foo3Obj = {
prop1: {
var foo3Obj = Object.assign(Object.create(null), {
prop1: Object.assign(Object.create(null), {
prop11: "313131"
}
};
})
});
debugger;
}

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

@ -0,0 +1,12 @@
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>test for bug 989025 - iframe child</title>
</head>
<body>
<p>test for bug 989025 - iframe child</p>
</body>
</html>

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

@ -1,13 +1,13 @@
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>test for bug 989025 - iframe parent</title>
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
</head>
<body>
<p>test for bug 989025 - iframe parent</p>
<iframe src="http://mochi.test:8888/browser/devtools/client/webconsole/test/test-bug-609872-cd-iframe-child.html"></iframe>
<iframe src="http://mochi.test:8888/browser/devtools/client/webconsole/new-console-output/test/mochitest/test-iframe-child.html"></iframe>
</body>
</html>

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

@ -203,6 +203,11 @@ public:
return mOffset.value();
}
/**
* Set() sets a point to aOffset or aChild.
* If it's set with offset, mRef is invalidated. If it's set with aChild,
* mOffset may be invalidated unless the offset can be computed simply.
*/
void
Set(nsINode* aContainer, int32_t aOffset)
{
@ -210,6 +215,29 @@ public:
mRef = nullptr;
mOffset = mozilla::Some(aOffset);
}
void
Set(const nsIContent* aChild)
{
MOZ_ASSERT(aChild);
mParent = aChild->GetParentNode();
mRef = aChild->GetPreviousSibling();
if (!mRef) {
mOffset = mozilla::Some(0);
} else {
mOffset.reset();
}
}
/**
* Clear() makes the instance not point anywhere.
*/
void
Clear()
{
mParent = nullptr;
mRef = nullptr;
mOffset.reset();
}
/**
* AdvanceOffset() tries to reference next sibling of mRef if its container

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

@ -51,6 +51,7 @@ TextTrackRegion::TextTrackRegion(nsISupports* aGlobal)
void
TextTrackRegion::CopyValues(TextTrackRegion& aRegion)
{
mId = aRegion.Id();
mWidth = aRegion.Width();
mLines = aRegion.Lines();
mRegionAnchorX = aRegion.RegionAnchorX();

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

@ -127,6 +127,16 @@ public:
mScroll = aScroll;
}
void GetId(nsAString& aId) const
{
aId = mId;
}
void SetId(const nsAString& aId)
{
mId = aId;
}
/** end WebIDL Methods. */
@ -139,11 +149,16 @@ public:
{
return mScroll;
}
const nsAString& Id() const
{
return mId;
}
private:
~TextTrackRegion() {}
nsCOMPtr<nsISupports> mParent;
nsString mId;
double mWidth;
long mLines;
double mRegionAnchorX;

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

@ -120,11 +120,12 @@ H264Converter::Decode(MediaRawData* aSample)
return DecodePromise::CreateAndResolve(DecodedData(), __func__);
}
if (!*mNeedAVCC &&
mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample, mNeedKeyframe).isErr()) {
auto res = !*mNeedAVCC
? mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample, mNeedKeyframe)
: Ok();
if (res.isErr()) {
return DecodePromise::CreateAndReject(
MediaResult(NS_ERROR_OUT_OF_MEMORY,
RESULT_DETAIL("ConvertSampleToAnnexB")),
MediaResult(res.unwrapErr(), RESULT_DETAIL("ConvertSampleToAnnexB")),
__func__);
}
@ -374,10 +375,12 @@ H264Converter::DecodeFirstSample(MediaRawData* aSample)
return;
}
if (!*mNeedAVCC &&
mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample, mNeedKeyframe).isErr()) {
mDecodePromise.Reject(MediaResult(NS_ERROR_OUT_OF_MEMORY,
RESULT_DETAIL("ConvertSampleToAnnexB")),
auto res = !*mNeedAVCC
? mp4_demuxer::AnnexB::ConvertSampleToAnnexB(aSample, mNeedKeyframe)
: Ok();
if (res.isErr()) {
mDecodePromise.Reject(
MediaResult(res.unwrapErr(), RESULT_DETAIL("ConvertSampleToAnnexB")),
__func__);
return;
}

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

@ -113,14 +113,11 @@
Promise.all(test.track.fragments.map(fragment => DownloadMedia(fragment, test.track.type, ms)))
.then(() => {
ms.endOfStream();
LoadEME();
})
.then(() => {
video.play();
});
});
video.addEventListener("ended", SimpleTest.finish);
once(video, "ended", SimpleTest.finish);
});
}

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

@ -1116,6 +1116,7 @@ const { XPCOMUtils } = require("resource://gre/modules/XPCOMUtils.jsm");
if (settings.has("id")) {
try {
var region = new self.window.VTTRegion();
region.id = settings.get("id", "");
region.width = settings.get("width", 100);
region.lines = settings.get("lines", 3);
region.regionAnchorX = settings.get("regionanchorX", 0);

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

@ -9,6 +9,7 @@
[Constructor, Pref="media.webvtt.regions.enabled"]
interface VTTRegion {
attribute DOMString id;
[SetterThrows]
attribute double width;

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

@ -3969,7 +3969,7 @@ EditorBase::SplitNodeDeep(nsIContent& aNode,
nsCOMPtr<nsIContent>* ioChildAtSplitPointOffset)
{
MOZ_ASSERT(&aSplitPointParent == &aNode ||
EditorUtils::IsDescendantOf(&aSplitPointParent, &aNode));
EditorUtils::IsDescendantOf(aSplitPointParent, aNode));
int32_t offset = aSplitPointOffset;
nsCOMPtr<nsIContent> leftNode, rightNode;

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

@ -5,6 +5,7 @@
#include "mozilla/EditorUtils.h"
#include "mozilla/EditorDOMPoint.h"
#include "mozilla/OwningNonNull.h"
#include "mozilla/dom/Selection.h"
#include "nsComponentManagerUtils.h"
@ -135,19 +136,23 @@ DOMSubtreeIterator::~DOMSubtreeIterator()
*****************************************************************************/
bool
EditorUtils::IsDescendantOf(nsINode* aNode,
nsINode* aParent,
int32_t* aOffset)
EditorUtils::IsDescendantOf(const nsINode& aNode,
const nsINode& aParent,
EditorRawDOMPoint* aOutPoint /* = nullptr */)
{
MOZ_ASSERT(aNode && aParent);
if (aNode == aParent) {
if (aOutPoint) {
aOutPoint->Clear();
}
if (&aNode == &aParent) {
return false;
}
for (nsCOMPtr<nsINode> node = aNode; node; node = node->GetParentNode()) {
if (node->GetParentNode() == aParent) {
if (aOffset) {
*aOffset = aParent->IndexOf(node);
for (const nsINode* node = &aNode; node; node = node->GetParentNode()) {
if (node->GetParentNode() == &aParent) {
if (aOutPoint) {
MOZ_ASSERT(node->IsContent());
aOutPoint->Set(node->AsContent());
}
return true;
}
@ -157,19 +162,20 @@ EditorUtils::IsDescendantOf(nsINode* aNode,
}
bool
EditorUtils::IsDescendantOf(nsINode* aNode,
nsINode* aParent,
nsIContent** aChild)
EditorUtils::IsDescendantOf(const nsINode& aNode,
const nsINode& aParent,
EditorDOMPoint* aOutPoint)
{
MOZ_ASSERT(aNode && aParent && aChild);
*aChild = nullptr;
if (aNode == aParent) {
MOZ_ASSERT(aOutPoint);
aOutPoint->Clear();
if (&aNode == &aParent) {
return false;
}
for (nsCOMPtr<nsINode> node = aNode; node; node = node->GetParentNode()) {
if (node->GetParentNode() == aParent) {
*aChild = node->AsContent();
for (const nsINode* node = &aNode; node; node = node->GetParentNode()) {
if (node->GetParentNode() == &aParent) {
MOZ_ASSERT(node->IsContent());
aOutPoint->Set(node->AsContent());
return true;
}
}
@ -177,17 +183,6 @@ EditorUtils::IsDescendantOf(nsINode* aNode,
return false;
}
bool
EditorUtils::IsDescendantOf(nsIDOMNode* aNode,
nsIDOMNode* aParent,
int32_t* aOffset)
{
nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
nsCOMPtr<nsINode> parent = do_QueryInterface(aParent);
NS_ENSURE_TRUE(node && parent, false);
return IsDescendantOf(node, parent, aOffset);
}
bool
EditorUtils::IsLeafNode(nsIDOMNode* aNode)
{

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

@ -9,6 +9,7 @@
#include "mozilla/dom/Selection.h"
#include "mozilla/EditorBase.h"
#include "mozilla/EditorDOMPoint.h"
#include "mozilla/GuardObjects.h"
#include "nsCOMPtr.h"
#include "nsDebug.h"
@ -378,13 +379,19 @@ public:
class EditorUtils final
{
public:
// Note that aChild isn't a normal XPCOM outparam and won't get AddRef'ed.
static bool IsDescendantOf(nsINode* aNode, nsINode* aParent,
nsIContent** aChild);
static bool IsDescendantOf(nsINode* aNode, nsINode* aParent,
int32_t* aOffset = nullptr);
static bool IsDescendantOf(nsIDOMNode* aNode, nsIDOMNode* aParent,
int32_t* aOffset = nullptr);
/**
* IsDescendantOf() checks if aNode is a child or a descendant of aParent.
* aOutPoint is set to the child of aParent.
*
* @return true if aNode is a child or a descendant of aParent.
*/
static bool IsDescendantOf(const nsINode& aNode,
const nsINode& aParent,
EditorRawDOMPoint* aOutPoint = nullptr);
static bool IsDescendantOf(const nsINode& aNode,
const nsINode& aParent,
EditorDOMPoint* aOutPoint);
static bool IsLeafNode(nsIDOMNode* aNode);
};

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

@ -2858,19 +2858,20 @@ HTMLEditRules::TryToJoinBlocks(nsIContent& aLeftNode,
// different lists, join the lists instead.
bool mergeLists = false;
nsAtom* existingList = nsGkAtoms::_empty;
nsIContent* childInBlock = nullptr;
EditorDOMPoint childInBlock;
nsCOMPtr<Element> leftList, rightList;
if (HTMLEditUtils::IsListItem(leftBlock) &&
HTMLEditUtils::IsListItem(rightBlock)) {
leftList = leftBlock->GetParentElement();
rightList = rightBlock->GetParentElement();
if (leftList && rightList && leftList != rightList &&
!EditorUtils::IsDescendantOf(leftList, rightBlock, &childInBlock) &&
!EditorUtils::IsDescendantOf(rightList, leftBlock, &childInBlock)) {
!EditorUtils::IsDescendantOf(*leftList, *rightBlock, &childInBlock) &&
!EditorUtils::IsDescendantOf(*rightList, *leftBlock, &childInBlock)) {
// There are some special complications if the lists are descendants of
// the other lists' items. Note that it is okay for them to be
// descendants of the other lists themselves, which is the usual case for
// sublists in our implementation.
MOZ_DIAGNOSTIC_ASSERT(!childInBlock.IsSet());
leftBlock = leftList;
rightBlock = rightList;
mergeLists = true;
@ -2880,15 +2881,13 @@ HTMLEditRules::TryToJoinBlocks(nsIContent& aLeftNode,
AutoTransactionsConserveSelection dontChangeMySelection(htmlEditor);
int32_t rightOffset = 0;
int32_t leftOffset = -1;
// offset below is where you find yourself in rightBlock when you traverse
// upwards from leftBlock
if (EditorUtils::IsDescendantOf(leftBlock, rightBlock, &rightOffset)) {
EditorDOMPoint rightBlockChild;
if (EditorUtils::IsDescendantOf(*leftBlock, *rightBlock, &rightBlockChild)) {
// Tricky case. Left block is inside right block. Do ws adjustment. This
// just destroys non-visible ws at boundaries we will be joining.
rightOffset++;
rightBlockChild.AdvanceOffset();
nsresult rv = WSRunObject::ScrubBlockBoundary(htmlEditor,
WSRunObject::kBlockEnd,
leftBlock);
@ -2898,23 +2897,25 @@ HTMLEditRules::TryToJoinBlocks(nsIContent& aLeftNode,
{
// We can't just track rightBlock because it's an Element.
nsCOMPtr<nsINode> trackingRightBlock(rightBlock);
AutoTrackDOMPoint tracker(htmlEditor->mRangeUpdater,
address_of(trackingRightBlock), &rightOffset);
AutoTrackDOMPoint tracker(htmlEditor->mRangeUpdater, &rightBlockChild);
rv = WSRunObject::ScrubBlockBoundary(htmlEditor,
WSRunObject::kAfterBlock,
rightBlock, rightOffset);
rightBlock,
rightBlockChild.Offset());
if (NS_WARN_IF(NS_FAILED(rv))) {
return EditActionIgnored(rv);
}
if (trackingRightBlock->IsElement()) {
rightBlock = trackingRightBlock->AsElement();
// XXX AutoTrackDOMPoint instance, tracker, hasn't been destroyed here.
// Do we really need to do update rightBlock here??
MOZ_ASSERT(rightBlock == rightBlockChild.Container());
if (rightBlockChild.Container()->IsElement()) {
rightBlock = rightBlockChild.Container()->AsElement();
} else {
if (NS_WARN_IF(!trackingRightBlock->GetParentElement())) {
if (NS_WARN_IF(!rightBlockChild.Container()->GetParentElement())) {
return EditActionIgnored(NS_ERROR_UNEXPECTED);
}
rightBlock = trackingRightBlock->GetParentElement();
rightBlock = rightBlockChild.Container()->GetParentElement();
}
}
// Do br adjustment.
@ -2924,8 +2925,12 @@ HTMLEditRules::TryToJoinBlocks(nsIContent& aLeftNode,
if (mergeLists) {
// The idea here is to take all children in rightList that are past
// offset, and pull them into leftlist.
for (nsCOMPtr<nsIContent> child = childInBlock;
child; child = rightList->GetChildAt(rightOffset)) {
// XXX Looks like that when mergeLists is true, childInBlock has never
// been set. So, this block must be dead code.
MOZ_DIAGNOSTIC_ASSERT(childInBlock.IsSet());
uint32_t offset = rightBlockChild.Offset();
for (nsCOMPtr<nsIContent> child = childInBlock.GetChildAtOffset();
child; child = rightList->GetChildAt(offset)) {
rv = htmlEditor->MoveNode(child, leftList, -1);
if (NS_WARN_IF(NS_FAILED(rv))) {
return EditActionIgnored(rv);
@ -2933,13 +2938,21 @@ HTMLEditRules::TryToJoinBlocks(nsIContent& aLeftNode,
}
// XXX Should this set to true only when above for loop moves the node?
ret.MarkAsHandled();
// childInBlock and rightBlockChild were moved to leftList. So, they
// are now invalid.
rightBlockChild.Clear();
childInBlock.Clear();
} else {
// XXX Why do we ignore the result of MoveBlock()?
EditActionResult retMoveBlock =
MoveBlock(*leftBlock, *rightBlock, leftOffset, rightOffset);
MoveBlock(*leftBlock, *rightBlock,
-1, rightBlockChild.Offset());
if (retMoveBlock.Handled()) {
ret.MarkAsHandled();
}
// Now, all children of rightBlock were moved to leftBlock. So,
// rightBlockChild is now invalid.
rightBlockChild.Clear();
}
if (brNode && NS_SUCCEEDED(htmlEditor->DeleteNode(brNode))) {
ret.MarkAsHandled();
@ -2947,9 +2960,12 @@ HTMLEditRules::TryToJoinBlocks(nsIContent& aLeftNode,
return ret;
}
MOZ_DIAGNOSTIC_ASSERT(!rightBlockChild.IsSet());
// Offset below is where you find yourself in leftBlock when you traverse
// upwards from rightBlock
if (EditorUtils::IsDescendantOf(rightBlock, leftBlock, &leftOffset)) {
EditorDOMPoint leftBlockChild;
if (EditorUtils::IsDescendantOf(*rightBlock, *leftBlock, &leftBlockChild)) {
// Tricky case. Right block is inside left block. Do ws adjustment. This
// just destroys non-visible ws at boundaries we will be joining.
nsresult rv = WSRunObject::ScrubBlockBoundary(htmlEditor,
@ -2962,50 +2978,51 @@ HTMLEditRules::TryToJoinBlocks(nsIContent& aLeftNode,
{
// We can't just track leftBlock because it's an Element, so track
// something else.
nsCOMPtr<nsINode> trackingLeftBlock(leftBlock);
AutoTrackDOMPoint tracker(htmlEditor->mRangeUpdater,
address_of(trackingLeftBlock), &leftOffset);
AutoTrackDOMPoint tracker(htmlEditor->mRangeUpdater, &leftBlockChild);
rv = WSRunObject::ScrubBlockBoundary(htmlEditor,
WSRunObject::kBeforeBlock,
leftBlock, leftOffset);
leftBlock, leftBlockChild.Offset());
if (NS_WARN_IF(NS_FAILED(rv))) {
return EditActionIgnored(rv);
}
if (trackingLeftBlock->IsElement()) {
leftBlock = trackingLeftBlock->AsElement();
// XXX AutoTrackDOMPoint instance, tracker, hasn't been destroyed here.
// Do we really need to do update rightBlock here??
MOZ_DIAGNOSTIC_ASSERT(leftBlock == leftBlockChild.Container());
if (leftBlockChild.Container()->IsElement()) {
leftBlock = leftBlockChild.Container()->AsElement();
} else {
if (NS_WARN_IF(!trackingLeftBlock->GetParentElement())) {
if (NS_WARN_IF(!leftBlockChild.Container()->GetParentElement())) {
return EditActionIgnored(NS_ERROR_UNEXPECTED);
}
leftBlock = trackingLeftBlock->GetParentElement();
leftBlock = leftBlockChild.Container()->GetParentElement();
}
}
// Do br adjustment.
nsCOMPtr<Element> brNode =
CheckForInvisibleBR(*leftBlock, BRLocation::beforeBlock, leftOffset);
CheckForInvisibleBR(*leftBlock, BRLocation::beforeBlock,
leftBlockChild.Offset());
EditActionResult ret(NS_OK);
if (mergeLists) {
// XXX Why do we ignore the result of MoveContents()?
int32_t offset = leftBlockChild.Offset();
EditActionResult retMoveContents =
MoveContents(*rightList, *leftList, &leftOffset);
MoveContents(*rightList, *leftList, &offset);
if (retMoveContents.Handled()) {
ret.MarkAsHandled();
}
// leftBlockChild was moved to rightList. So, it's invalid now.
leftBlockChild.Clear();
} else {
// Left block is a parent of right block, and the parent of the previous
// visible content. Right block is a child and contains the contents we
// want to move.
int32_t previousContentOffset;
nsCOMPtr<nsINode> previousContentParent;
EditorDOMPoint previousContent;
if (&aLeftNode == leftBlock) {
// We are working with valid HTML, aLeftNode is a block node, and is
// therefore allowed to contain rightBlock. This is the simple case,
// we will simply move the content in rightBlock out of its block.
previousContentParent = leftBlock;
previousContentOffset = leftOffset;
previousContent = leftBlockChild;
} else {
// We try to work as well as possible with HTML that's already invalid.
// Although "right block" is a block, and a block must not be contained
@ -3016,13 +3033,10 @@ HTMLEditRules::TryToJoinBlocks(nsIContent& aLeftNode,
// However, in some situations this strategy moves the content to an
// unexpected position. (see bug 200416) The new idea is to make the
// moving content a sibling, next to the previous visible content.
previousContentParent = aLeftNode.GetParentNode();
previousContentOffset = previousContentParent ?
previousContentParent->IndexOf(&aLeftNode) : -1;
previousContent.Set(&aLeftNode);
// We want to move our content just after the previous visible node.
previousContentOffset++;
previousContent.AdvanceOffset();
}
// Because we don't want the moving content to receive the style of the
@ -3031,6 +3045,8 @@ HTMLEditRules::TryToJoinBlocks(nsIContent& aLeftNode,
nsCOMPtr<Element> editorRoot = htmlEditor->GetEditorRoot();
if (!editorRoot || &aLeftNode != editorRoot) {
nsCOMPtr<nsIContent> splittedPreviousContent;
nsCOMPtr<nsINode> previousContentParent = previousContent.Container();
int32_t previousContentOffset = previousContent.Offset();
rv = htmlEditor->SplitStyleAbovePoint(
address_of(previousContentParent),
&previousContentOffset,
@ -3041,18 +3057,18 @@ HTMLEditRules::TryToJoinBlocks(nsIContent& aLeftNode,
}
if (splittedPreviousContent) {
previousContentParent = splittedPreviousContent->GetParentNode();
previousContentOffset = previousContentParent ?
previousContentParent->IndexOf(splittedPreviousContent) : -1;
previousContent.Set(splittedPreviousContent);
} else {
previousContent.Set(previousContentParent, previousContentOffset);
}
}
if (NS_WARN_IF(!previousContentParent)) {
if (NS_WARN_IF(!previousContent.IsSet())) {
return EditActionIgnored(NS_ERROR_NULL_POINTER);
}
ret |= MoveBlock(*previousContentParent->AsElement(), *rightBlock,
previousContentOffset, rightOffset);
ret |= MoveBlock(*previousContent.Container()->AsElement(), *rightBlock,
previousContent.Offset(), 0);
if (NS_WARN_IF(ret.Failed())) {
return ret;
}
@ -3063,6 +3079,9 @@ HTMLEditRules::TryToJoinBlocks(nsIContent& aLeftNode,
return ret;
}
MOZ_DIAGNOSTIC_ASSERT(!rightBlockChild.IsSet());
MOZ_DIAGNOSTIC_ASSERT(!leftBlockChild.IsSet());
// Normal case. Blocks are siblings, or at least close enough. An example
// of the latter is <p>paragraph</p><ul><li>one<li>two<li>three</ul>. The
// first li and the p are not true siblings, but we still want to join them
@ -3089,7 +3108,7 @@ HTMLEditRules::TryToJoinBlocks(nsIContent& aLeftNode,
ret.MarkAsHandled();
} else {
// Nodes are dissimilar types.
ret |= MoveBlock(*leftBlock, *rightBlock, leftOffset, rightOffset);
ret |= MoveBlock(*leftBlock, *rightBlock, -1, 0);
if (NS_WARN_IF(ret.Failed())) {
return ret;
}
@ -3438,7 +3457,7 @@ HTMLEditRules::WillMakeList(Selection* aSelection,
if (HTMLEditUtils::IsList(curNode)) {
// do we have a curList already?
if (curList && !EditorUtils::IsDescendantOf(curNode, curList)) {
if (curList && !EditorUtils::IsDescendantOf(*curNode, *curList)) {
// move all of our children into curList. cheezy way to do it: move
// whole list and then RemoveContainer() on the list. ConvertListType
// first: that routine handles converting the list item types, if
@ -3469,7 +3488,7 @@ HTMLEditRules::WillMakeList(Selection* aSelection,
if (!curParent->IsHTMLElement(listType)) {
// list item is in wrong type of list. if we don't have a curList,
// split the old list and make a new list of correct type.
if (!curList || EditorUtils::IsDescendantOf(curNode, curList)) {
if (!curList || EditorUtils::IsDescendantOf(*curNode, *curList)) {
NS_ENSURE_STATE(mHTMLEditor);
NS_ENSURE_STATE(curParent->IsContent());
ErrorResult rv;
@ -4405,7 +4424,7 @@ HTMLEditRules::WillOutdent(Selection& aSelection,
// Do we have a blockquote that we are already committed to removing?
if (curBlockQuote) {
// If so, is this node a descendant?
if (EditorUtils::IsDescendantOf(curNode, curBlockQuote)) {
if (EditorUtils::IsDescendantOf(*curNode, *curBlockQuote)) {
lastBQChild = curNode;
// Then we don't need to do anything different for this node
continue;
@ -4532,7 +4551,7 @@ HTMLEditRules::WillOutdent(Selection& aSelection,
int32_t startOffset = aSelection.GetRangeAt(0)->StartOffset();
if (rememberedLeftBQ &&
(startNode == rememberedLeftBQ ||
EditorUtils::IsDescendantOf(startNode, rememberedLeftBQ))) {
EditorUtils::IsDescendantOf(*startNode, *rememberedLeftBQ))) {
// Selection is inside rememberedLeftBQ - push it past it.
startNode = rememberedLeftBQ->GetParentNode();
startOffset = startNode ? 1 + startNode->IndexOf(rememberedLeftBQ) : 0;
@ -4543,7 +4562,7 @@ HTMLEditRules::WillOutdent(Selection& aSelection,
startOffset = aSelection.GetRangeAt(0)->StartOffset();
if (rememberedRightBQ &&
(startNode == rememberedRightBQ ||
EditorUtils::IsDescendantOf(startNode, rememberedRightBQ))) {
EditorUtils::IsDescendantOf(*startNode, *rememberedRightBQ))) {
// Selection is inside rememberedRightBQ - push it before it.
startNode = rememberedRightBQ->GetParentNode();
startOffset = startNode ? startNode->IndexOf(rememberedRightBQ) : -1;
@ -4584,8 +4603,8 @@ HTMLEditRules::SplitBlock(Element& aBlock,
nsIContent** aOutMiddleNode)
{
// aStartChild and aEndChild must be exclusive descendants of aBlock
MOZ_ASSERT(EditorUtils::IsDescendantOf(&aStartChild, &aBlock) &&
EditorUtils::IsDescendantOf(&aEndChild, &aBlock));
MOZ_ASSERT(EditorUtils::IsDescendantOf(aStartChild, aBlock) &&
EditorUtils::IsDescendantOf(aEndChild, aBlock));
NS_ENSURE_TRUE_VOID(mHTMLEditor);
RefPtr<HTMLEditor> htmlEditor(mHTMLEditor);
@ -6396,7 +6415,7 @@ HTMLEditRules::GetHighestInlineParent(nsINode& aNode)
// such elements for now.
// XXX This should be MOZ_ASSERT after fixing bug 1413131 for avoiding
// calling this expensive method.
if (NS_WARN_IF(!EditorUtils::IsDescendantOf(&aNode, host))) {
if (NS_WARN_IF(!EditorUtils::IsDescendantOf(aNode, *host))) {
return nullptr;
}
@ -7088,7 +7107,7 @@ HTMLEditRules::RemoveBlockStyle(nsTArray<OwningNonNull<nsINode>>& aNodeArray)
} else if (IsInlineNode(curNode)) {
if (curBlock) {
// If so, is this node a descendant?
if (EditorUtils::IsDescendantOf(curNode, curBlock)) {
if (EditorUtils::IsDescendantOf(*curNode, *curBlock)) {
// Then we don't need to do anything different for this node
lastNode = curNode->AsContent();
continue;
@ -8160,7 +8179,7 @@ HTMLEditRules::SelectionEndpointInNode(nsINode* aNode,
*aResult = true;
return NS_OK;
}
if (EditorUtils::IsDescendantOf(startContainer, aNode)) {
if (EditorUtils::IsDescendantOf(*startContainer, *aNode)) {
*aResult = true;
return NS_OK;
}
@ -8174,7 +8193,7 @@ HTMLEditRules::SelectionEndpointInNode(nsINode* aNode,
*aResult = true;
return NS_OK;
}
if (EditorUtils::IsDescendantOf(endContainer, aNode)) {
if (EditorUtils::IsDescendantOf(*endContainer, *aNode)) {
*aResult = true;
return NS_OK;
}

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

@ -758,7 +758,7 @@ HTMLEditor::GetBlockNodeParent(nsINode* aNode,
MOZ_ASSERT(aNode);
MOZ_ASSERT(!aAncestorLimiter ||
aNode == aAncestorLimiter ||
EditorUtils::IsDescendantOf(aNode, aAncestorLimiter),
EditorUtils::IsDescendantOf(*aNode, *aAncestorLimiter),
"aNode isn't in aAncestorLimiter");
// The caller has already reached the limiter.
@ -791,7 +791,7 @@ HTMLEditor::GetBlock(nsINode& aNode,
{
MOZ_ASSERT(!aAncestorLimiter ||
&aNode == aAncestorLimiter ||
EditorUtils::IsDescendantOf(&aNode, aAncestorLimiter),
EditorUtils::IsDescendantOf(aNode, *aAncestorLimiter),
"aNode isn't in aAncestorLimiter");
if (NodeIsBlockStatic(&aNode)) {

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

@ -442,7 +442,11 @@ HTMLEditor::DoInsertHTMLWithContext(const nsAString& aInputString,
if (insertedContextParent) {
// if we had to insert something higher up in the paste hierarchy, we want to
// skip any further paste nodes that descend from that. Else we will paste twice.
if (EditorUtils::IsDescendantOf(curNode, insertedContextParent)) {
nsCOMPtr<nsINode> insertedContextParentNode =
do_QueryInterface(insertedContextParent);
if (NS_WARN_IF(!insertedContextParentNode) ||
EditorUtils::IsDescendantOf(*nodeList[j],
*insertedContextParentNode)) {
continue;
}
}
@ -2380,7 +2384,7 @@ HTMLEditor::ReplaceOrphanedStructure(
(i - removedCount) : (originalLength - i - 1);
OwningNonNull<nsINode> endpoint = aNodeArray[idx];
if (endpoint == replaceNode ||
EditorUtils::IsDescendantOf(endpoint, replaceNode)) {
EditorUtils::IsDescendantOf(*endpoint, *replaceNode)) {
aNodeArray.RemoveElementAt(idx);
removedCount++;
}

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

@ -287,7 +287,7 @@ RangeUpdater::SelAdjDeleteNode(nsINode* aNode)
// check for range endpoints that are in descendants of aNode
nsCOMPtr<nsINode> oldStart;
if (EditorUtils::IsDescendantOf(item->mStartContainer, aNode)) {
if (EditorUtils::IsDescendantOf(*item->mStartContainer, *aNode)) {
oldStart = item->mStartContainer; // save for efficiency hack below.
item->mStartContainer = parent;
item->mStartOffset = offset;
@ -295,7 +295,7 @@ RangeUpdater::SelAdjDeleteNode(nsINode* aNode)
// avoid having to call IsDescendantOf() for common case of range startnode == range endnode.
if (item->mEndContainer == oldStart ||
EditorUtils::IsDescendantOf(item->mEndContainer, aNode)) {
EditorUtils::IsDescendantOf(*item->mEndContainer, *aNode)) {
item->mEndContainer = parent;
item->mEndOffset = offset;
}

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

@ -6,6 +6,7 @@
#ifndef mozilla_SelectionState_h
#define mozilla_SelectionState_h
#include "mozilla/EditorDOMPoint.h"
#include "nsCOMPtr.h"
#include "nsIDOMNode.h"
#include "nsINode.h"
@ -180,6 +181,7 @@ private:
nsCOMPtr<nsINode>* mNode;
nsCOMPtr<nsIDOMNode>* mDOMNode;
int32_t* mOffset;
EditorDOMPoint* mPoint;
RefPtr<RangeItem> mRangeItem;
public:
@ -189,6 +191,7 @@ public:
, mNode(aNode)
, mDOMNode(nullptr)
, mOffset(aOffset)
, mPoint(nullptr)
{
mRangeItem = new RangeItem();
mRangeItem->mStartContainer = *mNode;
@ -204,6 +207,7 @@ public:
, mNode(nullptr)
, mDOMNode(aNode)
, mOffset(aOffset)
, mPoint(nullptr)
{
mRangeItem = new RangeItem();
mRangeItem->mStartContainer = do_QueryInterface(*mDOMNode);
@ -213,9 +217,29 @@ public:
mRangeUpdater.RegisterRangeItem(mRangeItem);
}
AutoTrackDOMPoint(RangeUpdater& aRangeUpdater,
EditorDOMPoint* aPoint)
: mRangeUpdater(aRangeUpdater)
, mNode(nullptr)
, mDOMNode(nullptr)
, mOffset(nullptr)
, mPoint(aPoint)
{
mRangeItem = new RangeItem();
mRangeItem->mStartContainer = mPoint->Container();
mRangeItem->mEndContainer = mPoint->Container();
mRangeItem->mStartOffset = mPoint->Offset();
mRangeItem->mEndOffset = mPoint->Offset();
mRangeUpdater.RegisterRangeItem(mRangeItem);
}
~AutoTrackDOMPoint()
{
mRangeUpdater.DropRangeItem(mRangeItem);
if (mPoint) {
mPoint->Set(mRangeItem->mStartContainer, mRangeItem->mStartOffset);
return;
}
if (mNode) {
*mNode = mRangeItem->mStartContainer;
} else {

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

@ -1,5 +1,6 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="autocomplete.css" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:html="http://www.w3.org/1999/xhtml"

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

@ -0,0 +1,3 @@
.textbox-input {
border-style: none;
}

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

@ -1,29 +1,18 @@
@namespace url('http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul');
@namespace html url('http://www.w3.org/1999/xhtml');
:root > html|input,
:root > html|textarea {
margin: 2px 4px;
padding: 2px 2px 3px;
padding-inline-start: 5px;
}
#mac html|input, #mac html|textarea {
margin: 4px;
padding: 0 1px;
}
#win html|input, #win html|textarea {
margin: 2px 4px;
padding: 2px 3px 3px;
padding-inline-start: 5px;
}
@media (-moz-windows-default-theme) {
#win html|input {
padding: 1px 2px 2px;
padding-inline-start: 4px;
}
}
#linux html|input, #linux html|textarea {
margin: 2px 4px;
padding: 2px 5px 3px;
}
textbox[multiline="true"], html|textarea {
border: none !important;
-moz-appearance: none !important;
@ -36,10 +25,6 @@ html|input, html|textarea {
font: inherit;
}
html|input.ac {
padding: 0 4px !important;
}
html|input.empty {
color: graytext;
}

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

@ -1,4 +1,4 @@
fails-if(Android) skip-if(browserIsRemote&&winWidget) == empty-1.xul empty-ref.xul # Windows: bug 1239170
fails-if(Android) skip-if(winWidget) == empty-1.xul empty-ref.xul # Windows: bug 1239170
!= empty-2.xul empty-ref.xul
# There is no way to simulate an autocomplete textbox in windows XP/Vista/7/8/10 default theme using CSS.
# Therefore, the equlity tests below should be marked as failing.
@ -6,11 +6,11 @@ fails-if(Android) fails-if(windowsDefaultTheme&&/^Windows\x20NT\x20(5\.[12]|6\.[
fails-if(Android) fails-if(windowsDefaultTheme&&/^Windows\x20NT\x20(5\.[12]|6\.[012]|10\.0)/.test(http.oscpu)) == emptyautocomplete-1.xul emptyautocomplete-ref.xul # bug 783658
!= emptymultiline-1.xul emptymultiline-ref.xul
fails-if(Android) == emptymultiline-2.xul emptymultiline-ref.xul # bug 783658
fails-if(Android) skip-if(browserIsRemote&&winWidget) == emptytextbox-1.xul emptytextbox-ref.xul # Windows: bug 1239170
fails-if(Android) skip-if(browserIsRemote&&winWidget) == emptytextbox-2.xul emptytextbox-ref.xul # Windows: bug 1239170
fails-if(Android) skip-if(winWidget) == emptytextbox-1.xul emptytextbox-ref.xul # Windows: bug 1239170
fails-if(Android) skip-if(winWidget) == emptytextbox-2.xul emptytextbox-ref.xul # Windows: bug 1239170
!= emptytextbox-3.xul emptytextbox-ref.xul
!= emptytextbox-4.xul emptytextbox-ref.xul
fails-if(Android) skip-if(browserIsRemote&&winWidget) == emptytextbox-5.xul emptytextbox-ref.xul # Windows: bug 1239170
fails-if(Android) skip-if(winWidget) == emptytextbox-5.xul emptytextbox-ref.xul # Windows: bug 1239170
# There is no way to simulate a number textbox in windows XP/Vista/7 default theme using CSS.
# Therefore, the equlity tests below should be marked as failing.
!= number-1.xul number-ref.xul
@ -19,11 +19,11 @@ fails-if(Android) fails-if(windowsDefaultTheme&&/^Windows\x20NT\x20(5\.[12]|6\.[
!= number-4.xul number-ref.xul
fails-if(Android) fails-if(windowsDefaultTheme&&/^Windows\x20NT\x20(5\.[12]|6\.[012]|10\.0)/.test(http.oscpu)) == number-5.xul number-ref.xul # bug 783658
fails-if(Android) fails-if(windowsDefaultTheme&&/^Windows\x20NT\x20(5\.[12]|6\.[012]|10\.0)/.test(http.oscpu)) == numberwithvalue-1.xul numberwithvalue-ref.xul # bug 783658
fails-if(Android) skip-if(browserIsRemote&&winWidget) == passwd-1.xul passwd-ref.xul # Windows: bug 1239170
fails-if(Android) skip-if(browserIsRemote&&winWidget) == passwd-2.xul passwd-ref.xul # Windows: bug 1239170
fails-if(Android) skip-if(winWidget) == passwd-1.xul passwd-ref.xul # Windows: bug 1239170
fails-if(Android) skip-if(winWidget) == passwd-2.xul passwd-ref.xul # Windows: bug 1239170
!= passwd-3.xul passwd-ref.xul
fails-if(Android) == plain-1.xul plain-ref.xul # bug 783658
fails-if(Android) skip-if(browserIsRemote&&winWidget) == textbox-1.xul textbox-ref.xul # Windows: bug 1239170
fails-if(Android) skip-if(winWidget) == textbox-1.xul textbox-ref.xul # Windows: bug 1239170
!= textbox-disabled.xul textbox-ref.xul
# Read-only textboxes look like normal textboxes in windows Vista/7 default theme
fails-if(windowsDefaultTheme&&/^Windows\x20NT\x20(6\.[012]|10\.0)/.test(http.oscpu)) skip-if(browserIsRemote&&winWidget) != textbox-readonly.xul textbox-ref.xul # Windows: bug 1239170
fails-if(windowsDefaultTheme&&/^Windows\x20NT\x20(6\.[012]|10\.0)/.test(http.oscpu)) skip-if(winWidget) != textbox-readonly.xul textbox-ref.xul # Windows: bug 1239170

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

@ -175,4 +175,4 @@ Troubleshooting tips:
-------------------------------------------------------------------------------
The version of WebRender currently in the tree is:
fae962bfd6e1997f4b921ee93c3c1cc5abca3256
34f1e8ed19a19cb950deef89ee31c1cf3d442d22

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

@ -111,7 +111,8 @@ impl Example for App {
(50, 350).by(50, 50),
SideOffsets2D::new(Some(10.0), None, Some(10.0), None),
StickyOffsetBounds::new(-40.0, 60.0),
StickyOffsetBounds::new(0.0, 0.0)
StickyOffsetBounds::new(0.0, 0.0),
LayoutVector2D::new(0.0, 0.0)
);
builder.push_clip_id(sticky_id);

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

@ -19,7 +19,8 @@ void brush_vs(
struct BrushInstance {
int picture_address;
int prim_address;
int layer_address;
int clip_node_id;
int scroll_node_id;
int clip_address;
int z;
int flags;
@ -31,7 +32,8 @@ BrushInstance load_brush() {
bi.picture_address = aData0.x;
bi.prim_address = aData0.y;
bi.layer_address = aData0.z;
bi.clip_node_id = aData0.z / 65536;
bi.scroll_node_id = aData0.z % 65536;
bi.clip_address = aData0.w;
bi.z = aData1.x;
bi.flags = aData1.y;
@ -66,7 +68,7 @@ void main(void) {
gl_Position = uTransform * vec4(device_pos, 0.0, 1.0);
} else {
AlphaBatchTask alpha_task = fetch_alpha_batch_task(brush.picture_address);
Layer layer = fetch_layer(brush.layer_address);
Layer layer = fetch_layer(brush.clip_node_id, brush.scroll_node_id);
ClipArea clip_area = fetch_clip_area(brush.clip_address);
// Write the normal vertex information out.

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

@ -7,6 +7,7 @@
varying vec3 vUv;
flat varying int vImageKind;
flat varying vec4 vUvBounds;
flat varying vec4 vUvBounds_NoClamp;
flat varying vec4 vParams;
#if defined WR_FEATURE_ALPHA_TARGET
@ -42,8 +43,8 @@ void brush_vs(
#endif
vec2 uv0 = task.target_rect.p0;
vec2 src_size = task.target_rect.size;
vec2 uv1 = uv0 + src_size;
vec2 src_size = task.target_rect.size * task.scale_factor;
vec2 uv1 = uv0 + task.target_rect.size;
// TODO(gw): In the future we'll probably draw these as segments
// with the brush shader. When that occurs, we can
@ -74,6 +75,7 @@ void brush_vs(
}
vUvBounds = vec4(uv0 + vec2(0.5), uv1 - vec2(0.5)) / texture_size.xyxy;
vUvBounds_NoClamp = vec4(uv0, uv1) / texture_size.xyxy;
}
#endif
@ -89,7 +91,8 @@ vec4 brush_fs() {
case BRUSH_IMAGE_NINEPATCH: {
uv = clamp(vUv.xy, vec2(0.0), vParams.xy);
uv += max(vec2(0.0), vUv.xy - vParams.zw);
uv = mix(vUvBounds.xy, vUvBounds.zw, uv);
uv = mix(vUvBounds_NoClamp.xy, vUvBounds_NoClamp.zw, uv);
uv = clamp(uv, vUvBounds.xy, vUvBounds.zw);
break;
}
case BRUSH_IMAGE_MIRROR: {
@ -101,7 +104,8 @@ vec4 brush_fs() {
// shadow corner. This can happen, for example, when
// drawing the outer parts of an inset box shadow.
uv = clamp(uv, vec2(0.0), vec2(1.0));
uv = mix(vUvBounds.xy, vUvBounds.zw, uv);
uv = mix(vUvBounds_NoClamp.xy, vUvBounds_NoClamp.zw, uv);
uv = clamp(uv, vUvBounds.xy, vUvBounds.zw);
break;
}
}

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

@ -52,10 +52,6 @@ ClipVertexInfo write_clip_tile_vertex(RectWithSize local_clip_rect,
Layer layer,
ClipArea area,
int segment) {
RectWithSize clipped_local_rect = intersect_rect(local_clip_rect,
layer.local_clip_rect);
vec2 outer_p0 = area.screen_origin_target_index.xy;
vec2 outer_p1 = outer_p0 + area.task_bounds.zw - area.task_bounds.xy;
vec2 inner_p0 = area.inner_rect.xy;
@ -94,9 +90,9 @@ ClipVertexInfo write_clip_tile_vertex(RectWithSize local_clip_rect,
gl_Position = uTransform * vec4(vertex_pos, 0.0, 1);
vLocalBounds = vec4(clipped_local_rect.p0, clipped_local_rect.p0 + clipped_local_rect.size);
vLocalBounds = vec4(local_clip_rect.p0, local_clip_rect.p0 + local_clip_rect.size);
ClipVertexInfo vi = ClipVertexInfo(layer_pos.xyw, actual_pos, clipped_local_rect);
ClipVertexInfo vi = ClipVertexInfo(layer_pos.xyw, actual_pos, local_clip_rect);
return vi;
}

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

@ -64,7 +64,7 @@ BorderClipDot fetch_border_clip_dot(ivec2 address, int segment) {
void main(void) {
ClipMaskInstance cmi = fetch_clip_item();
ClipArea area = fetch_clip_area(cmi.render_task_address);
Layer layer = fetch_layer(cmi.layer_address);
Layer layer = fetch_layer(cmi.layer_address, cmi.layer_address);
// Fetch the header information for this corner clip.
BorderCorner corner = fetch_border_corner(cmi.clip_data_address);

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

@ -24,7 +24,7 @@ ImageMaskData fetch_mask_data(ivec2 address) {
void main(void) {
ClipMaskInstance cmi = fetch_clip_item();
ClipArea area = fetch_clip_area(cmi.render_task_address);
Layer layer = fetch_layer(cmi.layer_address);
Layer layer = fetch_layer(cmi.layer_address, cmi.layer_address);
ImageMaskData mask = fetch_mask_data(cmi.clip_data_address);
RectWithSize local_rect = mask.local_rect;
ImageResource res = fetch_image_resource_direct(cmi.resource_address);

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

@ -58,7 +58,7 @@ ClipData fetch_clip(ivec2 address) {
void main(void) {
ClipMaskInstance cmi = fetch_clip_item();
ClipArea area = fetch_clip_area(cmi.render_task_address);
Layer layer = fetch_layer(cmi.layer_address);
Layer layer = fetch_layer(cmi.layer_address, cmi.layer_address);
ClipData clip = fetch_clip(cmi.clip_data_address);
RectWithSize local_rect = clip.rect.rect;

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

@ -71,14 +71,14 @@ vec4[2] fetch_from_resource_cache_2(int address) {
#ifdef WR_VERTEX_SHADER
#define VECS_PER_LAYER 9
#define VECS_PER_LAYER 10
#define VECS_PER_RENDER_TASK 3
#define VECS_PER_PRIM_HEADER 2
#define VECS_PER_TEXT_RUN 3
#define VECS_PER_GRADIENT 3
#define VECS_PER_GRADIENT_STOP 2
uniform HIGHP_SAMPLER_FLOAT sampler2D sLayers;
uniform HIGHP_SAMPLER_FLOAT sampler2D sClipScrollNodes;
uniform HIGHP_SAMPLER_FLOAT sampler2D sRenderTasks;
// Instanced attributes
@ -143,14 +143,16 @@ vec4 fetch_from_resource_cache_1(int address) {
return texelFetch(sResourceCache, uv, 0);
}
struct Layer {
struct ClipScrollNode {
mat4 transform;
mat4 inv_transform;
RectWithSize local_clip_rect;
vec4 local_clip_rect;
vec2 reference_frame_relative_scroll_offset;
vec2 scroll_offset;
};
Layer fetch_layer(int index) {
Layer layer;
ClipScrollNode fetch_clip_scroll_node(int index) {
ClipScrollNode node;
// Create a UV base coord for each 8 texels.
// This is required because trying to use an offset
@ -160,18 +162,46 @@ Layer fetch_layer(int index) {
ivec2 uv0 = ivec2(uv.x + 0, uv.y);
ivec2 uv1 = ivec2(uv.x + 8, uv.y);
layer.transform[0] = TEXEL_FETCH(sLayers, uv0, 0, ivec2(0, 0));
layer.transform[1] = TEXEL_FETCH(sLayers, uv0, 0, ivec2(1, 0));
layer.transform[2] = TEXEL_FETCH(sLayers, uv0, 0, ivec2(2, 0));
layer.transform[3] = TEXEL_FETCH(sLayers, uv0, 0, ivec2(3, 0));
node.transform[0] = TEXEL_FETCH(sClipScrollNodes, uv0, 0, ivec2(0, 0));
node.transform[1] = TEXEL_FETCH(sClipScrollNodes, uv0, 0, ivec2(1, 0));
node.transform[2] = TEXEL_FETCH(sClipScrollNodes, uv0, 0, ivec2(2, 0));
node.transform[3] = TEXEL_FETCH(sClipScrollNodes, uv0, 0, ivec2(3, 0));
layer.inv_transform[0] = TEXEL_FETCH(sLayers, uv0, 0, ivec2(4, 0));
layer.inv_transform[1] = TEXEL_FETCH(sLayers, uv0, 0, ivec2(5, 0));
layer.inv_transform[2] = TEXEL_FETCH(sLayers, uv0, 0, ivec2(6, 0));
layer.inv_transform[3] = TEXEL_FETCH(sLayers, uv0, 0, ivec2(7, 0));
node.inv_transform[0] = TEXEL_FETCH(sClipScrollNodes, uv0, 0, ivec2(4, 0));
node.inv_transform[1] = TEXEL_FETCH(sClipScrollNodes, uv0, 0, ivec2(5, 0));
node.inv_transform[2] = TEXEL_FETCH(sClipScrollNodes, uv0, 0, ivec2(6, 0));
node.inv_transform[3] = TEXEL_FETCH(sClipScrollNodes, uv0, 0, ivec2(7, 0));
vec4 clip_rect = TEXEL_FETCH(sLayers, uv1, 0, ivec2(0, 0));
layer.local_clip_rect = RectWithSize(clip_rect.xy, clip_rect.zw);
vec4 clip_rect = TEXEL_FETCH(sClipScrollNodes, uv1, 0, ivec2(0, 0));
node.local_clip_rect = clip_rect;
vec4 offsets = TEXEL_FETCH(sClipScrollNodes, uv1, 0, ivec2(1, 0));
node.reference_frame_relative_scroll_offset = offsets.xy;
node.scroll_offset = offsets.zw;
return node;
}
struct Layer {
mat4 transform;
mat4 inv_transform;
RectWithSize local_clip_rect;
};
Layer fetch_layer(int clip_node_id, int scroll_node_id) {
ClipScrollNode clip_node = fetch_clip_scroll_node(clip_node_id);
ClipScrollNode scroll_node = fetch_clip_scroll_node(scroll_node_id);
Layer layer;
layer.transform = scroll_node.transform;
layer.inv_transform = scroll_node.inv_transform;
vec4 local_clip_rect = clip_node.local_clip_rect;
local_clip_rect.xy += clip_node.reference_frame_relative_scroll_offset;
local_clip_rect.xy -= scroll_node.reference_frame_relative_scroll_offset;
local_clip_rect.xy -= scroll_node.scroll_offset;
layer.local_clip_rect = RectWithSize(local_clip_rect.xy, local_clip_rect.zw);
return layer;
}
@ -228,6 +258,7 @@ struct BlurTask {
RectWithSize target_rect;
float render_target_layer_index;
float blur_radius;
float scale_factor;
vec4 color;
};
@ -238,6 +269,7 @@ BlurTask fetch_blur_task(int address) {
RectWithSize(task_data.data0.xy, task_data.data0.zw),
task_data.data1.x,
task_data.data1.y,
task_data.data1.z,
task_data.data2
);
}
@ -358,7 +390,8 @@ struct PrimitiveInstance {
int specific_prim_address;
int render_task_index;
int clip_task_index;
int layer_index;
int scroll_node_id;
int clip_node_id;
int z;
int user_data0;
int user_data1;
@ -372,7 +405,8 @@ PrimitiveInstance fetch_prim_instance() {
pi.specific_prim_address = pi.prim_address + VECS_PER_PRIM_HEADER;
pi.render_task_index = aData0.y;
pi.clip_task_index = aData0.z;
pi.layer_index = aData0.w;
pi.clip_node_id = aData0.w / 65536;
pi.scroll_node_id = aData0.w % 65536;
pi.z = aData1.x;
pi.user_data0 = aData1.y;
pi.user_data1 = aData1.z;
@ -388,6 +422,8 @@ struct CompositeInstance {
int user_data0;
int user_data1;
float z;
int user_data2;
int user_data3;
};
CompositeInstance fetch_composite_instance() {
@ -400,6 +436,8 @@ CompositeInstance fetch_composite_instance() {
ci.user_data0 = aData1.x;
ci.user_data1 = aData1.y;
ci.user_data2 = aData1.z;
ci.user_data3 = aData1.w;
return ci;
}
@ -437,7 +475,7 @@ Primitive load_primitive() {
Primitive prim;
prim.layer = fetch_layer(pi.layer_index);
prim.layer = fetch_layer(pi.clip_node_id, pi.scroll_node_id);
prim.clip_area = fetch_clip_area(pi.clip_task_index);
#ifdef PRIMITIVE_HAS_PICTURE_TASK
prim.task = fetch_picture_task(pi.render_task_index);
@ -546,8 +584,7 @@ VertexInfo write_vertex(RectWithSize instance_rect,
vec2 local_pos = instance_rect.p0 + instance_rect.size * aPosition.xy;
// Clamp to the two local clip rects.
vec2 clamped_local_pos = clamp_rect(clamp_rect(local_pos, local_clip_rect),
layer.local_clip_rect);
vec2 clamped_local_pos = clamp_rect(clamp_rect(local_pos, local_clip_rect), layer.local_clip_rect);
/// Compute the snapping offset.
vec2 snap_offset = compute_snap_offset(clamped_local_pos, local_clip_rect, layer, snap_rect);
@ -739,10 +776,9 @@ Image fetch_image(int address) {
}
void write_clip(vec2 global_pos, ClipArea area) {
vec2 texture_size = vec2(textureSize(sSharedCacheA8, 0).xy);
vec2 uv = global_pos + area.task_bounds.xy - area.screen_origin_target_index.xy;
vClipMaskUvBounds = area.task_bounds / texture_size.xyxy;
vClipMaskUv = vec3(uv / texture_size, area.screen_origin_target_index.z);
vClipMaskUvBounds = area.task_bounds;
vClipMaskUv = vec3(uv, area.screen_origin_target_index.z);
}
#endif //WR_VERTEX_SHADER
@ -807,7 +843,7 @@ float do_clip() {
vec4(vClipMaskUv.xy, vClipMaskUvBounds.zw));
// check for the dummy bounds, which are given to the opaque objects
return vClipMaskUvBounds.xy == vClipMaskUvBounds.zw ? 1.0:
all(inside) ? textureLod(sSharedCacheA8, vClipMaskUv, 0.0).r : 0.0;
all(inside) ? texelFetch(sSharedCacheA8, ivec3(vClipMaskUv), 0).r : 0.0;
}
#ifdef WR_FEATURE_DITHERING

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

@ -18,7 +18,7 @@ void main(void) {
vec2(ci.user_data0, ci.user_data1);
vec2 local_pos = mix(dest_origin,
dest_origin + src_task.size,
dest_origin + vec2(ci.user_data2, ci.user_data3),
aPosition.xy);
vec2 texture_size = vec2(textureSize(sCacheRGBA8, 0));

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

@ -15,12 +15,13 @@ varying vec3 vLocalPos;
#ifdef WR_VERTEX_SHADER
#define MODE_ALPHA 0
#define MODE_SUBPX_PASS0 1
#define MODE_SUBPX_PASS1 2
#define MODE_SUBPX_BG_PASS0 3
#define MODE_SUBPX_BG_PASS1 4
#define MODE_SUBPX_BG_PASS2 5
#define MODE_COLOR_BITMAP 6
#define MODE_SUBPX_OPAQUE 1
#define MODE_SUBPX_PASS0 2
#define MODE_SUBPX_PASS1 3
#define MODE_SUBPX_BG_PASS0 4
#define MODE_SUBPX_BG_PASS1 5
#define MODE_SUBPX_BG_PASS2 6
#define MODE_COLOR_BITMAP 7
void main(void) {
Primitive prim = load_primitive();
@ -76,6 +77,11 @@ void main(void) {
case MODE_COLOR_BITMAP:
vColor = vec4(text.color.a);
break;
case MODE_SUBPX_OPAQUE:
// The text foreground color is handled by the constant
// color blend mode.
vColor = vec4(1.0);
break;
case MODE_SUBPX_BG_PASS1:
// This should never be reached.
break;

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

@ -170,7 +170,6 @@ impl FrameBuilder {
LayerSize::new(width, height));
let brush_info = LayerPrimitiveInfo::new(brush_rect);
let brush_prim_index = self.create_primitive(
clip_and_scroll,
&brush_info,
Vec::new(),
PrimitiveContainer::Brush(brush_prim),
@ -239,7 +238,6 @@ impl FrameBuilder {
};
let brush_info = LayerPrimitiveInfo::new(brush_rect);
let brush_prim_index = self.create_primitive(
clip_and_scroll,
&brush_info,
Vec::new(),
PrimitiveContainer::Brush(brush_prim),

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

@ -21,7 +21,6 @@ pub type ClipSourcesWeakHandle = WeakFreeListHandle<ClipSources>;
#[derive(Clone, Debug)]
pub struct ClipRegion {
pub origin: LayerPoint,
pub main: LayerRect,
pub image_mask: Option<ImageMask>,
pub complex_clips: Vec<ComplexClipRegion>,
@ -32,32 +31,39 @@ impl ClipRegion {
rect: LayerRect,
mut complex_clips: Vec<ComplexClipRegion>,
mut image_mask: Option<ImageMask>,
reference_frame_relative_offset: &LayoutVector2D,
) -> ClipRegion {
// All the coordinates we receive are relative to the stacking context, but we want
// to convert them to something relative to the origin of the clip.
let negative_origin = -rect.origin.to_vector();
let rect = rect.translate(reference_frame_relative_offset);
if let Some(ref mut image_mask) = image_mask {
image_mask.rect = image_mask.rect.translate(&negative_origin);
image_mask.rect = image_mask.rect.translate(reference_frame_relative_offset);
}
for complex_clip in complex_clips.iter_mut() {
complex_clip.rect = complex_clip.rect.translate(&negative_origin);
complex_clip.rect = complex_clip.rect.translate(reference_frame_relative_offset);
}
ClipRegion {
origin: rect.origin,
main: LayerRect::new(LayerPoint::zero(), rect.size),
main: rect,
image_mask,
complex_clips,
}
}
pub fn create_for_clip_node_with_local_clip(local_clip: &LocalClip) -> ClipRegion {
pub fn create_for_clip_node_with_local_clip(
local_clip: &LocalClip,
reference_frame_relative_offset: &LayoutVector2D
) -> ClipRegion {
let complex_clips = match local_clip {
&LocalClip::Rect(_) => Vec::new(),
&LocalClip::RoundedRect(_, ref region) => vec![region.clone()],
};
ClipRegion::create_for_clip_node(*local_clip.clip_rect(), complex_clips, None)
ClipRegion::create_for_clip_node(
*local_clip.clip_rect(),
complex_clips,
None,
reference_frame_relative_offset
)
}
}

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

@ -3,19 +3,19 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use api::{ClipId, DeviceIntRect, LayerPixel, LayerPoint, LayerRect, LayerSize};
use api::{LayerToScrollTransform, LayerToWorldTransform, LayerVector2D, PipelineId};
use api::{ScrollClamping, ScrollEventPhase, ScrollLocation, ScrollSensitivity, StickyOffsetBounds};
use api::WorldPoint;
use api::{LayerToScrollTransform, LayerToWorldTransform, LayerVector2D, LayoutVector2D, PipelineId};
use api::{ScrollClamping, ScrollEventPhase, ScrollLocation, ScrollSensitivity};
use api::{StickyOffsetBounds, WorldPoint};
use clip::{ClipRegion, ClipSources, ClipSourcesHandle, ClipStore};
use clip_scroll_tree::{CoordinateSystemId, TransformUpdateState};
use euclid::SideOffsets2D;
use geometry::ray_intersects_rect;
use gpu_cache::GpuCache;
use gpu_types::{ClipScrollNodeIndex, ClipScrollNodeData};
use render_task::{ClipChain, ClipChainNode, ClipWorkItem};
use resource_cache::ResourceCache;
use spring::{DAMPING, STIFFNESS, Spring};
use std::rc::Rc;
use tiling::{PackedLayer, PackedLayerIndex};
use util::{MatrixHelpers, MaxRect};
#[cfg(target_os = "macos")]
@ -24,15 +24,13 @@ const CAN_OVERSCROLL: bool = true;
#[cfg(not(target_os = "macos"))]
const CAN_OVERSCROLL: bool = false;
const MAX_LOCAL_VIEWPORT: f32 = 1000000.0;
#[derive(Debug)]
pub struct ClipInfo {
/// The clips for this node.
pub clip_sources: ClipSourcesHandle,
/// The packed layer index for this node, which is used to render a clip mask
/// for it, if necessary.
pub packed_layer_index: PackedLayerIndex,
/// Whether or not this clip node automatically creates a mask.
pub is_masking: bool,
}
@ -40,7 +38,6 @@ pub struct ClipInfo {
impl ClipInfo {
pub fn new(
clip_region: ClipRegion,
packed_layer_index: PackedLayerIndex,
clip_store: &mut ClipStore,
) -> ClipInfo {
let clip_sources = ClipSources::from(clip_region);
@ -48,7 +45,6 @@ impl ClipInfo {
ClipInfo {
clip_sources: clip_store.insert(clip_sources),
packed_layer_index,
is_masking,
}
}
@ -59,6 +55,7 @@ pub struct StickyFrameInfo {
pub margins: SideOffsets2D<Option<f32>>,
pub vertical_offset_bounds: StickyOffsetBounds,
pub horizontal_offset_bounds: StickyOffsetBounds,
pub previously_applied_offset: LayoutVector2D,
pub current_offset: LayerVector2D,
}
@ -66,12 +63,14 @@ impl StickyFrameInfo {
pub fn new(
margins: SideOffsets2D<Option<f32>>,
vertical_offset_bounds: StickyOffsetBounds,
horizontal_offset_bounds: StickyOffsetBounds
horizontal_offset_bounds: StickyOffsetBounds,
previously_applied_offset: LayoutVector2D
) -> StickyFrameInfo {
StickyFrameInfo {
margins,
vertical_offset_bounds,
horizontal_offset_bounds,
previously_applied_offset,
current_offset: LayerVector2D::zero(),
}
}
@ -110,7 +109,8 @@ pub struct ClipScrollNode {
/// This is in the coordinate system of the node origin.
/// Precisely, it combines the local clipping rectangles of all the parent
/// nodes on the way to the root, including those of `ClipRegion` rectangles.
/// The combined clip is lossy/concervative on `ReferenceFrame` nodes.
/// The combined clip is reset to maximum when an incompatible coordinate
/// system is encountered.
pub combined_local_viewport_rect: LayerRect,
/// World transform for the viewport rect itself. This is the parent
@ -148,6 +148,10 @@ pub struct ClipScrollNode {
/// The axis-aligned coordinate system id of this node.
pub coordinate_system_id: CoordinateSystemId,
/// A linear ID / index of this clip-scroll node. Used as a reference to
/// pass to shaders, to allow them to fetch a given clip-scroll node.
pub id: ClipScrollNodeIndex,
}
impl ClipScrollNode {
@ -171,6 +175,7 @@ impl ClipScrollNode {
clip_chain_node: None,
combined_clip_outer_bounds: DeviceIntRect::max_rect(),
coordinate_system_id: CoordinateSystemId(0),
id: ClipScrollNodeIndex(0),
}
}
@ -287,15 +292,11 @@ impl ClipScrollNode {
pub fn update_clip_work_item(
&mut self,
state: &mut TransformUpdateState,
screen_rect: &DeviceIntRect,
device_pixel_ratio: f32,
packed_layers: &mut Vec<PackedLayer>,
clip_store: &mut ClipStore,
resource_cache: &mut ResourceCache,
gpu_cache: &mut GpuCache,
) {
self.coordinate_system_id = state.current_coordinate_system_id;
let current_clip_chain = state.parent_clip_chain.clone();
let clip_info = match self.node_type {
NodeType::Clip(ref mut info) if info.is_masking => info,
@ -306,29 +307,9 @@ impl ClipScrollNode {
}
};
// The coordinates of the mask are relative to the origin of the node itself,
// so we need to account for that origin in the transformation we assign to
// the packed layer.
let transform = self.world_viewport_transform
.pre_translate(self.local_viewport_rect.origin.to_vector().to_3d());
let packed_layer = &mut packed_layers[clip_info.packed_layer_index.0];
if packed_layer.set_transform(transform) {
// Meanwhile, the combined viewport rect is relative to the reference frame, so
// we move it into the local coordinate system of the node.
let local_viewport_rect = self.combined_local_viewport_rect
.translate(&-self.local_viewport_rect.origin.to_vector());
packed_layer.set_rect(
&local_viewport_rect,
screen_rect,
device_pixel_ratio,
);
}
let clip_sources = clip_store.get_mut(&clip_info.clip_sources);
clip_sources.update(
&transform,
&self.world_viewport_transform,
gpu_cache,
resource_cache,
device_pixel_ratio,
@ -345,7 +326,7 @@ impl ClipScrollNode {
// TODO: Combine rectangles in the same axis-aligned clip space here?
self.clip_chain_node = Some(Rc::new(ClipChainNode {
work_item: ClipWorkItem {
layer_index: clip_info.packed_layer_index,
scroll_node_id: self.id,
clip_sources: clip_info.clip_sources.weak(),
coordinate_system_id: state.current_coordinate_system_id,
},
@ -356,7 +337,11 @@ impl ClipScrollNode {
state.parent_clip_chain = self.clip_chain_node.clone();
}
pub fn update_transform(&mut self, state: &mut TransformUpdateState) {
pub fn update_transform(
&mut self,
state: &mut TransformUpdateState,
node_data: &mut Vec<ClipScrollNodeData>,
) {
// We calculate this here to avoid a double-borrow later.
let sticky_offset = self.calculate_sticky_offset(
&state.nearest_scrolling_ancestor_offset,
@ -452,6 +437,39 @@ impl ClipScrollNode {
info.current_offset + state.parent_accumulated_scroll_offset;
}
}
// Store coord system ID, and also the ID used for shaders to reference this node.
self.coordinate_system_id = state.current_coordinate_system_id;
self.id = ClipScrollNodeIndex(node_data.len() as u32);
let local_clip_rect = if self.world_content_transform.has_perspective_component() {
LayerRect::new(
LayerPoint::new(-MAX_LOCAL_VIEWPORT, -MAX_LOCAL_VIEWPORT),
LayerSize::new(2.0 * MAX_LOCAL_VIEWPORT, 2.0 * MAX_LOCAL_VIEWPORT)
)
} else {
self.combined_local_viewport_rect
};
let data = match self.world_content_transform.inverse() {
Some(inverse) => {
ClipScrollNodeData {
transform: self.world_content_transform,
inv_transform: inverse,
local_clip_rect,
reference_frame_relative_scroll_offset: self.reference_frame_relative_scroll_offset,
scroll_offset: self.scroll_offset(),
}
}
None => {
state.combined_outer_clip_bounds = DeviceIntRect::zero();
ClipScrollNodeData::invalid()
}
};
// Write the data that will be made available to the GPU for this node.
node_data.push(data);
}
fn calculate_sticky_offset(
@ -478,54 +496,87 @@ impl ClipScrollNode {
let mut sticky_offset = LayerVector2D::zero();
if let Some(margin) = info.margins.top {
// If the sticky rect is positioned above the top edge of the viewport (plus margin)
// we move it down so that it is fully inside the viewport.
let top_viewport_edge = viewport_rect.min_y() + margin;
if sticky_rect.min_y() < top_viewport_edge {
// If the sticky rect is positioned above the top edge of the viewport (plus margin)
// we move it down so that it is fully inside the viewport.
sticky_offset.y = top_viewport_edge - sticky_rect.min_y();
} else if info.previously_applied_offset.y > 0.0 &&
sticky_rect.min_y() > top_viewport_edge {
// However, if the sticky rect is positioned *below* the top edge of the viewport
// and there is already some offset applied to the sticky rect's position, then
// we need to move it up so that it remains at the correct position. This
// makes sticky_offset.y negative and effectively reduces the amount of the
// offset that was already applied. We limit the reduction so that it can, at most,
// cancel out the already-applied offset, but should never end up adjusting the
// position the other way.
sticky_offset.y = top_viewport_edge - sticky_rect.min_y();
sticky_offset.y = sticky_offset.y.max(-info.previously_applied_offset.y);
}
debug_assert!(sticky_offset.y >= 0.0);
debug_assert!(sticky_offset.y + info.previously_applied_offset.y >= 0.0);
}
if sticky_offset.y == 0.0 {
// If we don't have a sticky-top offset (sticky_offset.y + info.previously_applied_offset.y
// == 0), or if we have a previously-applied bottom offset (previously_applied_offset.y < 0)
// then we check for handling the bottom margin case.
if sticky_offset.y + info.previously_applied_offset.y <= 0.0 {
if let Some(margin) = info.margins.bottom {
// If the bottom of the sticky rect is positioned below the bottom viewport edge
// (accounting for margin), we move it up so that it is fully inside the viewport.
// Same as the above case, but inverted for bottom-sticky items. Here
// we adjust items upwards, resulting in a negative sticky_offset.y,
// or reduce the already-present upward adjustment, resulting in a positive
// sticky_offset.y.
let bottom_viewport_edge = viewport_rect.max_y() - margin;
if sticky_rect.max_y() > bottom_viewport_edge {
sticky_offset.y = bottom_viewport_edge - sticky_rect.max_y();
} else if info.previously_applied_offset.y < 0.0 &&
sticky_rect.max_y() < bottom_viewport_edge {
sticky_offset.y = bottom_viewport_edge - sticky_rect.max_y();
sticky_offset.y = sticky_offset.y.min(-info.previously_applied_offset.y);
}
debug_assert!(sticky_offset.y <= 0.0);
debug_assert!(sticky_offset.y + info.previously_applied_offset.y <= 0.0);
}
}
// Same as above, but for the x-axis.
if let Some(margin) = info.margins.left {
// If the sticky rect is positioned left of the left edge of the viewport (plus margin)
// we move it right so that it is fully inside the viewport.
let left_viewport_edge = viewport_rect.min_x() + margin;
if sticky_rect.min_x() < left_viewport_edge {
sticky_offset.x = left_viewport_edge - sticky_rect.min_x();
} else if info.previously_applied_offset.x > 0.0 &&
sticky_rect.min_x() > left_viewport_edge {
sticky_offset.x = left_viewport_edge - sticky_rect.min_x();
sticky_offset.x = sticky_offset.x.max(-info.previously_applied_offset.x);
}
debug_assert!(sticky_offset.x >= 0.0);
debug_assert!(sticky_offset.x + info.previously_applied_offset.x >= 0.0);
}
if sticky_offset.x == 0.0 {
if sticky_offset.x + info.previously_applied_offset.x <= 0.0 {
if let Some(margin) = info.margins.right {
// If the right edge of the sticky rect is positioned right of the right viewport
// edge (accounting for margin), we move it left so that it is fully inside the
// viewport.
let right_viewport_edge = viewport_rect.max_x() - margin;
if sticky_rect.max_x() > right_viewport_edge {
sticky_offset.x = right_viewport_edge - sticky_rect.max_x();
} else if info.previously_applied_offset.x < 0.0 &&
sticky_rect.max_x() < right_viewport_edge {
sticky_offset.x = right_viewport_edge - sticky_rect.max_x();
sticky_offset.x = sticky_offset.x.min(-info.previously_applied_offset.x);
}
debug_assert!(sticky_offset.x <= 0.0);
debug_assert!(sticky_offset.x + info.previously_applied_offset.x <= 0.0);
}
}
sticky_offset.y = sticky_offset.y.max(info.vertical_offset_bounds.min);
sticky_offset.y = sticky_offset.y.min(info.vertical_offset_bounds.max);
sticky_offset.x = sticky_offset.x.max(info.horizontal_offset_bounds.min);
sticky_offset.x = sticky_offset.x.min(info.horizontal_offset_bounds.max);
// The total "sticky offset" (which is the sum that was already applied by
// the calling code, stored in info.previously_applied_offset, and the extra amount we
// computed as a result of scrolling, stored in sticky_offset) needs to be
// clamped to the provided bounds.
let clamp_adjusted = |value: f32, adjust: f32, bounds: &StickyOffsetBounds| {
(value + adjust).max(bounds.min).min(bounds.max) - adjust
};
sticky_offset.y = clamp_adjusted(sticky_offset.y,
info.previously_applied_offset.y,
&info.vertical_offset_bounds);
sticky_offset.x = clamp_adjusted(sticky_offset.x,
info.previously_applied_offset.x,
&info.horizontal_offset_bounds);
sticky_offset
}

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

@ -8,11 +8,11 @@ use api::{ScrollLayerState, ScrollLocation, WorldPoint};
use clip::ClipStore;
use clip_scroll_node::{ClipScrollNode, NodeType, ScrollingState, StickyFrameInfo};
use gpu_cache::GpuCache;
use gpu_types::ClipScrollNodeData;
use internal_types::{FastHashMap, FastHashSet};
use print_tree::{PrintTree, PrintTreePrinter};
use render_task::ClipChain;
use resource_cache::ResourceCache;
use tiling::PackedLayer;
pub type ScrollStates = FastHashMap<ClipId, ScrollingState>;
@ -329,11 +329,11 @@ impl ClipScrollTree {
&mut self,
screen_rect: &DeviceIntRect,
device_pixel_ratio: f32,
packed_layers: &mut Vec<PackedLayer>,
clip_store: &mut ClipStore,
resource_cache: &mut ResourceCache,
gpu_cache: &mut GpuCache,
pan: LayerPoint,
node_data: &mut Vec<ClipScrollNodeData>,
) {
if self.nodes.is_empty() {
return;
@ -360,12 +360,11 @@ impl ClipScrollTree {
self.update_node_transform(
root_reference_frame_id,
&mut state,
&screen_rect,
device_pixel_ratio,
packed_layers,
clip_store,
resource_cache,
gpu_cache,
node_data,
);
}
@ -373,12 +372,11 @@ impl ClipScrollTree {
&mut self,
layer_id: ClipId,
state: &mut TransformUpdateState,
screen_rect: &DeviceIntRect,
device_pixel_ratio: f32,
packed_layers: &mut Vec<PackedLayer>,
clip_store: &mut ClipStore,
resource_cache: &mut ResourceCache,
gpu_cache: &mut GpuCache,
node_data: &mut Vec<ClipScrollNodeData>,
) {
// TODO(gw): This is an ugly borrow check workaround to clone these.
// Restructure this to avoid the clones!
@ -389,12 +387,13 @@ impl ClipScrollTree {
None => return,
};
node.update_transform(&mut state);
node.update_transform(
&mut state,
node_data
);
node.update_clip_work_item(
&mut state,
screen_rect,
device_pixel_ratio,
packed_layers,
clip_store,
resource_cache,
gpu_cache,
@ -407,12 +406,11 @@ impl ClipScrollTree {
self.update_node_transform(
child_layer_id,
&mut state,
screen_rect,
device_pixel_ratio,
packed_layers,
clip_store,
resource_cache,
gpu_cache,
node_data,
);
}
}

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

@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use super::shader_source;
use api::ImageFormat;
use api::{ColorF, ImageFormat};
use api::{DeviceIntRect, DeviceUintSize};
use euclid::Transform3D;
use gleam::gl;
@ -1925,6 +1925,12 @@ impl Device {
self.gl.blend_func_separate(gl::ONE, gl::ONE, gl::ONE, gl::ONE_MINUS_SRC_ALPHA);
self.gl.blend_equation(gl::FUNC_ADD);
}
pub fn set_blend_mode_subpixel_opaque(&self, color: ColorF) {
self.gl.blend_color(color.r, color.g, color.b, color.a);
self.gl
.blend_func(gl::CONSTANT_COLOR, gl::ONE_MINUS_SRC_COLOR);
self.gl.blend_equation(gl::FUNC_ADD);
}
}
/// return (gl_internal_format, gl_format)

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

@ -322,8 +322,10 @@ impl<'a> FlattenContext<'a> {
None => return,
};
let mut clip_region = ClipRegion::create_for_clip_node_with_local_clip(local_clip);
clip_region.origin += reference_frame_relative_offset;
let clip_region = ClipRegion::create_for_clip_node_with_local_clip(
local_clip,
&reference_frame_relative_offset
);
let parent_pipeline_id = parent_id.pipeline_id();
let clip_id = self.clip_scroll_tree
.generate_new_clip_id(parent_pipeline_id);
@ -552,13 +554,12 @@ impl<'a> FlattenContext<'a> {
}
SpecificDisplayItem::Clip(ref info) => {
let complex_clips = self.get_complex_clips(pipeline_id, item.complex_clip().0);
let mut clip_region = ClipRegion::create_for_clip_node(
let clip_region = ClipRegion::create_for_clip_node(
*item.local_clip().clip_rect(),
complex_clips,
info.image_mask,
&reference_frame_relative_offset,
);
clip_region.origin += reference_frame_relative_offset;
self.flatten_clip(
pipeline_id,
&clip_and_scroll.scroll_node_id,
@ -568,13 +569,12 @@ impl<'a> FlattenContext<'a> {
}
SpecificDisplayItem::ScrollFrame(ref info) => {
let complex_clips = self.get_complex_clips(pipeline_id, item.complex_clip().0);
let mut clip_region = ClipRegion::create_for_clip_node(
let clip_region = ClipRegion::create_for_clip_node(
*item.local_clip().clip_rect(),
complex_clips,
info.image_mask,
&reference_frame_relative_offset,
);
clip_region.origin += reference_frame_relative_offset;
// Just use clip rectangle as the frame rect for this scroll frame.
// This is useful when calculating scroll extents for the
// ClipScrollNode::scroll(..) API as well as for properly setting sticky
@ -599,6 +599,7 @@ impl<'a> FlattenContext<'a> {
info.margins,
info.vertical_offset_bounds,
info.horizontal_offset_bounds,
info.previously_applied_offset,
);
self.clip_scroll_tree.add_sticky_frame(
info.id,

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

@ -16,7 +16,7 @@ use app_units::Au;
use border::ImageBorderSegment;
use clip::{ClipRegion, ClipSource, ClipSources, ClipStore, Contains};
use clip_scroll_node::{ClipInfo, ClipScrollNode, NodeType};
use clip_scroll_tree::{ClipScrollTree, CoordinateSystemId};
use clip_scroll_tree::{ClipScrollTree};
use euclid::{SideOffsets2D, TypedTransform3D, vec2, vec3};
use frame::FrameId;
use gpu_cache::GpuCache;
@ -29,14 +29,14 @@ use prim_store::{PrimitiveContainer, PrimitiveIndex};
use prim_store::{PrimitiveStore, RadialGradientPrimitiveCpu};
use prim_store::{RectangleContent, RectanglePrimitive, TextRunPrimitiveCpu};
use profiler::{FrameProfileCounters, GpuCacheProfileCounters, TextureCacheProfileCounters};
use render_task::{AlphaRenderItem, ClearMode, ClipChain, RenderTask, RenderTaskId, RenderTaskLocation};
use render_task::{AlphaRenderItem, ClearMode, RenderTask, RenderTaskId, RenderTaskLocation};
use render_task::RenderTaskTree;
use resource_cache::ResourceCache;
use scene::ScenePipeline;
use std::{mem, usize, f32, i32};
use tiling::{ClipScrollGroup, ClipScrollGroupIndex, CompositeOps, Frame};
use tiling::{CompositeOps, Frame};
use tiling::{ContextIsolation, RenderTargetKind, StackingContextIndex};
use tiling::{PackedLayer, PackedLayerIndex, PrimitiveFlags, PrimitiveRunCmd, RenderPass};
use tiling::{PrimitiveFlags, PrimitiveRunCmd, RenderPass};
use tiling::{RenderTargetContext, ScrollbarPrimitive, StackingContext};
use util::{self, pack_as_float, RectHelpers, recycle_vec};
use box_shadow::BLUR_SAMPLE_SCALE;
@ -113,11 +113,6 @@ pub struct FrameBuilder {
pub config: FrameBuilderConfig,
stacking_context_store: Vec<StackingContext>,
clip_scroll_group_store: Vec<ClipScrollGroup>,
// Note: value here is meant to be `ClipScrollGroupIndex`,
// but we already have `ClipAndScrollInfo` in the key
clip_scroll_group_indices: FastHashMap<ClipAndScrollInfo, usize>,
packed_layers: Vec<PackedLayer>,
// A stack of the current shadow primitives.
// The sub-Vec stores a buffer of fast-path primitives to be appended on pop.
@ -141,36 +136,24 @@ pub struct FrameBuilder {
}
pub struct PrimitiveContext<'a> {
pub packed_layer_index: PackedLayerIndex,
pub packed_layer: &'a PackedLayer,
pub device_pixel_ratio: f32,
pub clip_chain: ClipChain,
pub clip_bounds: DeviceIntRect,
pub clip_id: ClipId,
pub coordinate_system_id: CoordinateSystemId,
pub display_list: &'a BuiltDisplayList,
pub clip_node: &'a ClipScrollNode,
pub scroll_node: &'a ClipScrollNode,
}
impl<'a> PrimitiveContext<'a> {
fn new(
packed_layer_index: PackedLayerIndex,
packed_layer: &'a PackedLayer,
clip_id: ClipId,
clip_chain: ClipChain,
clip_bounds: DeviceIntRect,
coordinate_system_id: CoordinateSystemId,
device_pixel_ratio: f32,
display_list: &'a BuiltDisplayList,
clip_node: &'a ClipScrollNode,
scroll_node: &'a ClipScrollNode,
) -> Self {
PrimitiveContext {
packed_layer_index,
packed_layer,
clip_chain,
clip_bounds,
coordinate_system_id,
device_pixel_ratio,
clip_id,
display_list,
clip_node,
scroll_node,
}
}
}
@ -185,11 +168,8 @@ impl FrameBuilder {
match previous {
Some(prev) => FrameBuilder {
stacking_context_store: recycle_vec(prev.stacking_context_store),
clip_scroll_group_store: recycle_vec(prev.clip_scroll_group_store),
clip_scroll_group_indices: FastHashMap::default(),
cmds: recycle_vec(prev.cmds),
hit_testing_runs: recycle_vec(prev.hit_testing_runs),
packed_layers: recycle_vec(prev.packed_layers),
shadow_prim_stack: recycle_vec(prev.shadow_prim_stack),
pending_shadow_contents: recycle_vec(prev.pending_shadow_contents),
scrollbar_prims: recycle_vec(prev.scrollbar_prims),
@ -204,11 +184,8 @@ impl FrameBuilder {
},
None => FrameBuilder {
stacking_context_store: Vec::new(),
clip_scroll_group_store: Vec::new(),
clip_scroll_group_indices: FastHashMap::default(),
cmds: Vec::new(),
hit_testing_runs: Vec::new(),
packed_layers: Vec::new(),
shadow_prim_stack: Vec::new(),
pending_shadow_contents: Vec::new(),
scrollbar_prims: Vec::new(),
@ -229,16 +206,10 @@ impl FrameBuilder {
/// sub-primitives.
pub fn create_primitive(
&mut self,
clip_and_scroll: ClipAndScrollInfo,
info: &LayerPrimitiveInfo,
mut clip_sources: Vec<ClipSource>,
container: PrimitiveContainer,
) -> PrimitiveIndex {
if !self.clip_scroll_group_indices.contains_key(&clip_and_scroll) {
let group_id = self.create_clip_scroll_group(&clip_and_scroll);
self.clip_scroll_group_indices.insert(clip_and_scroll, group_id);
}
if let &LocalClip::RoundedRect(main, region) = &info.local_clip {
clip_sources.push(ClipSource::Rectangle(main));
clip_sources.push(ClipSource::RoundedRectangle(
@ -322,28 +293,12 @@ impl FrameBuilder {
container: PrimitiveContainer,
) -> PrimitiveIndex {
self.add_primitive_to_hit_testing_list(info, clip_and_scroll);
let prim_index = self.create_primitive(clip_and_scroll, info, clip_sources, container);
let prim_index = self.create_primitive(info, clip_sources, container);
self.add_primitive_to_draw_list(prim_index, clip_and_scroll);
prim_index
}
fn create_clip_scroll_group(&mut self, info: &ClipAndScrollInfo) -> usize {
let packed_layer_index = PackedLayerIndex(self.packed_layers.len());
self.packed_layers.push(PackedLayer::empty());
let group_id = self.clip_scroll_group_store.len();
self.clip_scroll_group_store.push(ClipScrollGroup {
scroll_node_id: info.scroll_node_id,
clip_node_id: info.clip_node_id(),
packed_layer_index,
screen_bounding_rect: None,
coordinate_system_id: CoordinateSystemId(0),
});
group_id
}
pub fn notify_waiting_for_root_stacking_context(&mut self) {
self.has_root_stacking_context = false;
}
@ -517,15 +472,13 @@ impl FrameBuilder {
clip_region: ClipRegion,
clip_scroll_tree: &mut ClipScrollTree,
) {
let clip_rect = LayerRect::new(clip_region.origin, clip_region.main.size);
let clip_rect = clip_region.main;
let clip_info = ClipInfo::new(
clip_region,
PackedLayerIndex(self.packed_layers.len()),
&mut self.clip_store,
);
let node = ClipScrollNode::new_clip_node(pipeline_id, parent_id, clip_info, clip_rect);
clip_scroll_tree.add_node(node, new_node_id);
self.packed_layers.push(PackedLayer::empty());
}
pub fn add_scroll_frame(
@ -566,7 +519,6 @@ impl FrameBuilder {
// before any visual text elements that are added as
// part of this shadow context.
let prim_index = self.create_primitive(
clip_and_scroll,
info,
Vec::new(),
PrimitiveContainer::Picture(prim),
@ -676,7 +628,6 @@ impl FrameBuilder {
let mut info = info.clone();
info.rect = info.rect.translate(&shadow.offset);
let prim_index = self.create_primitive(
clip_and_scroll,
&info,
Vec::new(),
PrimitiveContainer::Line(line),
@ -685,7 +636,6 @@ impl FrameBuilder {
}
let prim_index = self.create_primitive(
clip_and_scroll,
&info,
Vec::new(),
PrimitiveContainer::Line(line),
@ -1183,7 +1133,6 @@ impl FrameBuilder {
let mut info = info.clone();
info.rect = rect.translate(&text_prim.offset);
let prim_index = self.create_primitive(
clip_and_scroll,
&info,
Vec::new(),
PrimitiveContainer::TextRun(text_prim),
@ -1194,7 +1143,6 @@ impl FrameBuilder {
// 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(
clip_and_scroll,
info,
Vec::new(),
PrimitiveContainer::TextRun(prim),
@ -1317,19 +1265,6 @@ impl FrameBuilder {
stacking_context.isolated_items_bounds = LayerRect::zero();
}
pub fn get_packed_layer_index_if_visible(
&self,
clip_and_scroll: &ClipAndScrollInfo
) -> Option<PackedLayerIndex> {
let group_id = self.clip_scroll_group_indices[&clip_and_scroll];
let clip_scroll_group = &self.clip_scroll_group_store[group_id];
if clip_scroll_group.is_visible() {
Some(clip_scroll_group.packed_layer_index)
} else {
None
}
}
pub fn hit_test(
&self,
clip_scroll_tree: &ClipScrollTree,
@ -1414,33 +1349,13 @@ impl FrameBuilder {
profile_counters: &mut FrameProfileCounters,
) -> bool {
let stacking_context_index = *self.stacking_context_stack.last().unwrap();
let packed_layer_index =
match self.get_packed_layer_index_if_visible(&clip_and_scroll) {
Some(index) => index,
None => {
debug!("{:?} of invisible {:?}", base_prim_index, stacking_context_index);
return false;
}
};
let (clip_chain, clip_bounds, coordinate_system_id) =
match clip_scroll_tree.nodes.get(&clip_and_scroll.clip_node_id()) {
Some(node) if node.combined_clip_outer_bounds != DeviceIntRect::zero() => {
let group_id = self.clip_scroll_group_indices[&clip_and_scroll];
(
node.clip_chain_node.clone(),
node.combined_clip_outer_bounds,
self.clip_scroll_group_store[group_id].coordinate_system_id,
)
}
_ => {
let group_id = self.clip_scroll_group_indices[&clip_and_scroll];
self.clip_scroll_group_store[group_id].screen_bounding_rect = None;
let scroll_node = &clip_scroll_tree.nodes[&clip_and_scroll.scroll_node_id];
let clip_node = &clip_scroll_tree.nodes[&clip_and_scroll.clip_node_id()];
if clip_node.combined_clip_outer_bounds == DeviceIntRect::zero() {
debug!("{:?} of clipped out {:?}", base_prim_index, stacking_context_index);
return false;
}
};
let stacking_context = &mut self.stacking_context_store[stacking_context_index.0];
let pipeline_id = {
@ -1455,37 +1370,25 @@ impl FrameBuilder {
};
debug!(
"\t{:?} of {:?} at {:?}",
"\t{:?} of {:?}",
base_prim_index,
stacking_context_index,
packed_layer_index
);
let packed_layer = &self.packed_layers[packed_layer_index.0];
let display_list = &pipelines
.get(&pipeline_id)
.expect("No display list?")
.display_list;
if !stacking_context.is_backface_visible && packed_layer.transform.is_backface_visible() {
if !stacking_context.is_backface_visible && scroll_node.world_content_transform.is_backface_visible() {
return false;
}
let prim_context = PrimitiveContext::new(
packed_layer_index,
packed_layer,
clip_and_scroll.clip_node_id(),
clip_chain,
clip_bounds,
coordinate_system_id,
device_pixel_ratio,
display_list,
);
debug!(
"\tclip_bounds {:?}, layer_local_clip {:?}",
prim_context.clip_bounds,
packed_layer.local_clip_rect
clip_node,
scroll_node,
);
for i in 0 .. prim_count {
@ -1571,55 +1474,6 @@ impl FrameBuilder {
}
}
fn recalculate_clip_scroll_groups(
&mut self,
clip_scroll_tree: &ClipScrollTree,
screen_rect: &DeviceIntRect,
device_pixel_ratio: f32
) {
debug!("recalculate_clip_scroll_groups");
for ref mut group in &mut self.clip_scroll_group_store {
let scroll_node = &clip_scroll_tree.nodes[&group.scroll_node_id];
let clip_node = &clip_scroll_tree.nodes[&group.clip_node_id];
let packed_layer = &mut self.packed_layers[group.packed_layer_index.0];
debug!(
"\tProcessing group scroll={:?}, clip={:?}",
group.scroll_node_id,
group.clip_node_id
);
let transform = scroll_node.world_content_transform;
if !packed_layer.set_transform(transform) {
group.screen_bounding_rect = None;
debug!("\t\tUnable to set transform {:?}", transform);
continue;
}
// Here we move the viewport rectangle into the coordinate system
// of the stacking context content.
let local_viewport_rect = clip_node
.combined_local_viewport_rect
.translate(&clip_node.reference_frame_relative_scroll_offset)
.translate(&-scroll_node.reference_frame_relative_scroll_offset)
.translate(&-scroll_node.scroll_offset());
group.screen_bounding_rect = packed_layer.set_rect(
&local_viewport_rect,
screen_rect,
device_pixel_ratio,
);
group.coordinate_system_id = scroll_node.coordinate_system_id;
debug!(
"\t\tlocal viewport {:?} screen bound {:?}",
local_viewport_rect,
group.screen_bounding_rect
);
}
}
/// Compute the contribution (bounding rectangles, and resources) of layers and their
/// primitives in screen space.
fn build_layer_screen_rects_and_cull_layers(
@ -1635,12 +1489,6 @@ impl FrameBuilder {
) {
profile_scope!("cull");
self.recalculate_clip_scroll_groups(
clip_scroll_tree,
screen_rect,
device_pixel_ratio
);
debug!("processing commands...");
let commands = mem::replace(&mut self.cmds, Vec::new());
for cmd in &commands {
@ -1839,6 +1687,7 @@ impl FrameBuilder {
{
let mut prev_task = alpha_task_stack.pop().unwrap();
let screen_origin = current_task.as_alpha_batch().screen_origin;
let current_task_size = current_task.get_dynamic_size();
let current_task_id = render_tasks.add(current_task);
let item = AlphaRenderItem::HardwareComposite(
stacking_context_index,
@ -1846,6 +1695,7 @@ impl FrameBuilder {
HardwareCompositeOp::PremultipliedAlpha,
screen_origin,
next_z,
current_task_size,
);
next_z += 1;
prev_task.as_alpha_batch_mut().items.push(item);
@ -1883,6 +1733,7 @@ impl FrameBuilder {
screen_origin.y - inflate_size as i32,
),
next_z,
render_tasks.get(current_task_id).get_dynamic_size(),
);
prev_task.as_alpha_batch_mut().items.push(item);
prev_task.children.push(blur_render_task_id);
@ -1973,6 +1824,7 @@ impl FrameBuilder {
{
let mut prev_task = alpha_task_stack.pop().unwrap();
let screen_origin = current_task.as_alpha_batch().screen_origin;
let current_task_size = current_task.get_dynamic_size();
let current_task_id = render_tasks.add(current_task);
let item = AlphaRenderItem::HardwareComposite(
stacking_context_index,
@ -1980,6 +1832,7 @@ impl FrameBuilder {
HardwareCompositeOp::PremultipliedAlpha,
screen_origin,
next_z,
current_task_size,
);
next_z += 1;
prev_task.as_alpha_batch_mut().items.push(item);
@ -1993,19 +1846,11 @@ impl FrameBuilder {
continue;
}
let group_id = self.clip_scroll_group_indices[&clip_and_scroll];
let group_index = ClipScrollGroupIndex(group_id, clip_and_scroll);
if self.clip_scroll_group_store[group_id]
.screen_bounding_rect
.is_none()
{
debug!("\tcs-group {:?} screen rect is None", group_index);
continue;
}
debug!("\trun of {} items", prim_count);
let scroll_node = &clip_scroll_tree.nodes[&clip_and_scroll.scroll_node_id];
let clip_node = &clip_scroll_tree.nodes[&clip_and_scroll.clip_node_id()];
for i in 0 .. prim_count {
let prim_index = PrimitiveIndex(first_prim_index.0 + i);
@ -2013,7 +1858,7 @@ impl FrameBuilder {
self.prim_store
.add_render_tasks_for_prim(prim_index, &mut current_task);
let item =
AlphaRenderItem::Primitive(Some(group_index), prim_index, next_z);
AlphaRenderItem::Primitive(clip_node.id, scroll_node.id, prim_index, next_z);
current_task.as_alpha_batch_mut().items.push(item);
next_z += 1;
}
@ -2058,14 +1903,16 @@ impl FrameBuilder {
),
);
let mut node_data = Vec::new();
clip_scroll_tree.update_all_node_transforms(
&screen_rect,
device_pixel_ratio,
&mut self.packed_layers,
&mut self.clip_store,
resource_cache,
gpu_cache,
pan
pan,
&mut node_data,
);
self.update_scroll_bars(clip_scroll_tree, gpu_cache);
@ -2112,9 +1959,9 @@ impl FrameBuilder {
let ctx = RenderTargetContext {
device_pixel_ratio,
stacking_context_store: &self.stacking_context_store,
clip_scroll_group_store: &self.clip_scroll_group_store,
prim_store: &self.prim_store,
resource_cache,
node_data: &node_data,
};
pass.build(
@ -2146,7 +1993,7 @@ impl FrameBuilder {
window_size: self.screen_size,
profile_counters,
passes,
layer_texture_data: self.packed_layers.clone(),
node_data,
render_tasks,
deferred_resolves,
gpu_cache_updates: Some(gpu_cache_updates),

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

@ -2,22 +2,12 @@
* 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::LayerRect;
use api::{LayerVector2D, LayerRect, LayerToWorldTransform, WorldToLayerTransform};
use gpu_cache::GpuCacheAddress;
use render_task::RenderTaskAddress;
use tiling::PackedLayerIndex;
// Contains type that must exactly match the same structures declared in GLSL.
#[derive(Debug, Copy, Clone)]
pub struct PackedLayerAddress(i32);
impl From<PackedLayerIndex> for PackedLayerAddress {
fn from(index: PackedLayerIndex) -> PackedLayerAddress {
PackedLayerAddress(index.0 as i32)
}
}
#[repr(i32)]
#[derive(Debug, Copy, Clone)]
pub enum BlurDirection {
@ -41,7 +31,7 @@ pub struct BlurInstance {
#[repr(C)]
pub struct ClipMaskInstance {
pub render_task_address: RenderTaskAddress,
pub layer_address: PackedLayerAddress,
pub scroll_node_id: ClipScrollNodeIndex,
pub segment: i32,
pub clip_data_address: GpuCacheAddress,
pub resource_address: GpuCacheAddress,
@ -57,7 +47,8 @@ pub struct SimplePrimitiveInstance {
pub specific_prim_address: GpuCacheAddress,
pub task_address: RenderTaskAddress,
pub clip_task_address: RenderTaskAddress,
pub layer_address: PackedLayerAddress,
pub clip_id: ClipScrollNodeIndex,
pub scroll_id: ClipScrollNodeIndex,
pub z_sort_index: i32,
}
@ -66,14 +57,16 @@ impl SimplePrimitiveInstance {
specific_prim_address: GpuCacheAddress,
task_address: RenderTaskAddress,
clip_task_address: RenderTaskAddress,
layer_address: PackedLayerAddress,
clip_id: ClipScrollNodeIndex,
scroll_id: ClipScrollNodeIndex,
z_sort_index: i32,
) -> SimplePrimitiveInstance {
SimplePrimitiveInstance {
specific_prim_address,
task_address,
clip_task_address,
layer_address,
clip_id,
scroll_id,
z_sort_index,
}
}
@ -84,7 +77,7 @@ impl SimplePrimitiveInstance {
self.specific_prim_address.as_int(),
self.task_address.0 as i32,
self.clip_task_address.0 as i32,
self.layer_address.0,
((self.clip_id.0 as i32) << 16) | self.scroll_id.0 as i32,
self.z_sort_index,
data0,
data1,
@ -101,6 +94,8 @@ pub struct CompositePrimitiveInstance {
pub data0: i32,
pub data1: i32,
pub z: i32,
pub data2: i32,
pub data3: i32,
}
impl CompositePrimitiveInstance {
@ -111,6 +106,8 @@ impl CompositePrimitiveInstance {
data0: i32,
data1: i32,
z: i32,
data2: i32,
data3: i32,
) -> CompositePrimitiveInstance {
CompositePrimitiveInstance {
task_address,
@ -119,6 +116,8 @@ impl CompositePrimitiveInstance {
data0,
data1,
z,
data2,
data3,
}
}
}
@ -133,8 +132,8 @@ impl From<CompositePrimitiveInstance> for PrimitiveInstance {
instance.z,
instance.data0,
instance.data1,
0,
0,
instance.data2,
instance.data3,
],
}
}
@ -156,7 +155,8 @@ pub const BRUSH_FLAG_USES_PICTURE: i32 = (1 << 0);
pub struct BrushInstance {
pub picture_address: RenderTaskAddress,
pub prim_address: GpuCacheAddress,
pub layer_address: PackedLayerAddress,
pub clip_id: ClipScrollNodeIndex,
pub scroll_id: ClipScrollNodeIndex,
pub clip_task_address: RenderTaskAddress,
pub z: i32,
pub flags: i32,
@ -170,7 +170,7 @@ impl From<BrushInstance> for PrimitiveInstance {
data: [
instance.picture_address.0 as i32,
instance.prim_address.as_int(),
instance.layer_address.0,
((instance.clip_id.0 as i32) << 16) | instance.scroll_id.0 as i32,
instance.clip_task_address.0 as i32,
instance.z,
instance.flags,
@ -190,3 +190,29 @@ pub enum BrushImageKind {
NinePatch = 1, // A nine-patch image (stretch inside segments)
Mirror = 2, // A top left corner only (mirror across x/y axes)
}
#[derive(Copy, Debug, Clone)]
#[repr(C)]
pub struct ClipScrollNodeIndex(pub u32);
#[derive(Debug)]
#[repr(C)]
pub struct ClipScrollNodeData {
pub transform: LayerToWorldTransform,
pub inv_transform: WorldToLayerTransform,
pub local_clip_rect: LayerRect,
pub reference_frame_relative_scroll_offset: LayerVector2D,
pub scroll_offset: LayerVector2D,
}
impl ClipScrollNodeData {
pub fn invalid() -> ClipScrollNodeData {
ClipScrollNodeData {
transform: LayerToWorldTransform::identity(),
inv_transform: WorldToLayerTransform::identity(),
local_clip_rect: LayerRect::zero(),
reference_frame_relative_scroll_offset: LayerVector2D::zero(),
scroll_offset: LayerVector2D::zero(),
}
}
}

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

@ -287,9 +287,9 @@ impl FontContext {
let length = pixels.len() / 3;
let mut bgra_pixels: Vec<u8> = vec![0; length * 4];
for i in 0 .. length {
bgra_pixels[i * 4 + 0] = pixels[i * 3 + 0];
bgra_pixels[i * 4 + 0] = pixels[i * 3 + 2];
bgra_pixels[i * 4 + 1] = pixels[i * 3 + 1];
bgra_pixels[i * 4 + 2] = pixels[i * 3 + 2];
bgra_pixels[i * 4 + 2] = pixels[i * 3 + 0];
bgra_pixels[i * 4 + 3] = 0xff;
}
bgra_pixels

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

@ -18,7 +18,7 @@ use renderer::MAX_VERTEX_TEXTURE_WIDTH;
use resource_cache::{ImageProperties, ResourceCache};
use std::{mem, usize};
use std::rc::Rc;
use util::{MatrixHelpers, pack_as_float, recycle_vec, TransformedRect};
use util::{pack_as_float, recycle_vec, MatrixHelpers, TransformedRect, TransformedRectKind};
#[derive(Debug, Copy, Clone)]
pub struct PrimitiveOpacity {
@ -1209,8 +1209,10 @@ impl PrimitiveStore {
clip_store: &mut ClipStore,
) -> bool {
let metadata = &mut self.cpu_metadata[prim_index.0];
let transform = &prim_context.scroll_node.world_content_transform;
clip_store.get_mut(&metadata.clip_sources).update(
&prim_context.packed_layer.transform,
transform,
gpu_cache,
resource_cache,
prim_context.device_pixel_ratio,
@ -1218,8 +1220,9 @@ impl PrimitiveStore {
// Try to create a mask if we may need to.
let prim_clips = clip_store.get(&metadata.clip_sources);
let is_axis_aligned = prim_context.packed_layer.transform.preserves_2d_axis_alignment();
let clip_task = if prim_context.clip_chain.is_some() || prim_clips.is_masking() {
let is_axis_aligned = transform.transform_kind() == TransformedRectKind::AxisAligned;
let clip_task = if prim_context.clip_node.clip_chain_node.is_some() || prim_clips.is_masking() {
// Take into account the actual clip info of the primitive, and
// mutate the current bounds accordingly.
let mask_rect = match prim_clips.bounds.outer {
@ -1236,9 +1239,9 @@ impl PrimitiveStore {
let extra_clip = if prim_clips.is_masking() {
Some(Rc::new(ClipChainNode {
work_item: ClipWorkItem {
layer_index: prim_context.packed_layer_index,
scroll_node_id: prim_context.scroll_node.id,
clip_sources: metadata.clip_sources.weak(),
coordinate_system_id: prim_context.coordinate_system_id,
coordinate_system_id: prim_context.scroll_node.coordinate_system_id,
},
prev: None,
}))
@ -1249,12 +1252,12 @@ impl PrimitiveStore {
RenderTask::new_mask(
None,
mask_rect,
prim_context.clip_chain.clone(),
prim_context.clip_node.clip_chain_node.clone(),
extra_clip,
prim_screen_rect,
clip_store,
is_axis_aligned,
prim_context.coordinate_system_id,
prim_context.scroll_node.coordinate_system_id,
)
} else {
None
@ -1284,14 +1287,13 @@ impl PrimitiveStore {
}
if !metadata.is_backface_visible &&
prim_context.packed_layer.transform.is_backface_visible() {
prim_context.scroll_node.world_content_transform.is_backface_visible() {
return None;
}
let local_rect = metadata
.local_rect
.intersection(&metadata.local_clip_rect)
.and_then(|rect| rect.intersection(&prim_context.packed_layer.local_clip_rect));
.intersection(&metadata.local_clip_rect);
let local_rect = match local_rect {
Some(local_rect) => local_rect,
@ -1300,13 +1302,13 @@ impl PrimitiveStore {
let xf_rect = TransformedRect::new(
&local_rect,
&prim_context.packed_layer.transform,
&prim_context.scroll_node.world_content_transform,
prim_context.device_pixel_ratio
);
metadata.screen_rect = xf_rect
.bounding_rect
.intersection(&prim_context.clip_bounds);
let clip_bounds = &prim_context.clip_node.combined_clip_outer_bounds;
metadata.screen_rect = xf_rect.bounding_rect
.intersection(clip_bounds);
let geometry = match metadata.screen_rect {
Some(device_rect) => Geometry {

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

@ -326,19 +326,21 @@ impl FrameProfileCounters {
#[derive(Clone)]
pub struct TextureCacheProfileCounters {
pub pages_a8: ResourceProfileCounter,
pub pages_rgb8: ResourceProfileCounter,
pub pages_rgba8: ResourceProfileCounter,
pub pages_rg8: ResourceProfileCounter,
pub pages_a8_linear: ResourceProfileCounter,
pub pages_rgb8_linear: ResourceProfileCounter,
pub pages_rgba8_linear: ResourceProfileCounter,
pub pages_rgba8_nearest: ResourceProfileCounter,
pub pages_rg8_linear: ResourceProfileCounter,
}
impl TextureCacheProfileCounters {
pub fn new() -> Self {
TextureCacheProfileCounters {
pages_a8: ResourceProfileCounter::new("Texture A8 cached pages"),
pages_rgb8: ResourceProfileCounter::new("Texture RGB8 cached pages"),
pages_rgba8: ResourceProfileCounter::new("Texture RGBA8 cached pages"),
pages_rg8: ResourceProfileCounter::new("Texture RG8 cached pages"),
pages_a8_linear: ResourceProfileCounter::new("Texture A8 cached pages"),
pages_rgb8_linear: ResourceProfileCounter::new("Texture RGB8 cached pages"),
pages_rgba8_linear: ResourceProfileCounter::new("Texture RGBA8 cached pages (L)"),
pages_rgba8_nearest: ResourceProfileCounter::new("Texture RGBA8 cached pages (N)"),
pages_rg8_linear: ResourceProfileCounter::new("Texture RG8 cached pages"),
}
}
}
@ -842,10 +844,11 @@ impl Profiler {
self.draw_counters(
&[
&backend_profile.resources.texture_cache.pages_a8,
&backend_profile.resources.texture_cache.pages_rgb8,
&backend_profile.resources.texture_cache.pages_rgba8,
&backend_profile.resources.texture_cache.pages_rg8,
&backend_profile.resources.texture_cache.pages_a8_linear,
&backend_profile.resources.texture_cache.pages_rgb8_linear,
&backend_profile.resources.texture_cache.pages_rgba8_linear,
&backend_profile.resources.texture_cache.pages_rgba8_nearest,
&backend_profile.resources.texture_cache.pages_rg8_linear,
&backend_profile.ipc.display_lists,
],
debug_renderer,

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

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use api::ApiMsg;
use api::{ApiMsg, DocumentMsg};
use bincode::{serialize, Infinite};
use byteorder::{LittleEndian, WriteBytesExt};
use std::any::TypeId;
@ -65,8 +65,14 @@ pub fn should_record_msg(msg: &ApiMsg) -> bool {
match *msg {
ApiMsg::UpdateResources(..) |
ApiMsg::AddDocument { .. } |
ApiMsg::UpdateDocument(..) |
ApiMsg::DeleteDocument(..) => true,
ApiMsg::UpdateDocument(_, ref msg) => {
match *msg {
DocumentMsg::GetScrollNodeState(..) |
DocumentMsg::HitTest(..) => false,
_ => true,
}
}
_ => false,
}
}

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

@ -8,11 +8,12 @@ use api::{LayerRect, PipelineId};
use clip::{ClipSource, ClipSourcesWeakHandle, ClipStore};
use clip_scroll_tree::CoordinateSystemId;
use gpu_cache::GpuCacheHandle;
use gpu_types::{ClipScrollNodeIndex};
use internal_types::HardwareCompositeOp;
use prim_store::PrimitiveIndex;
use std::{cmp, usize, f32, i32};
use std::rc::Rc;
use tiling::{ClipScrollGroupIndex, PackedLayerIndex, RenderPass, RenderTargetIndex};
use tiling::{RenderPass, RenderTargetIndex};
use tiling::{RenderTargetKind, StackingContextIndex};
const FLOATS_PER_RENDER_TASK_INFO: usize = 12;
@ -151,7 +152,7 @@ pub enum RenderTaskLocation {
#[derive(Debug)]
pub enum AlphaRenderItem {
Primitive(Option<ClipScrollGroupIndex>, PrimitiveIndex, i32),
Primitive(ClipScrollNodeIndex, ClipScrollNodeIndex, PrimitiveIndex, i32),
Blend(StackingContextIndex, RenderTaskId, FilterOp, i32),
Composite(
StackingContextIndex,
@ -167,6 +168,7 @@ pub enum AlphaRenderItem {
HardwareCompositeOp,
DeviceIntPoint,
i32,
DeviceIntSize,
),
}
@ -200,7 +202,7 @@ pub enum MaskGeometryKind {
#[derive(Debug, Clone)]
pub struct ClipWorkItem {
pub layer_index: PackedLayerIndex,
pub scroll_node_id: ClipScrollNodeIndex,
pub clip_sources: ClipSourcesWeakHandle,
pub coordinate_system_id: CoordinateSystemId,
}
@ -268,6 +270,7 @@ pub struct BlurTask {
pub target_kind: RenderTargetKind,
pub regions: Vec<LayerRect>,
pub color: ColorF,
pub scale_factor: f32,
}
#[derive(Debug)]
@ -284,6 +287,7 @@ pub enum RenderTaskKind {
HorizontalBlur(BlurTask),
Readback(DeviceIntRect),
Alias(RenderTaskId),
Scaling(RenderTargetKind),
}
#[derive(Debug, Copy, Clone)]
@ -447,14 +451,17 @@ impl RenderTask {
})
}
// Construct a render task to apply a blur to a primitive. For now,
// this is only used for text runs, but we can probably extend this
// to handle general blurs to any render task in the future.
// Construct a render task to apply a blur to a primitive.
// The render task chain that is constructed looks like:
//
// PrimitiveCacheTask: Draw the text run.
// PrimitiveCacheTask: Draw the primitives.
// ^
// |
// DownscalingTask(s): Each downscaling task reduces the size of render target to
// ^ half. Also reduce the std deviation to half until the std
// | deviation less than 4.0.
// |
// |
// VerticalBlurTask: Apply the separable vertical blur to the primitive.
// ^
// |
@ -471,17 +478,41 @@ impl RenderTask {
clear_mode: ClearMode,
color: ColorF,
) -> RenderTask {
// Adjust large std deviation value.
const MAX_BLUR_STD_DEVIATION: f32 = 4.0;
const MIN_DOWNSCALING_RT_SIZE: i32 = 128;
let mut adjusted_blur_std_deviation = blur_std_deviation;
let blur_target_size = render_tasks.get(src_task_id).get_dynamic_size();
let mut adjusted_blur_target_size = blur_target_size;
let mut downscaling_src_task_id = src_task_id;
let mut scale_factor = 1.0;
while adjusted_blur_std_deviation > MAX_BLUR_STD_DEVIATION {
if adjusted_blur_target_size.width < MIN_DOWNSCALING_RT_SIZE ||
adjusted_blur_target_size.height < MIN_DOWNSCALING_RT_SIZE {
break;
}
adjusted_blur_std_deviation *= 0.5;
scale_factor *= 2.0;
adjusted_blur_target_size = (blur_target_size.to_f32() / scale_factor).to_i32();
let downscaling_task = RenderTask::new_scaling(
target_kind,
downscaling_src_task_id,
adjusted_blur_target_size
);
downscaling_src_task_id = render_tasks.add(downscaling_task);
}
scale_factor = blur_target_size.width as f32 / adjusted_blur_target_size.width as f32;
let blur_task_v = RenderTask {
cache_key: None,
children: vec![src_task_id],
location: RenderTaskLocation::Dynamic(None, blur_target_size),
children: vec![downscaling_src_task_id],
location: RenderTaskLocation::Dynamic(None, adjusted_blur_target_size),
kind: RenderTaskKind::VerticalBlur(BlurTask {
blur_std_deviation,
blur_std_deviation: adjusted_blur_std_deviation,
target_kind,
regions: regions.to_vec(),
color,
scale_factor,
}),
clear_mode,
};
@ -491,12 +522,13 @@ impl RenderTask {
let blur_task_h = RenderTask {
cache_key: None,
children: vec![blur_task_v_id],
location: RenderTaskLocation::Dynamic(None, blur_target_size),
location: RenderTaskLocation::Dynamic(None, adjusted_blur_target_size),
kind: RenderTaskKind::HorizontalBlur(BlurTask {
blur_std_deviation,
blur_std_deviation: adjusted_blur_std_deviation,
target_kind,
regions: regions.to_vec(),
color,
scale_factor,
}),
clear_mode,
};
@ -504,6 +536,23 @@ impl RenderTask {
blur_task_h
}
pub fn new_scaling(
target_kind: RenderTargetKind,
src_task_id: RenderTaskId,
target_size: DeviceIntSize,
) -> RenderTask {
RenderTask {
cache_key: None,
children: vec![src_task_id],
location: RenderTaskLocation::Dynamic(None, target_size),
kind: RenderTaskKind::Scaling(target_kind),
clear_mode: match target_kind {
RenderTargetKind::Color => ClearMode::Transparent,
RenderTargetKind::Alpha => ClearMode::One,
},
}
}
pub fn as_alpha_batch_mut<'a>(&'a mut self) -> &'a mut AlphaRenderTask {
match self.kind {
RenderTaskKind::Alpha(ref mut task) => task,
@ -512,7 +561,8 @@ impl RenderTask {
RenderTaskKind::VerticalBlur(..) |
RenderTaskKind::Readback(..) |
RenderTaskKind::HorizontalBlur(..) |
RenderTaskKind::Alias(..) => unreachable!(),
RenderTaskKind::Alias(..) |
RenderTaskKind::Scaling(..) => unreachable!(),
}
}
@ -524,7 +574,8 @@ impl RenderTask {
RenderTaskKind::VerticalBlur(..) |
RenderTaskKind::Readback(..) |
RenderTaskKind::HorizontalBlur(..) |
RenderTaskKind::Alias(..) => unreachable!(),
RenderTaskKind::Alias(..) |
RenderTaskKind::Scaling(..) => unreachable!(),
}
}
@ -609,7 +660,7 @@ impl RenderTask {
target_rect.size.height as f32,
target_index.0 as f32,
task_info.blur_std_deviation,
0.0,
task_info.scale_factor,
0.0,
task_info.color.r,
task_info.color.g,
@ -618,7 +669,8 @@ impl RenderTask {
],
}
}
RenderTaskKind::Readback(..) => {
RenderTaskKind::Readback(..) |
RenderTaskKind::Scaling(..) => {
let (target_rect, target_index) = self.get_target_rect();
RenderTaskData {
data: [
@ -662,7 +714,8 @@ impl RenderTask {
RenderTaskKind::VerticalBlur(..) |
RenderTaskKind::HorizontalBlur(..) |
RenderTaskKind::Picture(..) |
RenderTaskKind::Alias(..) => {
RenderTaskKind::Alias(..) |
RenderTaskKind::Scaling(..) => {
panic!("bug: inflate only supported for alpha tasks");
}
}
@ -700,6 +753,10 @@ impl RenderTask {
task_info.target_kind
}
RenderTaskKind::Scaling(target_kind) => {
target_kind
}
RenderTaskKind::Picture(ref task_info) => {
task_info.target_kind
}
@ -722,7 +779,8 @@ impl RenderTask {
RenderTaskKind::Picture(..) |
RenderTaskKind::VerticalBlur(..) |
RenderTaskKind::Readback(..) |
RenderTaskKind::HorizontalBlur(..) => false,
RenderTaskKind::HorizontalBlur(..) |
RenderTaskKind::Scaling(..) => false,
RenderTaskKind::CacheMask(..) => true,

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

@ -10,7 +10,7 @@
//! [renderer]: struct.Renderer.html
use api::{channel, BlobImageRenderer, FontRenderMode};
use api::{ColorF, Epoch, PipelineId, RenderApiSender, RenderNotifier};
use api::{ColorF, ColorU, Epoch, PipelineId, RenderApiSender, RenderNotifier};
use api::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DeviceUintRect, DeviceUintSize};
use api::{ExternalImageId, ExternalImageType, ImageFormat};
use api::{YUV_COLOR_SPACES, YUV_FORMATS};
@ -62,7 +62,7 @@ use std::thread;
use texture_cache::TextureCache;
use thread_profiler::{register_thread_with_profiler, write_profile};
use tiling::{AlphaRenderTarget, ColorRenderTarget, RenderTargetKind};
use tiling::{BatchKey, BatchKind, BrushBatchKind, Frame, RenderTarget, TransformBatchKind};
use tiling::{BatchKey, BatchKind, BrushBatchKind, Frame, RenderTarget, ScalingInfo, TransformBatchKind};
use time::precise_time_ns;
use util::TransformedRectKind;
@ -221,12 +221,13 @@ type ShaderMode = i32;
#[repr(C)]
enum TextShaderMode {
Alpha = 0,
SubpixelPass0 = 1,
SubpixelPass1 = 2,
SubpixelWithBgColorPass0 = 3,
SubpixelWithBgColorPass1 = 4,
SubpixelWithBgColorPass2 = 5,
ColorBitmap = 6,
SubpixelOpaque = 1,
SubpixelPass0 = 2,
SubpixelPass1 = 3,
SubpixelWithBgColorPass0 = 4,
SubpixelWithBgColorPass1 = 5,
SubpixelWithBgColorPass2 = 6,
ColorBitmap = 7,
}
impl Into<ShaderMode> for TextShaderMode {
@ -255,7 +256,7 @@ enum TextureSampler {
CacheA8,
CacheRGBA8,
ResourceCache,
Layers,
ClipScrollNodes,
RenderTasks,
Dither,
// A special sampler that is bound to the A8 output of
@ -286,7 +287,7 @@ impl Into<TextureSlot> for TextureSampler {
TextureSampler::CacheA8 => TextureSlot(3),
TextureSampler::CacheRGBA8 => TextureSlot(4),
TextureSampler::ResourceCache => TextureSlot(5),
TextureSampler::Layers => TextureSlot(6),
TextureSampler::ClipScrollNodes => TextureSlot(6),
TextureSampler::RenderTasks => TextureSlot(7),
TextureSampler::Dither => TextureSlot(8),
TextureSampler::SharedCacheA8 => TextureSlot(9),
@ -640,7 +641,8 @@ pub enum BlendMode {
Alpha,
PremultipliedAlpha,
PremultipliedDestOut,
Subpixel,
SubpixelOpaque(ColorU),
SubpixelWithAlpha,
SubpixelWithBgColor,
}
@ -1013,7 +1015,8 @@ impl BrushShader {
BlendMode::Alpha |
BlendMode::PremultipliedAlpha |
BlendMode::PremultipliedDestOut |
BlendMode::Subpixel |
BlendMode::SubpixelOpaque(..) |
BlendMode::SubpixelWithAlpha |
BlendMode::SubpixelWithBgColor => {
self.alpha.bind(device, projection, mode, renderer_errors)
}
@ -1126,7 +1129,7 @@ fn create_prim_shader(
("sDither", TextureSampler::Dither),
("sCacheA8", TextureSampler::CacheA8),
("sCacheRGBA8", TextureSampler::CacheRGBA8),
("sLayers", TextureSampler::Layers),
("sClipScrollNodes", TextureSampler::ClipScrollNodes),
("sRenderTasks", TextureSampler::RenderTasks),
("sResourceCache", TextureSampler::ResourceCache),
("sSharedCacheA8", TextureSampler::SharedCacheA8),
@ -1153,7 +1156,7 @@ fn create_clip_shader(name: &'static str, device: &mut Device) -> Result<Program
program,
&[
("sColor0", TextureSampler::Color0),
("sLayers", TextureSampler::Layers),
("sClipScrollNodes", TextureSampler::ClipScrollNodes),
("sRenderTasks", TextureSampler::RenderTasks),
("sResourceCache", TextureSampler::ResourceCache),
("sSharedCacheA8", TextureSampler::SharedCacheA8),
@ -1254,7 +1257,7 @@ pub struct Renderer {
blur_vao: VAO,
clip_vao: VAO,
layer_texture: VertexDataTexture,
node_data_texture: VertexDataTexture,
render_task_texture: VertexDataTexture,
gpu_cache_texture: CacheTexture,
@ -1760,7 +1763,7 @@ impl Renderer {
let texture_resolver = SourceTextureResolver::new(&mut device);
let layer_texture = VertexDataTexture::new(&mut device);
let node_data_texture = VertexDataTexture::new(&mut device);
let render_task_texture = VertexDataTexture::new(&mut device);
device.end_frame();
@ -1868,7 +1871,7 @@ impl Renderer {
prim_vao,
blur_vao,
clip_vao,
layer_texture,
node_data_texture,
render_task_texture,
pipeline_epoch_map: FastHashMap::default(),
dither_matrix_texture,
@ -2492,7 +2495,8 @@ impl Renderer {
BlendMode::Alpha |
BlendMode::PremultipliedAlpha |
BlendMode::PremultipliedDestOut |
BlendMode::Subpixel |
BlendMode::SubpixelOpaque(..) |
BlendMode::SubpixelWithAlpha |
BlendMode::SubpixelWithBgColor => true,
BlendMode::None => false,
}
@ -2689,6 +2693,30 @@ impl Renderer {
self.draw_instanced_batch(instances, VertexArrayKind::Primitive, &key.textures);
}
fn handle_scaling(
&mut self,
render_tasks: &RenderTaskTree,
scalings: &Vec<ScalingInfo>,
source: SourceTexture,
) {
let cache_texture = self.texture_resolver
.resolve(&source)
.unwrap();
for scaling in scalings {
let source = render_tasks.get(scaling.src_task_id);
let dest = render_tasks.get(scaling.dest_task_id);
let (source_rect, source_layer) = source.get_target_rect();
let (dest_rect, _) = dest.get_target_rect();
let cache_draw_target = (cache_texture, source_layer.0 as i32);
self.device
.bind_read_target(Some(cache_draw_target));
self.device.blit_render_target(source_rect, dest_rect);
}
}
fn draw_color_target(
&mut self,
render_target: Option<(&Texture, i32)>,
@ -2755,6 +2783,8 @@ impl Renderer {
}
}
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
@ -2832,12 +2862,13 @@ impl Renderer {
for batch in &target.alpha_batcher.batch_list.alpha_batch_list.batches {
if self.debug_flags.contains(DebugFlags::ALPHA_PRIM_DBG) {
let color = match batch.key.blend_mode {
BlendMode::None => ColorF::new(0.3, 0.3, 0.3, 1.0),
BlendMode::Alpha => ColorF::new(0.0, 0.9, 0.1, 1.0),
BlendMode::PremultipliedAlpha => ColorF::new(0.0, 0.3, 0.7, 1.0),
BlendMode::PremultipliedDestOut => ColorF::new(0.6, 0.2, 0.0, 1.0),
BlendMode::Subpixel => ColorF::new(0.5, 0.0, 0.4, 1.0),
BlendMode::SubpixelWithBgColor => ColorF::new(0.6, 0.0, 0.5, 1.0),
BlendMode::None => debug_colors::BLACK,
BlendMode::Alpha => debug_colors::YELLOW,
BlendMode::PremultipliedAlpha => debug_colors::GREY,
BlendMode::PremultipliedDestOut => debug_colors::SALMON,
BlendMode::SubpixelOpaque(..) => debug_colors::GREEN,
BlendMode::SubpixelWithAlpha => debug_colors::RED,
BlendMode::SubpixelWithBgColor => debug_colors::BLUE,
}.into();
for item_rect in &batch.item_rects {
self.debug.add_rect(item_rect, color);
@ -2875,7 +2906,24 @@ impl Renderer {
&batch.key.textures
);
}
BlendMode::Subpixel => {
BlendMode::SubpixelOpaque(color) => {
self.device.set_blend_mode_subpixel_opaque(color.into());
self.ps_text_run.bind(
&mut self.device,
transform_kind,
projection,
TextShaderMode::SubpixelOpaque,
&mut self.renderer_errors,
);
self.draw_instanced_batch(
&batch.instances,
VertexArrayKind::Primitive,
&batch.key.textures
);
}
BlendMode::SubpixelWithAlpha => {
// Using the two pass component alpha rendering technique:
//
// http://anholt.livejournal.com/32058.html
@ -2991,7 +3039,9 @@ impl Renderer {
self.device.set_blend(true);
self.device.set_blend_mode_premultiplied_dest_out();
}
BlendMode::Subpixel | BlendMode::SubpixelWithBgColor => {
BlendMode::SubpixelOpaque(..) |
BlendMode::SubpixelWithAlpha |
BlendMode::SubpixelWithBgColor => {
unreachable!("bug: subpx text handled earlier");
}
}
@ -3114,6 +3164,8 @@ impl Renderer {
}
}
self.handle_scaling(render_tasks, &target.scalings, SourceTexture::CacheA8);
if !target.brush_mask_corners.is_empty() {
self.device.set_blend(false);
@ -3349,7 +3401,7 @@ impl Renderer {
pass.max_alpha_target_size.width,
pass.max_alpha_target_size.height,
ImageFormat::A8,
TextureFilter::Nearest,
TextureFilter::Linear,
RenderTargetMode::RenderTarget,
alpha_target_count as i32,
None,
@ -3357,13 +3409,13 @@ impl Renderer {
}
}
self.layer_texture
.update(&mut self.device, &mut frame.layer_texture_data);
self.node_data_texture
.update(&mut self.device, &mut frame.node_data);
self.device
.bind_texture(TextureSampler::ClipScrollNodes, &self.node_data_texture.texture);
self.render_task_texture
.update(&mut self.device, &mut frame.render_tasks.task_data);
self.device
.bind_texture(TextureSampler::Layers, &self.layer_texture.texture);
self.device.bind_texture(
TextureSampler::RenderTasks,
&self.render_task_texture.texture,
@ -3669,7 +3721,7 @@ impl Renderer {
if let Some(dither_matrix_texture) = self.dither_matrix_texture {
self.device.delete_texture(dither_matrix_texture);
}
self.layer_texture.deinit(&mut self.device);
self.node_data_texture.deinit(&mut self.device);
self.render_task_texture.deinit(&mut self.device);
for texture in self.alpha_render_targets {
self.device.delete_texture(texture);

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

@ -18,7 +18,8 @@ use std::mem;
// The fixed number of layers for the shared texture cache.
// There is one array texture per image format, allocated lazily.
const TEXTURE_ARRAY_LAYERS: i32 = 4;
const TEXTURE_ARRAY_LAYERS_LINEAR: usize = 4;
const TEXTURE_ARRAY_LAYERS_NEAREST: usize = 1;
// The dimensions of each layer in the texture cache.
const TEXTURE_LAYER_DIMENSIONS: u32 = 2048;
@ -91,6 +92,7 @@ struct CacheEntry {
uv_rect_handle: GpuCacheHandle,
// Image format of the item.
format: ImageFormat,
filter: TextureFilter,
// The actual device texture ID this is part of.
texture_id: CacheTextureId,
}
@ -101,6 +103,7 @@ impl CacheEntry {
texture_id: CacheTextureId,
size: DeviceUintSize,
format: ImageFormat,
filter: TextureFilter,
user_data: [f32; 3],
last_access: FrameId,
) -> CacheEntry {
@ -111,6 +114,7 @@ impl CacheEntry {
kind: EntryKind::Standalone,
texture_id,
format,
filter,
uv_rect_handle: GpuCacheHandle::new(),
}
}
@ -164,10 +168,11 @@ pub struct TextureCache {
// each format the texture cache supports.
// TODO(gw): Do we actually need RG8 and RGB8 or
// are they only used by external textures?
array_a8: TextureArray,
array_rgba8: TextureArray,
array_rg8: TextureArray,
array_rgb8: TextureArray,
array_rgba8_nearest: TextureArray,
array_a8_linear: TextureArray,
array_rgba8_linear: TextureArray,
array_rg8_linear: TextureArray,
array_rgb8_linear: TextureArray,
// Maximum texture size supported by hardware.
max_texture_size: u32,
@ -204,10 +209,31 @@ impl TextureCache {
pub fn new(max_texture_size: u32) -> TextureCache {
TextureCache {
max_texture_size,
array_a8: TextureArray::new(ImageFormat::A8),
array_rgba8: TextureArray::new(ImageFormat::BGRA8),
array_rg8: TextureArray::new(ImageFormat::RG8),
array_rgb8: TextureArray::new(ImageFormat::RGB8),
array_a8_linear: TextureArray::new(
ImageFormat::A8,
TextureFilter::Linear,
TEXTURE_ARRAY_LAYERS_LINEAR,
),
array_rgba8_linear: TextureArray::new(
ImageFormat::BGRA8,
TextureFilter::Linear,
TEXTURE_ARRAY_LAYERS_LINEAR,
),
array_rg8_linear: TextureArray::new(
ImageFormat::RG8,
TextureFilter::Linear,
TEXTURE_ARRAY_LAYERS_LINEAR,
),
array_rgb8_linear: TextureArray::new(
ImageFormat::RGB8,
TextureFilter::Linear,
TEXTURE_ARRAY_LAYERS_LINEAR,
),
array_rgba8_nearest: TextureArray::new(
ImageFormat::BGRA8,
TextureFilter::Nearest,
TEXTURE_ARRAY_LAYERS_NEAREST
),
cache_textures: CacheTextureIdList::new(),
pending_updates: TextureUpdateList::new(),
frame_id: FrameId(0),
@ -224,14 +250,16 @@ impl TextureCache {
pub fn end_frame(&mut self, texture_cache_profile: &mut TextureCacheProfileCounters) {
self.expire_old_standalone_entries();
self.array_a8
.update_profile(&mut texture_cache_profile.pages_a8);
self.array_rg8
.update_profile(&mut texture_cache_profile.pages_rg8);
self.array_rgb8
.update_profile(&mut texture_cache_profile.pages_rgb8);
self.array_rgba8
.update_profile(&mut texture_cache_profile.pages_rgba8);
self.array_a8_linear
.update_profile(&mut texture_cache_profile.pages_a8_linear);
self.array_rg8_linear
.update_profile(&mut texture_cache_profile.pages_rg8_linear);
self.array_rgb8_linear
.update_profile(&mut texture_cache_profile.pages_rgb8_linear);
self.array_rgba8_linear
.update_profile(&mut texture_cache_profile.pages_rgba8_linear);
self.array_rgba8_nearest
.update_profile(&mut texture_cache_profile.pages_rgba8_nearest);
}
// Request an item in the texture cache. All images that will
@ -349,13 +377,22 @@ impl TextureCache {
}
// Get a specific region by index from a shared texture array.
fn get_region_mut(&mut self, format: ImageFormat, region_index: u16) -> &mut TextureRegion {
let texture_array = match format {
ImageFormat::A8 => &mut self.array_a8,
ImageFormat::BGRA8 => &mut self.array_rgba8,
ImageFormat::RGB8 => &mut self.array_rgb8,
ImageFormat::RG8 => &mut self.array_rg8,
ImageFormat::Invalid | ImageFormat::RGBAF32 => unreachable!(),
fn get_region_mut(&mut self,
format: ImageFormat,
filter: TextureFilter,
region_index: u16
) -> &mut TextureRegion {
let texture_array = match (format, filter) {
(ImageFormat::A8, TextureFilter::Linear) => &mut self.array_a8_linear,
(ImageFormat::BGRA8, TextureFilter::Linear) => &mut self.array_rgba8_linear,
(ImageFormat::BGRA8, TextureFilter::Nearest) => &mut self.array_rgba8_nearest,
(ImageFormat::RGB8, TextureFilter::Linear) => &mut self.array_rgb8_linear,
(ImageFormat::RG8, TextureFilter::Linear) => &mut self.array_rg8_linear,
(ImageFormat::Invalid, _) |
(ImageFormat::RGBAF32, _) |
(ImageFormat::A8, TextureFilter::Nearest) |
(ImageFormat::RG8, TextureFilter::Nearest) |
(ImageFormat::RGB8, TextureFilter::Nearest) => unreachable!(),
};
&mut texture_array.regions[region_index as usize]
@ -501,7 +538,11 @@ impl TextureCache {
..
} => {
// Free the block in the given region.
let region = self.get_region_mut(entry.format, region_index);
let region = self.get_region_mut(
entry.format,
entry.filter,
region_index
);
region.free(origin);
Some(region)
}
@ -512,15 +553,21 @@ impl TextureCache {
fn allocate_from_shared_cache(
&mut self,
descriptor: &ImageDescriptor,
filter: TextureFilter,
user_data: [f32; 3],
) -> Option<CacheEntry> {
// Work out which cache it goes in, based on format.
let texture_array = match descriptor.format {
ImageFormat::A8 => &mut self.array_a8,
ImageFormat::BGRA8 => &mut self.array_rgba8,
ImageFormat::RGB8 => &mut self.array_rgb8,
ImageFormat::RG8 => &mut self.array_rg8,
ImageFormat::Invalid | ImageFormat::RGBAF32 => unreachable!(),
let texture_array = match (descriptor.format, filter) {
(ImageFormat::A8, TextureFilter::Linear) => &mut self.array_a8_linear,
(ImageFormat::BGRA8, TextureFilter::Linear) => &mut self.array_rgba8_linear,
(ImageFormat::BGRA8, TextureFilter::Nearest) => &mut self.array_rgba8_nearest,
(ImageFormat::RGB8, TextureFilter::Linear) => &mut self.array_rgb8_linear,
(ImageFormat::RG8, TextureFilter::Linear) => &mut self.array_rg8_linear,
(ImageFormat::Invalid, _) |
(ImageFormat::RGBAF32, _) |
(ImageFormat::A8, TextureFilter::Nearest) |
(ImageFormat::RG8, TextureFilter::Nearest) |
(ImageFormat::RGB8, TextureFilter::Nearest) => unreachable!(),
};
// Lazy initialize this texture array if required.
@ -533,8 +580,8 @@ impl TextureCache {
width: TEXTURE_LAYER_DIMENSIONS,
height: TEXTURE_LAYER_DIMENSIONS,
format: descriptor.format,
filter: TextureFilter::Linear,
layer_count: TEXTURE_ARRAY_LAYERS,
filter: texture_array.filter,
layer_count: texture_array.layer_count as i32,
mode: RenderTargetMode::RenderTarget, // todo: !!!! remove me!?
},
};
@ -572,12 +619,10 @@ impl TextureCache {
let size = DeviceUintSize::new(descriptor.width, descriptor.height);
let frame_id = self.frame_id;
// TODO(gw): For now, anything that requests nearest filtering
// TODO(gw): For now, anything that requests nearest filtering and isn't BGRA8
// just fails to allocate in a texture page, and gets a standalone
// texture. This isn't ideal, as it causes lots of batch breaks,
// but is probably rare enough that it can be fixed up later (it's also
// fairly trivial to implement, just tedious).
if filter == TextureFilter::Nearest {
// texture. This is probably rare enough that it can be fixed up later.
if filter == TextureFilter::Nearest && descriptor.format != ImageFormat::BGRA8 {
allowed_in_shared_cache = false;
}
@ -591,14 +636,22 @@ impl TextureCache {
// If it's allowed in the cache, see if there is a spot for it.
if allowed_in_shared_cache {
new_cache_entry = self.allocate_from_shared_cache(&descriptor, user_data);
new_cache_entry = self.allocate_from_shared_cache(
&descriptor,
filter,
user_data
);
// If we failed to allocate in the shared cache, run an
// eviction cycle, and then try to allocate again.
if new_cache_entry.is_none() {
self.expire_old_shared_entries(&descriptor);
new_cache_entry = self.allocate_from_shared_cache(&descriptor, user_data);
new_cache_entry = self.allocate_from_shared_cache(
&descriptor,
filter,
user_data
);
}
}
@ -627,6 +680,7 @@ impl TextureCache {
texture_id,
size,
descriptor.format,
filter,
user_data,
frame_id,
));
@ -824,6 +878,8 @@ impl TextureRegion {
// each layer contains one or more regions that can act
// as slab allocators.
struct TextureArray {
filter: TextureFilter,
layer_count: usize,
format: ImageFormat,
is_allocated: bool,
regions: Vec<TextureRegion>,
@ -831,9 +887,15 @@ struct TextureArray {
}
impl TextureArray {
fn new(format: ImageFormat) -> TextureArray {
fn new(
format: ImageFormat,
filter: TextureFilter,
layer_count: usize
) -> TextureArray {
TextureArray {
format,
filter,
layer_count,
is_allocated: false,
regions: Vec::new(),
texture_id: None,
@ -842,9 +904,9 @@ impl TextureArray {
fn update_profile(&self, counter: &mut ResourceProfileCounter) {
if self.is_allocated {
let size = TEXTURE_ARRAY_LAYERS as u32 * TEXTURE_LAYER_DIMENSIONS *
let size = self.layer_count as u32 * TEXTURE_LAYER_DIMENSIONS *
TEXTURE_LAYER_DIMENSIONS * self.format.bytes_per_pixel();
counter.set(TEXTURE_ARRAY_LAYERS as usize, size as usize);
counter.set(self.layer_count as usize, size as usize);
} else {
counter.set(0, 0);
}
@ -864,15 +926,18 @@ impl TextureArray {
if !self.is_allocated {
debug_assert!(TEXTURE_LAYER_DIMENSIONS % TEXTURE_REGION_DIMENSIONS == 0);
let regions_per_axis = TEXTURE_LAYER_DIMENSIONS / TEXTURE_REGION_DIMENSIONS;
for layer_index in 0 .. TEXTURE_ARRAY_LAYERS {
for layer_index in 0 .. self.layer_count {
for y in 0 .. regions_per_axis {
for x in 0 .. regions_per_axis {
let origin = DeviceUintPoint::new(
x * TEXTURE_REGION_DIMENSIONS,
y * TEXTURE_REGION_DIMENSIONS,
);
let region =
TextureRegion::new(TEXTURE_REGION_DIMENSIONS, layer_index, origin);
let region = TextureRegion::new(
TEXTURE_REGION_DIMENSIONS,
layer_index as i32,
origin
);
self.regions.push(region);
}
}
@ -936,6 +1001,7 @@ impl TextureArray {
kind,
uv_rect_handle: GpuCacheHandle::new(),
format: self.format,
filter: self.filter,
texture_id: self.texture_id.unwrap(),
}
})

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

@ -5,8 +5,8 @@
use api::{BorderRadiusKind, ClipAndScrollInfo, ClipId, ColorF, DeviceIntPoint, ImageKey};
use api::{DeviceIntRect, DeviceIntSize, DeviceUintPoint, DeviceUintSize};
use api::{ExternalImageType, FilterOp, FontRenderMode, ImageRendering, LayerRect};
use api::{LayerToWorldTransform, MixBlendMode, PipelineId, PropertyBinding, TransformStyle};
use api::{LayerVector2D, TileOffset, WorldToLayerTransform, YuvColorSpace, YuvFormat};
use api::{MixBlendMode, PipelineId, PropertyBinding, TransformStyle};
use api::{LayerVector2D, TileOffset, YuvColorSpace, YuvFormat};
use border::{BorderCornerInstance, BorderCornerSide};
use clip::{ClipSource, ClipStore};
use clip_scroll_tree::CoordinateSystemId;
@ -15,7 +15,7 @@ use glyph_rasterizer::GlyphFormat;
use gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle, GpuCacheUpdateList};
use gpu_types::{BlurDirection, BlurInstance, BrushInstance, BrushImageKind, ClipMaskInstance};
use gpu_types::{CompositePrimitiveInstance, PrimitiveInstance, SimplePrimitiveInstance};
use gpu_types::{BRUSH_FLAG_USES_PICTURE};
use gpu_types::{BRUSH_FLAG_USES_PICTURE, ClipScrollNodeIndex, ClipScrollNodeData};
use internal_types::{FastHashMap, SourceTexture};
use internal_types::BatchTextures;
use picture::PictureKind;
@ -30,8 +30,7 @@ use renderer::ImageBufferKind;
use resource_cache::{GlyphFetchResult, ResourceCache};
use std::{cmp, usize, f32, i32};
use texture_allocator::GuillotineAllocator;
use util::{MatrixHelpers, TransformedRect, TransformedRectKind};
use euclid::rect;
use util::{MatrixHelpers, TransformedRectKind};
// Special sentinel value recognized by the shader. It is considered to be
// a dummy task that doesn't mask out anything.
@ -59,11 +58,15 @@ impl AlphaBatchHelpers for PrimitiveStore {
PrimitiveKind::TextRun => {
let font = &self.cpu_text_runs[metadata.cpu_prim_index.0].font;
match font.render_mode {
FontRenderMode::Subpixel => if font.bg_color.a != 0 {
FontRenderMode::Subpixel => {
if font.bg_color.a != 0 {
BlendMode::SubpixelWithBgColor
} else if font.color.a != 255 || metadata.clip_task_id.is_some() {
BlendMode::SubpixelWithAlpha
} else {
BlendMode::Subpixel
},
BlendMode::SubpixelOpaque(font.color)
}
}
FontRenderMode::Alpha |
FontRenderMode::Mono |
FontRenderMode::Bitmap => BlendMode::PremultipliedAlpha,
@ -157,14 +160,15 @@ impl AlphaBatchList {
) -> &mut Vec<PrimitiveInstance> {
let mut selected_batch_index = None;
match key.kind {
BatchKind::Composite { .. } => {
match (key.kind, key.blend_mode) {
(BatchKind::Composite { .. }, _) => {
// Composites always get added to their own batch.
// This is because the result of a composite can affect
// the input to the next composite. Perhaps we can
// optimize this in the future.
}
BatchKind::Transformable(_, TransformBatchKind::TextRun(_)) => {
(BatchKind::Transformable(_, TransformBatchKind::TextRun(_)), BlendMode::SubpixelWithBgColor) |
(BatchKind::Transformable(_, TransformBatchKind::TextRun(_)), BlendMode::SubpixelWithAlpha) => {
'outer_text: for (batch_index, batch) in self.batches.iter().enumerate().rev().take(10) {
// Subpixel text is drawn in two passes. Because of this, we need
// to check for overlaps with every batch (which is a bit different
@ -281,7 +285,9 @@ impl BatchList {
match key.blend_mode {
BlendMode::None => self.opaque_batch_list.get_suitable_batch(key),
BlendMode::Alpha | BlendMode::PremultipliedAlpha |
BlendMode::PremultipliedDestOut | BlendMode::Subpixel |
BlendMode::PremultipliedDestOut |
BlendMode::SubpixelOpaque(..) |
BlendMode::SubpixelWithAlpha |
BlendMode::SubpixelWithBgColor => {
self.alpha_batch_list
.get_suitable_batch(key, item_bounding_rect)
@ -346,6 +352,8 @@ impl AlphaRenderItem {
filter_mode,
amount,
z,
0,
0,
);
batch.push(PrimitiveInstance::from(instance));
@ -356,6 +364,7 @@ impl AlphaRenderItem {
composite_op,
screen_origin,
z,
dest_rect,
) => {
let stacking_context = &ctx.stacking_context_store[stacking_context_index.0];
let src_task_address = render_tasks.get_task_address(src_id);
@ -365,6 +374,11 @@ impl AlphaRenderItem {
BatchTextures::no_texture(),
);
let batch = batch_list.get_suitable_batch(key, &stacking_context.screen_bounds);
let dest_rect = if dest_rect.width > 0 && dest_rect.height > 0 {
dest_rect
} else {
render_tasks.get(src_id).get_dynamic_size()
};
let instance = CompositePrimitiveInstance::new(
task_address,
@ -373,6 +387,8 @@ impl AlphaRenderItem {
screen_origin.x,
screen_origin.y,
z,
dest_rect.width,
dest_rect.height,
);
batch.push(PrimitiveInstance::from(instance));
@ -399,20 +415,19 @@ impl AlphaRenderItem {
mode as u32 as i32,
0,
z,
0,
0,
);
batch.push(PrimitiveInstance::from(instance));
}
AlphaRenderItem::Primitive(clip_scroll_group_index_opt, prim_index, z) => {
AlphaRenderItem::Primitive(clip_id, scroll_id, prim_index, z) => {
let prim_metadata = ctx.prim_store.get_metadata(prim_index);
let (transform_kind, packed_layer_index) = match clip_scroll_group_index_opt {
Some(group_index) => {
let group = &ctx.clip_scroll_group_store[group_index.0];
let bounding_rect = group.screen_bounding_rect.as_ref().unwrap();
(bounding_rect.0, group.packed_layer_index)
}
None => (TransformedRectKind::AxisAligned, PackedLayerIndex(0)),
};
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 item_bounding_rect = prim_metadata.screen_rect.as_ref().unwrap();
let prim_cache_address = gpu_cache.get_address(&prim_metadata.gpu_location);
let no_textures = BatchTextures::no_texture();
@ -423,7 +438,8 @@ impl AlphaRenderItem {
prim_cache_address,
task_address,
clip_task_address,
packed_layer_index.into(),
clip_id,
scroll_id,
z,
);
@ -631,7 +647,8 @@ impl AlphaRenderItem {
let instance = BrushInstance {
picture_address: task_address,
prim_address: prim_cache_address,
layer_address: packed_layer_index.into(),
clip_id,
scroll_id,
clip_task_address,
z,
flags: 0,
@ -773,6 +790,8 @@ impl AlphaRenderItem {
gpu_address,
0,
z,
0,
0,
);
batch.push(PrimitiveInstance::from(instance));
@ -864,7 +883,7 @@ impl ClipBatcher {
for work_item in clips.iter() {
let instance = ClipMaskInstance {
render_task_address: task_address,
layer_address: work_item.layer_index.into(),
scroll_node_id: work_item.scroll_node_id,
segment: 0,
clip_data_address: GpuCacheAddress::invalid(),
resource_address: GpuCacheAddress::invalid(),
@ -956,9 +975,9 @@ impl ClipBatcher {
pub struct RenderTargetContext<'a> {
pub device_pixel_ratio: f32,
pub stacking_context_store: &'a [StackingContext],
pub clip_scroll_group_store: &'a [ClipScrollGroup],
pub prim_store: &'a PrimitiveStore,
pub resource_cache: &'a ResourceCache,
pub node_data: &'a [ClipScrollNodeData],
}
struct TextureAllocator {
@ -1109,6 +1128,11 @@ pub struct FrameOutput {
pub pipeline_id: PipelineId,
}
pub struct ScalingInfo {
pub src_task_id: RenderTaskId,
pub dest_task_id: RenderTaskId,
}
/// A render target represents a number of rendering operations on a surface.
pub struct ColorRenderTarget {
pub alpha_batcher: AlphaBatcher,
@ -1119,6 +1143,7 @@ pub struct ColorRenderTarget {
pub vertical_blurs: Vec<BlurInstance>,
pub horizontal_blurs: Vec<BlurInstance>,
pub readbacks: Vec<DeviceIntRect>,
pub scalings: Vec<ScalingInfo>,
// List of frame buffer outputs for this render target.
pub outputs: Vec<FrameOutput>,
allocator: Option<TextureAllocator>,
@ -1141,6 +1166,7 @@ impl RenderTarget for ColorRenderTarget {
vertical_blurs: Vec::new(),
horizontal_blurs: Vec::new(),
readbacks: Vec::new(),
scalings: Vec::new(),
allocator: size.map(|size| TextureAllocator::new(size)),
glyph_fetch_buffer: Vec::new(),
outputs: Vec::new(),
@ -1228,7 +1254,8 @@ impl RenderTarget for ColorRenderTarget {
sub_prim_address,
task_index,
RenderTaskAddress(0),
PackedLayerIndex(0).into(),
ClipScrollNodeIndex(0),
ClipScrollNodeIndex(0),
0,
); // z is disabled for rendering cache primitives
@ -1286,6 +1313,12 @@ impl RenderTarget for ColorRenderTarget {
RenderTaskKind::Readback(device_rect) => {
self.readbacks.push(device_rect);
}
RenderTaskKind::Scaling(..) => {
self.scalings.push(ScalingInfo {
src_task_id: task.children[0],
dest_task_id: task_id,
});
}
}
}
}
@ -1297,6 +1330,7 @@ pub struct AlphaRenderTarget {
// List of blur operations to apply for this render target.
pub vertical_blurs: Vec<BlurInstance>,
pub horizontal_blurs: Vec<BlurInstance>,
pub scalings: Vec<ScalingInfo>,
pub zero_clears: Vec<RenderTaskId>,
allocator: TextureAllocator,
}
@ -1313,6 +1347,7 @@ impl RenderTarget for AlphaRenderTarget {
brush_mask_rounded_rects: Vec::new(),
vertical_blurs: Vec::new(),
horizontal_blurs: Vec::new(),
scalings: Vec::new(),
zero_clears: Vec::new(),
allocator: TextureAllocator::new(size.expect("bug: alpha targets need size")),
}
@ -1395,7 +1430,8 @@ impl RenderTarget for AlphaRenderTarget {
// tasks support clip masks and
// transform primitives, these
// will need to be filled out!
layer_address: PackedLayerIndex(0).into(),
clip_id: ClipScrollNodeIndex(0),
scroll_id: ClipScrollNodeIndex(0),
clip_task_address: RenderTaskAddress(0),
z: 0,
flags: BRUSH_FLAG_USES_PICTURE,
@ -1438,6 +1474,12 @@ impl RenderTarget for AlphaRenderTarget {
clip_store,
);
}
RenderTaskKind::Scaling(..) => {
self.scalings.push(ScalingInfo {
src_task_id: task.children[0],
dest_task_id: task_id,
});
}
}
}
}
@ -1700,9 +1742,6 @@ impl OpaquePrimitiveBatch {
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct PackedLayerIndex(pub usize);
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct StackingContextIndex(pub usize);
@ -1808,73 +1847,6 @@ impl StackingContext {
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct ClipScrollGroupIndex(pub usize, pub ClipAndScrollInfo);
#[derive(Debug)]
pub struct ClipScrollGroup {
pub scroll_node_id: ClipId,
pub clip_node_id: ClipId,
pub packed_layer_index: PackedLayerIndex,
pub screen_bounding_rect: Option<(TransformedRectKind, DeviceIntRect)>,
pub coordinate_system_id: CoordinateSystemId,
}
impl ClipScrollGroup {
pub fn is_visible(&self) -> bool {
self.screen_bounding_rect.is_some()
}
}
#[derive(Debug, Clone)]
#[repr(C)]
pub struct PackedLayer {
pub transform: LayerToWorldTransform,
pub inv_transform: WorldToLayerTransform,
pub local_clip_rect: LayerRect,
}
impl PackedLayer {
pub fn empty() -> PackedLayer {
PackedLayer {
transform: LayerToWorldTransform::identity(),
inv_transform: WorldToLayerTransform::identity(),
local_clip_rect: LayerRect::zero(),
}
}
pub fn set_transform(&mut self, transform: LayerToWorldTransform) -> bool {
self.transform = transform;
match self.transform.inverse() {
Some(inv) => {
self.inv_transform = inv;
true
}
None => false,
}
}
pub fn set_rect(
&mut self,
local_rect: &LayerRect,
screen_rect: &DeviceIntRect,
device_pixel_ratio: f32,
) -> Option<(TransformedRectKind, DeviceIntRect)> {
self.local_clip_rect = if self.transform.has_perspective_component() {
// Given a very large rect which means any rect would be inside this rect.
// That is, nothing would be clipped.
rect(f32::MIN / 2.0, f32::MIN / 2.0, f32::MAX, f32::MAX)
} else {
*local_rect
};
let xf_rect = TransformedRect::new(local_rect, &self.transform, device_pixel_ratio);
xf_rect
.bounding_rect
.intersection(screen_rect)
.map(|rect| (xf_rect.kind, rect))
}
}
#[derive(Debug, Clone, Default)]
pub struct CompositeOps {
// Requires only a single texture as input (e.g. most filters)
@ -1915,8 +1887,7 @@ pub struct Frame {
pub passes: Vec<RenderPass>,
pub profile_counters: FrameProfileCounters,
pub layer_texture_data: Vec<PackedLayer>,
pub node_data: Vec<ClipScrollNodeData>,
pub render_tasks: RenderTaskTree,
// List of updates that need to be pushed to the

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

@ -22,6 +22,7 @@ pub trait MatrixHelpers<Src, Dst> {
fn has_perspective_component(&self) -> bool;
fn inverse_project(&self, target: &TypedPoint2D<f32, Dst>) -> Option<TypedPoint2D<f32, Src>>;
fn inverse_rect_footprint(&self, rect: &TypedRect<f32, Dst>) -> TypedRect<f32, Src>;
fn transform_kind(&self) -> TransformedRectKind;
}
impl<Src, Dst> MatrixHelpers<Src, Dst> for TypedTransform3D<f32, Src, Dst> {
@ -98,6 +99,14 @@ impl<Src, Dst> MatrixHelpers<Src, Dst> for TypedTransform3D<f32, Src, Dst> {
.unwrap_or(TypedPoint2D::zero()),
])
}
fn transform_kind(&self) -> TransformedRectKind {
if self.preserves_2d_axis_alignment() {
TransformedRectKind::AxisAligned
} else {
TransformedRectKind::Complex
}
}
}
pub trait RectHelpers<U>

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше