blob: 257418f969f413897cf56322e69e173390087e11 [file] [log] [blame]
/*
* Copyright (C) 2025 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "HTMLVideoElementCaptionDisplaySettings.h"
#if ENABLE(VIDEO)
#include "CSSParserContext.h"
#include "CSSParserMode.h"
#include "CSSParserTokenRange.h"
#include "CSSPrimitiveValue.h"
#include "CSSPropertyParserConsumer+Anchor.h"
#include "CSSPropertyParserState.h"
#include "CSSTokenizer.h"
#include "CSSValuePair.h"
#include "CaptionDisplaySettingsOptions.h"
#include "Element.h"
#include "HTMLVideoElement.h"
#include "JSDOMPromiseDeferred.h"
#include "ResolvedCaptionDisplaySettingsOptions.h"
namespace WebCore {
static void parsePositionAreaString(const String& positionArea, ResolvedCaptionDisplaySettingsOptions& options)
{
CSSParserContext context { HTMLStandardMode };
CSS::PropertyParserState state { context };
CSSTokenizer tokenizer { positionArea };
auto tokenRange = tokenizer.tokenRange();
options.xPositionArea = std::nullopt;
options.yPositionArea = std::nullopt;
RefPtr value = CSSPropertyParserHelpers::consumePositionArea(tokenRange, state);
if (!value)
return;
RefPtr valuePair = dynamicDowncast<CSSValuePair>(value.get());
if (!valuePair)
return;
RefPtr firstValue = valuePair->first();
RefPtr secondValue = valuePair->second();
if (!firstValue->isValueID() || !secondValue->isValueID())
return;
using XPositionArea = ResolvedCaptionDisplaySettingsOptions::XPositionArea;
switch (firstValue->valueID()) {
case CSSValueLeft:
case CSSValueSpanLeft:
case CSSValueXStart:
case CSSValueSpanXStart:
case CSSValueSelfXStart:
case CSSValueSpanSelfXStart:
options.xPositionArea = XPositionArea::Left;
break;
case CSSValueCenter:
options.xPositionArea = XPositionArea::Center;
break;
case CSSValueRight:
case CSSValueSpanRight:
case CSSValueXEnd:
case CSSValueSpanXEnd:
case CSSValueSelfXEnd:
case CSSValueSpanSelfXEnd:
options.xPositionArea = XPositionArea::Right;
break;
default:
return;
}
using YPositionArea = ResolvedCaptionDisplaySettingsOptions::YPositionArea;
switch (secondValue->valueID()) {
case CSSValueTop:
case CSSValueSpanTop:
case CSSValueYStart:
case CSSValueSpanYStart:
case CSSValueSelfYStart:
case CSSValueSpanSelfYStart:
options.yPositionArea = YPositionArea::Top;
break;
case CSSValueCenter:
options.yPositionArea = YPositionArea::Center;
break;
case CSSValueBottom:
case CSSValueSpanBottom:
case CSSValueYEnd:
case CSSValueSpanYEnd:
case CSSValueSelfYEnd:
case CSSValueSpanSelfYEnd:
options.yPositionArea = YPositionArea::Bottom;
break;
default:
return;
}
}
void HTMLVideoElementCaptionDisplaySettings::showCaptionDisplaySettings(HTMLVideoElement& element, std::optional<CaptionDisplaySettingsOptions>&& options, Ref<DeferredPromise>&& promise)
{
RefPtr page = element.document().page();
if (!page) {
promise->reject();
return;
}
ResolvedCaptionDisplaySettingsOptions resolvedOptions;
if (options) {
if (RefPtr anchorElement = dynamicDowncast<Element>(options->anchorNode.get()))
resolvedOptions.anchorBounds = anchorElement->boundingBoxInRootViewCoordinates();
if (!options->positionArea.isEmpty())
parsePositionAreaString(options->positionArea, resolvedOptions);
}
element.showCaptionDisplaySettingsPreview();
page->showCaptionDisplaySettings(element, resolvedOptions, [weakElement = WeakPtr { element }, promise = WTF::move(promise)] (ExceptionOr<void>&& result) {
if (RefPtr element = weakElement.get())
element->hideCaptionDisplaySettingsPreview();
if (result.hasException())
promise->reject(result.releaseException());
else
promise->resolve();
});
}
}
#endif