Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[WebVTT] Modernize VTTCue
https://bugs.webkit.org/show_bug.cgi?id=258578
rdar://111393504

Reviewed by Eric Carlson.

VTTCue has a number of stylistic and functional implementation details that
are held over from its original implementation in 2014, and could benefit from
being brought up to a more modern set of practices and language features used
in other parts of WebKit.

The bindings generator now supports IDL-defined enumerations, and automatically
converts between them and C++ defined enumerations, so there is no need to
have string checks exist in VTTCue for properties that take those enumerations.

C++ enumerations should have the same type name as IDL enumerations, and values
for those enumerations should be equivalent as well (after converting to
CamelCase from snake-case). Those enumerations should therefore be `enum class`.

The existing enumerations included sentinel values for static checks of the
enumerations' sizes. Add support in EnumTraits for calculating the minimum,
maximum, and count of values at compile time, making sentinal values unnecessary.

The WebVTT specification now defines heights and font sizes in terms of 'vh' and
'vw', which are percentages of the video viewport height and width, respectively.
Now that WebKit supports these CSS units (as well as 'cqh' and 'cqw', which are
the equivalent units for percentage of container height and width), it is no
longer necessary to pass the layout size of the video element into the VTTCue
(and its subclasses) to calculate the CSS values of cue properties.

The WebVTT specification added more default CSS properties which need to be set
on the resulting elements, so those are added here too.

Add support for lineAlign and positionAlign properties in layout, where those
properties were already parsed and exposed though DOM APIs.

* Source/WTF/wtf/EnumTraits.h:
(WTF::EnumValues::std::max):
(WTF::EnumValues::std::min):
(WTF::EnumValues::forEach):
* Source/WebCore/html/shadow/MediaControlTextTrackContainerElement.cpp:
(WebCore::MediaControlTextTrackContainerElement::updateDisplay):
(WebCore::MediaControlTextTrackContainerElement::processActiveVTTCue):
(WebCore::MediaControlTextTrackContainerElement::updateActiveCuesFontSize):
* Source/WebCore/html/track/InbandGenericTextTrack.cpp:
(WebCore::InbandGenericTextTrack::updateCueFromCueData):
* Source/WebCore/html/track/TextTrackCue.cpp:
(WebCore::TextTrackCue::getDisplayTree):
(WebCore::TextTrackCue::setFontSize):
* Source/WebCore/html/track/TextTrackCue.h:
(WebCore::TextTrackCueBox::applyCSSProperties):
* Source/WebCore/html/track/TextTrackCueGeneric.cpp:
(WebCore::TextTrackCueGenericBoxElement::applyCSSProperties):
(WebCore::TextTrackCueGeneric::setFontSize):
(WebCore::TextTrackCueGeneric::setLine): Deleted.
* Source/WebCore/html/track/TextTrackCueGeneric.h:
* Source/WebCore/html/track/VTTCue.cpp:
(WebCore::VTTCueBox::applyCSSProperties):
(WebCore::VTTCue::VTTCue):
(WebCore::VTTCue::setVertical):
(WebCore::VTTCue::setLine):
(WebCore::VTTCue::setLineAlign):
(WebCore::VTTCue::position const):
(WebCore::VTTCue::setPositionAlign):
(WebCore::VTTCue::setAlign):
(WebCore::VTTCue::calculateComputedLinePosition const):
(WebCore::VTTCue::calculateComputedTextPosition const):
(WebCore::VTTCue::calculateComputedPositionAlignment const):
(WebCore::VTTCue::calculateMaximumSize const):
(WebCore::VTTCue::calculateDisplayParameters):
(WebCore::VTTCue::obtainCSSBoxes):
(WebCore::VTTCue::updateDisplayTree):
(WebCore::VTTCue::getDisplayTree):
(WebCore::VTTCue::getPositionCoordinates const):
(WebCore::VTTCue::setCueSettings):
(WebCore::VTTCue::getCSSAlignment const):
(WebCore::VTTCue::getCSSWritingMode const):
(WebCore::VTTCue::setFontSize):
(WebCore::VTTCue::toJSON const):
(WebCore::horizontalKeyword): Deleted.
(WebCore::VTTCue::initialize): Deleted.
(WebCore::VTTCue::vertical const): Deleted.
(WebCore::VTTCue::lineAlign const): Deleted.
(WebCore::VTTCue::positionAlign const): Deleted.
(WebCore::VTTCue::align const): Deleted.
* Source/WebCore/html/track/VTTCue.h:
(WebCore::VTTCue::vertical const):
(WebCore::VTTCue::lineAlign const):
(WebCore::VTTCue::positionAlign const):
(WebCore::VTTCue::align const):
(WebCore::VTTCue::element const):
(WebCore::VTTCue::backdrop const):
(WebCore::VTTCue::fontSize const):
(WebCore::VTTCue::fontSizeIsImportant const):
(WebCore::VTTCue::left const):
(WebCore::VTTCue::top const):
(WebCore::VTTCue::width const):
(WebCore::VTTCue::height const):
(WebCore::VTTCue::getWritingDirection const): Deleted.
(WebCore::VTTCue::getAlignment const): Deleted.
* Source/WebCore/html/track/VTTCue.idl:
* Source/WebCore/rendering/RenderVTTCue.cpp:
(WebCore::RenderVTTCue::initializeLayoutParameters):
(WebCore::RenderVTTCue::placeBoxInDefaultPosition):
(WebCore::RenderVTTCue::overlappingObjectForRect const):
(WebCore::RenderVTTCue::shouldSwitchDirection const):
(WebCore::RenderVTTCue::moveBoxesByStep):
(WebCore::RenderVTTCue::findNonOverlappingPosition const):
(WebCore::RenderVTTCue::repositionCueSnapToLinesSet):
(WebCore::RenderVTTCue::repositionGenericCue):
(WebCore::RenderVTTCue::repositionCueSnapToLinesNotSet):
* Tools/TestWebKitAPI/Tests/WTF/EnumTraits.cpp:
(TestWebKitAPI::TEST):

