Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support of fontSize in percentages and cell resolution unit for TTML captions #2442

Merged
merged 14 commits into from
Mar 6, 2020

Conversation

glhvta
Copy link
Contributor

@glhvta glhvta commented Mar 4, 2020

Scope of PR:

  • parse ttp:cellResolution and provide it to shaka.text.Cue, so text displayers can use it in next calculations
  • add support of fontSize in '%' and 'c' to ttml_text_parser
  • add support of font size in cell resolution units to shaka.ui.TextDisplayer
  • add unit tests

Note:

  • add partial support of font size in percentages to shaka.ui.TextDisplayer

*From w3c spec:
Percentages: if not region element, then relative to the parent element's computed font size; otherwise, relative to the Computed Cell Size.
Currently will be calculated relative to the Computed Cell Size.

Spec:
tts:fontSize - https://www.w3.org/TR/ttml1/#style-attribute-fontSize
ttp:cellResolution - https://www.w3.org/TR/ttml1/#parameter-attribute-cellResolution
- https://www.w3.org/TR/ttml1/#style-value-length

Useful links that helped during development and documentation investigation:
https://www.w3.org/TR/ttml1/
http://sandflow.com/imsc1_1/ - IMSC1 Renderer
https://trac.videolan.org/vlc/ticket/18347

Sample TTML that can be used for testing:
ttml-captions-test.zip

Closes #2403

@joeyparrish joeyparrish self-assigned this Mar 4, 2020
@joeyparrish joeyparrish added the type: enhancement New feature or request label Mar 4, 2020
lib/text/cue.js Outdated
* @const
* @export
*/
shaka.text.Cue.cellResolution = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The enums below and above are possible options for each field. This is a set of defaults. I would prefer you move it to the initialization of the member:

this.cellResolution = [32, 15]; // columns, rows

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

Comment on lines 960 to 961
// If not specified, the number of columns and rows must be considered
// to be 32 and 15 respectively
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You've already defined a default in the Cue constructor. Why duplicate it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agree,
changed the logic, so now cue.cellResolution default value will be replaced only if ttp:cellResolution was presented in ttml

Comment on lines 892 to 895
cellResolution: [
Cue.cellResolution.COLUMNS,
Cue.cellResolution.ROWS,
],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it doesn't matter what the cellResolution is in this output cue (since it's not using c units), you can omit this field. verifyHelper below uses jasmine.objectContaining() to match, so any field you don't specify in the expectation won't count.

In fact, it seems that this test case doesn't have much to do with cellResolution at all, so maybe you could omit it.

Copy link
Contributor Author

@glhvta glhvta Mar 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this test was added to check that Cue has default cellResolution when ttp:cellResolution was not presented in ttml
I guess it would be nice to leave this check

