mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 865407 - Part 8: Update vtt.js to latest version. r=rillian
This completes the initial implementation of the processing algorithm. The algorithm doesn't support vertical text yet, but that's not a big issue since Firefox doesn't support it.
This commit is contained in:
parent
2b1ee432d6
commit
0610cbd281
@ -52,7 +52,7 @@ WebVTTParserWrapper.prototype =
|
|||||||
|
|
||||||
processCues: function(window, cues, overlay)
|
processCues: function(window, cues, overlay)
|
||||||
{
|
{
|
||||||
WebVTTParser.processCues(window, cues, null, overlay);
|
WebVTTParser.processCues(window, cues, overlay);
|
||||||
},
|
},
|
||||||
|
|
||||||
classDescription: "Wrapper for the JS WebVTTParser (vtt.js)",
|
classDescription: "Wrapper for the JS WebVTTParser (vtt.js)",
|
||||||
|
@ -8,7 +8,7 @@ this.EXPORTED_SYMBOLS = ["WebVTTParser"];
|
|||||||
* Code below is vtt.js the JS WebVTTParser.
|
* Code below is vtt.js the JS WebVTTParser.
|
||||||
* Current source code can be found at http://github.com/andreasgal/vtt.js
|
* Current source code can be found at http://github.com/andreasgal/vtt.js
|
||||||
*
|
*
|
||||||
* Code taken from commit d819872e198d051dfcebcfb7ecf260462c9a9c6f
|
* Code taken from commit b812cd783d4284de1bc6b0349b7bda151052a1df
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* Copyright 2013 vtt.js Contributors
|
* Copyright 2013 vtt.js Contributors
|
||||||
@ -101,22 +101,20 @@ this.EXPORTED_SYMBOLS = ["WebVTTParser"];
|
|||||||
// Accept a setting if its a valid (signed) integer.
|
// Accept a setting if its a valid (signed) integer.
|
||||||
integer: function(k, v) {
|
integer: function(k, v) {
|
||||||
if (/^-?\d+$/.test(v)) { // integer
|
if (/^-?\d+$/.test(v)) { // integer
|
||||||
this.set(k, parseInt(v, 10));
|
// Only take values in the range of -1000 ~ 1000
|
||||||
|
this.set(k, Math.min(Math.max(parseInt(v, 10), -1000), 1000));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// Accept a setting if its a valid percentage.
|
// Accept a setting if its a valid percentage.
|
||||||
percent: function(k, v, frac) {
|
percent: function(k, v) {
|
||||||
var m;
|
var m;
|
||||||
if ((m = v.match(/^([\d]{1,3})(\.[\d]*)?%$/))) {
|
if ((m = v.match(/^([\d]{1,3})(\.[\d]*)?%$/))) {
|
||||||
v = v.replace("%", "");
|
|
||||||
if (!m[2] || (m[2] && frac)) {
|
|
||||||
v = parseFloat(v);
|
v = parseFloat(v);
|
||||||
if (v >= 0 && v <= 100) {
|
if (v >= 0 && v <= 100) {
|
||||||
this.set(k, v);
|
this.set(k, v);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -664,25 +662,59 @@ this.EXPORTED_SYMBOLS = ["WebVTTParser"];
|
|||||||
return ++count * -1;
|
return ++count * -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
function BoundingBox() {
|
function StyleBox() {
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundingBox.prototype.applyStyles = function(styles) {
|
// Apply styles to a div. If there is no div passed then it defaults to the
|
||||||
var div = this.div;
|
// div on 'this'.
|
||||||
|
StyleBox.prototype.applyStyles = function(styles, div) {
|
||||||
|
div = div || this.div;
|
||||||
Object.keys(styles).forEach(function(style) {
|
Object.keys(styles).forEach(function(style) {
|
||||||
div.style[style] = styles[style];
|
div.style[style] = styles[style];
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
BoundingBox.prototype.formatStyle = function(val, unit) {
|
StyleBox.prototype.formatStyle = function(val, unit) {
|
||||||
return val === 0 ? 0 : val + unit;
|
return val === 0 ? 0 : val + unit;
|
||||||
};
|
};
|
||||||
|
|
||||||
function BasicBoundingBox(window, cue) {
|
// Constructs the computed display state of the cue (a div). Places the div
|
||||||
BoundingBox.call(this);
|
// into the overlay which should be a block level element (usually a div).
|
||||||
|
function CueStyleBox(window, cue, styleOptions) {
|
||||||
|
StyleBox.call(this);
|
||||||
|
this.cue = cue;
|
||||||
|
|
||||||
// Parse our cue's text into a DOM tree rooted at 'div'.
|
// Parse our cue's text into a DOM tree rooted at 'cueDiv'. This div will
|
||||||
this.div = parseContent(window, cue.text);
|
// have inline positioning and will function as the cue background box.
|
||||||
|
this.cueDiv = parseContent(window, cue.text);
|
||||||
|
this.applyStyles({
|
||||||
|
color: "rgba(255, 255, 255, 1)",
|
||||||
|
backgroundColor: "rgba(0, 0, 0, 0.8)",
|
||||||
|
position: "relative",
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
top: 0,
|
||||||
|
bottom: 0,
|
||||||
|
display: "inline"
|
||||||
|
}, this.cueDiv);
|
||||||
|
|
||||||
|
// Create an absolutely positioned div that will be used to position the cue
|
||||||
|
// div. Note, all WebVTT cue-setting alignments are equivalent to the CSS
|
||||||
|
// mirrors of them except "middle" which is "center" in CSS.
|
||||||
|
this.div = window.document.createElement("div");
|
||||||
|
this.applyStyles({
|
||||||
|
textAlign: cue.align === "middle" ? "center" : cue.align,
|
||||||
|
direction: determineBidi(this.cueDiv),
|
||||||
|
writingMode: cue.vertical === "" ? "horizontal-tb"
|
||||||
|
: cue.vertical === "lr" ? "vertical-lr"
|
||||||
|
: "vertical-rl",
|
||||||
|
unicodeBidi: "plaintext",
|
||||||
|
font: styleOptions.font,
|
||||||
|
whiteSpace: "pre-line",
|
||||||
|
position: "absolute"
|
||||||
|
});
|
||||||
|
|
||||||
|
this.div.appendChild(this.cueDiv);
|
||||||
|
|
||||||
// Calculate the distance from the reference edge of the viewport to the text
|
// Calculate the distance from the reference edge of the viewport to the text
|
||||||
// position of the cue box. The reference edge will be resolved later when
|
// position of the cue box. The reference edge will be resolved later when
|
||||||
@ -718,150 +750,278 @@ this.EXPORTED_SYMBOLS = ["WebVTTParser"];
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// All WebVTT cue-setting alignments are equivalent to the CSS mirrors of
|
this.move = function(box) {
|
||||||
// them except "middle" which is "center" in CSS.
|
|
||||||
this.applyStyles({
|
this.applyStyles({
|
||||||
"textAlign": cue.align === "middle" ? "center" : cue.align
|
top: this.formatStyle(box.top, "px"),
|
||||||
|
bottom: this.formatStyle(box.bottom, "px"),
|
||||||
|
left: this.formatStyle(box.left, "px"),
|
||||||
|
right: this.formatStyle(box.right, "px"),
|
||||||
|
height: this.formatStyle(box.height, "px"),
|
||||||
|
width: this.formatStyle(box.width, "px"),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
CueStyleBox.prototype = Object.create(StyleBox.prototype);
|
||||||
|
CueStyleBox.prototype.constructor = CueStyleBox;
|
||||||
|
|
||||||
|
// Represents the co-ordinates of an Element in a way that we can easily
|
||||||
|
// compute things with such as if it overlaps or intersects with another Element.
|
||||||
|
// Can initialize it with either a StyleBox or another BoxPosition.
|
||||||
|
function BoxPosition(obj) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
// Either a BoxPosition was passed in and we need to copy it, or a StyleBox
|
||||||
|
// was passed in and we need to copy the results of 'getBoundingClientRect'
|
||||||
|
// as the object returned is readonly. All co-ordinate values are in reference
|
||||||
|
// to the viewport origin (top left).
|
||||||
|
var lh;
|
||||||
|
if (obj.div) {
|
||||||
|
var rects = (rects = obj.div.childNodes) && (rects = rects[0]) &&
|
||||||
|
rects.getClientRects && rects.getClientRects();
|
||||||
|
obj = obj.div.getBoundingClientRect();
|
||||||
|
// In certain cases the outter div will be slightly larger then the sum of
|
||||||
|
// the inner div's lines. This could be due to bold text, etc, on some platforms.
|
||||||
|
// In this case we should get the average line height and use that. This will
|
||||||
|
// result in the desired behaviour.
|
||||||
|
lh = rects ? Math.max((rects[0] && rects[0].height) || 0, obj.height / rects.length)
|
||||||
|
: 0;
|
||||||
|
}
|
||||||
|
this.left = obj.left;
|
||||||
|
this.right = obj.right;
|
||||||
|
this.top = obj.top;
|
||||||
|
this.height = obj.height;
|
||||||
|
this.bottom = obj.bottom;
|
||||||
|
this.width = obj.width;
|
||||||
|
this.lineHeight = lh !== undefined ? lh : obj.lineHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move the box along a particular axis. If no amount to move is passed, via
|
||||||
|
// the val parameter, then the default amount is the line height of the box.
|
||||||
|
BoxPosition.prototype.move = function(axis, val) {
|
||||||
|
val = val !== undefined ? val : this.lineHeight;
|
||||||
|
switch (axis) {
|
||||||
|
case "+x":
|
||||||
|
this.left += val;
|
||||||
|
this.right += val;
|
||||||
|
break;
|
||||||
|
case "-x":
|
||||||
|
this.left -= val;
|
||||||
|
this.right -= val;
|
||||||
|
break;
|
||||||
|
case "+y":
|
||||||
|
this.top += val;
|
||||||
|
this.bottom += val;
|
||||||
|
break;
|
||||||
|
case "-y":
|
||||||
|
this.top -= val;
|
||||||
|
this.bottom -= val;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check if this box overlaps another box, b2.
|
||||||
|
BoxPosition.prototype.overlaps = function(b2) {
|
||||||
|
return this.left < b2.right &&
|
||||||
|
this.right > b2.left &&
|
||||||
|
this.top < b2.bottom &&
|
||||||
|
this.bottom > b2.top;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check if this box overlaps any other boxes in boxes.
|
||||||
|
BoxPosition.prototype.overlapsAny = function(boxes) {
|
||||||
|
for (var i = 0; i < boxes.length; i++) {
|
||||||
|
if (this.overlaps(boxes[i])) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check if this box is within another box.
|
||||||
|
BoxPosition.prototype.within = function(container) {
|
||||||
|
return this.top >= container.top &&
|
||||||
|
this.bottom <= container.bottom &&
|
||||||
|
this.left >= container.left &&
|
||||||
|
this.right <= container.right;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check if this box is entirely within the container or it is overlapping
|
||||||
|
// on the edge opposite of the axis direction passed. For example, if "+x" is
|
||||||
|
// passed and the box is overlapping on the left edge of the container, then
|
||||||
|
// return true.
|
||||||
|
BoxPosition.prototype.overlapsOppositeAxis = function(container, axis) {
|
||||||
|
switch (axis) {
|
||||||
|
case "+x":
|
||||||
|
return this.left < container.left;
|
||||||
|
case "-x":
|
||||||
|
return this.right > container.right;
|
||||||
|
case "+y":
|
||||||
|
return this.top < container.top;
|
||||||
|
case "-y":
|
||||||
|
return this.bottom > container.bottom;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Find the percentage of the area that this box is overlapping with another
|
||||||
|
// box.
|
||||||
|
BoxPosition.prototype.intersectPercentage = function(b2) {
|
||||||
|
var x = Math.max(0, Math.min(this.right, b2.right) - Math.max(this.left, b2.left)),
|
||||||
|
y = Math.max(0, Math.min(this.bottom, b2.bottom) - Math.max(this.top, b2.top)),
|
||||||
|
intersectArea = x * y;
|
||||||
|
return intersectArea / (this.height * this.width);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Convert the positions from this box to CSS compatible positions using
|
||||||
|
// the reference container's positions. This has to be done because this
|
||||||
|
// box's positions are in reference to the viewport origin, whereas, CSS
|
||||||
|
// values are in referecne to their respective edges.
|
||||||
|
BoxPosition.prototype.toCSSCompatValues = function(reference) {
|
||||||
|
return {
|
||||||
|
top: this.top - reference.top,
|
||||||
|
bottom: reference.bottom - this.bottom,
|
||||||
|
left: this.left - reference.left,
|
||||||
|
right: reference.right - this.right,
|
||||||
|
height: this.height,
|
||||||
|
width: this.width
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get an object that represents the box's position without anything extra.
|
||||||
|
// Can pass a StyleBox, HTMLElement, or another BoxPositon.
|
||||||
|
BoxPosition.getSimpleBoxPosition = function(obj) {
|
||||||
|
obj = obj.div ? obj.div.getBoundingClientRect() :
|
||||||
|
obj.tagName ? obj.getBoundingClientRect() : obj;
|
||||||
|
return {
|
||||||
|
left: obj.left,
|
||||||
|
right: obj.right,
|
||||||
|
top: obj.top,
|
||||||
|
height: obj.height,
|
||||||
|
bottom: obj.bottom,
|
||||||
|
width: obj.width
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Move a StyleBox to its specified, or next best, position. The containerBox
|
||||||
|
// is the box that contains the StyleBox, such as a div. boxPositions are
|
||||||
|
// a list of other boxes that the styleBox can't overlap with.
|
||||||
|
function moveBoxToLinePosition(window, styleBox, containerBox, boxPositions) {
|
||||||
|
|
||||||
|
// Find the best position for a cue box, b, on the video. The axis parameter
|
||||||
|
// is a list of axis, the order of which, it will move the box along. For example:
|
||||||
|
// Passing ["+x", "-x"] will move the box first along the x axis in the positive
|
||||||
|
// direction. If it doesn't find a good position for it there it will then move
|
||||||
|
// it along the x axis in the negative direction.
|
||||||
|
function findBestPosition(b, axis) {
|
||||||
|
var bestPosition,
|
||||||
|
specifiedPosition = new BoxPosition(b),
|
||||||
|
percentage = 1; // Highest possible so the first thing we get is better.
|
||||||
|
|
||||||
|
for (var i = 0; i < axis.length; i++) {
|
||||||
|
while (b.overlapsOppositeAxis(containerBox, axis[i]) ||
|
||||||
|
(b.within(containerBox) && b.overlapsAny(boxPositions))) {
|
||||||
|
b.move(axis[i]);
|
||||||
|
}
|
||||||
|
// We found a spot where we aren't overlapping anything. This is our
|
||||||
|
// best position.
|
||||||
|
if (b.within(containerBox)) {
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
var p = b.intersectPercentage(containerBox);
|
||||||
|
// If we're outside the container box less then we were on our last try
|
||||||
|
// then remember this position as the best position.
|
||||||
|
if (percentage > p) {
|
||||||
|
bestPosition = new BoxPosition(b);
|
||||||
|
percentage = p;
|
||||||
|
}
|
||||||
|
// Reset the box position to the specified position.
|
||||||
|
b = new BoxPosition(specifiedPosition);
|
||||||
|
}
|
||||||
|
return bestPosition || specifiedPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
function reverseAxis(axis) {
|
||||||
|
return axis.map(function(a) {
|
||||||
|
return a.indexOf("+") !== -1 ? a.replace("+", "-") : a.replace("-", "+");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
BasicBoundingBox.prototype = Object.create(BoundingBox.prototype);
|
|
||||||
BasicBoundingBox.prototype.constructor = BasicBoundingBox;
|
|
||||||
|
|
||||||
const CUE_FONT_SIZE = 2.5;
|
var boxPosition = new BoxPosition(styleBox),
|
||||||
const SCROLL_DURATION = 0.433;
|
cue = styleBox.cue,
|
||||||
const LINE_HEIGHT = 0.0533;
|
linePos = computeLinePos(cue),
|
||||||
const REGION_FONT_SIZE = 1.3;
|
axis = [];
|
||||||
|
|
||||||
// Constructs the computed display state of the cue (a div). Places the div
|
|
||||||
// into the overlay which should be a block level element (usually a div).
|
|
||||||
function CueBoundingBox(window, cue, overlay) {
|
|
||||||
BasicBoundingBox.call(this, window, cue);
|
|
||||||
this.applyStyles({
|
|
||||||
direction: determineBidi(this.div),
|
|
||||||
writingMode: cue.vertical === "" ? "horizontal-tb"
|
|
||||||
: cue.vertical === "lr" ? "vertical-lr"
|
|
||||||
: "vertical-rl",
|
|
||||||
position: "absolute",
|
|
||||||
unicodeBidi: "plaintext",
|
|
||||||
fontSize: CUE_FONT_SIZE + "vh",
|
|
||||||
fontFamily: "sans-serif",
|
|
||||||
color: "rgba(255, 255, 255, 1)",
|
|
||||||
backgroundColor: "rgba(0, 0, 0, 0.8)",
|
|
||||||
whiteSpace: "pre-line"
|
|
||||||
});
|
|
||||||
|
|
||||||
// Append the div to the overlay so we can get the computed styles of the
|
|
||||||
// element in order to position for overlap avoidance.
|
|
||||||
overlay.appendChild(this.div);
|
|
||||||
|
|
||||||
// Calculate the distance from the reference edge of the viewport to the line
|
|
||||||
// position of the cue box. The reference edge will be resolved later when
|
|
||||||
// the box orientation styles are applied. Default if snapToLines is not set
|
|
||||||
// is 85.
|
|
||||||
var linePos = 85;
|
|
||||||
if (!cue.snapToLines) {
|
|
||||||
var computedLinePos = computeLinePos(cue),
|
|
||||||
boxComputedStyle = window.getComputedStyle(this.div),
|
|
||||||
size = cue.vertical === "" ? boxComputedStyle.getPropertyValue("height") :
|
|
||||||
boxComputedStyle.getPropertyValue("width"),
|
|
||||||
// Get the percentage value of the computed height as getPropertyValue
|
|
||||||
// returns pixels.
|
|
||||||
overlayHeight = window.getComputedStyle(overlay).getPropertyValue("height"),
|
|
||||||
calculatedPercentage = (size.replace("px", "") / overlayHeight.replace("px", "")) * 100;
|
|
||||||
|
|
||||||
switch (cue.lineAlign) {
|
|
||||||
case "start":
|
|
||||||
linePos = computedLinePos;
|
|
||||||
break;
|
|
||||||
case "middle":
|
|
||||||
linePos = computedLinePos - (calculatedPercentage / 2);
|
|
||||||
break;
|
|
||||||
case "end":
|
|
||||||
linePos = computedLinePos - calculatedPercentage;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// If we have a line number to align the cue to.
|
||||||
|
if (cue.snapToLines) {
|
||||||
switch (cue.vertical) {
|
switch (cue.vertical) {
|
||||||
case "":
|
case "":
|
||||||
this.applyStyles({
|
axis = [ "+y", "-y" ];
|
||||||
top: this.formatStyle(linePos, "%")
|
break;
|
||||||
|
case "rl":
|
||||||
|
axis = [ "+x", "-x" ];
|
||||||
|
break;
|
||||||
|
case "lr":
|
||||||
|
axis = [ "-x", "+x" ];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If computed line position returns negative then line numbers are
|
||||||
|
// relative to the bottom of the video instead of the top. Therefore, we
|
||||||
|
// need to increase our initial position by the length or width of the
|
||||||
|
// video, depending on the writing direction, and reverse our axis directions.
|
||||||
|
var initialPosition = boxPosition.lineHeight * Math.floor(linePos + 0.5),
|
||||||
|
initialAxis = axis[0];
|
||||||
|
if (linePos < 0) {
|
||||||
|
initialPosition += cue.vertical === "" ? containerBox.height : containerBox.width;
|
||||||
|
axis = reverseAxis(axis);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move the box to the specified position. This may not be its best
|
||||||
|
// position.
|
||||||
|
boxPosition.move(initialAxis, initialPosition);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// If we have a percentage line value for the cue.
|
||||||
|
var calculatedPercentage = (boxPosition.lineHeight / containerBox.height) * 100;
|
||||||
|
|
||||||
|
switch (cue.lineAlign) {
|
||||||
|
case "middle":
|
||||||
|
linePos -= (calculatedPercentage / 2);
|
||||||
|
break;
|
||||||
|
case "end":
|
||||||
|
linePos -= calculatedPercentage;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply initial line position to the cue box.
|
||||||
|
switch (cue.vertical) {
|
||||||
|
case "":
|
||||||
|
styleBox.applyStyles({
|
||||||
|
top: styleBox.formatStyle(linePos, "%")
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case "rl":
|
case "rl":
|
||||||
this.applyStyles({
|
styleBox.applyStyles({
|
||||||
left: this.formatStyle(linePos, "%")
|
left: styleBox.formatStyle(linePos, "%")
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case "lr":
|
case "lr":
|
||||||
this.applyStyles({
|
styleBox.applyStyles({
|
||||||
right: this.formatStyle(linePos, "%")
|
right: styleBox.formatStyle(linePos, "%")
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
cue.displayState = this.div;
|
axis = [ "+y", "-x", "+x", "-y" ];
|
||||||
}
|
|
||||||
CueBoundingBox.prototype = Object.create(BasicBoundingBox.prototype);
|
|
||||||
CueBoundingBox.prototype.constuctor = CueBoundingBox;
|
|
||||||
|
|
||||||
function RegionBoundingBox(window, region) {
|
// Get the box position again after we've applied the specified positioning
|
||||||
BoundingBox.call(this);
|
// to it.
|
||||||
this.div = window.document.createElement("div");
|
boxPosition = new BoxPosition(styleBox);
|
||||||
|
|
||||||
var left = region.viewportAnchorX -
|
|
||||||
region.regionAnchorX * region.width / 100,
|
|
||||||
top = region.viewportAnchorY -
|
|
||||||
region.regionAnchorY * region.lines * LINE_HEIGHT / 100;
|
|
||||||
|
|
||||||
this.applyStyles({
|
|
||||||
position: "absolute",
|
|
||||||
writingMode: "horizontal-tb",
|
|
||||||
backgroundColor: "rgba(0, 0, 0, 0.8)",
|
|
||||||
wordWrap: "break-word",
|
|
||||||
overflowWrap: "break-word",
|
|
||||||
font: REGION_FONT_SIZE + "vh/" + LINE_HEIGHT + "vh sans-serif",
|
|
||||||
lineHeight: LINE_HEIGHT + "vh",
|
|
||||||
color: "rgba(255, 255, 255, 1)",
|
|
||||||
overflow: "hidden",
|
|
||||||
width: this.formatStyle(region.width, "%"),
|
|
||||||
minHeight: "0",
|
|
||||||
// TODO: This value is undefined in the spec, but I am assuming that they
|
|
||||||
// refer to lines * line height to get the max height See issue #107.
|
|
||||||
maxHeight: this.formatStyle(region.lines * LINE_HEIGHT, "px"),
|
|
||||||
left: this.formatStyle(left, "%"),
|
|
||||||
top: this.formatStyle(top, "%"),
|
|
||||||
display: "inline-flex",
|
|
||||||
flexFlow: "column",
|
|
||||||
justifyContent: "flex-end"
|
|
||||||
});
|
|
||||||
|
|
||||||
this.maybeAddCue = function(cue) {
|
|
||||||
if (region.id !== cue.regionId) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var basicBox = new BasicBoundingBox(window, cue);
|
var bestPosition = findBestPosition(boxPosition, axis);
|
||||||
basicBox.applyStyles({
|
styleBox.move(bestPosition.toCSSCompatValues(containerBox));
|
||||||
position: "relative",
|
|
||||||
unicodeBidi: "plaintext",
|
|
||||||
width: "auto"
|
|
||||||
});
|
|
||||||
|
|
||||||
if (this.div.childNodes.length === 1 && region.scroll === "up") {
|
|
||||||
this.applyStyles({
|
|
||||||
transitionProperty: "top",
|
|
||||||
transitionDuration: SCROLL_DURATION + "s"
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.div.appendChild(basicBox.div);
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
RegionBoundingBox.prototype = Object.create(BoundingBox.prototype);
|
|
||||||
RegionBoundingBox.prototype.constructor = RegionBoundingBox;
|
|
||||||
|
|
||||||
function WebVTTParser(window, decoder) {
|
function WebVTTParser(window, decoder) {
|
||||||
this.window = window;
|
this.window = window;
|
||||||
this.state = "INITIAL";
|
this.state = "INITIAL";
|
||||||
@ -891,10 +1051,14 @@ this.EXPORTED_SYMBOLS = ["WebVTTParser"];
|
|||||||
return parseContent(window, cuetext);
|
return parseContent(window, cuetext);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const FONT_SIZE_PERCENT = 0.05;
|
||||||
|
const FONT_STYLE = "sans-serif";
|
||||||
|
const CUE_BACKGROUND_PADDING = "1.5%";
|
||||||
|
|
||||||
// Runs the processing model over the cues and regions passed to it.
|
// Runs the processing model over the cues and regions passed to it.
|
||||||
// @param overlay A block level element (usually a div) that the computed cues
|
// @param overlay A block level element (usually a div) that the computed cues
|
||||||
// and regions will be placed into.
|
// and regions will be placed into.
|
||||||
WebVTTParser.processCues = function(window, cues, regions, overlay) {
|
WebVTTParser.processCues = function(window, cues, overlay) {
|
||||||
if (!window || !cues || !overlay) {
|
if (!window || !cues || !overlay) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -904,32 +1068,56 @@ this.EXPORTED_SYMBOLS = ["WebVTTParser"];
|
|||||||
overlay.removeChild(overlay.firstChild);
|
overlay.removeChild(overlay.firstChild);
|
||||||
}
|
}
|
||||||
|
|
||||||
var regionBoxes = regions ? regions.map(function(region) {
|
var paddedOverlay = window.document.createElement("div");
|
||||||
return new RegionBoundingBox(window, region);
|
paddedOverlay.style.position = "absolute";
|
||||||
}) : null;
|
paddedOverlay.style.left = "0";
|
||||||
|
paddedOverlay.style.right = "0";
|
||||||
|
paddedOverlay.style.top = "0";
|
||||||
|
paddedOverlay.style.bottom = "0";
|
||||||
|
paddedOverlay.style.margin = CUE_BACKGROUND_PADDING;
|
||||||
|
overlay.appendChild(paddedOverlay);
|
||||||
|
|
||||||
function mapCueToRegion(cue) {
|
// Determine if we need to compute the display states of the cues. This could
|
||||||
for (var i = 0; i < regionBoxes.length; i++) {
|
// be the case if a cue's state has been changed since the last computation or
|
||||||
if (regionBoxes[i].maybeAddCue(cue)) {
|
// if it has not been computed yet.
|
||||||
|
function shouldCompute(cues) {
|
||||||
|
for (var i = 0; i < cues.length; i++) {
|
||||||
|
if (cues[i].hasBeenReset || !cues[i].displayState) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < cues.length; i++) {
|
// We don't need to recompute the cues' display states. Just reuse them.
|
||||||
// Check to see if this cue is contained within a VTTRegion.
|
if (!shouldCompute(cues)) {
|
||||||
if (regionBoxes && mapCueToRegion(cues[i])) {
|
cues.forEach(function(cue) {
|
||||||
continue;
|
paddedOverlay.appendChild(cue.displayState);
|
||||||
}
|
});
|
||||||
// Check to see if we can just reuse the last computed styles of the cue.
|
return;
|
||||||
if (cues[i].hasBeenReset !== true && cues[i].displayState) {
|
|
||||||
overlay.appendChild(cues[i].displayState);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// Compute the position of the cue box on the cue overlay.
|
|
||||||
var cueBox = new CueBoundingBox(window, cues[i], overlay);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var boxPositions = [],
|
||||||
|
containerBox = BoxPosition.getSimpleBoxPosition(paddedOverlay),
|
||||||
|
fontSize = Math.round(containerBox.height * FONT_SIZE_PERCENT * 100) / 100;
|
||||||
|
var styleOptions = {
|
||||||
|
font: fontSize + "px " + FONT_STYLE
|
||||||
|
};
|
||||||
|
|
||||||
|
cues.forEach(function(cue) {
|
||||||
|
// Compute the intial position and styles of the cue div.
|
||||||
|
var styleBox = new CueStyleBox(window, cue, styleOptions);
|
||||||
|
paddedOverlay.appendChild(styleBox.div);
|
||||||
|
|
||||||
|
// Move the cue div to it's correct line position.
|
||||||
|
moveBoxToLinePosition(window, styleBox, containerBox, boxPositions);
|
||||||
|
|
||||||
|
// Remember the computed div so that we don't have to recompute it later
|
||||||
|
// if we don't have too.
|
||||||
|
cue.displayState = styleBox.div;
|
||||||
|
|
||||||
|
boxPositions.push(BoxPosition.getSimpleBoxPosition(styleBox));
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
WebVTTParser.prototype = {
|
WebVTTParser.prototype = {
|
||||||
@ -972,7 +1160,7 @@ this.EXPORTED_SYMBOLS = ["WebVTTParser"];
|
|||||||
settings.set(k, v);
|
settings.set(k, v);
|
||||||
break;
|
break;
|
||||||
case "width":
|
case "width":
|
||||||
settings.percent(k, v, true);
|
settings.percent(k, v);
|
||||||
break;
|
break;
|
||||||
case "lines":
|
case "lines":
|
||||||
settings.integer(k, v);
|
settings.integer(k, v);
|
||||||
@ -986,8 +1174,8 @@ this.EXPORTED_SYMBOLS = ["WebVTTParser"];
|
|||||||
// We have to make sure both x and y parse, so use a temporary
|
// We have to make sure both x and y parse, so use a temporary
|
||||||
// settings object here.
|
// settings object here.
|
||||||
var anchor = new Settings();
|
var anchor = new Settings();
|
||||||
anchor.percent("x", xy[0], true);
|
anchor.percent("x", xy[0]);
|
||||||
anchor.percent("y", xy[1], true);
|
anchor.percent("y", xy[1]);
|
||||||
if (!anchor.has("x") || !anchor.has("y")) {
|
if (!anchor.has("x") || !anchor.has("y")) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user