Canonical link: https://commits.webkit.org/265596@main
  • Loading branch information
jernoble committed Jun 28, 2023
1 parent fc5258f commit 687a6e6
Show file tree
Hide file tree
Showing 13 changed files with 618 additions and 504 deletions.
15 changes: 15 additions & 0 deletions Source/WTF/wtf/EnumTraits.h
Expand Up @@ -25,6 +25,7 @@

#pragma once

#include <algorithm>
#include <type_traits>

namespace WTF {
Expand All @@ -34,6 +35,20 @@ template<typename> struct EnumTraitsForPersistence;

template<typename E, E...> struct EnumValues;

template<typename E, E... values>
struct EnumValues {
static constexpr E max = std::max({ values... });
static constexpr E min = std::min({ values... });
static constexpr size_t count = sizeof...(values);

template <typename Callable>
static void forEach(Callable&& c)
{
for (auto value : { values... })
c(value);
}
};

template<typename T, typename E> struct EnumValueChecker;

template<typename T, typename E, E e, E... es>
Expand Down
Expand Up @@ -48,13 +48,24 @@ video[controls]::-webkit-media-text-track-container.visible-controls-bar {
height: calc(100% - var(--inline-controls-bar-height) - var(--inline-controls-inside-margin));
}

/* https://w3c.github.io/webvtt/#applying-css-properties
7.4. Applying CSS properties to WebVTT Node Objects */

video::cue {
background-color: rgba(0, 0, 0, 0.8);
overflow: visible;
}

video::-webkit-media-text-track-display {
position: absolute;
overflow: hidden;
unicode-bidi: plaintext;
overflow: visible;
writing-mode: writing-mode;
overflow-wrap: break-word;
white-space: pre-line;
}

video::-webkit-media-text-track-display {
white-space: pre-wrap;
box-sizing: border-box;
font: 22px sans-serif; /* Keep in sync with `DEFAULTCAPTIONFONTSIZE`. */
Expand Down
Expand Up @@ -168,11 +168,11 @@ void MediaControlTextTrackContainerElement::updateDisplay()
if (cue->track()->isSpoken())
continue;

cue->setFontSize(m_fontSize, m_videoDisplaySize.size(), m_fontSizeIsImportant);
cue->setFontSize(m_fontSize, m_fontSizeIsImportant);
if (is<VTTCue>(*cue))
processActiveVTTCue(downcast<VTTCue>(*cue));
else {
auto displayBox = cue->getDisplayTree(m_videoDisplaySize.size(), m_fontSize);
auto displayBox = cue->getDisplayTree();
if (displayBox->hasChildNodes() && !contains(displayBox.get()))
appendChild(*displayBox);
}
Expand Down Expand Up @@ -207,7 +207,7 @@ void MediaControlTextTrackContainerElement::updateTextTrackRepresentationImageIf
void MediaControlTextTrackContainerElement::processActiveVTTCue(VTTCue& cue)
{
DEBUG_LOG(LOGIDENTIFIER, "adding and positioning cue: \"", cue.text(), "\", start=", cue.startTime(), ", end=", cue.endTime());
Ref<TextTrackCueBox> displayBox = *cue.getDisplayTree(m_videoDisplaySize.size(), m_fontSize);
Ref<TextTrackCueBox> displayBox = *cue.getDisplayTree();

if (auto region = cue.track()->regions()->getRegionById(cue.regionId())) {
// Let region be the WebVTT region whose region identifier
Expand Down Expand Up @@ -237,14 +237,17 @@ void MediaControlTextTrackContainerElement::updateActiveCuesFontSize()
if (!m_mediaElement)
return;

float smallestDimension = std::min(m_videoDisplaySize.size().height(), m_videoDisplaySize.size().width());
float fontScale = document().page()->group().ensureCaptionPreferences().captionFontSizeScaleAndImportance(m_fontSizeIsImportant);
m_fontSize = lroundf(smallestDimension * fontScale);

// Caption fonts are defined as |size vh| units, so there's no need to
// scale by display size. Since |vh| is a decimal percentage, multiply
// the scale factor by 100 to achive the final font size.
m_fontSize = lroundf(100 * fontScale);

for (auto& activeCue : m_mediaElement->currentlyActiveCues()) {
RefPtr<TextTrackCue> cue = activeCue.data();
if (cue->isRenderable())
cue->setFontSize(m_fontSize, m_videoDisplaySize.size(), m_fontSizeIsImportant);
cue->setFontSize(m_fontSize, m_fontSizeIsImportant);
}
}

Expand Down
6 changes: 3 additions & 3 deletions Source/WebCore/html/track/InbandGenericTextTrack.cpp
Expand Up @@ -107,11 +107,11 @@ void InbandGenericTextTrack::updateCueFromCueData(TextTrackCueGeneric& cue, Inba
cue.setHighlightColor(inbandCue.highlightColor());

if (inbandCue.align() == GenericCueData::Alignment::Start)
cue.setAlign("start"_s);
cue.setAlign(VTTCue::AlignSetting::Start);
else if (inbandCue.align() == GenericCueData::Alignment::Middle)
cue.setAlign("middle"_s);
cue.setAlign(VTTCue::AlignSetting::Center);
else if (inbandCue.align() == GenericCueData::Alignment::End)
cue.setAlign("end"_s);
cue.setAlign(VTTCue::AlignSetting::End);
cue.setSnapToLines(false);

cue.didChange();
Expand Down
4 changes: 2 additions & 2 deletions Source/WebCore/html/track/TextTrackCue.cpp
Expand Up @@ -453,7 +453,7 @@ bool TextTrackCue::isRenderable() const
return m_cueNode && m_cueNode->firstChild();
}

RefPtr<TextTrackCueBox> TextTrackCue::getDisplayTree(const IntSize&, int)
RefPtr<TextTrackCueBox> TextTrackCue::getDisplayTree()
{
if (m_displayTree && !m_displayTreeNeedsUpdate)
return m_displayTree;
Expand All @@ -473,7 +473,7 @@ void TextTrackCue::removeDisplayTree()
m_displayTree->remove();
}

void TextTrackCue::setFontSize(int fontSize, const IntSize&, bool important)
void TextTrackCue::setFontSize(int fontSize, bool important)
{
if (fontSize == m_fontSize && important == m_fontSizeIsImportant)
return;
Expand Down
6 changes: 3 additions & 3 deletions Source/WebCore/html/track/TextTrackCue.h
Expand Up @@ -51,7 +51,7 @@ class TextTrackCueBox : public HTMLElement {
static Ref<TextTrackCueBox> create(Document&, TextTrackCue&);

TextTrackCue* getCue() const;
virtual void applyCSSProperties(const IntSize&) { }
virtual void applyCSSProperties() { }

protected:
void initialize();
Expand Down Expand Up @@ -109,7 +109,7 @@ class TextTrackCue : public RefCounted<TextTrackCue>, public EventTarget, public
void willChange();
virtual void didChange();

virtual RefPtr<TextTrackCueBox> getDisplayTree(const IntSize& videoSize, int fontSize);
virtual RefPtr<TextTrackCueBox> getDisplayTree();
virtual void removeDisplayTree();

virtual RefPtr<DocumentFragment> getCueAsHTML();
Expand All @@ -121,7 +121,7 @@ class TextTrackCue : public RefCounted<TextTrackCue>, public EventTarget, public
using RefCounted::deref;

virtual void recalculateStyles() { m_displayTreeNeedsUpdate = true; }
virtual void setFontSize(int fontSize, const IntSize& videoSize, bool important);
virtual void setFontSize(int fontSize, bool important);
virtual void updateDisplayTree(const MediaTime&) { }

unsigned cueIndex() const;
Expand Down
35 changes: 12 additions & 23 deletions Source/WebCore/html/track/TextTrackCueGeneric.cpp
Expand Up @@ -53,7 +53,7 @@ class TextTrackCueGenericBoxElement final : public VTTCueBox {
public:
static Ref<TextTrackCueGenericBoxElement> create(Document&, TextTrackCueGeneric&);

void applyCSSProperties(const IntSize&) override;
void applyCSSProperties() override;

private:
TextTrackCueGenericBoxElement(Document&, VTTCue&);
Expand All @@ -71,7 +71,7 @@ TextTrackCueGenericBoxElement::TextTrackCueGenericBoxElement(Document& document,
{
}

void TextTrackCueGenericBoxElement::applyCSSProperties(const IntSize& videoSize)
void TextTrackCueGenericBoxElement::applyCSSProperties()
{
RefPtr<TextTrackCueGeneric> cue = static_cast<TextTrackCueGeneric*>(getCue());
if (!cue)
Expand All @@ -94,7 +94,7 @@ void TextTrackCueGenericBoxElement::applyCSSProperties(const IntSize& videoSize)
setInlineStyleProperty(CSSPropertyLeft, static_cast<float>(textPosition), CSSUnitType::CSS_PERCENTAGE);
setInlineStyleProperty(CSSPropertyTop, static_cast<float>(linePosition), CSSUnitType::CSS_PERCENTAGE);

double authorFontSize = videoSize.height() * cue->baseFontSizeRelativeToVideoHeight() / 100.0;
double authorFontSize = cue->baseFontSizeRelativeToVideoHeight();
if (!authorFontSize)
authorFontSize = DEFAULTCAPTIONFONTSIZE;

Expand All @@ -103,7 +103,7 @@ void TextTrackCueGenericBoxElement::applyCSSProperties(const IntSize& videoSize)

double multiplier = fontSizeFromCaptionUserPrefs() / authorFontSize;
double newCueSize = std::min(size * multiplier, 100.0);
if (cue->getWritingDirection() == VTTCue::Horizontal) {
if (cue->vertical() == VTTCue::DirectionSetting::Horizontal) {
setInlineStyleProperty(CSSPropertyWidth, newCueSize, CSSUnitType::CSS_PERCENTAGE);
if ((alignment == CSSValueMiddle || alignment == CSSValueCenter) && multiplier != 1.0)
setInlineStyleProperty(CSSPropertyLeft, static_cast<double>(textPosition - (newCueSize - cue->getCSSSize()) / 2), CSSUnitType::CSS_PERCENTAGE);
Expand All @@ -121,7 +121,7 @@ void TextTrackCueGenericBoxElement::applyCSSProperties(const IntSize& videoSize)
else if (alignment == CSSValueStart || alignment == CSSValueLeft)
maxSize = 100.0 - textPosition;

if (cue->getWritingDirection() == VTTCue::Horizontal) {
if (cue->vertical() == VTTCue::DirectionSetting::Horizontal) {
setInlineStyleProperty(CSSPropertyMinWidth, "min-content"_s);
setInlineStyleProperty(CSSPropertyMaxWidth, maxSize, CSSUnitType::CSS_PERCENTAGE);
} else {
Expand All @@ -134,17 +134,17 @@ void TextTrackCueGenericBoxElement::applyCSSProperties(const IntSize& videoSize)
if (cue->highlightColor().isValid())
cueElement->setInlineStyleProperty(CSSPropertyBackgroundColor, serializationForHTML(cue->highlightColor()));

if (cue->getWritingDirection() == VTTCue::Horizontal)
if (cue->vertical() == VTTCue::DirectionSetting::Horizontal)
setInlineStyleProperty(CSSPropertyHeight, CSSValueAuto);
else
setInlineStyleProperty(CSSPropertyWidth, CSSValueAuto);

if (cue->baseFontSizeRelativeToVideoHeight())
cue->setFontSize(cue->baseFontSizeRelativeToVideoHeight(), videoSize, false);
cue->setFontSize(cue->baseFontSizeRelativeToVideoHeight(), false);

if (cue->getAlignment() == VTTCue::Center)
if (cue->align() == VTTCue::AlignSetting::Center)
setInlineStyleProperty(CSSPropertyTextAlign, CSSValueCenter);
else if (cue->getAlignment() == VTTCue::End)
else if (cue->align() == VTTCue::AlignSetting::End)
setInlineStyleProperty(CSSPropertyTextAlign, CSSValueEnd);
else
setInlineStyleProperty(CSSPropertyTextAlign, CSSValueStart);
Expand Down Expand Up @@ -179,14 +179,6 @@ RefPtr<VTTCueBox> TextTrackCueGeneric::createDisplayTree()
return nullptr;
}

ExceptionOr<void> TextTrackCueGeneric::setLine(const LineAndPositionSetting& line)
{
auto result = VTTCue::setLine(line);
if (!result.hasException())
m_useDefaultPosition = false;
return result;
}

ExceptionOr<void> TextTrackCueGeneric::setPosition(const LineAndPositionSetting& position)
{
auto result = VTTCue::setPosition(position);
Expand All @@ -195,21 +187,18 @@ ExceptionOr<void> TextTrackCueGeneric::setPosition(const LineAndPositionSetting&
return result;
}

void TextTrackCueGeneric::setFontSize(int fontSize, const IntSize& videoSize, bool important)
void TextTrackCueGeneric::setFontSize(int fontSize, bool important)
{
if (!fontSize)
return;

if (important || !hasDisplayTree() || !baseFontSizeRelativeToVideoHeight()) {
VTTCue::setFontSize(fontSize, videoSize, important);
VTTCue::setFontSize(fontSize, important);
return;
}

double size = videoSize.height() * baseFontSizeRelativeToVideoHeight() / 100;
if (fontSizeMultiplier())
size *= fontSizeMultiplier() / 100;
if (auto* displayTree = displayTreeInternal())
displayTree->setInlineStyleProperty(CSSPropertyFontSize, lround(size), CSSUnitType::CSS_PX);
displayTree->setInlineStyleProperty(CSSPropertyFontSize, fontSize, CSSUnitType::CSS_CQH);
}

bool TextTrackCueGeneric::cueContentsMatch(const TextTrackCue& otherTextTrackCue) const
Expand Down
3 changes: 1 addition & 2 deletions Source/WebCore/html/track/TextTrackCueGeneric.h
Expand Up @@ -38,7 +38,6 @@ class TextTrackCueGeneric final : public VTTCue {
public:
WEBCORE_EXPORT static Ref<TextTrackCueGeneric> create(ScriptExecutionContext&, const MediaTime& start, const MediaTime& end, const String& content);

ExceptionOr<void> setLine(const LineAndPositionSetting&) final;
ExceptionOr<void> setPosition(const LineAndPositionSetting&) final;

bool useDefaultPosition() const { return m_useDefaultPosition; }
Expand All @@ -61,7 +60,7 @@ class TextTrackCueGeneric final : public VTTCue {
const Color& highlightColor() const { return m_highlightColor; }
void setHighlightColor(const Color& color) { m_highlightColor = color; }

void setFontSize(int, const IntSize&, bool important) final;
void setFontSize(int, bool important) final;

private:
TextTrackCueGeneric(Document&, const MediaTime& start, const MediaTime& end, const String&);
Expand Down

0 comments on commit 687a6e6

Please sign in to comment.