diff --git a/.concierge/templates/pullRequestOpened.hbs b/.concierge/templates/pullRequestOpened.hbs
index 8408c266f8ab..f5dbb8aa6364 100644
--- a/.concierge/templates/pullRequestOpened.hbs
+++ b/.concierge/templates/pullRequestOpened.hbs
@@ -12,6 +12,7 @@ Thanks for the pull request @{{ userName }}!
{{#if errorCla}}
* :grey_exclamation: There was an error checking the CLA! If this is your first contribution, please send in a [Contributor License Agreement](https://github.com/CesiumGS/cesium/blob/master/CONTRIBUTING.md#contributor-license-agreement-cla).
* Maintainers, this was the error I ran into while attempting to process the CLA check. Please resolve it to continue CLA checking.
+ * You'll need to [manually check for a submitted CLA](https://github.com/CesiumGS/cesium/blob/master/Documentation/Contributors/CLAs/README.md)
```
{{ errorCla }}
```
@@ -19,6 +20,7 @@ Thanks for the pull request @{{ userName }}!
{{#if askForCla}}
* :x: Missing CLA.
* Please send in a [Contributor License Agreement](https://github.com/CesiumGS/cesium/blob/master/CONTRIBUTING.md#contributor-license-agreement-cla) (CLA) and comment back here to let us know to check this!
+ * Maintainers, [here's how to check](https://github.com/CesiumGS/cesium/blob/master/Documentation/Contributors/CLAs/README.md) for a submitted CLA.
{{else}}
* :heavy_check_mark: Signed CLA found.
{{/if}}
diff --git a/.eslintignore b/.eslintignore
index f6d729a51549..6f4e8d9c4532 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -12,3 +12,4 @@ Apps/Sandcastle/jsHintOptions.js
Apps/Sandcastle/gallery/gallery-index.js
Source/Core/buildModuleUrl.js
Specs/spec-main.js
+index.release.html
\ No newline at end of file
diff --git a/.eslintrc.json b/.eslintrc.json
index 9cdd09c0f44a..ce574a6c8ea1 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -1,22 +1,13 @@
{
- "extends": ["./Tools/eslint-config-cesium/browser.js", "prettier"],
- "plugins": [
- "html"
+ "extends": [
+ "./Tools/eslint-config-cesium/node.js",
+ "prettier"
],
- "rules": {
- "no-unused-vars": ["error", {"vars": "all", "args": "none"}]
+ "env": {
+ "node": true,
+ "es6": true
},
- "overrides": [
- {
- "files": [
- "index.cjs",
- "server.cjs",
- "gulpfile.js",
- "Source/Workers/transferTypedArrayTest.js"
- ],
- "parserOptions": {
- "sourceType": "script"
- }
- }
- ]
+ "parserOptions": {
+ "ecmaVersion": 2019
+ }
}
diff --git a/.gitignore b/.gitignore
index 240b38f501bf..004aac89e86e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -32,3 +32,4 @@ yarn.lock
# WebStorm user-specific
.idea/workspace.xml
.idea/tasks.xml
+.idea/shelf
diff --git a/.npmignore b/.npmignore
index b6218280c65f..1cb3f6eb5ce5 100644
--- a/.npmignore
+++ b/.npmignore
@@ -19,7 +19,7 @@
/Cesium-*.zip
/Documentation
/favicon.ico
-/gulpfile.js
+/gulpfile.cjs
/index.html
/index.release.html
/launches
diff --git a/.slackbot.yml b/.slackbot.yml
index 3b5002c95827..8265ca44697d 100644
--- a/.slackbot.yml
+++ b/.slackbot.yml
@@ -1,12 +1,14 @@
# List of Slack usernames (not GitHub) for the Cesium Concierge Slackbot to send release reminders for.
releaseSchedule:
- mamato: 3/2/2020
- oshehata: 4/1/2020
- lilleyse: 5/1/2020
- ian: 6/1/2020
- sam.suhag: 7/1/2020
- sam.vargas: 8/3/2020
- kevin: 9/1/2020
- mamato: 10/1/2020
- oshehata: 11/2/2020
- lilleyse: 12/1/2020
+ - gary, 1/4/2021
+ - ian, 2/1/2021
+ - kevin, 3/1/2021
+ - sam.vargas, 4/1/2021
+ - mamato, 5/3/2021
+ - oshehata, 6/1/2021
+ - bao, 7/1/2021
+ - lilleyse, 8/2/2021
+ - sam.suhag, 9/1/2021
+ - peter, 10/1/2021
+ - eli, 11/1/2021
+ - erixen, 12/1/2021
diff --git a/Apps/.eslintrc.json b/Apps/.eslintrc.json
new file mode 100644
index 000000000000..ae9a392652a3
--- /dev/null
+++ b/Apps/.eslintrc.json
@@ -0,0 +1,3 @@
+{
+ "extends": "../Source/.eslintrc.json"
+}
diff --git a/Apps/SampleData/models/CesiumDrone/CesiumDrone.glb b/Apps/SampleData/models/CesiumDrone/CesiumDrone.glb
new file mode 100644
index 000000000000..22dbdc0b2337
Binary files /dev/null and b/Apps/SampleData/models/CesiumDrone/CesiumDrone.glb differ
diff --git a/Apps/SampleData/models/GroundVehicle/GroundVehicle.glb b/Apps/SampleData/models/GroundVehicle/GroundVehicle.glb
index bef189903265..dd7671587de1 100644
Binary files a/Apps/SampleData/models/GroundVehicle/GroundVehicle.glb and b/Apps/SampleData/models/GroundVehicle/GroundVehicle.glb differ
diff --git a/Apps/Sandcastle/.eslintrc.json b/Apps/Sandcastle/.eslintrc.json
index deade47938cb..9b032d1d2e7d 100644
--- a/Apps/Sandcastle/.eslintrc.json
+++ b/Apps/Sandcastle/.eslintrc.json
@@ -1,5 +1,5 @@
{
- "extends": "../../.eslintrc.json",
+ "extends": "../.eslintrc.json",
"env": {
"amd": true
},
diff --git a/Apps/Sandcastle/CesiumSandcastle.js b/Apps/Sandcastle/CesiumSandcastle.js
index c3d282189683..5c4a3f2dfb0a 100644
--- a/Apps/Sandcastle/CesiumSandcastle.js
+++ b/Apps/Sandcastle/CesiumSandcastle.js
@@ -48,7 +48,6 @@ require({
"dojo/promise/all",
"dojo/query",
"dojo/when",
- "dojo/Deferred",
"dojo/request/script",
"Sandcastle/LinkButton",
"ThirdParty/clipboard.min",
@@ -94,7 +93,6 @@ require({
all,
query,
when,
- Deferred,
dojoscript,
LinkButton,
ClipboardJS,
@@ -853,51 +851,45 @@ require({
var parser = new DOMParser();
var doc = parser.parseFromString(demo.code, "text/html");
- return waitForDoc(doc, function () {
- return doc.querySelector('script[id="cesium_sandcastle_script"]');
- }).then(function () {
- var script = doc.querySelector(
- 'script[id="cesium_sandcastle_script"]'
+ var script = doc.querySelector('script[id="cesium_sandcastle_script"]');
+ if (!script) {
+ appendConsole(
+ "consoleError",
+ "Error reading source file: " + demo.name,
+ true
);
- if (!script) {
- appendConsole(
- "consoleError",
- "Error reading source file: " + demo.name,
- true
- );
- return;
- }
+ return;
+ }
- var scriptMatch = scriptCodeRegex.exec(script.textContent);
- if (!scriptMatch) {
- appendConsole(
- "consoleError",
- "Error reading source file: " + demo.name,
- true
- );
- return;
- }
+ var scriptMatch = scriptCodeRegex.exec(script.textContent);
+ if (!scriptMatch) {
+ appendConsole(
+ "consoleError",
+ "Error reading source file: " + demo.name,
+ true
+ );
+ return;
+ }
- var scriptCode = scriptMatch[1];
- scriptCode = scriptCode.replace(/^ {8}/gm, ""); //Account for Prettier spacing
+ var scriptCode = scriptMatch[1];
+ scriptCode = scriptCode.replace(/^ {8}/gm, ""); //Account for Prettier spacing
- var htmlText = "";
- var childIndex = 0;
- var childNode = doc.body.childNodes[childIndex];
- while (
- childIndex < doc.body.childNodes.length &&
- childNode !== script
- ) {
- htmlText +=
- childNode.nodeType === 1
- ? childNode.outerHTML
- : childNode.nodeValue;
- childNode = doc.body.childNodes[++childIndex];
- }
- htmlText = htmlText.replace(/^\s+/, "");
+ var htmlText = "";
+ var childIndex = 0;
+ var childNode = doc.body.childNodes[childIndex];
+ while (
+ childIndex < doc.body.childNodes.length &&
+ childNode !== script
+ ) {
+ htmlText +=
+ childNode.nodeType === 1
+ ? childNode.outerHTML
+ : childNode.nodeValue;
+ childNode = doc.body.childNodes[++childIndex];
+ }
+ htmlText = htmlText.replace(/^\s+/, "");
- applyLoadedDemo(scriptCode, htmlText);
- });
+ applyLoadedDemo(scriptCode, htmlText);
}
});
}
@@ -1232,82 +1224,57 @@ require({
});
}
- // Work around Chrome 79 bug: https://github.com/CesiumGS/cesium/issues/8460
- function waitForDoc(doc, test) {
- var deferred = new Deferred();
- if (test()) {
- deferred.resolve(doc);
- } else {
- var counter = 1;
- setTimeout(function () {
- if (test() || counter++ > 10) {
- deferred.resolve(doc);
- }
- }, 100 * counter);
- }
- return deferred.promise;
- }
-
var newInLabel = "New in " + VERSION;
function loadDemoFromFile(demo) {
- return requestDemo(demo.name)
- .then(function (value) {
- // Store the file contents for later searching.
- demo.code = value;
+ return requestDemo(demo.name).then(function (value) {
+ // Store the file contents for later searching.
+ demo.code = value;
- var parser = new DOMParser();
- var doc = parser.parseFromString(value, "text/html");
- return waitForDoc(doc, function () {
- return doc.body.getAttribute("data-sandcastle-bucket");
- });
- })
- .then(function (doc) {
- var bucket = doc.body.getAttribute("data-sandcastle-bucket");
- demo.bucket = bucket ? bucket : "bucket-requirejs.html";
-
- var descriptionMeta = doc.querySelector('meta[name="description"]');
- var description =
- descriptionMeta && descriptionMeta.getAttribute("content");
- demo.description = description ? description : "";
-
- var labelsMeta = doc.querySelector(
- 'meta[name="cesium-sandcastle-labels"]'
- );
- var labels = labelsMeta && labelsMeta.getAttribute("content");
- if (demo.isNew) {
- demo.label = labels ? labels + "," + newInLabel : newInLabel;
- } else {
- demo.label = labels ? labels : "";
- }
+ var parser = new DOMParser();
+ var doc = parser.parseFromString(value, "text/html");
- // Select the demo to load upon opening based on the query parameter.
- if (defined(queryObject.src)) {
- if (demo.name === queryObject.src.replace(".html", "")) {
- loadFromGallery(demo).then(function () {
- window.history.replaceState(
- demo,
- demo.name,
- getPushStateUrl(demo)
- );
- if (defined(queryObject.gist)) {
- document.title = "Gist Import - Cesium Sandcastle";
- } else {
- document.title = demo.name + " - Cesium Sandcastle";
- }
- });
- }
- }
+ var bucket = doc.body.getAttribute("data-sandcastle-bucket");
+ demo.bucket = bucket ? bucket : "bucket-requirejs.html";
- // Create a tooltip containing the demo's description.
- demoTooltips[demo.name] = new TooltipDialog({
- id: demo.name + "TooltipDialog",
- style: "width: 200px; font-size: 12px;",
- content: demo.description.replace(/\\n/g, "
"),
- });
+ var descriptionMeta = doc.querySelector('meta[name="description"]');
+ var description =
+ descriptionMeta && descriptionMeta.getAttribute("content");
+ demo.description = description ? description : "";
- addFileToTab(demo);
- return demo;
+ var labelsMeta = doc.querySelector(
+ 'meta[name="cesium-sandcastle-labels"]'
+ );
+ var labels = labelsMeta && labelsMeta.getAttribute("content");
+ if (demo.isNew) {
+ demo.label = labels ? labels + "," + newInLabel : newInLabel;
+ } else {
+ demo.label = labels ? labels : "";
+ }
+
+ // Select the demo to load upon opening based on the query parameter.
+ if (defined(queryObject.src)) {
+ if (demo.name === queryObject.src.replace(".html", "")) {
+ loadFromGallery(demo).then(function () {
+ window.history.replaceState(demo, demo.name, getPushStateUrl(demo));
+ if (defined(queryObject.gist)) {
+ document.title = "Gist Import - Cesium Sandcastle";
+ } else {
+ document.title = demo.name + " - Cesium Sandcastle";
+ }
+ });
+ }
+ }
+
+ // Create a tooltip containing the demo's description.
+ demoTooltips[demo.name] = new TooltipDialog({
+ id: demo.name + "TooltipDialog",
+ style: "width: 200px; font-size: 12px;",
+ content: demo.description.replace(/\\n/g, "
"),
});
+
+ addFileToTab(demo);
+ return demo;
+ });
}
var loading = true;
diff --git a/Apps/Sandcastle/gallery/3D Models.html b/Apps/Sandcastle/gallery/3D Models.html
index 1db0cc2d8d10..3172c1023b00 100644
--- a/Apps/Sandcastle/gallery/3D Models.html
+++ b/Apps/Sandcastle/gallery/3D Models.html
@@ -79,6 +79,15 @@
);
},
},
+ {
+ text: "Drone",
+ onselect: function () {
+ createModel(
+ "../../SampleData/models/CesiumDrone/CesiumDrone.glb",
+ 150.0
+ );
+ },
+ },
{
text: "Ground Vehicle",
onselect: function () {
diff --git a/Apps/Sandcastle/gallery/3D Tiles Clipping Planes.html b/Apps/Sandcastle/gallery/3D Tiles Clipping Planes.html
index b364c68412eb..a542d9fd663e 100644
--- a/Apps/Sandcastle/gallery/3D Tiles Clipping Planes.html
+++ b/Apps/Sandcastle/gallery/3D Tiles Clipping Planes.html
@@ -71,7 +71,6 @@
var viewer = new Cesium.Viewer("cesiumContainer", {
infoBox: false,
selectionIndicator: false,
- terrainProvider: Cesium.createWorldTerrain(),
});
var scene = viewer.scene;
diff --git a/Apps/Sandcastle/gallery/3D Tiles Feature Styling.html b/Apps/Sandcastle/gallery/3D Tiles Feature Styling.html
index 7065ceb67727..38873972a130 100644
--- a/Apps/Sandcastle/gallery/3D Tiles Feature Styling.html
+++ b/Apps/Sandcastle/gallery/3D Tiles Feature Styling.html
@@ -2,14 +2,16 @@
Click on a building to select as the central location | +
Background Transparency | ++ + | +
Band Transparency | ++ + | +
Band Thickness | ++ + | +
Band 1 Position | ++ + | +
Band 2 Position | ++ + | +
Band 3 Position | ++ + | +
Gradient | ++ + | +
Intersect.INTESECTING
if the rectangles intersect, Intersect.OUTSIDE
otherwise.
+ * @returns {Intersect} Intersect.INTERSECTING
if the rectangles intersect, Intersect.OUTSIDE
otherwise.
*/
BoundingRectangle.intersect = function (left, right) {
//>>includeStart('debug', pragmas.debug);
@@ -354,7 +354,7 @@ BoundingRectangle.prototype.clone = function (result) {
* Determines if this rectangle intersects with another.
*
* @param {BoundingRectangle} right A rectangle to check for intersection.
- * @returns {Intersect} Intersect.INTESECTING
if the rectangles intersect, Intersect.OUTSIDE
otherwise.
+ * @returns {Intersect} Intersect.INTERSECTING
if the rectangles intersect, Intersect.OUTSIDE
otherwise.
*/
BoundingRectangle.prototype.intersect = function (right) {
return BoundingRectangle.intersect(this, right);
diff --git a/Source/Core/Cartesian2.js b/Source/Core/Cartesian2.js
index 64a5ca0422bf..986b109eb4f4 100644
--- a/Source/Core/Cartesian2.js
+++ b/Source/Core/Cartesian2.js
@@ -406,6 +406,22 @@ Cartesian2.dot = function (left, right) {
return left.x * right.x + left.y * right.y;
};
+/**
+ * Computes the magnitude of the cross product that would result from implicitly setting the Z coordinate of the input vectors to 0
+ *
+ * @param {Cartesian2} left The first Cartesian.
+ * @param {Cartesian2} right The second Cartesian.
+ * @returns {Number} The cross product.
+ */
+Cartesian2.cross = function (left, right) {
+ //>>includeStart('debug', pragmas.debug);
+ Check.typeOf.object("left", left);
+ Check.typeOf.object("right", right);
+ //>>includeEnd('debug');
+
+ return left.x * right.y - left.y * right.x;
+};
+
/**
* Computes the componentwise product of two Cartesians.
*
diff --git a/Source/Core/Cartesian4.js b/Source/Core/Cartesian4.js
index 3309b0749536..1c639db14a30 100644
--- a/Source/Core/Cartesian4.js
+++ b/Source/Core/Cartesian4.js
@@ -869,21 +869,18 @@ Cartesian4.prototype.toString = function () {
return "(" + this.x + ", " + this.y + ", " + this.z + ", " + this.w + ")";
};
-var scratchFloatArray = new Float32Array(1);
-var SHIFT_LEFT_8 = 256.0;
-var SHIFT_LEFT_16 = 65536.0;
-var SHIFT_LEFT_24 = 16777216.0;
+// scratchU8Array and scratchF32Array are views into the same buffer
+var scratchF32Array = new Float32Array(1);
+var scratchU8Array = new Uint8Array(scratchF32Array.buffer);
-var SHIFT_RIGHT_8 = 1.0 / SHIFT_LEFT_8;
-var SHIFT_RIGHT_16 = 1.0 / SHIFT_LEFT_16;
-var SHIFT_RIGHT_24 = 1.0 / SHIFT_LEFT_24;
-
-var BIAS = 38.0;
+var testU32 = new Uint32Array([0x11223344]);
+var testU8 = new Uint8Array(testU32.buffer);
+var littleEndian = testU8[0] === 0x44;
/**
* Packs an arbitrary floating point value to 4 values representable using uint8.
*
- * @param {Number} value A floating point number
+ * @param {Number} value A floating point number.
* @param {Cartesian4} [result] The Cartesian4 that will contain the packed float.
* @returns {Cartesian4} A Cartesian4 representing the float packed to values in x, y, z, and w.
*/
@@ -896,34 +893,21 @@ Cartesian4.packFloat = function (value, result) {
result = new Cartesian4();
}
- // Force the value to 32 bit precision
- scratchFloatArray[0] = value;
- value = scratchFloatArray[0];
-
- if (value === 0.0) {
- return Cartesian4.clone(Cartesian4.ZERO, result);
- }
-
- var sign = value < 0.0 ? 1.0 : 0.0;
- var exponent;
+ // scratchU8Array and scratchF32Array are views into the same buffer
+ scratchF32Array[0] = value;
- if (!isFinite(value)) {
- value = 0.1;
- exponent = BIAS;
+ if (littleEndian) {
+ result.x = scratchU8Array[0];
+ result.y = scratchU8Array[1];
+ result.z = scratchU8Array[2];
+ result.w = scratchU8Array[3];
} else {
- value = Math.abs(value);
- exponent = Math.floor(CesiumMath.logBase(value, 10)) + 1.0;
- value = value / Math.pow(10.0, exponent);
+ // convert from big-endian to little-endian
+ result.x = scratchU8Array[3];
+ result.y = scratchU8Array[2];
+ result.z = scratchU8Array[1];
+ result.w = scratchU8Array[0];
}
-
- var temp = value * SHIFT_LEFT_8;
- result.x = Math.floor(temp);
- temp = (temp - result.x) * SHIFT_LEFT_8;
- result.y = Math.floor(temp);
- temp = (temp - result.y) * SHIFT_LEFT_8;
- result.z = Math.floor(temp);
- result.w = (exponent + BIAS) * 2.0 + sign;
-
return result;
};
@@ -939,22 +923,19 @@ Cartesian4.unpackFloat = function (packedFloat) {
Check.typeOf.object("packedFloat", packedFloat);
//>>includeEnd('debug');
- var temp = packedFloat.w / 2.0;
- var exponent = Math.floor(temp);
- var sign = (temp - exponent) * 2.0;
- exponent = exponent - BIAS;
-
- sign = sign * 2.0 - 1.0;
- sign = -sign;
-
- if (exponent >= BIAS) {
- return sign < 0.0 ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY;
+ // scratchU8Array and scratchF32Array are views into the same buffer
+ if (littleEndian) {
+ scratchU8Array[0] = packedFloat.x;
+ scratchU8Array[1] = packedFloat.y;
+ scratchU8Array[2] = packedFloat.z;
+ scratchU8Array[3] = packedFloat.w;
+ } else {
+ // convert from little-endian to big-endian
+ scratchU8Array[0] = packedFloat.w;
+ scratchU8Array[1] = packedFloat.z;
+ scratchU8Array[2] = packedFloat.y;
+ scratchU8Array[3] = packedFloat.x;
}
-
- var unpacked = sign * packedFloat.x * SHIFT_RIGHT_8;
- unpacked += sign * packedFloat.y * SHIFT_RIGHT_16;
- unpacked += sign * packedFloat.z * SHIFT_RIGHT_24;
-
- return unpacked * Math.pow(10.0, exponent);
+ return scratchF32Array[0];
};
export default Cartesian4;
diff --git a/Source/Core/CesiumTerrainProvider.js b/Source/Core/CesiumTerrainProvider.js
index d4c9b9da8322..201bd9eb8c40 100644
--- a/Source/Core/CesiumTerrainProvider.js
+++ b/Source/Core/CesiumTerrainProvider.js
@@ -9,7 +9,7 @@ import DeveloperError from "./DeveloperError.js";
import Event from "./Event.js";
import GeographicTilingScheme from "./GeographicTilingScheme.js";
import WebMercatorTilingScheme from "./WebMercatorTilingScheme.js";
-import getStringFromTypedArray from "./getStringFromTypedArray.js";
+import getJsonFromTypedArray from "./getJsonFromTypedArray.js";
import HeightmapTerrainData from "./HeightmapTerrainData.js";
import IndexDatatype from "./IndexDatatype.js";
import OrientedBoundingBox from "./OrientedBoundingBox.js";
@@ -34,7 +34,6 @@ function LayerInformation(layer) {
this.availabilityLevels = layer.availabilityLevels;
this.availabilityTilesLoaded = layer.availabilityTilesLoaded;
this.littleEndianExtensionSize = layer.littleEndianExtensionSize;
- this.availabilityTilesLoaded = layer.availabilityTilesLoaded;
this.availabilityPromiseCache = {};
}
@@ -711,12 +710,11 @@ function createQuantizedMeshTerrainData(provider, buffer, level, x, y, layer) {
) {
var stringLength = view.getUint32(pos, true);
if (stringLength > 0) {
- var jsonString = getStringFromTypedArray(
+ var metadata = getJsonFromTypedArray(
new Uint8Array(buffer),
pos + Uint32Array.BYTES_PER_ELEMENT,
stringLength
);
- var metadata = JSON.parse(jsonString);
var availableTiles = metadata.available;
if (defined(availableTiles)) {
for (var offset = 0; offset < availableTiles.length; ++offset) {
diff --git a/Source/Core/EasingFunction.js b/Source/Core/EasingFunction.js
index c38aeddabad7..4521fda30d61 100644
--- a/Source/Core/EasingFunction.js
+++ b/Source/Core/EasingFunction.js
@@ -22,21 +22,21 @@ var EasingFunction = {
* @type {EasingFunction.Callback}
* @constant
*/
- QUADRACTIC_IN: Tween.Easing.Quadratic.In,
+ QUADRATIC_IN: Tween.Easing.Quadratic.In,
/**
* Quadratic out.
*
* @type {EasingFunction.Callback}
* @constant
*/
- QUADRACTIC_OUT: Tween.Easing.Quadratic.Out,
+ QUADRATIC_OUT: Tween.Easing.Quadratic.Out,
/**
* Quadratic in then out.
*
* @type {EasingFunction.Callback}
* @constant
*/
- QUADRACTIC_IN_OUT: Tween.Easing.Quadratic.InOut,
+ QUADRATIC_IN_OUT: Tween.Easing.Quadratic.InOut,
/**
* Cubic in.
@@ -253,4 +253,5 @@ var EasingFunction = {
* return time * (2.0 - time);
* }
*/
+
export default Object.freeze(EasingFunction);
diff --git a/Source/Core/Ellipsoid.js b/Source/Core/Ellipsoid.js
index 2b565cbef675..b3ad7ba36b18 100644
--- a/Source/Core/Ellipsoid.js
+++ b/Source/Core/Ellipsoid.js
@@ -359,7 +359,7 @@ Ellipsoid.prototype.geodeticSurfaceNormalCartographic = function (
*
* @param {Cartesian3} cartesian The Cartesian position for which to to determine the surface normal.
* @param {Cartesian3} [result] The object onto which to store the result.
- * @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if none was provided.
+ * @returns {Cartesian3} The modified result parameter or a new Cartesian3 instance if none was provided, or undefined if a normal cannot be found.
*/
Ellipsoid.prototype.geodeticSurfaceNormal = function (cartesian, result) {
if (
diff --git a/Source/Core/EllipsoidGeodesic.js b/Source/Core/EllipsoidGeodesic.js
index 29272cf19e99..bc4720b93212 100644
--- a/Source/Core/EllipsoidGeodesic.js
+++ b/Source/Core/EllipsoidGeodesic.js
@@ -171,7 +171,7 @@ function vincentyInverseFormula(
cosineTwiceSigmaMidpoint = cosineSigma - (2.0 * ss) / cosineSquaredAlpha;
- if (isNaN(cosineTwiceSigmaMidpoint)) {
+ if (!isFinite(cosineTwiceSigmaMidpoint)) {
cosineTwiceSigmaMidpoint = 0.0;
}
diff --git a/Source/Core/EllipsoidTangentPlane.js b/Source/Core/EllipsoidTangentPlane.js
index 254e2891e27a..f0393ba95470 100644
--- a/Source/Core/EllipsoidTangentPlane.js
+++ b/Source/Core/EllipsoidTangentPlane.js
@@ -137,6 +137,7 @@ var tmp = new AxisAlignedBoundingBox();
*
* @param {Cartesian3[]} cartesians The list of positions surrounding the center point.
* @param {Ellipsoid} [ellipsoid=Ellipsoid.WGS84] The ellipsoid to use.
+ * @returns {EllipsoidTangentPlane} The new instance of EllipsoidTangentPlane.
*/
EllipsoidTangentPlane.fromPoints = function (cartesians, ellipsoid) {
//>>includeStart('debug', pragmas.debug);
diff --git a/Source/Core/EncodedCartesian3.js b/Source/Core/EncodedCartesian3.js
index ca0af127a89d..07b2d0561a7d 100644
--- a/Source/Core/EncodedCartesian3.js
+++ b/Source/Core/EncodedCartesian3.js
@@ -84,7 +84,7 @@ var scratchEncode = {
* Encodes a {@link Cartesian3} with 64-bit floating-point components as two {@link Cartesian3}
* values that, when converted to 32-bit floating-point and added, approximate the original input.
* - * The fixed-point encoding follows {@link http://blogs.agi.com/insight3d/index.php/2008/09/03/precisions-precisions/|Precisions, Precisions}. + * The fixed-point encoding follows {@link https://help.agi.com/AGIComponents/html/BlogPrecisionsPrecisions.htm|Precisions, Precisions}. *
* * @param {Cartesian3} cartesian The cartesian to encode. diff --git a/Source/Core/GoogleEarthEnterpriseMetadata.js b/Source/Core/GoogleEarthEnterpriseMetadata.js index da939555ae1c..feff17a4497f 100644 --- a/Source/Core/GoogleEarthEnterpriseMetadata.js +++ b/Source/Core/GoogleEarthEnterpriseMetadata.js @@ -291,10 +291,7 @@ GoogleEarthEnterpriseMetadata.prototype.isValid = function (quadKey) { return valid; }; -var taskProcessor = new TaskProcessor( - "decodeGoogleEarthEnterprisePacket", - Number.POSITIVE_INFINITY -); +var taskProcessor = new TaskProcessor("decodeGoogleEarthEnterprisePacket"); /** * Retrieves a Google Earth Enterprise quadtree packet. diff --git a/Source/Core/GoogleEarthEnterpriseTerrainData.js b/Source/Core/GoogleEarthEnterpriseTerrainData.js index f8137464e24f..c743ebf09e63 100644 --- a/Source/Core/GoogleEarthEnterpriseTerrainData.js +++ b/Source/Core/GoogleEarthEnterpriseTerrainData.js @@ -12,6 +12,7 @@ import OrientedBoundingBox from "./OrientedBoundingBox.js"; import QuantizedMeshTerrainData from "./QuantizedMeshTerrainData.js"; import Rectangle from "./Rectangle.js"; import TaskProcessor from "./TaskProcessor.js"; +import TerrainData from "./TerrainData.js"; import TerrainEncoding from "./TerrainEncoding.js"; import TerrainMesh from "./TerrainMesh.js"; @@ -116,8 +117,11 @@ Object.defineProperties(GoogleEarthEnterpriseTerrainData.prototype, { }, }); -var taskProcessor = new TaskProcessor( - "createVerticesFromGoogleEarthEnterpriseBuffer" +var createMeshTaskName = "createVerticesFromGoogleEarthEnterpriseBuffer"; +var createMeshTaskProcessorNoThrottle = new TaskProcessor(createMeshTaskName); +var createMeshTaskProcessorThrottle = new TaskProcessor( + createMeshTaskName, + TerrainData.maximumAsynchronousTasks ); var nativeRectangleScratch = new Rectangle(); @@ -128,33 +132,37 @@ var rectangleScratch = new Rectangle(); * * @private * - * @param {TilingScheme} tilingScheme The tiling scheme to which this tile belongs. - * @param {Number} x The X coordinate of the tile for which to create the terrain data. - * @param {Number} y The Y coordinate of the tile for which to create the terrain data. - * @param {Number} level The level of the tile for which to create the terrain data. - * @param {Number} [exaggeration=1.0] The scale used to exaggerate the terrain. + * @param {Object} options Object with the following properties: + * @param {TilingScheme} options.tilingScheme The tiling scheme to which this tile belongs. + * @param {Number} options.x The X coordinate of the tile for which to create the terrain data. + * @param {Number} options.y The Y coordinate of the tile for which to create the terrain data. + * @param {Number} options.level The level of the tile for which to create the terrain data. + * @param {Number} [options.exaggeration=1.0] The scale used to exaggerate the terrain. + * @param {Boolean} [options.throttle=true] If true, indicates that this operation will need to be retried if too many asynchronous mesh creations are already in progress. * @returns {Promise.value
.
*/
+// eslint-disable-next-line es/no-math-sinh
CesiumMath.sinh = defaultValue(Math.sinh, function sinh(value) {
return (Math.exp(value) - Math.exp(-value)) / 2.0;
});
@@ -315,6 +317,7 @@ CesiumMath.sinh = defaultValue(Math.sinh, function sinh(value) {
* @param {Number} value The number whose hyperbolic cosine is to be returned.
* @returns {Number} The hyperbolic cosine of value
.
*/
+// eslint-disable-next-line es/no-math-cosh
CesiumMath.cosh = defaultValue(Math.cosh, function cosh(value) {
return (Math.exp(value) + Math.exp(-value)) / 2.0;
});
@@ -525,6 +528,11 @@ CesiumMath.negativePiToPi = function (angle) {
throw new DeveloperError("angle is required.");
}
//>>includeEnd('debug');
+ if (angle >= -CesiumMath.PI && angle <= CesiumMath.PI) {
+ // Early exit if the input is already inside the range. This avoids
+ // unnecessary math which could introduce floating point error.
+ return angle;
+ }
return CesiumMath.zeroToTwoPi(angle + CesiumMath.PI) - CesiumMath.PI;
};
@@ -540,6 +548,11 @@ CesiumMath.zeroToTwoPi = function (angle) {
throw new DeveloperError("angle is required.");
}
//>>includeEnd('debug');
+ if (angle >= 0 && angle <= CesiumMath.TWO_PI) {
+ // Early exit if the input is already inside the range. This avoids
+ // unnecessary math which could introduce floating point error.
+ return angle;
+ }
var mod = CesiumMath.mod(angle, CesiumMath.TWO_PI);
if (
Math.abs(mod) < CesiumMath.EPSILON14 &&
@@ -565,7 +578,16 @@ CesiumMath.mod = function (m, n) {
if (!defined(n)) {
throw new DeveloperError("n is required.");
}
+ if (n === 0.0) {
+ throw new DeveloperError("divisor cannot be 0.");
+ }
//>>includeEnd('debug');
+ if (CesiumMath.sign(m) === CesiumMath.sign(n) && Math.abs(m) < Math.abs(n)) {
+ // Early exit if the input does not need to be modded. This avoids
+ // unnecessary math which could introduce floating point error.
+ return m;
+ }
+
return ((m % n) + n) % n;
};
@@ -631,7 +653,7 @@ CesiumMath.lessThan = function (left, right, absoluteEpsilon) {
throw new DeveloperError("second is required.");
}
if (!defined(absoluteEpsilon)) {
- throw new DeveloperError("relativeEpsilon is required.");
+ throw new DeveloperError("absoluteEpsilon is required.");
}
//>>includeEnd('debug');
return left - right < -absoluteEpsilon;
@@ -656,7 +678,7 @@ CesiumMath.lessThanOrEquals = function (left, right, absoluteEpsilon) {
throw new DeveloperError("second is required.");
}
if (!defined(absoluteEpsilon)) {
- throw new DeveloperError("relativeEpsilon is required.");
+ throw new DeveloperError("absoluteEpsilon is required.");
}
//>>includeEnd('debug');
return left - right < absoluteEpsilon;
@@ -682,7 +704,7 @@ CesiumMath.greaterThan = function (left, right, absoluteEpsilon) {
throw new DeveloperError("second is required.");
}
if (!defined(absoluteEpsilon)) {
- throw new DeveloperError("relativeEpsilon is required.");
+ throw new DeveloperError("absoluteEpsilon is required.");
}
//>>includeEnd('debug');
return left - right > absoluteEpsilon;
@@ -707,7 +729,7 @@ CesiumMath.greaterThanOrEquals = function (left, right, absoluteEpsilon) {
throw new DeveloperError("second is required.");
}
if (!defined(absoluteEpsilon)) {
- throw new DeveloperError("relativeEpsilon is required.");
+ throw new DeveloperError("absoluteEpsilon is required.");
}
//>>includeEnd('debug');
return left - right > -absoluteEpsilon;
@@ -785,12 +807,13 @@ CesiumMath.incrementWrap = function (n, maximumValue, minimumValue) {
};
/**
- * Determines if a positive integer is a power of two.
+ * Determines if a non-negative integer is a power of two.
+ * The maximum allowed input is (2^32)-1 due to 32-bit bitwise operator limitation in Javascript.
*
- * @param {Number} n The positive integer to test.
+ * @param {Number} n The integer to test in the range [0, (2^32)-1].
* @returns {Boolean} true
if the number if a power of two; otherwise, false
.
*
- * @exception {DeveloperError} A number greater than or equal to 0 is required.
+ * @exception {DeveloperError} A number between 0 and (2^32)-1 is required.
*
* @example
* var t = Cesium.Math.isPowerOfTwo(16); // true
@@ -798,10 +821,8 @@ CesiumMath.incrementWrap = function (n, maximumValue, minimumValue) {
*/
CesiumMath.isPowerOfTwo = function (n) {
//>>includeStart('debug', pragmas.debug);
- if (typeof n !== "number" || n < 0) {
- throw new DeveloperError(
- "A number greater than or equal to 0 is required."
- );
+ if (typeof n !== "number" || n < 0 || n > 4294967295) {
+ throw new DeveloperError("A number between 0 and (2^32)-1 is required.");
}
//>>includeEnd('debug');
@@ -809,12 +830,13 @@ CesiumMath.isPowerOfTwo = function (n) {
};
/**
- * Computes the next power-of-two integer greater than or equal to the provided positive integer.
+ * Computes the next power-of-two integer greater than or equal to the provided non-negative integer.
+ * The maximum allowed input is 2^31 due to 32-bit bitwise operator limitation in Javascript.
*
- * @param {Number} n The positive integer to test.
+ * @param {Number} n The integer to test in the range [0, 2^31].
* @returns {Number} The next power-of-two integer.
*
- * @exception {DeveloperError} A number greater than or equal to 0 is required.
+ * @exception {DeveloperError} A number between 0 and 2^31 is required.
*
* @example
* var n = Cesium.Math.nextPowerOfTwo(29); // 32
@@ -822,10 +844,8 @@ CesiumMath.isPowerOfTwo = function (n) {
*/
CesiumMath.nextPowerOfTwo = function (n) {
//>>includeStart('debug', pragmas.debug);
- if (typeof n !== "number" || n < 0) {
- throw new DeveloperError(
- "A number greater than or equal to 0 is required."
- );
+ if (typeof n !== "number" || n < 0 || n > 2147483648) {
+ throw new DeveloperError("A number between 0 and 2^31 is required.");
}
//>>includeEnd('debug');
@@ -841,6 +861,39 @@ CesiumMath.nextPowerOfTwo = function (n) {
return n;
};
+/**
+ * Computes the previous power-of-two integer less than or equal to the provided non-negative integer.
+ * The maximum allowed input is (2^32)-1 due to 32-bit bitwise operator limitation in Javascript.
+ *
+ * @param {Number} n The integer to test in the range [0, (2^32)-1].
+ * @returns {Number} The previous power-of-two integer.
+ *
+ * @exception {DeveloperError} A number between 0 and (2^32)-1 is required.
+ *
+ * @example
+ * var n = Cesium.Math.previousPowerOfTwo(29); // 16
+ * var m = Cesium.Math.previousPowerOfTwo(32); // 32
+ */
+CesiumMath.previousPowerOfTwo = function (n) {
+ //>>includeStart('debug', pragmas.debug);
+ if (typeof n !== "number" || n < 0 || n > 4294967295) {
+ throw new DeveloperError("A number between 0 and (2^32)-1 is required.");
+ }
+ //>>includeEnd('debug');
+
+ n |= n >> 1;
+ n |= n >> 2;
+ n |= n >> 4;
+ n |= n >> 8;
+ n |= n >> 16;
+ n |= n >> 32;
+
+ // The previous bitwise operations implicitly convert to signed 32-bit. Use `>>>` to convert to unsigned
+ n = (n >>> 0) - (n >>> 1);
+
+ return n;
+};
+
/**
* Constraint a value to lie between two values.
*
@@ -986,6 +1039,7 @@ CesiumMath.logBase = function (number, base) {
* @param {Number} [number] The number.
* @returns {Number} The result.
*/
+// eslint-disable-next-line es/no-math-cbrt
CesiumMath.cbrt = defaultValue(Math.cbrt, function cbrt(number) {
var result = Math.pow(Math.abs(number), 1.0 / 3.0);
return number < 0.0 ? -result : result;
@@ -998,6 +1052,7 @@ CesiumMath.cbrt = defaultValue(Math.cbrt, function cbrt(number) {
* @param {Number} number The number.
* @returns {Number} The result.
*/
+// eslint-disable-next-line es/no-math-log2
CesiumMath.log2 = defaultValue(Math.log2, function log2(number) {
return Math.log(number) * Math.LOG2E;
});
diff --git a/Source/Core/PolylineVolumeGeometry.js b/Source/Core/PolylineVolumeGeometry.js
index c5c8d3e5f335..3fc156167293 100644
--- a/Source/Core/PolylineVolumeGeometry.js
+++ b/Source/Core/PolylineVolumeGeometry.js
@@ -176,7 +176,7 @@ function computeAttributes(
* @constructor
*
* @param {Object} options Object with the following properties:
- * @param {Cartesian3[]} options.polylinePositions An array of {@link Cartesain3} positions that define the center of the polyline volume.
+ * @param {Cartesian3[]} options.polylinePositions An array of {@link Cartesian3} positions that define the center of the polyline volume.
* @param {Cartesian2[]} options.shapePositions An array of {@link Cartesian2} positions that define the shape to be extruded along the polyline
* @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid to be used as a reference.
* @param {Number} [options.granularity=CesiumMath.RADIANS_PER_DEGREE] The distance, in radians, between each latitude and longitude. Determines the number of positions in the buffer.
diff --git a/Source/Core/QuantizedMeshTerrainData.js b/Source/Core/QuantizedMeshTerrainData.js
index 8bd031b9174b..ebf65f8cfa14 100644
--- a/Source/Core/QuantizedMeshTerrainData.js
+++ b/Source/Core/QuantizedMeshTerrainData.js
@@ -2,6 +2,7 @@ import when from "../ThirdParty/when.js";
import BoundingSphere from "./BoundingSphere.js";
import Cartesian2 from "./Cartesian2.js";
import Cartesian3 from "./Cartesian3.js";
+import Check from "./Check.js";
import defaultValue from "./defaultValue.js";
import defined from "./defined.js";
import DeveloperError from "./DeveloperError.js";
@@ -10,6 +11,7 @@ import Intersections2D from "./Intersections2D.js";
import CesiumMath from "./Math.js";
import OrientedBoundingBox from "./OrientedBoundingBox.js";
import TaskProcessor from "./TaskProcessor.js";
+import TerrainData from "./TerrainData.js";
import TerrainEncoding from "./TerrainEncoding.js";
import TerrainMesh from "./TerrainMesh.js";
@@ -262,8 +264,11 @@ function sortIndicesIfNecessary(indices, sortFunction, vertexCount) {
return indices;
}
-var createMeshTaskProcessor = new TaskProcessor(
- "createVerticesFromQuantizedTerrainMesh"
+var createMeshTaskName = "createVerticesFromQuantizedTerrainMesh";
+var createMeshTaskProcessorNoThrottle = new TaskProcessor(createMeshTaskName);
+var createMeshTaskProcessorThrottle = new TaskProcessor(
+ createMeshTaskName,
+ TerrainData.maximumAsynchronousTasks
);
/**
@@ -271,40 +276,40 @@ var createMeshTaskProcessor = new TaskProcessor(
*
* @private
*
- * @param {TilingScheme} tilingScheme The tiling scheme to which this tile belongs.
- * @param {Number} x The X coordinate of the tile for which to create the terrain data.
- * @param {Number} y The Y coordinate of the tile for which to create the terrain data.
- * @param {Number} level The level of the tile for which to create the terrain data.
- * @param {Number} [exaggeration=1.0] The scale used to exaggerate the terrain.
+ * @param {Object} options Object with the following properties:
+ * @param {TilingScheme} options.tilingScheme The tiling scheme to which this tile belongs.
+ * @param {Number} options.x The X coordinate of the tile for which to create the terrain data.
+ * @param {Number} options.y The Y coordinate of the tile for which to create the terrain data.
+ * @param {Number} options.level The level of the tile for which to create the terrain data.
+ * @param {Number} [options.exaggeration=1.0] The scale used to exaggerate the terrain.
+ * @param {Boolean} [options.throttle=true] If true, indicates that this operation will need to be retried if too many asynchronous mesh creations are already in progress.
* @returns {Promise.@@ -903,6 +912,7 @@ function Cesium3DTileset(options) { .then(function (url) { var basePath; resource = Resource.createIfNeeded(url); + that._resource = resource; // ion resources have a credits property we can use for additional attribution. that._credits = resource.credits; @@ -1164,16 +1174,16 @@ Object.defineProperties(Cesium3DTileset.prototype, { }, /** - * The url to a tileset JSON file. + * The resource used to fetch the tileset JSON file * * @memberof Cesium3DTileset.prototype * - * @type {String} + * @type {Resource} * @readonly */ - url: { + resource: { get: function () { - return this._url; + return this._resource; }, }, @@ -1697,6 +1707,7 @@ Cesium3DTileset.prototype.loadTileset = function ( if (defined(tilesetVersion)) { // Append the tileset version to the resource this._basePath += "?v=" + tilesetVersion; + resource = resource.clone(); resource.setQueryParameters({ v: tilesetVersion }); } @@ -1892,6 +1903,7 @@ Cesium3DTileset.prototype.postPassesUpdate = function (frameState) { cancelOutOfViewRequests(this, frameState); raiseLoadProgressEvent(this, frameState); this._cache.unloadTiles(this, unloadTile); + this._styleEngine.resetDirty(); }; /** @@ -2173,7 +2185,7 @@ function updateTileDebugLabels(tileset, frameState) { } function updateTiles(tileset, frameState, passOptions) { - tileset._styleEngine.applyStyle(tileset, passOptions); + tileset._styleEngine.applyStyle(tileset); var isRender = passOptions.isRender; var statistics = tileset._statistics; @@ -2423,10 +2435,12 @@ function detectModelMatrixChanged(tileset, frameState) { tileset.modelMatrix, tileset._previousModelMatrix ); - tileset._previousModelMatrix = Matrix4.clone( - tileset.modelMatrix, - tileset._previousModelMatrix - ); + if (tileset._modelMatrixChanged) { + tileset._previousModelMatrix = Matrix4.clone( + tileset.modelMatrix, + tileset._previousModelMatrix + ); + } } } @@ -2538,13 +2552,17 @@ Cesium3DTileset.prototype.updateForPass = function ( var passStatistics = this._statisticsPerPass[pass]; if (this.show || ignoreCommands) { - this._pass = pass; - tilesetPassState.ready = update( - this, - frameState, - passStatistics, - passOptions - ); + if (frameState.passes.pick && defined(this.pickPrimitive)) { + this.pickPrimitive.update(frameState); + } else { + this._pass = pass; + tilesetPassState.ready = update( + this, + frameState, + passStatistics, + passOptions + ); + } } if (ignoreCommands) { diff --git a/Source/Scene/Geometry3DTileContent.js b/Source/Scene/Geometry3DTileContent.js index 1c9e749e4cf0..974b32c5d80e 100644 --- a/Source/Scene/Geometry3DTileContent.js +++ b/Source/Scene/Geometry3DTileContent.js @@ -3,7 +3,7 @@ import defaultValue from "../Core/defaultValue.js"; import defined from "../Core/defined.js"; import destroyObject from "../Core/destroyObject.js"; import DeveloperError from "../Core/DeveloperError.js"; -import getStringFromTypedArray from "../Core/getStringFromTypedArray.js"; +import getJsonFromTypedArray from "../Core/getJsonFromTypedArray.js"; import Matrix4 from "../Core/Matrix4.js"; import RuntimeError from "../Core/RuntimeError.js"; import when from "../ThirdParty/when.js"; @@ -290,12 +290,11 @@ function initialize(content, arrayBuffer, byteOffset) { var batchTableBinaryByteLength = view.getUint32(byteOffset, true); byteOffset += sizeOfUint32; - var featureTableString = getStringFromTypedArray( + var featureTableJson = getJsonFromTypedArray( uint8Array, byteOffset, featureTableJSONByteLength ); - var featureTableJson = JSON.parse(featureTableString); byteOffset += featureTableJSONByteLength; var featureTableBinary = new Uint8Array( @@ -313,12 +312,11 @@ function initialize(content, arrayBuffer, byteOffset) { // // We could also make another request for it, but that would make the property set/get // API async, and would double the number of numbers in some cases. - var batchTableString = getStringFromTypedArray( + batchTableJson = getJsonFromTypedArray( uint8Array, byteOffset, batchTableJSONByteLength ); - batchTableJson = JSON.parse(batchTableString); byteOffset += batchTableJSONByteLength; if (batchTableBinaryByteLength > 0) { diff --git a/Source/Scene/GlobeSurfaceTile.js b/Source/Scene/GlobeSurfaceTile.js index 1034d7706bc9..a014c659680c 100644 --- a/Source/Scene/GlobeSurfaceTile.js +++ b/Source/Scene/GlobeSurfaceTile.js @@ -627,17 +627,28 @@ function requestTileGeometry(surfaceTile, terrainProvider, x, y, level) { doRequest(); } +var scratchCreateMeshOptions = { + tilingScheme: undefined, + x: 0, + y: 0, + level: 0, + exaggeration: 1.0, + throttle: true, +}; + function transform(surfaceTile, frameState, terrainProvider, x, y, level) { var tilingScheme = terrainProvider.tilingScheme; + var createMeshOptions = scratchCreateMeshOptions; + createMeshOptions.tilingScheme = tilingScheme; + createMeshOptions.x = x; + createMeshOptions.y = y; + createMeshOptions.level = level; + createMeshOptions.exaggeration = frameState.terrainExaggeration; + createMeshOptions.throttle = true; + var terrainData = surfaceTile.terrainData; - var meshPromise = terrainData.createMesh( - tilingScheme, - x, - y, - level, - frameState.terrainExaggeration - ); + var meshPromise = terrainData.createMesh(createMeshOptions); if (!defined(meshPromise)) { // Postponed. diff --git a/Source/Scene/GridImageryProvider.js b/Source/Scene/GridImageryProvider.js index 1e780c0e6e15..934a657a6435 100644 --- a/Source/Scene/GridImageryProvider.js +++ b/Source/Scene/GridImageryProvider.js @@ -14,18 +14,18 @@ var defaultBackgroundColor = new Color(0.0, 0.5, 0.0, 0.2); * * Initialization options for the GridImageryProvider constructor * - * @param {TilingScheme} [tilingScheme=new GeographicTilingScheme()] The tiling scheme for which to draw tiles. - * @param {Ellipsoid} [ellipsoid] The ellipsoid. If the tilingScheme is specified, + * @property {TilingScheme} [tilingScheme=new GeographicTilingScheme()] The tiling scheme for which to draw tiles. + * @property {Ellipsoid} [ellipsoid] The ellipsoid. If the tilingScheme is specified, * this parameter is ignored and the tiling scheme's ellipsoid is used instead. If neither * parameter is specified, the WGS84 ellipsoid is used. - * @param {Number} [cells=8] The number of grids cells. - * @param {Color} [color=Color(1.0, 1.0, 1.0, 0.4)] The color to draw grid lines. - * @param {Color} [glowColor=Color(0.0, 1.0, 0.0, 0.05)] The color to draw glow for grid lines. - * @param {Number} [glowWidth=6] The width of lines used for rendering the line glow effect. - * @param {Color} [backgroundColor=Color(0.0, 0.5, 0.0, 0.2)] Background fill color. - * @param {Number} [tileWidth=256] The width of the tile for level-of-detail selection purposes. - * @param {Number} [tileHeight=256] The height of the tile for level-of-detail selection purposes. - * @param {Number} [canvasSize=256] The size of the canvas used for rendering. + * @property {Number} [cells=8] The number of grids cells. + * @property {Color} [color=Color(1.0, 1.0, 1.0, 0.4)] The color to draw grid lines. + * @property {Color} [glowColor=Color(0.0, 1.0, 0.0, 0.05)] The color to draw glow for grid lines. + * @property {Number} [glowWidth=6] The width of lines used for rendering the line glow effect. + * @property {Color} [backgroundColor=Color(0.0, 0.5, 0.0, 0.2)] Background fill color. + * @property {Number} [tileWidth=256] The width of the tile for level-of-detail selection purposes. + * @property {Number} [tileHeight=256] The height of the tile for level-of-detail selection purposes. + * @property {Number} [canvasSize=256] The size of the canvas used for rendering. */ /** diff --git a/Source/Scene/ImageryLayer.js b/Source/Scene/ImageryLayer.js index 4cd1cb84b750..eb082de5309a 100644 --- a/Source/Scene/ImageryLayer.js +++ b/Source/Scene/ImageryLayer.js @@ -1235,6 +1235,10 @@ ImageryLayer.prototype._reprojectTexture = function ( imagery.state = ImageryState.READY; imagery.releaseReference(); }, + canceled: function () { + imagery.state = ImageryState.TEXTURE_LOADED; + imagery.releaseReference(); + }, }); this._reprojectComputeCommands.push(computeCommand); } else { @@ -1268,6 +1272,11 @@ ImageryLayer.prototype.queueReprojectionCommands = function (frameState) { * @private */ ImageryLayer.prototype.cancelReprojections = function () { + this._reprojectComputeCommands.forEach(function (command) { + if (defined(command.canceled)) { + command.canceled(); + } + }); this._reprojectComputeCommands.length = 0; }; diff --git a/Source/Scene/ImageryProvider.js b/Source/Scene/ImageryProvider.js index 77c53f6975a9..297ce3044137 100644 --- a/Source/Scene/ImageryProvider.js +++ b/Source/Scene/ImageryProvider.js @@ -11,6 +11,7 @@ import Resource from "../Core/Resource.js"; * * @alias ImageryProvider * @constructor + * @abstract * * @see ArcGisMapServerImageryProvider * @see BingMapsImageryProvider diff --git a/Source/Scene/Instanced3DModel3DTileContent.js b/Source/Scene/Instanced3DModel3DTileContent.js index 747e3aff4ff2..8cab629cb609 100644 --- a/Source/Scene/Instanced3DModel3DTileContent.js +++ b/Source/Scene/Instanced3DModel3DTileContent.js @@ -8,6 +8,7 @@ import deprecationWarning from "../Core/deprecationWarning.js"; import destroyObject from "../Core/destroyObject.js"; import DeveloperError from "../Core/DeveloperError.js"; import Ellipsoid from "../Core/Ellipsoid.js"; +import getJsonFromTypedArray from "../Core/getJsonFromTypedArray.js"; import getStringFromTypedArray from "../Core/getStringFromTypedArray.js"; import Matrix3 from "../Core/Matrix3.js"; import Matrix4 from "../Core/Matrix4.js"; @@ -203,12 +204,11 @@ function initialize(content, arrayBuffer, byteOffset) { } byteOffset += sizeOfUint32; - var featureTableString = getStringFromTypedArray( + var featureTableJson = getJsonFromTypedArray( uint8Array, byteOffset, featureTableJsonByteLength ); - var featureTableJson = JSON.parse(featureTableString); byteOffset += featureTableJsonByteLength; var featureTableBinary = new Uint8Array( @@ -234,12 +234,11 @@ function initialize(content, arrayBuffer, byteOffset) { var batchTableJson; var batchTableBinary; if (batchTableJsonByteLength > 0) { - var batchTableString = getStringFromTypedArray( + batchTableJson = getJsonFromTypedArray( uint8Array, byteOffset, batchTableJsonByteLength ); - batchTableJson = JSON.parse(batchTableString); byteOffset += batchTableJsonByteLength; if (batchTableBinaryByteLength > 0) { diff --git a/Source/Scene/Label.js b/Source/Scene/Label.js index f05082add20d..05d69ec01f97 100644 --- a/Source/Scene/Label.js +++ b/Source/Scene/Label.js @@ -58,7 +58,7 @@ function parseFont(label) { div.style.font = label._font; document.body.appendChild(div); - var lineHeight = Number.parseFloat(getCSSValue(div, "line-height")); + var lineHeight = parseFloat(getCSSValue(div, "line-height")); if (isNaN(lineHeight)) { // line-height isn't a number, i.e. 'normal'; apply default line-spacing lineHeight = undefined; diff --git a/Source/Scene/LabelCollection.js b/Source/Scene/LabelCollection.js index ec907af14348..7ee4b2e77a8a 100644 --- a/Source/Scene/LabelCollection.js +++ b/Source/Scene/LabelCollection.js @@ -576,6 +576,7 @@ function destroyLabel(labelCollection, label) { * @param {BlendOption} [options.blendOption=BlendOption.OPAQUE_AND_TRANSLUCENT] The label blending option. The default * is used for rendering both opaque and translucent labels. However, if either all of the labels are completely opaque or all are completely translucent, * setting the technique to BlendOption.OPAQUE or BlendOption.TRANSLUCENT can improve performance by up to 2x. + * @param {Boolean} [options.show=true] Determines if the labels in the collection will be shown. * * @performance For best performance, prefer a few collections, each with many labels, to * many collections with only a few labels each. Avoid having collections where some @@ -631,6 +632,14 @@ function LabelCollection(options) { this._highlightColor = Color.clone(Color.WHITE); // Only used by Vector3DTilePoints + /** + * Determines if labels in this collection will be shown. + * + * @type {Boolean} + * @default true + */ + this.show = defaultValue(options.show, true); + /** * The 4x4 transformation matrix that transforms each label in this collection from model to world coordinates. * When this is the identity matrix, the labels are drawn in world coordinates, i.e., Earth's WGS84 coordinates. @@ -887,6 +896,10 @@ LabelCollection.prototype.get = function (index) { * */ LabelCollection.prototype.update = function (frameState) { + if (!this.show) { + return; + } + var billboardCollection = this._billboardCollection; var backgroundBillboardCollection = this._backgroundBillboardCollection; diff --git a/Source/Scene/Material.js b/Source/Scene/Material.js index 4b882b71ce40..fbc00dd38dfa 100644 --- a/Source/Scene/Material.js +++ b/Source/Scene/Material.js @@ -19,6 +19,7 @@ import AspectRampMaterial from "../Shaders/Materials/AspectRampMaterial.js"; import BumpMapMaterial from "../Shaders/Materials/BumpMapMaterial.js"; import CheckerboardMaterial from "../Shaders/Materials/CheckerboardMaterial.js"; import DotMaterial from "../Shaders/Materials/DotMaterial.js"; +import ElevationBandMaterial from "../Shaders/Materials/ElevationBandMaterial.js"; import ElevationContourMaterial from "../Shaders/Materials/ElevationContourMaterial.js"; import ElevationRampMaterial from "../Shaders/Materials/ElevationRampMaterial.js"; import FadeMaterial from "../Shaders/Materials/FadeMaterial.js"; @@ -216,6 +217,11 @@ import when from "../ThirdParty/when.js"; *
image
: color ramp image to use for color the terrain by aspect.heights
: image of heights sorted from lowest to highest.colors
: image of colors at the corresponding heights.
* Implements the {@link Cesium3DTileContent} interface.
@@ -297,12 +297,11 @@ function initialize(content, arrayBuffer, byteOffset) {
var pointsPositionByteLength = view.getUint32(byteOffset, true);
byteOffset += sizeOfUint32;
- var featureTableString = getStringFromTypedArray(
+ var featureTableJson = getJsonFromTypedArray(
uint8Array,
byteOffset,
featureTableJSONByteLength
);
- var featureTableJson = JSON.parse(featureTableString);
byteOffset += featureTableJSONByteLength;
var featureTableBinary = new Uint8Array(
@@ -320,12 +319,11 @@ function initialize(content, arrayBuffer, byteOffset) {
//
// We could also make another request for it, but that would make the property set/get
// API async, and would double the number of numbers in some cases.
- var batchTableString = getStringFromTypedArray(
+ batchTableJson = getJsonFromTypedArray(
uint8Array,
byteOffset,
batchTableJSONByteLength
);
- batchTableJson = JSON.parse(batchTableString);
byteOffset += batchTableJSONByteLength;
if (batchTableBinaryByteLength > 0) {
diff --git a/Source/Scene/Vector3DTileGeometry.js b/Source/Scene/Vector3DTileGeometry.js
index 63e8ca8b74b3..dedaef7aa996 100644
--- a/Source/Scene/Vector3DTileGeometry.js
+++ b/Source/Scene/Vector3DTileGeometry.js
@@ -210,7 +210,8 @@ function unpackBuffer(geometries, packedBuffer) {
}
var createVerticesTaskProcessor = new TaskProcessor(
- "createVectorTileGeometries"
+ "createVectorTileGeometries",
+ 5
);
var scratchColor = new Color();
diff --git a/Source/Scene/Vector3DTilePoints.js b/Source/Scene/Vector3DTilePoints.js
index b6cd9346dc90..d4d12de11cd7 100644
--- a/Source/Scene/Vector3DTilePoints.js
+++ b/Source/Scene/Vector3DTilePoints.js
@@ -122,7 +122,10 @@ function packBuffer(points, ellipsoid) {
return packedBuffer;
}
-var createVerticesTaskProcessor = new TaskProcessor("createVectorTilePoints");
+var createVerticesTaskProcessor = new TaskProcessor(
+ "createVectorTilePoints",
+ 5
+);
var scratchPosition = new Cartesian3();
function createPoints(points, ellipsoid) {
diff --git a/Source/Scene/Vector3DTilePolygons.js b/Source/Scene/Vector3DTilePolygons.js
index afe4f440b18e..bdbcf35eec49 100644
--- a/Source/Scene/Vector3DTilePolygons.js
+++ b/Source/Scene/Vector3DTilePolygons.js
@@ -215,7 +215,10 @@ function unpackBuffer(polygons, packedBuffer) {
}
}
-var createVerticesTaskProcessor = new TaskProcessor("createVectorTilePolygons");
+var createVerticesTaskProcessor = new TaskProcessor(
+ "createVectorTilePolygons",
+ 5
+);
var scratchColor = new Color();
function createPrimitive(polygons) {
diff --git a/Source/Scene/Vector3DTilePolylines.js b/Source/Scene/Vector3DTilePolylines.js
index d9672ddd222b..3473c5ba2c8d 100644
--- a/Source/Scene/Vector3DTilePolylines.js
+++ b/Source/Scene/Vector3DTilePolylines.js
@@ -161,7 +161,8 @@ function packBuffer(polylines) {
}
var createVerticesTaskProcessor = new TaskProcessor(
- "createVectorTilePolylines"
+ "createVectorTilePolylines",
+ 5
);
var attributeLocations = {
previousPosition: 0,
@@ -221,21 +222,27 @@ function createVertexArray(polylines, context) {
return;
}
- when(verticesPromise, function (result) {
- polylines._currentPositions = new Float32Array(result.currentPositions);
- polylines._previousPositions = new Float32Array(result.previousPositions);
- polylines._nextPositions = new Float32Array(result.nextPositions);
- polylines._expandAndWidth = new Float32Array(result.expandAndWidth);
- polylines._vertexBatchIds = new Uint16Array(result.batchIds);
-
- var indexDatatype = result.indexDatatype;
- polylines._indices =
- indexDatatype === IndexDatatype.UNSIGNED_SHORT
- ? new Uint16Array(result.indices)
- : new Uint32Array(result.indices);
-
- polylines._ready = true;
- });
+ when(verticesPromise)
+ .then(function (result) {
+ polylines._currentPositions = new Float32Array(result.currentPositions);
+ polylines._previousPositions = new Float32Array(
+ result.previousPositions
+ );
+ polylines._nextPositions = new Float32Array(result.nextPositions);
+ polylines._expandAndWidth = new Float32Array(result.expandAndWidth);
+ polylines._vertexBatchIds = new Uint16Array(result.batchIds);
+
+ var indexDatatype = result.indexDatatype;
+ polylines._indices =
+ indexDatatype === IndexDatatype.UNSIGNED_SHORT
+ ? new Uint16Array(result.indices)
+ : new Uint32Array(result.indices);
+
+ polylines._ready = true;
+ })
+ .otherwise(function (error) {
+ polylines._readyPromise.reject(error);
+ });
}
if (polylines._ready && !defined(polylines._va)) {
diff --git a/Source/Scene/createElevationBandMaterial.js b/Source/Scene/createElevationBandMaterial.js
new file mode 100644
index 000000000000..0760aa55ac1a
--- /dev/null
+++ b/Source/Scene/createElevationBandMaterial.js
@@ -0,0 +1,585 @@
+import Cartesian4 from "../Core/Cartesian4.js";
+import CesiumMath from "../Core/Math.js";
+import Check from "../Core/Check.js";
+import Color from "../Core/Color.js";
+import defaultValue from "../Core/defaultValue.js";
+import defined from "../Core/defined.js";
+import DeveloperError from "../Core/DeveloperError.js";
+import mergeSort from "../Core/mergeSort.js";
+import PixelFormat from "../Core/PixelFormat.js";
+import PixelDatatype from "../Renderer/PixelDatatype.js";
+import Sampler from "../Renderer/Sampler.js";
+import Texture from "../Renderer/Texture.js";
+import TextureMagnificationFilter from "../Renderer/TextureMagnificationFilter.js";
+import TextureMinificationFilter from "../Renderer/TextureMinificationFilter.js";
+import TextureWrap from "../Renderer/TextureWrap.js";
+import Material from "./Material.js";
+
+var scratchColor = new Color();
+var scratchColorAbove = new Color();
+var scratchColorBelow = new Color();
+var scratchColorBlend = new Color();
+var scratchPackedFloat = new Cartesian4();
+var scratchColorBytes = new Uint8Array(4);
+
+function lerpEntryColor(height, entryBefore, entryAfter, result) {
+ var lerpFactor =
+ entryBefore.height === entryAfter.height
+ ? 0.0
+ : (height - entryBefore.height) /
+ (entryAfter.height - entryBefore.height);
+ return Color.lerp(entryBefore.color, entryAfter.color, lerpFactor, result);
+}
+
+function createNewEntry(height, color) {
+ return {
+ height: height,
+ color: Color.clone(color),
+ };
+}
+
+function removeDuplicates(entries) {
+ // This function expects entries to be sorted from lowest to highest.
+
+ // Remove entries that have the same height as before and after.
+ entries = entries.filter(function (entry, index, array) {
+ var hasPrev = index > 0;
+ var hasNext = index < array.length - 1;
+
+ var sameHeightAsPrev = hasPrev
+ ? entry.height === array[index - 1].height
+ : true;
+ var sameHeightAsNext = hasNext
+ ? entry.height === array[index + 1].height
+ : true;
+
+ var keep = !sameHeightAsPrev || !sameHeightAsNext;
+ return keep;
+ });
+
+ // Remove entries that have the same color as before and after.
+ entries = entries.filter(function (entry, index, array) {
+ var hasPrev = index > 0;
+ var hasNext = index < array.length - 1;
+
+ var sameColorAsPrev = hasPrev
+ ? Color.equals(entry.color, array[index - 1].color)
+ : false;
+ var sameColorAsNext = hasNext
+ ? Color.equals(entry.color, array[index + 1].color)
+ : false;
+
+ var keep = !sameColorAsPrev || !sameColorAsNext;
+ return keep;
+ });
+
+ // Also remove entries that have the same height AND color as the entry before.
+ entries = entries.filter(function (entry, index, array) {
+ var hasPrev = index > 0;
+
+ var sameColorAsPrev = hasPrev
+ ? Color.equals(entry.color, array[index - 1].color)
+ : false;
+
+ var sameHeightAsPrev = hasPrev
+ ? entry.height === array[index - 1].height
+ : true;
+
+ var keep = !sameColorAsPrev || !sameHeightAsPrev;
+ return keep;
+ });
+
+ return entries;
+}
+
+function preprocess(layers) {
+ var i, j;
+
+ var layeredEntries = [];
+
+ var layersLength = layers.length;
+ for (i = 0; i < layersLength; i++) {
+ var layer = layers[i];
+ var entriesOrig = layer.entries;
+ var entriesLength = entriesOrig.length;
+
+ //>>includeStart('debug', pragmas.debug);
+ if (!Array.isArray(entriesOrig) || entriesLength === 0) {
+ throw new DeveloperError("entries must be an array with size > 0.");
+ }
+ //>>includeEnd('debug');
+
+ var entries = [];
+
+ for (j = 0; j < entriesLength; j++) {
+ var entryOrig = entriesOrig[j];
+
+ //>>includeStart('debug', pragmas.debug);
+ if (!defined(entryOrig.height)) {
+ throw new DeveloperError("entry requires a height.");
+ }
+ if (!defined(entryOrig.color)) {
+ throw new DeveloperError("entry requires a color.");
+ }
+ //>>includeEnd('debug');
+
+ var height = CesiumMath.clamp(
+ entryOrig.height,
+ createElevationBandMaterial._minimumHeight,
+ createElevationBandMaterial._maximumHeight
+ );
+
+ // premultiplied alpha
+ var color = Color.clone(entryOrig.color, scratchColor);
+ color.red *= color.alpha;
+ color.green *= color.alpha;
+ color.blue *= color.alpha;
+
+ entries.push(createNewEntry(height, color));
+ }
+
+ var sortedAscending = true;
+ var sortedDescending = true;
+ for (j = 0; j < entriesLength - 1; j++) {
+ var currEntry = entries[j + 0];
+ var nextEntry = entries[j + 1];
+
+ sortedAscending = sortedAscending && currEntry.height <= nextEntry.height;
+ sortedDescending =
+ sortedDescending && currEntry.height >= nextEntry.height;
+ }
+
+ // When the array is fully descending, reverse it.
+ if (sortedDescending) {
+ entries = entries.reverse();
+ } else if (!sortedAscending) {
+ // Stable sort from lowest to greatest height.
+ mergeSort(entries, function (a, b) {
+ return CesiumMath.sign(a.height - b.height);
+ });
+ }
+
+ var extendDownwards = defaultValue(layer.extendDownwards, false);
+ var extendUpwards = defaultValue(layer.extendUpwards, false);
+
+ // Interpret a single entry to extend all the way up and down.
+ if (entries.length === 1 && !extendDownwards && !extendUpwards) {
+ extendDownwards = true;
+ extendUpwards = true;
+ }
+
+ if (extendDownwards) {
+ entries.splice(
+ 0,
+ 0,
+ createNewEntry(
+ createElevationBandMaterial._minimumHeight,
+ entries[0].color
+ )
+ );
+ }
+ if (extendUpwards) {
+ entries.splice(
+ entries.length,
+ 0,
+ createNewEntry(
+ createElevationBandMaterial._maximumHeight,
+ entries[entries.length - 1].color
+ )
+ );
+ }
+
+ entries = removeDuplicates(entries);
+
+ layeredEntries.push(entries);
+ }
+
+ return layeredEntries;
+}
+
+function createLayeredEntries(layers) {
+ // clean up the input data and check for errors
+ var layeredEntries = preprocess(layers);
+
+ var entriesAccumNext = [];
+ var entriesAccumCurr = [];
+ var i;
+
+ function addEntry(height, color) {
+ entriesAccumNext.push(createNewEntry(height, color));
+ }
+ function addBlendEntry(height, a, b) {
+ var result = Color.multiplyByScalar(b, 1.0 - a.alpha, scratchColorBlend);
+ result = Color.add(result, a, result);
+ addEntry(height, result);
+ }
+
+ // alpha blend new layers on top of old ones
+ var layerLength = layeredEntries.length;
+ for (i = 0; i < layerLength; i++) {
+ var entries = layeredEntries[i];
+ var idx = 0;
+ var accumIdx = 0;
+
+ // swap the arrays
+ entriesAccumCurr = entriesAccumNext;
+ entriesAccumNext = [];
+
+ var entriesLength = entries.length;
+ var entriesAccumLength = entriesAccumCurr.length;
+ while (idx < entriesLength || accumIdx < entriesAccumLength) {
+ var entry = idx < entriesLength ? entries[idx] : undefined;
+ var prevEntry = idx > 0 ? entries[idx - 1] : undefined;
+ var nextEntry = idx < entriesLength - 1 ? entries[idx + 1] : undefined;
+
+ var entryAccum =
+ accumIdx < entriesAccumLength ? entriesAccumCurr[accumIdx] : undefined;
+ var prevEntryAccum =
+ accumIdx > 0 ? entriesAccumCurr[accumIdx - 1] : undefined;
+ var nextEntryAccum =
+ accumIdx < entriesAccumLength - 1
+ ? entriesAccumCurr[accumIdx + 1]
+ : undefined;
+
+ if (
+ defined(entry) &&
+ defined(entryAccum) &&
+ entry.height === entryAccum.height
+ ) {
+ // New entry directly on top of accum entry
+ var isSplitAccum =
+ defined(nextEntryAccum) &&
+ entryAccum.height === nextEntryAccum.height;
+ var isStartAccum = !defined(prevEntryAccum);
+ var isEndAccum = !defined(nextEntryAccum);
+
+ var isSplit = defined(nextEntry) && entry.height === nextEntry.height;
+ var isStart = !defined(prevEntry);
+ var isEnd = !defined(nextEntry);
+
+ if (isSplitAccum) {
+ if (isSplit) {
+ addBlendEntry(entry.height, entry.color, entryAccum.color);
+ addBlendEntry(entry.height, nextEntry.color, nextEntryAccum.color);
+ } else if (isStart) {
+ addEntry(entry.height, entryAccum.color);
+ addBlendEntry(entry.height, entry.color, nextEntryAccum.color);
+ } else if (isEnd) {
+ addBlendEntry(entry.height, entry.color, entryAccum.color);
+ addEntry(entry.height, nextEntryAccum.color);
+ } else {
+ addBlendEntry(entry.height, entry.color, entryAccum.color);
+ addBlendEntry(entry.height, entry.color, nextEntryAccum.color);
+ }
+ } else if (isStartAccum) {
+ if (isSplit) {
+ addEntry(entry.height, entry.color);
+ addBlendEntry(entry.height, nextEntry.color, entryAccum.color);
+ } else if (isEnd) {
+ addEntry(entry.height, entry.color);
+ addEntry(entry.height, entryAccum.color);
+ } else if (isStart) {
+ addBlendEntry(entry.height, entry.color, entryAccum.color);
+ } else {
+ addEntry(entry.height, entry.color);
+ addBlendEntry(entry.height, entry.color, entryAccum.color);
+ }
+ } else if (isEndAccum) {
+ if (isSplit) {
+ addBlendEntry(entry.height, entry.color, entryAccum.color);
+ addEntry(entry.height, nextEntry.color);
+ } else if (isStart) {
+ addEntry(entry.height, entryAccum.color);
+ addEntry(entry.height, entry.color);
+ } else if (isEnd) {
+ addBlendEntry(entry.height, entry.color, entryAccum.color);
+ } else {
+ addBlendEntry(entry.height, entry.color, entryAccum.color);
+ addEntry(entry.height, entry.color);
+ }
+ } else {
+ // eslint-disable-next-line no-lonely-if
+ if (isSplit) {
+ addBlendEntry(entry.height, entry.color, entryAccum.color);
+ addBlendEntry(entry.height, nextEntry.color, entryAccum.color);
+ } else if (isStart) {
+ addEntry(entry.height, entryAccum.color);
+ addBlendEntry(entry.height, entry.color, entryAccum.color);
+ } else if (isEnd) {
+ addBlendEntry(entry.height, entry.color, entryAccum.color);
+ addEntry(entry.height, entryAccum.color);
+ } else {
+ addBlendEntry(entry.height, entry.color, entryAccum.color);
+ }
+ }
+ idx += isSplit ? 2 : 1;
+ accumIdx += isSplitAccum ? 2 : 1;
+ } else if (
+ defined(entry) &&
+ defined(entryAccum) &&
+ defined(prevEntryAccum) &&
+ entry.height < entryAccum.height
+ ) {
+ // New entry between two accum entries
+ var colorBelow = lerpEntryColor(
+ entry.height,
+ prevEntryAccum,
+ entryAccum,
+ scratchColorBelow
+ );
+
+ if (!defined(prevEntry)) {
+ addEntry(entry.height, colorBelow);
+ addBlendEntry(entry.height, entry.color, colorBelow);
+ } else if (!defined(nextEntry)) {
+ addBlendEntry(entry.height, entry.color, colorBelow);
+ addEntry(entry.height, colorBelow);
+ } else {
+ addBlendEntry(entry.height, entry.color, colorBelow);
+ }
+ idx++;
+ } else if (
+ defined(entryAccum) &&
+ defined(entry) &&
+ defined(prevEntry) &&
+ entryAccum.height < entry.height
+ ) {
+ // Accum entry between two new entries
+ var colorAbove = lerpEntryColor(
+ entryAccum.height,
+ prevEntry,
+ entry,
+ scratchColorAbove
+ );
+
+ if (!defined(prevEntryAccum)) {
+ addEntry(entryAccum.height, colorAbove);
+ addBlendEntry(entryAccum.height, colorAbove, entryAccum.color);
+ } else if (!defined(nextEntryAccum)) {
+ addBlendEntry(entryAccum.height, colorAbove, entryAccum.color);
+ addEntry(entryAccum.height, colorAbove);
+ } else {
+ addBlendEntry(entryAccum.height, colorAbove, entryAccum.color);
+ }
+ accumIdx++;
+ } else if (
+ defined(entry) &&
+ (!defined(entryAccum) || entry.height < entryAccum.height)
+ ) {
+ // New entry completely before or completely after accum entries
+ if (
+ defined(entryAccum) &&
+ !defined(prevEntryAccum) &&
+ !defined(nextEntry)
+ ) {
+ // Insert blank gap between last entry and first accum entry
+ addEntry(entry.height, entry.color);
+ addEntry(entry.height, createElevationBandMaterial._emptyColor);
+ addEntry(entryAccum.height, createElevationBandMaterial._emptyColor);
+ } else if (
+ !defined(entryAccum) &&
+ defined(prevEntryAccum) &&
+ !defined(prevEntry)
+ ) {
+ // Insert blank gap between last accum entry and first entry
+ addEntry(
+ prevEntryAccum.height,
+ createElevationBandMaterial._emptyColor
+ );
+ addEntry(entry.height, createElevationBandMaterial._emptyColor);
+ addEntry(entry.height, entry.color);
+ } else {
+ addEntry(entry.height, entry.color);
+ }
+ idx++;
+ } else if (
+ defined(entryAccum) &&
+ (!defined(entry) || entryAccum.height < entry.height)
+ ) {
+ // Accum entry completely before or completely after new entries
+ addEntry(entryAccum.height, entryAccum.color);
+ accumIdx++;
+ }
+ }
+ }
+
+ // one final cleanup pass in case duplicate colors show up in the final result
+ var allEntries = removeDuplicates(entriesAccumNext);
+ return allEntries;
+}
+
+/**
+ * @typedef createElevationBandMaterialEntry
+ *
+ * @property {Number} height The height.
+ * @property {Color} color The color at this height.
+ */
+/**
+ * @typedef createElevationBandMaterialBand
+ *
+ * @property {createElevationBandMaterialEntry[]} entries A list of elevation entries. They will automatically be sorted from lowest to highest. If there is only one entry and extendsDownards
and extendUpwards
are both false
, they will both be set to true
.
+ * @property {Boolean} [extendDownwards=false] If true
, the band's minimum elevation color will extend infinitely downwards.
+ * @property {Boolean} [extendUpwards=false] If true
, the band's maximum elevation color will extend infinitely upwards.
+ */
+
+/**
+ * Creates a {@link Material} that combines multiple layers of color/gradient bands and maps them to terrain heights.
+ *
+ * The shader does a binary search over all the heights to find out which colors are above and below a given height, and
+ * interpolates between them for the final color. This material supports hundreds of entries relatively cheaply.
+ *
+ * @function createElevationBandMaterial
+ *
+ * @param {Object} options Object with the following properties:
+ * @param {Scene} options.scene The scene where the visualization is taking place.
+ * @param {createElevationBandMaterialBand[]} options.layers A list of bands ordered from lowest to highest precedence.
+ * @returns {Material} A new {@link Material} instance.
+ *
+ * @demo {@link https://sandcastle.cesium.com/index.html?src=Elevation%20Band%20Material.html|Cesium Sandcastle Elevation Band Demo}
+ *
+ * @example
+ * scene.globe.material = Cesium.createElevationBandMaterial({
+ * scene : scene,
+ * layers : [{
+ * entries : [{
+ * height : 4200.0,
+ * color : new Cesium.Color(0.0, 0.0, 0.0, 1.0)
+ * }, {
+ * height : 8848.0,
+ * color : new Cesium.Color(1.0, 1.0, 1.0, 1.0)
+ * }],
+ * extendDownwards : true,
+ * extendUpwards : true,
+ * }, {
+ * entries : [{
+ * height : 7000.0,
+ * color : new Cesium.Color(1.0, 0.0, 0.0, 0.5)
+ * }, {
+ * height : 7100.0,
+ * color : new Cesium.Color(1.0, 0.0, 0.0, 0.5)
+ * }]
+ * }]
+ * });
+ */
+function createElevationBandMaterial(options) {
+ options = defaultValue(options, defaultValue.EMPTY_OBJECT);
+ var scene = options.scene;
+ var layers = options.layers;
+
+ //>>includeStart('debug', pragmas.debug);
+ Check.typeOf.object("options.scene", scene);
+ Check.defined("options.layers", layers);
+ Check.typeOf.number.greaterThan("options.layers.length", layers.length, 0);
+ //>>includeEnd('debug');
+
+ var entries = createLayeredEntries(layers);
+ var entriesLength = entries.length;
+ var i;
+
+ var heightTexBuffer;
+ var heightTexDatatype;
+ var heightTexFormat;
+
+ var isPackedHeight = !createElevationBandMaterial._useFloatTexture(
+ scene.context
+ );
+ if (isPackedHeight) {
+ heightTexDatatype = PixelDatatype.UNSIGNED_BYTE;
+ heightTexFormat = PixelFormat.RGBA;
+ heightTexBuffer = new Uint8Array(entriesLength * 4);
+ for (i = 0; i < entriesLength; i++) {
+ Cartesian4.packFloat(entries[i].height, scratchPackedFloat);
+ Cartesian4.pack(scratchPackedFloat, heightTexBuffer, i * 4);
+ }
+ } else {
+ heightTexDatatype = PixelDatatype.FLOAT;
+ heightTexFormat = PixelFormat.LUMINANCE;
+ heightTexBuffer = new Float32Array(entriesLength);
+ for (i = 0; i < entriesLength; i++) {
+ heightTexBuffer[i] = entries[i].height;
+ }
+ }
+
+ var heightsTex = Texture.create({
+ context: scene.context,
+ pixelFormat: heightTexFormat,
+ pixelDatatype: heightTexDatatype,
+ source: {
+ arrayBufferView: heightTexBuffer,
+ width: entriesLength,
+ height: 1,
+ },
+ sampler: new Sampler({
+ wrapS: TextureWrap.CLAMP_TO_EDGE,
+ wrapT: TextureWrap.CLAMP_TO_EDGE,
+ minificationFilter: TextureMinificationFilter.NEAREST,
+ magnificationFilter: TextureMagnificationFilter.NEAREST,
+ }),
+ });
+
+ var colorsArray = new Uint8Array(entriesLength * 4);
+ for (i = 0; i < entriesLength; i++) {
+ var color = entries[i].color;
+ color.toBytes(scratchColorBytes);
+ colorsArray[i * 4 + 0] = scratchColorBytes[0];
+ colorsArray[i * 4 + 1] = scratchColorBytes[1];
+ colorsArray[i * 4 + 2] = scratchColorBytes[2];
+ colorsArray[i * 4 + 3] = scratchColorBytes[3];
+ }
+
+ var colorsTex = Texture.create({
+ context: scene.context,
+ pixelFormat: PixelFormat.RGBA,
+ pixelDatatype: PixelDatatype.UNSIGNED_BYTE,
+ source: {
+ arrayBufferView: colorsArray,
+ width: entriesLength,
+ height: 1,
+ },
+ sampler: new Sampler({
+ wrapS: TextureWrap.CLAMP_TO_EDGE,
+ wrapT: TextureWrap.CLAMP_TO_EDGE,
+ minificationFilter: TextureMinificationFilter.LINEAR,
+ magnificationFilter: TextureMagnificationFilter.LINEAR,
+ }),
+ });
+
+ var material = Material.fromType("ElevationBand", {
+ heights: heightsTex,
+ colors: colorsTex,
+ });
+ return material;
+}
+
+/**
+ * Function for checking if the context will allow floating point textures for heights.
+ *
+ * @param {Context} context The {@link Context}.
+ * @returns {Boolean} true
if floating point textures can be used for heights.
+ * @private
+ */
+createElevationBandMaterial._useFloatTexture = function (context) {
+ return context.floatingPointTexture;
+};
+
+/**
+ * This is the height that gets stored in the texture when using extendUpwards.
+ * There's nothing special about it, it's just a really big number.
+ * @private
+ */
+createElevationBandMaterial._maximumHeight = +5906376425472;
+
+/**
+ * This is the height that gets stored in the texture when using extendDownwards.
+ * There's nothing special about it, it's just a really big number.
+ * @private
+ */
+createElevationBandMaterial._minimumHeight = -5906376425472;
+
+/**
+ * Color used to create empty space in the color texture
+ * @private
+ */
+createElevationBandMaterial._emptyColor = new Color(0.0, 0.0, 0.0, 0.0);
+
+export default createElevationBandMaterial;
diff --git a/Source/Scene/processPbrMaterials.js b/Source/Scene/processPbrMaterials.js
index edf6f39875c6..a255b502fe25 100644
--- a/Source/Scene/processPbrMaterials.js
+++ b/Source/Scene/processPbrMaterials.js
@@ -289,8 +289,6 @@ function generateTechnique(
defined(material.extensions.KHR_materials_unlit)
) {
isUnlit = true;
- hasNormals = false;
- hasTangents = false;
}
if (hasNormals) {
@@ -480,15 +478,16 @@ function generateTechnique(
semantic: "NORMAL",
};
vertexShader += "attribute vec3 a_normal;\n";
- vertexShader += "varying vec3 v_normal;\n";
- if (hasSkinning) {
- vertexShaderMain +=
- " v_normal = u_normalMatrix * mat3(skinMatrix) * weightedNormal;\n";
- } else {
- vertexShaderMain += " v_normal = u_normalMatrix * weightedNormal;\n";
+ if (!isUnlit) {
+ vertexShader += "varying vec3 v_normal;\n";
+ if (hasSkinning) {
+ vertexShaderMain +=
+ " v_normal = u_normalMatrix * mat3(skinMatrix) * weightedNormal;\n";
+ } else {
+ vertexShaderMain += " v_normal = u_normalMatrix * weightedNormal;\n";
+ }
+ fragmentShader += "varying vec3 v_normal;\n";
}
-
- fragmentShader += "varying vec3 v_normal;\n";
fragmentShader += "varying vec3 v_positionEC;\n";
}
@@ -638,7 +637,7 @@ function generateTechnique(
vertexShader += "}\n";
// Fragment shader lighting
- if (hasNormals) {
+ if (hasNormals && !isUnlit) {
fragmentShader += "const float M_PI = 3.141592653589793;\n";
fragmentShader +=
@@ -737,7 +736,7 @@ function generateTechnique(
fragmentShader += fragmentShaderMain;
// Add normal mapping to fragment shader
- if (hasNormals) {
+ if (hasNormals && !isUnlit) {
fragmentShader += " vec3 ng = normalize(v_normal);\n";
fragmentShader +=
" vec3 positionWC = vec3(czm_inverseView * vec4(v_positionEC, 1.0));\n";
@@ -814,7 +813,7 @@ function generateTechnique(
fragmentShader += " vec3 baseColor = baseColorWithAlpha.rgb;\n";
- if (hasNormals) {
+ if (hasNormals && !isUnlit) {
if (useSpecGloss) {
if (defined(generatedMaterialValues.u_specularGlossinessTexture)) {
fragmentShader +=
diff --git a/Source/Shaders/Builtin/Functions/unpackFloat.glsl b/Source/Shaders/Builtin/Functions/unpackFloat.glsl
index f13ce3c451a4..8cbcf4e51235 100644
--- a/Source/Shaders/Builtin/Functions/unpackFloat.glsl
+++ b/Source/Shaders/Builtin/Functions/unpackFloat.glsl
@@ -1,11 +1,5 @@
-#define SHIFT_RIGHT_8 0.00390625 //1.0 / 256.0
-#define SHIFT_RIGHT_16 0.00001525878 //1.0 / 65536.0
-#define SHIFT_RIGHT_24 5.960464477539063e-8//1.0 / 16777216.0
-
-#define BIAS 38.0
-
/**
- * Unpacks a vec4 value containing values expressable as uint8 to an arbitrary float.
+ * Unpack an IEEE 754 single-precision float that is packed as a little-endian unsigned normalized vec4.
*
* @name czm_unpackFloat
* @glslFunction
@@ -14,17 +8,17 @@
*
* @returns {float} The floating-point depth in arbitrary range.
*/
- float czm_unpackFloat(vec4 packedFloat)
+float czm_unpackFloat(vec4 packedFloat)
{
- packedFloat *= 255.0;
- float temp = packedFloat.w / 2.0;
- float exponent = floor(temp);
- float sign = (temp - exponent) * 2.0;
- exponent = exponent - float(BIAS);
- sign = sign * 2.0 - 1.0;
- sign = -sign;
- float unpacked = sign * packedFloat.x * float(SHIFT_RIGHT_8);
- unpacked += sign * packedFloat.y * float(SHIFT_RIGHT_16);
- unpacked += sign * packedFloat.z * float(SHIFT_RIGHT_24);
- return unpacked * pow(10.0, exponent);
+ // Convert to [0.0, 255.0] and round to integer
+ packedFloat = floor(packedFloat * 255.0 + 0.5);
+ float sign = 1.0 - step(128.0, packedFloat[3]) * 2.0;
+ float exponent = 2.0 * mod(packedFloat[3], 128.0) + step(128.0, packedFloat[2]) - 127.0;
+ if (exponent == -127.0)
+ {
+ return 0.0;
+ }
+ float mantissa = mod(packedFloat[2], 128.0) * 65536.0 + packedFloat[1] * 256.0 + packedFloat[0] + float(0x800000);
+ float result = sign * exp2(exponent - 23.0) * mantissa;
+ return result;
}
diff --git a/Source/Shaders/Materials/ElevationBandMaterial.glsl b/Source/Shaders/Materials/ElevationBandMaterial.glsl
new file mode 100644
index 000000000000..1e4a4ef53b3f
--- /dev/null
+++ b/Source/Shaders/Materials/ElevationBandMaterial.glsl
@@ -0,0 +1,74 @@
+uniform sampler2D heights;
+uniform sampler2D colors;
+
+// This material expects heights to be sorted from lowest to highest.
+
+float getHeight(int idx, float invTexSize)
+{
+ vec2 uv = vec2((float(idx) + 0.5) * invTexSize, 0.5);
+#ifdef OES_texture_float
+ return texture2D(heights, uv).x;
+#else
+ return czm_unpackFloat(texture2D(heights, uv));
+#endif
+}
+
+czm_material czm_getMaterial(czm_materialInput materialInput)
+{
+ czm_material material = czm_getDefaultMaterial(materialInput);
+
+ float height = materialInput.height;
+ float invTexSize = 1.0 / float(heightsDimensions.x);
+
+ float minHeight = getHeight(0, invTexSize);
+ float maxHeight = getHeight(heightsDimensions.x - 1, invTexSize);
+
+ // early-out when outside the height range
+ if (height < minHeight || height > maxHeight) {
+ material.diffuse = vec3(0.0);
+ material.alpha = 0.0;
+ return material;
+ }
+
+ // Binary search to find heights above and below.
+ int idxBelow = 0;
+ int idxAbove = heightsDimensions.x;
+ float heightBelow = minHeight;
+ float heightAbove = maxHeight;
+
+ // while loop not allowed, so use for loop with max iterations.
+ // maxIterations of 16 supports a texture size up to 65536 (2^16).
+ const int maxIterations = 16;
+ for (int i = 0; i < maxIterations; i++) {
+ if (idxBelow >= idxAbove - 1) {
+ break;
+ }
+
+ int idxMid = (idxBelow + idxAbove) / 2;
+ float heightTex = getHeight(idxMid, invTexSize);
+
+ if (height > heightTex) {
+ idxBelow = idxMid;
+ heightBelow = heightTex;
+ } else {
+ idxAbove = idxMid;
+ heightAbove = heightTex;
+ }
+ }
+
+ float lerper = heightBelow == heightAbove ? 1.0 : (height - heightBelow) / (heightAbove - heightBelow);
+ vec2 colorUv = vec2(invTexSize * (float(idxBelow) + 0.5 + lerper), 0.5);
+ vec4 color = texture2D(colors, colorUv);
+
+ // undo preumultiplied alpha
+ if (color.a > 0.0)
+ {
+ color.rgb /= color.a;
+ }
+
+ color.rgb = czm_gammaCorrect(color.rgb);
+
+ material.diffuse = color.rgb;
+ material.alpha = color.a;
+ return material;
+}
diff --git a/Source/ThirdParty/GltfPipeline/parseGlb.js b/Source/ThirdParty/GltfPipeline/parseGlb.js
index 937bf6ec283f..011efca02b38 100644
--- a/Source/ThirdParty/GltfPipeline/parseGlb.js
+++ b/Source/ThirdParty/GltfPipeline/parseGlb.js
@@ -2,8 +2,8 @@ import addPipelineExtras from './addPipelineExtras.js'
import removeExtensionsUsed from './removeExtensionsUsed.js'
import defaultValue from '../../Core/defaultValue.js'
import defined from '../../Core/defined.js'
+import getJsonFromTypedArray from '../../Core/getJsonFromTypedArray.js'
import getMagic from '../../Core/getMagic.js'
-import getStringFromTypedArray from '../../Core/getStringFromTypedArray.js'
import RuntimeError from '../../Core/RuntimeError.js'
var sizeOfUint32 = 4;
@@ -60,8 +60,7 @@ import RuntimeError from '../../Core/RuntimeError.js'
var jsonStart = 20;
var binaryStart = jsonStart + contentLength;
- var contentString = getStringFromTypedArray(glb, jsonStart, contentLength);
- var gltf = JSON.parse(contentString);
+ var gltf = getJsonFromTypedArray(glb, jsonStart, contentLength);
addPipelineExtras(gltf);
var binaryBuffer = glb.subarray(binaryStart, length);
@@ -93,8 +92,7 @@ import RuntimeError from '../../Core/RuntimeError.js'
byteOffset += chunkLength;
// Load JSON chunk
if (chunkType === 0x4E4F534A) {
- var jsonString = getStringFromTypedArray(chunkBuffer);
- gltf = JSON.parse(jsonString);
+ gltf = getJsonFromTypedArray(chunkBuffer);
addPipelineExtras(gltf);
}
// Load Binary chunk
diff --git a/Source/ThirdParty/purify.js b/Source/ThirdParty/purify.js
index 895787636304..b031c49dff0c 100644
--- a/Source/ThirdParty/purify.js
+++ b/Source/ThirdParty/purify.js
@@ -1,62 +1,197 @@
-var html = ['a', 'abbr', 'acronym', 'address', 'area', 'article', 'aside', 'audio', 'b', 'bdi', 'bdo', 'big', 'blink', 'blockquote', 'body', 'br', 'button', 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'content', 'data', 'datalist', 'dd', 'decorator', 'del', 'details', 'dfn', 'dir', 'div', 'dl', 'dt', 'element', 'em', 'fieldset', 'figcaption', 'figure', 'font', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'i', 'img', 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'main', 'map', 'mark', 'marquee', 'menu', 'menuitem', 'meter', 'nav', 'nobr', 'ol', 'optgroup', 'option', 'output', 'p', 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'section', 'select', 'shadow', 'small', 'source', 'spacer', 'span', 'strike', 'strong', 'style', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th', 'thead', 'time', 'tr', 'track', 'tt', 'u', 'ul', 'var', 'video', 'wbr'];
+/*! @license DOMPurify | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/2.0.8/LICENSE */
-// SVG
-var svg = ['svg', 'a', 'altglyph', 'altglyphdef', 'altglyphitem', 'animatecolor', 'animatemotion', 'animatetransform', 'audio', 'canvas', 'circle', 'clippath', 'defs', 'desc', 'ellipse', 'filter', 'font', 'g', 'glyph', 'glyphref', 'hkern', 'image', 'line', 'lineargradient', 'marker', 'mask', 'metadata', 'mpath', 'path', 'pattern', 'polygon', 'polyline', 'radialgradient', 'rect', 'stop', 'style', 'switch', 'symbol', 'text', 'textpath', 'title', 'tref', 'tspan', 'video', 'view', 'vkern'];
+function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
+
+var hasOwnProperty = Object.hasOwnProperty,
+ setPrototypeOf = Object.setPrototypeOf,
+ isFrozen = Object.isFrozen;
+var freeze = Object.freeze,
+ seal = Object.seal,
+ create = Object.create; // eslint-disable-line import/no-mutable-exports
+
+var _ref = typeof Reflect !== 'undefined' && Reflect,
+ apply = _ref.apply,
+ construct = _ref.construct;
+
+if (!apply) {
+ apply = function apply(fun, thisValue, args) {
+ return fun.apply(thisValue, args);
+ };
+}
+
+if (!freeze) {
+ freeze = function freeze(x) {
+ return x;
+ };
+}
-var svgFilters = ['feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence'];
+if (!seal) {
+ seal = function seal(x) {
+ return x;
+ };
+}
-var mathMl = ['math', 'menclose', 'merror', 'mfenced', 'mfrac', 'mglyph', 'mi', 'mlabeledtr', 'mmuliscripts', 'mn', 'mo', 'mover', 'mpadded', 'mphantom', 'mroot', 'mrow', 'ms', 'mpspace', 'msqrt', 'mystyle', 'msub', 'msup', 'msubsup', 'mtable', 'mtd', 'mtext', 'mtr', 'munder', 'munderover'];
+if (!construct) {
+ construct = function construct(Func, args) {
+ return new (Function.prototype.bind.apply(Func, [null].concat(_toConsumableArray(args))))();
+ };
+}
-var text = ['#text'];
+var arrayForEach = unapply(Array.prototype.forEach);
+var arrayPop = unapply(Array.prototype.pop);
+var arrayPush = unapply(Array.prototype.push);
-var html$1 = ['accept', 'action', 'align', 'alt', 'autocomplete', 'background', 'bgcolor', 'border', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'coords', 'crossorigin', 'datetime', 'default', 'dir', 'disabled', 'download', 'enctype', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'integrity', 'ismap', 'label', 'lang', 'list', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'multiple', 'name', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'pattern', 'placeholder', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'type', 'usemap', 'valign', 'value', 'width', 'xmlns'];
+var stringToLowerCase = unapply(String.prototype.toLowerCase);
+var stringMatch = unapply(String.prototype.match);
+var stringReplace = unapply(String.prototype.replace);
+var stringIndexOf = unapply(String.prototype.indexOf);
+var stringTrim = unapply(String.prototype.trim);
+
+var regExpTest = unapply(RegExp.prototype.test);
+
+var typeErrorCreate = unconstruct(TypeError);
+
+function unapply(func) {
+ return function (thisArg) {
+ for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
+ args[_key - 1] = arguments[_key];
+ }
-var svg$1 = ['accent-height', 'accumulate', 'additivive', 'alignment-baseline', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cx', 'cy', 'd', 'dx', 'dy', 'diffuseconstant', 'direction', 'display', 'divisor', 'dur', 'edgemode', 'elevation', 'end', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'fx', 'fy', 'g1', 'g2', 'glyph-name', 'glyphref', 'gradientunits', 'gradienttransform', 'height', 'href', 'id', 'image-rendering', 'in', 'in2', 'k', 'k1', 'k2', 'k3', 'k4', 'kerning', 'keypoints', 'keysplines', 'keytimes', 'lang', 'lengthadjust', 'letter-spacing', 'kernelmatrix', 'kernelunitlength', 'lighting-color', 'local', 'marker-end', 'marker-mid', 'marker-start', 'markerheight', 'markerunits', 'markerwidth', 'maskcontentunits', 'maskunits', 'max', 'mask', 'media', 'method', 'mode', 'min', 'name', 'numoctaves', 'offset', 'operator', 'opacity', 'order', 'orient', 'orientation', 'origin', 'overflow', 'paint-order', 'path', 'pathlength', 'patterncontentunits', 'patterntransform', 'patternunits', 'points', 'preservealpha', 'preserveaspectratio', 'r', 'rx', 'ry', 'radius', 'refx', 'refy', 'repeatcount', 'repeatdur', 'restart', 'result', 'rotate', 'scale', 'seed', 'shape-rendering', 'specularconstant', 'specularexponent', 'spreadmethod', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', 'tabindex', 'targetx', 'targety', 'transform', 'text-anchor', 'text-decoration', 'text-rendering', 'textlength', 'type', 'u1', 'u2', 'unicode', 'values', 'viewbox', 'visibility', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'width', 'word-spacing', 'wrap', 'writing-mode', 'xchannelselector', 'ychannelselector', 'x', 'x1', 'x2', 'xmlns', 'y', 'y1', 'y2', 'z', 'zoomandpan'];
+ return apply(func, thisArg, args);
+ };
+}
-var mathMl$1 = ['accent', 'accentunder', 'align', 'bevelled', 'close', 'columnsalign', 'columnlines', 'columnspan', 'denomalign', 'depth', 'dir', 'display', 'displaystyle', 'fence', 'frame', 'height', 'href', 'id', 'largeop', 'length', 'linethickness', 'lspace', 'lquote', 'mathbackground', 'mathcolor', 'mathsize', 'mathvariant', 'maxsize', 'minsize', 'movablelimits', 'notation', 'numalign', 'open', 'rowalign', 'rowlines', 'rowspacing', 'rowspan', 'rspace', 'rquote', 'scriptlevel', 'scriptminsize', 'scriptsizemultiplier', 'selection', 'separator', 'separators', 'stretchy', 'subscriptshift', 'supscriptshift', 'symmetric', 'voffset', 'width', 'xmlns'];
+function unconstruct(func) {
+ return function () {
+ for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
+ args[_key2] = arguments[_key2];
+ }
-var xml = ['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink'];
+ return construct(func, args);
+ };
+}
/* Add properties to a lookup table */
function addToSet(set, array) {
+ if (setPrototypeOf) {
+ // Make 'in' and truthy checks like Boolean(set.constructor)
+ // independent of any properties defined on Object.prototype.
+ // Prevent prototype setters from intercepting set as a this value.
+ setPrototypeOf(set, null);
+ }
+
var l = array.length;
while (l--) {
- if (typeof array[l] === 'string') {
- array[l] = array[l].toLowerCase();
+ var element = array[l];
+ if (typeof element === 'string') {
+ var lcElement = stringToLowerCase(element);
+ if (lcElement !== element) {
+ // Config presets (e.g. tags.js, attrs.js) are immutable.
+ if (!isFrozen(array)) {
+ array[l] = lcElement;
+ }
+
+ element = lcElement;
+ }
}
- set[array[l]] = true;
+
+ set[element] = true;
}
+
return set;
}
/* Shallow clone an object */
function clone(object) {
- var newObject = {};
+ var newObject = create(null);
+
var property = void 0;
for (property in object) {
- if (Object.prototype.hasOwnProperty.call(object, property)) {
+ if (apply(hasOwnProperty, object, [property])) {
newObject[property] = object[property];
}
}
+
return newObject;
}
-var MUSTACHE_EXPR = /\{\{[\s\S]*|[\s\S]*\}\}/gm; // Specify template detection regex for SAFE_FOR_TEMPLATES mode
-var ERB_EXPR = /<%[\s\S]*|[\s\S]*%>/gm;
-var DATA_ATTR = /^data-[\-\w.\u00B7-\uFFFF]/; // eslint-disable-line no-useless-escape
-var ARIA_ATTR = /^aria-[\-\w]+$/; // eslint-disable-line no-useless-escape
-var IS_ALLOWED_URI = /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i; // eslint-disable-line no-useless-escape
-var IS_SCRIPT_OR_DATA = /^(?:\w+script|data):/i;
-var ATTR_WHITESPACE = /[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205f\u3000]/g; // eslint-disable-line no-control-regex
+var html = freeze(['a', 'abbr', 'acronym', 'address', 'area', 'article', 'aside', 'audio', 'b', 'bdi', 'bdo', 'big', 'blink', 'blockquote', 'body', 'br', 'button', 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'content', 'data', 'datalist', 'dd', 'decorator', 'del', 'details', 'dfn', 'dialog', 'dir', 'div', 'dl', 'dt', 'element', 'em', 'fieldset', 'figcaption', 'figure', 'font', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'i', 'img', 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'main', 'map', 'mark', 'marquee', 'menu', 'menuitem', 'meter', 'nav', 'nobr', 'ol', 'optgroup', 'option', 'output', 'p', 'picture', 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'section', 'select', 'shadow', 'small', 'source', 'spacer', 'span', 'strike', 'strong', 'style', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th', 'thead', 'time', 'tr', 'track', 'tt', 'u', 'ul', 'var', 'video', 'wbr']);
+
+// SVG
+var svg = freeze(['svg', 'a', 'altglyph', 'altglyphdef', 'altglyphitem', 'animatecolor', 'animatemotion', 'animatetransform', 'audio', 'canvas', 'circle', 'clippath', 'defs', 'desc', 'ellipse', 'filter', 'font', 'g', 'glyph', 'glyphref', 'hkern', 'image', 'line', 'lineargradient', 'marker', 'mask', 'metadata', 'mpath', 'path', 'pattern', 'polygon', 'polyline', 'radialgradient', 'rect', 'stop', 'style', 'switch', 'symbol', 'text', 'textpath', 'title', 'tref', 'tspan', 'video', 'view', 'vkern']);
+
+var svgFilters = freeze(['feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence']);
+
+var mathMl = freeze(['math', 'menclose', 'merror', 'mfenced', 'mfrac', 'mglyph', 'mi', 'mlabeledtr', 'mmultiscripts', 'mn', 'mo', 'mover', 'mpadded', 'mphantom', 'mroot', 'mrow', 'ms', 'mspace', 'msqrt', 'mstyle', 'msub', 'msup', 'msubsup', 'mtable', 'mtd', 'mtext', 'mtr', 'munder', 'munderover']);
+
+var text = freeze(['#text']);
+
+var html$1 = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'pattern', 'placeholder', 'playsinline', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'xmlns']);
+
+var svg$1 = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', 'clippathunits', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cx', 'cy', 'd', 'dx', 'dy', 'diffuseconstant', 'direction', 'display', 'divisor', 'dur', 'edgemode', 'elevation', 'end', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'filterunits', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'fx', 'fy', 'g1', 'g2', 'glyph-name', 'glyphref', 'gradientunits', 'gradienttransform', 'height', 'href', 'id', 'image-rendering', 'in', 'in2', 'k', 'k1', 'k2', 'k3', 'k4', 'kerning', 'keypoints', 'keysplines', 'keytimes', 'lang', 'lengthadjust', 'letter-spacing', 'kernelmatrix', 'kernelunitlength', 'lighting-color', 'local', 'marker-end', 'marker-mid', 'marker-start', 'markerheight', 'markerunits', 'markerwidth', 'maskcontentunits', 'maskunits', 'max', 'mask', 'media', 'method', 'mode', 'min', 'name', 'numoctaves', 'offset', 'operator', 'opacity', 'order', 'orient', 'orientation', 'origin', 'overflow', 'paint-order', 'path', 'pathlength', 'patterncontentunits', 'patterntransform', 'patternunits', 'points', 'preservealpha', 'preserveaspectratio', 'primitiveunits', 'r', 'rx', 'ry', 'radius', 'refx', 'refy', 'repeatcount', 'repeatdur', 'restart', 'result', 'rotate', 'scale', 'seed', 'shape-rendering', 'specularconstant', 'specularexponent', 'spreadmethod', 'startoffset', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', 'systemlanguage', 'tabindex', 'targetx', 'targety', 'transform', 'text-anchor', 'text-decoration', 'text-rendering', 'textlength', 'type', 'u1', 'u2', 'unicode', 'values', 'viewbox', 'visibility', 'version', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'width', 'word-spacing', 'wrap', 'writing-mode', 'xchannelselector', 'ychannelselector', 'x', 'x1', 'x2', 'xmlns', 'y', 'y1', 'y2', 'z', 'zoomandpan']);
+
+var mathMl$1 = freeze(['accent', 'accentunder', 'align', 'bevelled', 'close', 'columnsalign', 'columnlines', 'columnspan', 'denomalign', 'depth', 'dir', 'display', 'displaystyle', 'encoding', 'fence', 'frame', 'height', 'href', 'id', 'largeop', 'length', 'linethickness', 'lspace', 'lquote', 'mathbackground', 'mathcolor', 'mathsize', 'mathvariant', 'maxsize', 'minsize', 'movablelimits', 'notation', 'numalign', 'open', 'rowalign', 'rowlines', 'rowspacing', 'rowspan', 'rspace', 'rquote', 'scriptlevel', 'scriptminsize', 'scriptsizemultiplier', 'selection', 'separator', 'separators', 'stretchy', 'subscriptshift', 'supscriptshift', 'symmetric', 'voffset', 'width', 'xmlns']);
+
+var xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);
+
+// eslint-disable-next-line unicorn/better-regex
+var MUSTACHE_EXPR = seal(/\{\{[\s\S]*|[\s\S]*\}\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode
+var ERB_EXPR = seal(/<%[\s\S]*|[\s\S]*%>/gm);
+var DATA_ATTR = seal(/^data-[\-\w.\u00B7-\uFFFF]/); // eslint-disable-line no-useless-escape
+var ARIA_ATTR = seal(/^aria-[\-\w]+$/); // eslint-disable-line no-useless-escape
+var IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i // eslint-disable-line no-useless-escape
+);
+var IS_SCRIPT_OR_DATA = seal(/^(?:\w+script|data):/i);
+var ATTR_WHITESPACE = seal(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g // eslint-disable-line no-control-regex
+);
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
-function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
+function _toConsumableArray$1(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
var getGlobal = function getGlobal() {
return typeof window === 'undefined' ? null : window;
};
+/**
+ * Creates a no-op policy for internal use only.
+ * Don't export this function outside this module!
+ * @param {?TrustedTypePolicyFactory} trustedTypes The policy factory.
+ * @param {Document} document The document object (to determine policy name suffix)
+ * @return {?TrustedTypePolicy} The policy created (or null, if Trusted Types
+ * are not supported).
+ */
+var _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, document) {
+ if ((typeof trustedTypes === 'undefined' ? 'undefined' : _typeof(trustedTypes)) !== 'object' || typeof trustedTypes.createPolicy !== 'function') {
+ return null;
+ }
+
+ // Allow the callers to control the unique policy name
+ // by adding a data-tt-policy-suffix to the script element with the DOMPurify.
+ // Policy creation with duplicate names throws in Trusted Types.
+ var suffix = null;
+ var ATTR_NAME = 'data-tt-policy-suffix';
+ if (document.currentScript && document.currentScript.hasAttribute(ATTR_NAME)) {
+ suffix = document.currentScript.getAttribute(ATTR_NAME);
+ }
+
+ var policyName = 'dompurify' + (suffix ? '#' + suffix : '');
+
+ try {
+ return trustedTypes.createPolicy(policyName, {
+ createHTML: function createHTML(html$$1) {
+ return html$$1;
+ }
+ });
+ } catch (_) {
+ // Policy creation failed (most likely another DOMPurify script has
+ // already run). Skip creating the policy, as this will only cause errors
+ // if TT are enforced.
+ console.warn('TrustedTypes policy ' + policyName + ' could not be created.');
+ return null;
+ }
+};
+
function createDOMPurify() {
var window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
@@ -68,7 +203,7 @@ function createDOMPurify() {
* Version label, exposed for easier checks
* if DOMPurify is up to date or not
*/
- DOMPurify.version = '1.0.8';
+ DOMPurify.version = '2.2.2';
/**
* Array of elements that DOMPurify removed during sanitation.
@@ -85,8 +220,6 @@ function createDOMPurify() {
}
var originalDocument = window.document;
- var useDOMParser = false; // See comment below
- var removeTitle = false; // See comment below
var document = window.document;
var DocumentFragment = window.DocumentFragment,
@@ -97,7 +230,8 @@ function createDOMPurify() {
NamedNodeMap = _window$NamedNodeMap === undefined ? window.NamedNodeMap || window.MozNamedAttrMap : _window$NamedNodeMap,
Text = window.Text,
Comment = window.Comment,
- DOMParser = window.DOMParser;
+ DOMParser = window.DOMParser,
+ trustedTypes = window.trustedTypes;
// As per issue #47, the web-components registry is inherited by a
// new document created via createHTMLDocument. As per the spec
@@ -113,6 +247,9 @@ function createDOMPurify() {
}
}
+ var trustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, originalDocument);
+ var emptyHTML = trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML('') : '';
+
var _document = document,
implementation = _document.implementation,
createNodeIterator = _document.createNodeIterator,
@@ -121,12 +258,17 @@ function createDOMPurify() {
var importNode = originalDocument.importNode;
+ var documentMode = {};
+ try {
+ documentMode = clone(document).documentMode ? document.documentMode : {};
+ } catch (_) {}
+
var hooks = {};
/**
* Expose whether this browser supports running the full DOMPurify.
*/
- DOMPurify.isSupported = implementation && typeof implementation.createHTMLDocument !== 'undefined' && document.documentMode !== 9;
+ DOMPurify.isSupported = implementation && typeof implementation.createHTMLDocument !== 'undefined' && documentMode !== 9;
var MUSTACHE_EXPR$$1 = MUSTACHE_EXPR,
ERB_EXPR$$1 = ERB_EXPR,
@@ -135,6 +277,7 @@ function createDOMPurify() {
IS_SCRIPT_OR_DATA$$1 = IS_SCRIPT_OR_DATA,
ATTR_WHITESPACE$$1 = ATTR_WHITESPACE;
var IS_ALLOWED_URI$$1 = IS_ALLOWED_URI;
+
/**
* We consider the elements and attributes below to be safe. Ideally
* don't add any new ones but feel free to remove unwanted ones.
@@ -143,11 +286,11 @@ function createDOMPurify() {
/* allowed element names */
var ALLOWED_TAGS = null;
- var DEFAULT_ALLOWED_TAGS = addToSet({}, [].concat(_toConsumableArray(html), _toConsumableArray(svg), _toConsumableArray(svgFilters), _toConsumableArray(mathMl), _toConsumableArray(text)));
+ var DEFAULT_ALLOWED_TAGS = addToSet({}, [].concat(_toConsumableArray$1(html), _toConsumableArray$1(svg), _toConsumableArray$1(svgFilters), _toConsumableArray$1(mathMl), _toConsumableArray$1(text)));
/* Allowed attribute names */
var ALLOWED_ATTR = null;
- var DEFAULT_ALLOWED_ATTR = addToSet({}, [].concat(_toConsumableArray(html$1), _toConsumableArray(svg$1), _toConsumableArray(mathMl$1), _toConsumableArray(xml)));
+ var DEFAULT_ALLOWED_ATTR = addToSet({}, [].concat(_toConsumableArray$1(html$1), _toConsumableArray$1(svg$1), _toConsumableArray$1(mathMl$1), _toConsumableArray$1(xml)));
/* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */
var FORBID_TAGS = null;
@@ -164,9 +307,6 @@ function createDOMPurify() {
/* Decide if unknown protocols are okay */
var ALLOW_UNKNOWN_PROTOCOLS = false;
- /* Output should be safe for jQuery's $() factory? */
- var SAFE_FOR_JQUERY = false;
-
/* Output should be safe for common template engines.
* This means, DOMPurify removes data attributes, mustaches and ERB
*/
@@ -182,19 +322,30 @@ function createDOMPurify() {
* document.body. By default, browsers might move them to document.head */
var FORCE_BODY = false;
- /* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html string.
+ /* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html
+ * string (or a TrustedHTML object if Trusted Types are supported).
* If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead
*/
var RETURN_DOM = false;
- /* Decide if a DOM `DocumentFragment` should be returned, instead of a html string */
+ /* Decide if a DOM `DocumentFragment` should be returned, instead of a html
+ * string (or a TrustedHTML object if Trusted Types are supported) */
var RETURN_DOM_FRAGMENT = false;
/* If `RETURN_DOM` or `RETURN_DOM_FRAGMENT` is enabled, decide if the returned DOM
* `Node` is imported into the current `Document`. If this flag is not enabled the
* `Node` will belong (its ownerDocument) to a fresh `HTMLDocument`, created by
- * DOMPurify. */
- var RETURN_DOM_IMPORT = false;
+ * DOMPurify.
+ *
+ * This defaults to `true` starting DOMPurify 2.2.0. Note that setting it to `false`
+ * might cause XSS from attacks hidden in closed shadowroots in case the browser
+ * supports Declarative Shadow: DOM https://web.dev/declarative-shadow-dom/
+ */
+ var RETURN_DOM_IMPORT = true;
+
+ /* Try to return a Trusted Type object instead of a string, return a string in
+ * case Trusted Types are not supported */
+ var RETURN_TRUSTED_TYPE = false;
/* Output should be free from DOM clobbering attacks? */
var SANITIZE_DOM = true;
@@ -210,13 +361,15 @@ function createDOMPurify() {
var USE_PROFILES = {};
/* Tags to ignore content of when KEEP_CONTENT is true */
- var FORBID_CONTENTS = addToSet({}, ['audio', 'head', 'math', 'script', 'style', 'template', 'svg', 'video']);
+ var FORBID_CONTENTS = addToSet({}, ['annotation-xml', 'audio', 'colgroup', 'desc', 'foreignobject', 'head', 'iframe', 'math', 'mi', 'mn', 'mo', 'ms', 'mtext', 'noembed', 'noframes', 'plaintext', 'script', 'style', 'svg', 'template', 'thead', 'title', 'video', 'xmp']);
/* Tags that are safe for data: URIs */
- var DATA_URI_TAGS = addToSet({}, ['audio', 'video', 'img', 'source', 'image']);
+ var DATA_URI_TAGS = null;
+ var DEFAULT_DATA_URI_TAGS = addToSet({}, ['audio', 'video', 'img', 'source', 'image', 'track']);
/* Attributes safe for values like "javascript:" */
- var URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'summary', 'title', 'value', 'style', 'xmlns']);
+ var URI_SAFE_ATTRIBUTES = null;
+ var DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'summary', 'title', 'value', 'style', 'xmlns']);
/* Keep a reference to config to pass to hooks */
var CONFIG = null;
@@ -233,32 +386,40 @@ function createDOMPurify() {
*/
// eslint-disable-next-line complexity
var _parseConfig = function _parseConfig(cfg) {
+ if (CONFIG && CONFIG === cfg) {
+ return;
+ }
+
/* Shield configuration object from tampering */
- if ((typeof cfg === 'undefined' ? 'undefined' : _typeof(cfg)) !== 'object') {
+ if (!cfg || (typeof cfg === 'undefined' ? 'undefined' : _typeof(cfg)) !== 'object') {
cfg = {};
}
+
+ /* Shield configuration object from prototype pollution */
+ cfg = clone(cfg);
+
/* Set configuration parameters */
ALLOWED_TAGS = 'ALLOWED_TAGS' in cfg ? addToSet({}, cfg.ALLOWED_TAGS) : DEFAULT_ALLOWED_TAGS;
ALLOWED_ATTR = 'ALLOWED_ATTR' in cfg ? addToSet({}, cfg.ALLOWED_ATTR) : DEFAULT_ALLOWED_ATTR;
+ URI_SAFE_ATTRIBUTES = 'ADD_URI_SAFE_ATTR' in cfg ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), cfg.ADD_URI_SAFE_ATTR) : DEFAULT_URI_SAFE_ATTRIBUTES;
+ DATA_URI_TAGS = 'ADD_DATA_URI_TAGS' in cfg ? addToSet(clone(DEFAULT_DATA_URI_TAGS), cfg.ADD_DATA_URI_TAGS) : DEFAULT_DATA_URI_TAGS;
FORBID_TAGS = 'FORBID_TAGS' in cfg ? addToSet({}, cfg.FORBID_TAGS) : {};
FORBID_ATTR = 'FORBID_ATTR' in cfg ? addToSet({}, cfg.FORBID_ATTR) : {};
USE_PROFILES = 'USE_PROFILES' in cfg ? cfg.USE_PROFILES : false;
ALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true
ALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true
ALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; // Default false
- SAFE_FOR_JQUERY = cfg.SAFE_FOR_JQUERY || false; // Default false
SAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false; // Default false
WHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; // Default false
RETURN_DOM = cfg.RETURN_DOM || false; // Default false
RETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; // Default false
- RETURN_DOM_IMPORT = cfg.RETURN_DOM_IMPORT || false; // Default false
+ RETURN_DOM_IMPORT = cfg.RETURN_DOM_IMPORT !== false; // Default true
+ RETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false; // Default false
FORCE_BODY = cfg.FORCE_BODY || false; // Default false
SANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true
KEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true
IN_PLACE = cfg.IN_PLACE || false; // Default false
-
IS_ALLOWED_URI$$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI$$1;
-
if (SAFE_FOR_TEMPLATES) {
ALLOW_DATA_ATTR = false;
}
@@ -269,22 +430,25 @@ function createDOMPurify() {
/* Parse profile info */
if (USE_PROFILES) {
- ALLOWED_TAGS = addToSet({}, [].concat(_toConsumableArray(text)));
+ ALLOWED_TAGS = addToSet({}, [].concat(_toConsumableArray$1(text)));
ALLOWED_ATTR = [];
if (USE_PROFILES.html === true) {
addToSet(ALLOWED_TAGS, html);
addToSet(ALLOWED_ATTR, html$1);
}
+
if (USE_PROFILES.svg === true) {
addToSet(ALLOWED_TAGS, svg);
addToSet(ALLOWED_ATTR, svg$1);
addToSet(ALLOWED_ATTR, xml);
}
+
if (USE_PROFILES.svgFilters === true) {
addToSet(ALLOWED_TAGS, svgFilters);
addToSet(ALLOWED_ATTR, svg$1);
addToSet(ALLOWED_ATTR, xml);
}
+
if (USE_PROFILES.mathMl === true) {
addToSet(ALLOWED_TAGS, mathMl);
addToSet(ALLOWED_ATTR, mathMl$1);
@@ -297,14 +461,18 @@ function createDOMPurify() {
if (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {
ALLOWED_TAGS = clone(ALLOWED_TAGS);
}
+
addToSet(ALLOWED_TAGS, cfg.ADD_TAGS);
}
+
if (cfg.ADD_ATTR) {
if (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {
ALLOWED_ATTR = clone(ALLOWED_ATTR);
}
+
addToSet(ALLOWED_ATTR, cfg.ADD_ATTR);
}
+
if (cfg.ADD_URI_SAFE_ATTR) {
addToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR);
}
@@ -319,15 +487,16 @@ function createDOMPurify() {
addToSet(ALLOWED_TAGS, ['html', 'head', 'body']);
}
- /* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286 */
+ /* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286, #365 */
if (ALLOWED_TAGS.table) {
addToSet(ALLOWED_TAGS, ['tbody']);
+ delete FORBID_TAGS.tbody;
}
// Prevent further manipulation of configuration.
// Not available in IE8, Safari 5, etc.
- if (Object && 'freeze' in Object) {
- Object.freeze(cfg);
+ if (freeze) {
+ freeze(cfg);
}
CONFIG = cfg;
@@ -339,11 +508,11 @@ function createDOMPurify() {
* @param {Node} node a DOM node
*/
var _forceRemove = function _forceRemove(node) {
- DOMPurify.removed.push({ element: node });
+ arrayPush(DOMPurify.removed, { element: node });
try {
node.parentNode.removeChild(node);
- } catch (err) {
- node.outerHTML = '';
+ } catch (_) {
+ node.outerHTML = emptyHTML;
}
};
@@ -355,16 +524,17 @@ function createDOMPurify() {
*/
var _removeAttribute = function _removeAttribute(name, node) {
try {
- DOMPurify.removed.push({
+ arrayPush(DOMPurify.removed, {
attribute: node.getAttributeNode(name),
from: node
});
- } catch (err) {
- DOMPurify.removed.push({
+ } catch (_) {
+ arrayPush(DOMPurify.removed, {
attribute: null,
from: node
});
}
+
node.removeAttribute(name);
};
@@ -383,37 +553,27 @@ function createDOMPurify() {
dirty = '