blob: 9ecf8f5d1e8ff37f5d15d0f7d54a2142fed29276 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "modules/media_controls/elements/MediaControlSliderElement.h"
#include "core/InputTypeNames.h"
#include "core/dom/ElementShadow.h"
#include "core/html/HTMLDivElement.h"
#include "core/layout/LayoutBoxModelObject.h"
#include "core/resize_observer/ResizeObserver.h"
#include "core/resize_observer/ResizeObserverEntry.h"
#include "platform/wtf/text/StringBuilder.h"
namespace {
void SetSegmentDivPosition(blink::HTMLDivElement* segment,
blink::MediaControlSliderElement::Position position,
int width) {
int segment_width = int(position.width * width);
int segment_left = int(position.left * width);
StringBuilder builder;
builder.Append("width: ");
builder.AppendNumber(segment_width);
builder.Append("px; left: ");
builder.AppendNumber(segment_left);
builder.Append("px;");
segment->setAttribute("style", builder.ToAtomicString());
}
} // namespace.
namespace blink {
class MediaControlSliderElement::MediaControlSliderElementResizeObserverDelegate
final : public ResizeObserver::Delegate {
public:
explicit MediaControlSliderElementResizeObserverDelegate(
MediaControlSliderElement* element)
: element_(element) {
DCHECK(element);
}
~MediaControlSliderElementResizeObserverDelegate() override = default;
void OnResize(
const HeapVector<Member<ResizeObserverEntry>>& entries) override {
DCHECK_EQ(1u, entries.size());
DCHECK_EQ(entries[0]->target(), element_);
element_->NotifyElementSizeChanged();
}
DEFINE_INLINE_TRACE() {
visitor->Trace(element_);
ResizeObserver::Delegate::Trace(visitor);
}
private:
Member<MediaControlSliderElement> element_;
};
MediaControlSliderElement::MediaControlSliderElement(
MediaControlsImpl& media_controls,
MediaControlElementType display_type)
: MediaControlInputElement(media_controls, display_type),
before_segment_position_(0, 0),
after_segment_position_(0, 0),
segment_highlight_before_(nullptr),
segment_highlight_after_(nullptr),
resize_observer_(ResizeObserver::Create(
GetDocument(),
new MediaControlSliderElementResizeObserverDelegate(this))) {
EnsureUserAgentShadowRoot();
setType(InputTypeNames::range);
setAttribute(HTMLNames::stepAttr, "any");
resize_observer_->observe(this);
}
void MediaControlSliderElement::SetupBarSegments() {
DCHECK((segment_highlight_after_ && segment_highlight_before_) ||
(!segment_highlight_after_ && !segment_highlight_before_));
if (segment_highlight_after_ || segment_highlight_before_)
return;
// The timeline element has a shadow root with the following
// structure:
//
// #shadow-root
// - div
// - div::-webkit-slider-runnable-track#track
ShadowRoot& shadow_root = Shadow()->OldestShadowRoot();
Element* track = shadow_root.getElementById(AtomicString("track"));
DCHECK(track);
track->SetShadowPseudoId("-internal-media-controls-segmented-track");
// Add the following structure to #track.
//
// div::internal-track-segment-background (container)
// - div::internal-track-segment-highlight-before (blue highlight)
// - div::internal-track-segment-highlight-after (dark gray highlight)
HTMLDivElement* background = HTMLDivElement::Create(GetDocument());
background->SetShadowPseudoId("-internal-track-segment-background");
track->appendChild(background);
segment_highlight_before_ = HTMLDivElement::Create(GetDocument());
segment_highlight_before_->SetShadowPseudoId(
"-internal-track-segment-highlight-before");
background->appendChild(segment_highlight_before_);
segment_highlight_after_ = HTMLDivElement::Create(GetDocument());
segment_highlight_after_->SetShadowPseudoId(
"-internal-track-segment-highlight-after");
background->appendChild(segment_highlight_after_);
}
void MediaControlSliderElement::SetBeforeSegmentPosition(
MediaControlSliderElement::Position position) {
DCHECK(segment_highlight_before_);
before_segment_position_ = position;
SetSegmentDivPosition(segment_highlight_before_, before_segment_position_,
Width());
}
void MediaControlSliderElement::SetAfterSegmentPosition(
MediaControlSliderElement::Position position) {
DCHECK(segment_highlight_after_);
after_segment_position_ = position;
SetSegmentDivPosition(segment_highlight_after_, after_segment_position_,
Width());
}
int MediaControlSliderElement::Width() {
if (LayoutBoxModelObject* box = GetLayoutBoxModelObject())
return box->OffsetWidth().Round();
return 0;
}
void MediaControlSliderElement::NotifyElementSizeChanged() {
SetSegmentDivPosition(segment_highlight_before_, before_segment_position_,
Width());
SetSegmentDivPosition(segment_highlight_after_, after_segment_position_,
Width());
}
DEFINE_TRACE(MediaControlSliderElement) {
visitor->Trace(segment_highlight_before_);
visitor->Trace(segment_highlight_after_);
visitor->Trace(resize_observer_);
MediaControlInputElement::Trace(visitor);
}
} // namespace blink