@@ -39,15 +41,20 @@ describe('UITextDisplayer', () => {
}


beforeAll(() => {
beforeEach(() => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The addition of video elements to the DOM should be beforeAll instead of beforeEach.

You could move textDisplayer setup specifically to beforeEach and leave the rest in beforeAll.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, you are right, thanks

was fixed

jasmine.objectContaining({'font-size': expectedFontSize}));
});

it('correctly displays styles for percentages units', async () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for adding these tests!

@@ -268,11 +268,15 @@ shaka.ui.TextDisplayer = class {
captionsStyle.margin = '0';
}

const {convertLengthValue_} = shaka.ui.TextDisplayer;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You only call this once. Just refer to it directly with its full name at the call site.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

}

/**
* Converts length value
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Converts length value" returning "string" is not enough information for the reader. What format is the string? What sort of conversion?

Copy link
Contributor Author

@glhvta glhvta Mar 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the description was updated,
could you please take a look if I need to add more details

static getLengthValueInfo_(lengthValue) {
const matches = new RegExp(/(\d*\.?\d+)([a-z]+|%+)/).exec(lengthValue);

if (!matches ) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style nit: remove extra space inside parens

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

*
* @private
* */
static getComputedValue_(value, cue, videoContainer) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"computed value" is a bit vague. This method actually does something very specific: computes an absolute value in pixels based on cell and video size.

Copy link
Contributor Author

@glhvta glhvta Mar 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

was renamed to getAbsoluteLengthInPixels_ and added the description for this method,
could you please take a look if I need to add more details
thanks

@glhvta glhvta requested a review from joeyparrish March 4, 2020 21:36
@glhvta
Copy link
Contributor Author

glhvta commented Mar 5, 2020

@theodab @joeyparrish , thank you for the review and quick feedback!

The comments were fixed. Could you please take a look and let me know if there is anything else that needs to be done.

@shaka-bot
Copy link
Collaborator

All tests passed!

@theodab
Copy link
Contributor

theodab commented Mar 5, 2020

Whoops, I accidentally started an extraneous test run. Sorry about that.

@shaka-project shaka-project deleted a comment from shaka-bot Mar 5, 2020
Copy link
Member

@joeyparrish joeyparrish left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great overall. Just a few things I'd like you to change. Thanks!

* The number of horizontal and vertical cells into which
* the Root Container Region area is divided
*
* @typedef {{ columns: number, rows: number }}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looked different from what we would normally use, so I checked. It seems that with this annotation, the compiler doesn't enforce the type correctly. What you want is @type {{ columns: number, rows: number }} instead.

A typedef in Closure Compiler is used for creating a new type, but not for assigning a type to a member. I know the compiler can be arcane, so I'm sorry for the trouble.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for the explanation!
done

@@ -239,12 +245,13 @@ shaka.text.TtmlTextParser = class {
* @param {!Array.<!shaka.text.CueRegion>} cueRegions
* @param {boolean} whitespaceTrim
* @param {boolean} isNested
* @param {?Object} cellResolution
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Object" is too general a type. Please use a record type like you did in Cue:
{?{columns: number, rows: number}}, so that the compiler can catch a caller using the wrong fields.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -334,6 +342,10 @@ shaka.text.TtmlTextParser = class {
const cue = new shaka.text.Cue(start, end, payload);
cue.nestedCues = nestedCues;

if (cellResolution) {
cue.cellResolution = Object.assign({}, cellResolution);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need Object.assign. The provided value won't be changed by the method that generated it, and you'll preserve type info in the compiler by assigning it directly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed Object.assign

* @private
*/
static getCellResolution_(cellResolution) {
const matches = /^(\d+) (\d+)$/.exec(cellResolution);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cellResolution can be null, and this would convert null into the string "null".

While that shouldn't cause any false positives, it may be best to handle !cellResolution explicitly, either here or when the attribute is extracted from the TTML.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done,
added check to getCellResolution_ method

textDisplayer = new shaka.ui.TextDisplayer(video, videoContainer);
});

afterEach(() => {
textDisplayer.destroy();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

destroy() is async, so please make this callback async and await the results of destroy().

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry, I can miss something, but as I see TextDisplayer destroy method is not async
https://github.com/google/shaka-player/blob/ea0131dc80483c7df2c9ec5c9ed62fbe560f37c3/ui/text_displayer.js#L67-L84

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That implementation is not async today, but the underlying interfaces shaka.extern.TextDisplayer and shaka.util.IDestroyable are async and return a Promise. In our codebase, any destroy() is async, and any release() is immediate.

It would be possible for us to add async steps to destroy() in shaka.ui.TextDisplayer at any time, and the tests should honor the contract of that API and use await.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for such a detailed explanation, now I've got it

done

*/
static convertLengthValue_(lengthValue, cue, videoContainer) {
const lengthValueInfo =
shaka.ui.TextDisplayer.getLengthValueInfo_(lengthValue);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style nit: indent +2 spaces

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry, not fully understood
should I remove 2 spaces to be like this

    const lengthValueInfo =
    shaka.ui.TextDisplayer.getLengthValueInfo_(lengthValue);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I meant +2 more, for a total of 4 more than the previous line

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

case '%':
return shaka.ui.TextDisplayer.getAbsoluteLengthInPixels_(
value / 100, cue, videoContainer
);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style nit: move to previous line

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

case 'c':
return shaka.ui.TextDisplayer.getAbsoluteLengthInPixels_(
value, cue, videoContainer
);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style nit: move to previous line

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@glhvta glhvta requested a review from joeyparrish March 5, 2020 22:22
Copy link
Member

@joeyparrish joeyparrish left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me! Thanks for all your hard work.

@shaka-bot
Copy link
Collaborator

All tests passed!

@joeyparrish joeyparrish merged commit d6de4e7 into shaka-project:master Mar 6, 2020
@glhvta glhvta deleted the add-cell-resolution-support branch March 6, 2020 16:56
@joeyparrish
Copy link
Member

Unfortunately, this change did not cherry-pick cleanly to v2.5.x, and so will not be in an official release until v2.6.0.

@github-actions github-actions bot added the status: archived Archived and locked; will not be updated label Jul 25, 2023
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jul 25, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
status: archived Archived and locked; will not be updated type: enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support of fontSize cellResolution units in TTML subtitles
4 participants