~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/WebCore/html/shadow/MediaControlElements.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
 
3
 *
 
4
 * Redistribution and use in source and binary forms, with or without
 
5
 * modification, are permitted provided that the following conditions
 
6
 * are met:
 
7
 *
 
8
 * 1.  Redistributions of source code must retain the above copyright
 
9
 *     notice, this list of conditions and the following disclaimer.
 
10
 * 2.  Redistributions in binary form must reproduce the above copyright
 
11
 *     notice, this list of conditions and the following disclaimer in the
 
12
 *     documentation and/or other materials provided with the distribution.
 
13
 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
 
14
 *     its contributors may be used to endorse or promote products derived
 
15
 *     from this software without specific prior written permission.
 
16
 *
 
17
 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
 
18
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 
19
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 
20
 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 
21
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 
22
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 
23
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 
24
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
27
 */
 
28
 
 
29
#include "config.h"
 
30
 
 
31
#if ENABLE(VIDEO)
 
32
 
 
33
#include "MediaControlElements.h"
 
34
 
 
35
#include "CSSStyleDeclaration.h"
 
36
#include "CSSValueKeywords.h"
 
37
#include "DOMTokenList.h"
 
38
#include "EventNames.h"
 
39
#include "EventTarget.h"
 
40
#include "FloatConversion.h"
 
41
#include "FloatPoint.h"
 
42
#include "Frame.h"
 
43
#include "HTMLDivElement.h"
 
44
#include "HTMLMediaElement.h"
 
45
#include "HTMLNames.h"
 
46
#include "HTMLVideoElement.h"
 
47
#include "Language.h"
 
48
#include "LayoutRepainter.h"
 
49
#include "LocalizedStrings.h"
 
50
#include "MediaControls.h"
 
51
#include "MouseEvent.h"
 
52
#include "Page.h"
 
53
#include "PageGroup.h"
 
54
#include "RenderDeprecatedFlexibleBox.h"
 
55
#include "RenderInline.h"
 
56
#include "RenderMedia.h"
 
57
#include "RenderSlider.h"
 
58
#include "RenderText.h"
 
59
#include "RenderTheme.h"
 
60
#include "RenderVideo.h"
 
61
#include "RenderView.h"
 
62
#include "ScriptController.h"
 
63
#include "Settings.h"
 
64
#include "StyleResolver.h"
 
65
#include "Text.h"
 
66
#if ENABLE(VIDEO_TRACK)
 
67
#include "TextTrack.h"
 
68
#include "TextTrackList.h"
 
69
#endif
 
70
 
 
71
namespace WebCore {
 
72
 
 
73
using namespace HTMLNames;
 
74
using namespace std;
 
75
 
 
76
// FIXME: These constants may need to be tweaked to better match the seeking in the QuickTime plug-in.
 
77
static const float cSkipRepeatDelay = 0.1f;
 
78
static const float cSkipTime = 0.2f;
 
79
static const float cScanRepeatDelay = 1.5f;
 
80
static const float cScanMaximumRate = 8;
 
81
 
 
82
#if ENABLE(VIDEO_TRACK)
 
83
static const char* textTracksOffAttrValue = "-1"; // This must match HTMLMediaElement::textTracksOffIndex()
 
84
static const int textTracksIndexNotFound = -2;
 
85
#endif
 
86
 
 
87
HTMLMediaElement* toParentMediaElement(Node* node)
 
88
{
 
89
    if (!node)
 
90
        return 0;
 
91
    Node* mediaNode = node->shadowHost();
 
92
    if (!mediaNode)
 
93
        mediaNode = node;
 
94
    if (!mediaNode || !mediaNode->isElementNode() || !static_cast<Element*>(mediaNode)->isMediaElement())
 
95
        return 0;
 
96
 
 
97
    return static_cast<HTMLMediaElement*>(mediaNode);
 
98
}
 
99
 
 
100
MediaControlElementType mediaControlElementType(Node* node)
 
101
{
 
102
    ASSERT(node->isMediaControlElement());
 
103
    HTMLElement* element = toHTMLElement(node);
 
104
    if (element->hasTagName(inputTag))
 
105
        return static_cast<MediaControlInputElement*>(element)->displayType();
 
106
    return static_cast<MediaControlElement*>(element)->displayType();
 
107
}
 
108
 
 
109
#if ENABLE(VIDEO_TRACK)
 
110
static const AtomicString& trackIndexAttributeName()
 
111
{
 
112
    DEFINE_STATIC_LOCAL(AtomicString, name, ("x-webkit-track-index", AtomicString::ConstructFromLiteral));
 
113
    return name;
 
114
}
 
115
 
 
116
static int trackListIndexForElement(Element* element)
 
117
{
 
118
    const AtomicString trackIndexAttributeValue = element->getAttribute(trackIndexAttributeName());
 
119
    if (trackIndexAttributeValue.isNull() || trackIndexAttributeValue.isEmpty())
 
120
        return textTracksIndexNotFound;
 
121
    bool ok;
 
122
    int trackIndex = trackIndexAttributeValue.toInt(&ok);
 
123
    if (!ok)
 
124
        return textTracksIndexNotFound;
 
125
    return trackIndex;
 
126
}
 
127
#endif
 
128
 
 
129
// ----------------------------
 
130
 
 
131
MediaControlElement::MediaControlElement(Document* document)
 
132
    : HTMLDivElement(divTag, document)
 
133
    , m_mediaController(0)
 
134
{
 
135
}
 
136
 
 
137
void MediaControlElement::show()
 
138
{
 
139
    removeInlineStyleProperty(CSSPropertyDisplay);
 
140
}
 
141
 
 
142
void MediaControlElement::hide()
 
143
{
 
144
    setInlineStyleProperty(CSSPropertyDisplay, CSSValueNone);
 
145
}
 
146
 
 
147
bool MediaControlElement::isShowing() const
 
148
{
 
149
    const StylePropertySet* propertySet = inlineStyle();
 
150
    // Following the code from show() and hide() above, we only have
 
151
    // to check for the presense of inline display.
 
152
    return (!propertySet || !propertySet->getPropertyCSSValue(CSSPropertyDisplay));
 
153
}
 
154
 
 
155
// ----------------------------
 
156
 
 
157
inline MediaControlPanelElement::MediaControlPanelElement(Document* document)
 
158
    : MediaControlElement(document)
 
159
    , m_canBeDragged(false)
 
160
    , m_isBeingDragged(false)
 
161
    , m_isDisplayed(false)
 
162
    , m_opaque(true)
 
163
    , m_transitionTimer(this, &MediaControlPanelElement::transitionTimerFired)
 
164
{
 
165
}
 
166
 
 
167
PassRefPtr<MediaControlPanelElement> MediaControlPanelElement::create(Document* document)
 
168
{
 
169
    return adoptRef(new MediaControlPanelElement(document));
 
170
}
 
171
 
 
172
MediaControlElementType MediaControlPanelElement::displayType() const
 
173
{
 
174
    return MediaControlsPanel;
 
175
}
 
176
 
 
177
const AtomicString& MediaControlPanelElement::shadowPseudoId() const
 
178
{
 
179
    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-panel", AtomicString::ConstructFromLiteral));
 
180
    return id;
 
181
}
 
182
 
 
183
void MediaControlPanelElement::startDrag(const LayoutPoint& eventLocation)
 
184
{
 
185
    if (!m_canBeDragged)
 
186
        return;
 
187
 
 
188
    if (m_isBeingDragged)
 
189
        return;
 
190
 
 
191
    RenderObject* renderer = this->renderer();
 
192
    if (!renderer || !renderer->isBox())
 
193
        return;
 
194
 
 
195
    Frame* frame = document()->frame();
 
196
    if (!frame)
 
197
        return;
 
198
 
 
199
    m_lastDragEventLocation = eventLocation;
 
200
 
 
201
    frame->eventHandler()->setCapturingMouseEventsNode(this);
 
202
 
 
203
    m_isBeingDragged = true;
 
204
}
 
205
 
 
206
void MediaControlPanelElement::continueDrag(const LayoutPoint& eventLocation)
 
207
{
 
208
    if (!m_isBeingDragged)
 
209
        return;
 
210
 
 
211
    LayoutSize distanceDragged = eventLocation - m_lastDragEventLocation;
 
212
    m_cumulativeDragOffset.move(distanceDragged);
 
213
    m_lastDragEventLocation = eventLocation;
 
214
    setPosition(m_cumulativeDragOffset);
 
215
}
 
216
 
 
217
void MediaControlPanelElement::endDrag()
 
218
{
 
219
    if (!m_isBeingDragged)
 
220
        return;
 
221
 
 
222
    m_isBeingDragged = false;
 
223
 
 
224
    Frame* frame = document()->frame();
 
225
    if (!frame)
 
226
        return;
 
227
 
 
228
    frame->eventHandler()->setCapturingMouseEventsNode(0);
 
229
}
 
230
 
 
231
void MediaControlPanelElement::startTimer()
 
232
{
 
233
    stopTimer();
 
234
 
 
235
    // The timer is required to set the property display:'none' on the panel,
 
236
    // such that captions are correctly displayed at the bottom of the video
 
237
    // at the end of the fadeout transition.
 
238
    double duration = document()->page() ? document()->page()->theme()->mediaControlsFadeOutDuration() : 0;
 
239
    m_transitionTimer.startOneShot(duration);
 
240
}
 
241
 
 
242
void MediaControlPanelElement::stopTimer()
 
243
{
 
244
    if (m_transitionTimer.isActive())
 
245
        m_transitionTimer.stop();
 
246
}
 
247
 
 
248
 
 
249
void MediaControlPanelElement::transitionTimerFired(Timer<MediaControlPanelElement>*)
 
250
{
 
251
    if (!m_opaque)
 
252
        hide();
 
253
 
 
254
    stopTimer();
 
255
}
 
256
 
 
257
void MediaControlPanelElement::setPosition(const LayoutPoint& position)
 
258
{
 
259
    double left = position.x();
 
260
    double top = position.y();
 
261
 
 
262
    // Set the left and top to control the panel's position; this depends on it being absolute positioned.
 
263
    // Set the margin to zero since the position passed in will already include the effect of the margin.
 
264
    setInlineStyleProperty(CSSPropertyLeft, left, CSSPrimitiveValue::CSS_PX);
 
265
    setInlineStyleProperty(CSSPropertyTop, top, CSSPrimitiveValue::CSS_PX);
 
266
    setInlineStyleProperty(CSSPropertyMarginLeft, 0.0, CSSPrimitiveValue::CSS_PX);
 
267
    setInlineStyleProperty(CSSPropertyMarginTop, 0.0, CSSPrimitiveValue::CSS_PX);
 
268
 
 
269
    ExceptionCode ignored;
 
270
    classList()->add("dragged", ignored);
 
271
}
 
272
 
 
273
void MediaControlPanelElement::resetPosition()
 
274
{
 
275
    removeInlineStyleProperty(CSSPropertyLeft);
 
276
    removeInlineStyleProperty(CSSPropertyTop);
 
277
    removeInlineStyleProperty(CSSPropertyMarginLeft);
 
278
    removeInlineStyleProperty(CSSPropertyMarginTop);
 
279
 
 
280
    ExceptionCode ignored;
 
281
    classList()->remove("dragged", ignored);
 
282
 
 
283
    m_cumulativeDragOffset.setX(0);
 
284
    m_cumulativeDragOffset.setY(0);
 
285
}
 
286
 
 
287
void MediaControlPanelElement::makeOpaque()
 
288
{
 
289
    if (m_opaque)
 
290
        return;
 
291
 
 
292
    double duration = document()->page() ? document()->page()->theme()->mediaControlsFadeInDuration() : 0;
 
293
 
 
294
    setInlineStyleProperty(CSSPropertyWebkitTransitionProperty, CSSPropertyOpacity);
 
295
    setInlineStyleProperty(CSSPropertyWebkitTransitionDuration, duration, CSSPrimitiveValue::CSS_S);
 
296
    setInlineStyleProperty(CSSPropertyOpacity, 1.0, CSSPrimitiveValue::CSS_NUMBER);
 
297
 
 
298
    m_opaque = true;
 
299
 
 
300
    if (m_isDisplayed)
 
301
        show();
 
302
}
 
303
 
 
304
void MediaControlPanelElement::makeTransparent()
 
305
{
 
306
    if (!m_opaque)
 
307
        return;
 
308
 
 
309
    double duration = document()->page() ? document()->page()->theme()->mediaControlsFadeOutDuration() : 0;
 
310
 
 
311
    setInlineStyleProperty(CSSPropertyWebkitTransitionProperty, CSSPropertyOpacity);
 
312
    setInlineStyleProperty(CSSPropertyWebkitTransitionDuration, duration, CSSPrimitiveValue::CSS_S);
 
313
    setInlineStyleProperty(CSSPropertyOpacity, 0.0, CSSPrimitiveValue::CSS_NUMBER);
 
314
 
 
315
    m_opaque = false;
 
316
    startTimer();
 
317
}
 
318
 
 
319
void MediaControlPanelElement::defaultEventHandler(Event* event)
 
320
{
 
321
    MediaControlElement::defaultEventHandler(event);
 
322
 
 
323
    if (event->isMouseEvent()) {
 
324
        LayoutPoint location = static_cast<MouseEvent*>(event)->absoluteLocation();
 
325
        if (event->type() == eventNames().mousedownEvent && event->target() == this) {
 
326
            startDrag(location);
 
327
            event->setDefaultHandled();
 
328
        } else if (event->type() == eventNames().mousemoveEvent && m_isBeingDragged)
 
329
            continueDrag(location);
 
330
        else if (event->type() == eventNames().mouseupEvent && m_isBeingDragged) {
 
331
            continueDrag(location);
 
332
            endDrag();
 
333
            event->setDefaultHandled();
 
334
        }
 
335
    }
 
336
}
 
337
 
 
338
void MediaControlPanelElement::setCanBeDragged(bool canBeDragged)
 
339
{
 
340
    if (m_canBeDragged == canBeDragged)
 
341
        return;
 
342
 
 
343
    m_canBeDragged = canBeDragged;
 
344
 
 
345
    if (!canBeDragged)
 
346
        endDrag();
 
347
}
 
348
 
 
349
void MediaControlPanelElement::setIsDisplayed(bool isDisplayed)
 
350
{
 
351
    m_isDisplayed = isDisplayed;
 
352
}
 
353
 
 
354
// ----------------------------
 
355
 
 
356
inline MediaControlTimelineContainerElement::MediaControlTimelineContainerElement(Document* document)
 
357
    : MediaControlElement(document)
 
358
{
 
359
}
 
360
 
 
361
PassRefPtr<MediaControlTimelineContainerElement> MediaControlTimelineContainerElement::create(Document* document)
 
362
{
 
363
    RefPtr<MediaControlTimelineContainerElement> element = adoptRef(new MediaControlTimelineContainerElement(document));
 
364
    element->hide();
 
365
    return element.release();
 
366
}
 
367
 
 
368
MediaControlElementType MediaControlTimelineContainerElement::displayType() const
 
369
{
 
370
    return MediaTimelineContainer;
 
371
}
 
372
 
 
373
const AtomicString& MediaControlTimelineContainerElement::shadowPseudoId() const
 
374
{
 
375
    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-timeline-container", AtomicString::ConstructFromLiteral));
 
376
    return id;
 
377
}
 
378
 
 
379
// ----------------------------
 
380
 
 
381
class RenderMediaVolumeSliderContainer : public RenderBlock {
 
382
public:
 
383
    RenderMediaVolumeSliderContainer(Node*);
 
384
 
 
385
private:
 
386
    virtual void layout();
 
387
};
 
388
 
 
389
RenderMediaVolumeSliderContainer::RenderMediaVolumeSliderContainer(Node* node)
 
390
    : RenderBlock(node)
 
391
{
 
392
}
 
393
 
 
394
void RenderMediaVolumeSliderContainer::layout()
 
395
{
 
396
    RenderBlock::layout();
 
397
 
 
398
    if (style()->display() == NONE || !nextSibling() || !nextSibling()->isBox())
 
399
        return;
 
400
 
 
401
    RenderBox* buttonBox = toRenderBox(nextSibling());
 
402
    int absoluteOffsetTop = buttonBox->localToAbsolute(FloatPoint(0, -size().height())).y();
 
403
 
 
404
    LayoutStateDisabler layoutStateDisabler(view());
 
405
 
 
406
    // If the slider would be rendered outside the page, it should be moved below the controls.
 
407
    if (UNLIKELY(absoluteOffsetTop < 0))
 
408
        setY(buttonBox->offsetTop() + theme()->volumeSliderOffsetFromMuteButton(buttonBox, pixelSnappedSize()).y());
 
409
}
 
410
 
 
411
inline MediaControlVolumeSliderContainerElement::MediaControlVolumeSliderContainerElement(Document* document)
 
412
    : MediaControlElement(document)
 
413
{
 
414
}
 
415
 
 
416
PassRefPtr<MediaControlVolumeSliderContainerElement> MediaControlVolumeSliderContainerElement::create(Document* document)
 
417
{
 
418
    RefPtr<MediaControlVolumeSliderContainerElement> element = adoptRef(new MediaControlVolumeSliderContainerElement(document));
 
419
    element->hide();
 
420
    return element.release();
 
421
}
 
422
 
 
423
RenderObject* MediaControlVolumeSliderContainerElement::createRenderer(RenderArena* arena, RenderStyle*)
 
424
{
 
425
    return new (arena) RenderMediaVolumeSliderContainer(this);
 
426
}
 
427
 
 
428
void MediaControlVolumeSliderContainerElement::defaultEventHandler(Event* event)
 
429
{
 
430
    if (!event->isMouseEvent() || event->type() != eventNames().mouseoutEvent)
 
431
        return;
 
432
 
 
433
    // Poor man's mouseleave event detection.
 
434
    MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
 
435
    if (!mouseEvent->relatedTarget() || !mouseEvent->relatedTarget()->toNode())
 
436
        return;
 
437
 
 
438
    if (this->containsIncludingShadowDOM(mouseEvent->relatedTarget()->toNode()))
 
439
        return;
 
440
 
 
441
    hide();
 
442
}
 
443
 
 
444
MediaControlElementType MediaControlVolumeSliderContainerElement::displayType() const
 
445
{
 
446
    return MediaVolumeSliderContainer;
 
447
}
 
448
 
 
449
const AtomicString& MediaControlVolumeSliderContainerElement::shadowPseudoId() const
 
450
{
 
451
    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-volume-slider-container", AtomicString::ConstructFromLiteral));
 
452
    return id;
 
453
}
 
454
 
 
455
// ----------------------------
 
456
 
 
457
inline MediaControlStatusDisplayElement::MediaControlStatusDisplayElement(Document* document)
 
458
    : MediaControlElement(document)
 
459
    , m_stateBeingDisplayed(Nothing)
 
460
{
 
461
}
 
462
 
 
463
PassRefPtr<MediaControlStatusDisplayElement> MediaControlStatusDisplayElement::create(Document* document)
 
464
{
 
465
    RefPtr<MediaControlStatusDisplayElement> element = adoptRef(new MediaControlStatusDisplayElement(document));
 
466
    element->hide();
 
467
    return element.release();
 
468
}
 
469
 
 
470
void MediaControlStatusDisplayElement::update()
 
471
{
 
472
    // Get the new state that we'll have to display.
 
473
    StateBeingDisplayed newStateToDisplay = Nothing;
 
474
 
 
475
    if (mediaController()->readyState() <= MediaControllerInterface::HAVE_METADATA && mediaController()->hasCurrentSrc())
 
476
        newStateToDisplay = Loading;
 
477
    else if (mediaController()->isLiveStream())
 
478
        newStateToDisplay = LiveBroadcast;
 
479
 
 
480
    if (newStateToDisplay == m_stateBeingDisplayed)
 
481
        return;
 
482
 
 
483
    ExceptionCode e;
 
484
 
 
485
    if (m_stateBeingDisplayed == Nothing)
 
486
        show();
 
487
    else if (newStateToDisplay == Nothing)
 
488
        hide();
 
489
 
 
490
    m_stateBeingDisplayed = newStateToDisplay;
 
491
 
 
492
    switch (m_stateBeingDisplayed) {
 
493
    case Nothing:
 
494
        setInnerText("", e);
 
495
        break;
 
496
    case Loading:
 
497
        setInnerText(mediaElementLoadingStateText(), e);
 
498
        break;
 
499
    case LiveBroadcast:
 
500
        setInnerText(mediaElementLiveBroadcastStateText(), e);
 
501
        break;
 
502
    }
 
503
}
 
504
 
 
505
MediaControlElementType MediaControlStatusDisplayElement::displayType() const
 
506
{
 
507
    return MediaStatusDisplay;
 
508
}
 
509
 
 
510
const AtomicString& MediaControlStatusDisplayElement::shadowPseudoId() const
 
511
{
 
512
    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-status-display", AtomicString::ConstructFromLiteral));
 
513
    return id;
 
514
}
 
515
 
 
516
// ----------------------------
 
517
    
 
518
MediaControlInputElement::MediaControlInputElement(Document* document, MediaControlElementType displayType)
 
519
    : HTMLInputElement(inputTag, document, 0, false)
 
520
    , m_mediaController(0)
 
521
    , m_displayType(displayType)
 
522
{
 
523
}
 
524
 
 
525
void MediaControlInputElement::show()
 
526
{
 
527
    removeInlineStyleProperty(CSSPropertyDisplay);
 
528
}
 
529
 
 
530
void MediaControlInputElement::hide()
 
531
{
 
532
    setInlineStyleProperty(CSSPropertyDisplay, CSSValueNone);
 
533
}
 
534
 
 
535
 
 
536
void MediaControlInputElement::setDisplayType(MediaControlElementType displayType)
 
537
{
 
538
    if (displayType == m_displayType)
 
539
        return;
 
540
 
 
541
    m_displayType = displayType;
 
542
    if (RenderObject* object = renderer())
 
543
        object->repaint();
 
544
}
 
545
 
 
546
// ----------------------------
 
547
 
 
548
inline MediaControlMuteButtonElement::MediaControlMuteButtonElement(Document* document, MediaControlElementType displayType)
 
549
    : MediaControlInputElement(document, displayType)
 
550
{
 
551
}
 
552
 
 
553
void MediaControlMuteButtonElement::defaultEventHandler(Event* event)
 
554
{
 
555
    if (event->type() == eventNames().clickEvent) {
 
556
        mediaController()->setMuted(!mediaController()->muted());
 
557
        event->setDefaultHandled();
 
558
    }
 
559
 
 
560
    HTMLInputElement::defaultEventHandler(event);
 
561
}
 
562
 
 
563
void MediaControlMuteButtonElement::changedMute()
 
564
{
 
565
    updateDisplayType();
 
566
}
 
567
 
 
568
void MediaControlMuteButtonElement::updateDisplayType()
 
569
{
 
570
    setDisplayType(mediaController()->muted() ? MediaUnMuteButton : MediaMuteButton);
 
571
}
 
572
 
 
573
// ----------------------------
 
574
 
 
575
inline MediaControlPanelMuteButtonElement::MediaControlPanelMuteButtonElement(Document* document, MediaControls* controls)
 
576
    : MediaControlMuteButtonElement(document, MediaMuteButton)
 
577
    , m_controls(controls)
 
578
{
 
579
}
 
580
 
 
581
PassRefPtr<MediaControlPanelMuteButtonElement> MediaControlPanelMuteButtonElement::create(Document* document, MediaControls* controls)
 
582
{
 
583
    ASSERT(controls);
 
584
 
 
585
    RefPtr<MediaControlPanelMuteButtonElement> button = adoptRef(new MediaControlPanelMuteButtonElement(document, controls));
 
586
    button->createShadowSubtree();
 
587
    button->setType("button");
 
588
    return button.release();
 
589
}
 
590
 
 
591
void MediaControlPanelMuteButtonElement::defaultEventHandler(Event* event)
 
592
{
 
593
    if (event->type() == eventNames().mouseoverEvent)
 
594
        m_controls->showVolumeSlider();
 
595
 
 
596
    MediaControlMuteButtonElement::defaultEventHandler(event);
 
597
}
 
598
 
 
599
const AtomicString& MediaControlPanelMuteButtonElement::shadowPseudoId() const
 
600
{
 
601
    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-mute-button", AtomicString::ConstructFromLiteral));
 
602
    return id;
 
603
}
 
604
 
 
605
// ----------------------------
 
606
 
 
607
inline MediaControlVolumeSliderMuteButtonElement::MediaControlVolumeSliderMuteButtonElement(Document* document)
 
608
    : MediaControlMuteButtonElement(document, MediaMuteButton)
 
609
{
 
610
}
 
611
 
 
612
PassRefPtr<MediaControlVolumeSliderMuteButtonElement> MediaControlVolumeSliderMuteButtonElement::create(Document* document)
 
613
{
 
614
    RefPtr<MediaControlVolumeSliderMuteButtonElement> button = adoptRef(new MediaControlVolumeSliderMuteButtonElement(document));
 
615
    button->createShadowSubtree();
 
616
    button->setType("button");
 
617
    return button.release();
 
618
}
 
619
 
 
620
const AtomicString& MediaControlVolumeSliderMuteButtonElement::shadowPseudoId() const
 
621
{
 
622
    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-volume-slider-mute-button", AtomicString::ConstructFromLiteral));
 
623
    return id;
 
624
}
 
625
 
 
626
// ----------------------------
 
627
 
 
628
inline MediaControlPlayButtonElement::MediaControlPlayButtonElement(Document* document)
 
629
    : MediaControlInputElement(document, MediaPlayButton)
 
630
{
 
631
}
 
632
 
 
633
PassRefPtr<MediaControlPlayButtonElement> MediaControlPlayButtonElement::create(Document* document)
 
634
{
 
635
    RefPtr<MediaControlPlayButtonElement> button = adoptRef(new MediaControlPlayButtonElement(document));
 
636
    button->createShadowSubtree();
 
637
    button->setType("button");
 
638
    return button.release();
 
639
}
 
640
 
 
641
void MediaControlPlayButtonElement::defaultEventHandler(Event* event)
 
642
{
 
643
    if (event->type() == eventNames().clickEvent) {
 
644
        if (mediaController()->canPlay())
 
645
            mediaController()->play();
 
646
        else
 
647
            mediaController()->pause();
 
648
        updateDisplayType();
 
649
        event->setDefaultHandled();
 
650
    }
 
651
    HTMLInputElement::defaultEventHandler(event);
 
652
}
 
653
 
 
654
void MediaControlPlayButtonElement::updateDisplayType()
 
655
{
 
656
    setDisplayType(mediaController()->canPlay() ? MediaPlayButton : MediaPauseButton);
 
657
}
 
658
 
 
659
const AtomicString& MediaControlPlayButtonElement::shadowPseudoId() const
 
660
{
 
661
    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-play-button", AtomicString::ConstructFromLiteral));
 
662
    return id;
 
663
}
 
664
 
 
665
// ----------------------------
 
666
 
 
667
inline MediaControlOverlayPlayButtonElement::MediaControlOverlayPlayButtonElement(Document* document)
 
668
    : MediaControlInputElement(document, MediaOverlayPlayButton)
 
669
{
 
670
}
 
671
 
 
672
PassRefPtr<MediaControlOverlayPlayButtonElement> MediaControlOverlayPlayButtonElement::create(Document* document)
 
673
{
 
674
    RefPtr<MediaControlOverlayPlayButtonElement> button = adoptRef(new MediaControlOverlayPlayButtonElement(document));
 
675
    button->createShadowSubtree();
 
676
    button->setType("button");
 
677
    return button.release();
 
678
}
 
679
 
 
680
void MediaControlOverlayPlayButtonElement::defaultEventHandler(Event* event)
 
681
{
 
682
    if (event->type() == eventNames().clickEvent && mediaController()->canPlay()) {
 
683
        mediaController()->play();
 
684
        updateDisplayType();
 
685
        event->setDefaultHandled();
 
686
    }
 
687
    HTMLInputElement::defaultEventHandler(event);
 
688
}
 
689
 
 
690
void MediaControlOverlayPlayButtonElement::updateDisplayType()
 
691
{
 
692
    if (mediaController()->canPlay()) {
 
693
        show();
 
694
        setDisplayType(MediaOverlayPlayButton);
 
695
    } else
 
696
        hide();
 
697
}
 
698
 
 
699
const AtomicString& MediaControlOverlayPlayButtonElement::shadowPseudoId() const
 
700
{
 
701
    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-overlay-play-button", AtomicString::ConstructFromLiteral));
 
702
    return id;
 
703
}
 
704
 
 
705
// ----------------------------
 
706
 
 
707
inline MediaControlSeekButtonElement::MediaControlSeekButtonElement(Document* document, MediaControlElementType displayType)
 
708
    : MediaControlInputElement(document, displayType)
 
709
    , m_actionOnStop(Nothing)
 
710
    , m_seekType(Skip)
 
711
    , m_seekTimer(this, &MediaControlSeekButtonElement::seekTimerFired)
 
712
{
 
713
}
 
714
 
 
715
void MediaControlSeekButtonElement::defaultEventHandler(Event* event)
 
716
{
 
717
    // Set the mousedown and mouseup events as defaultHandled so they
 
718
    // do not trigger drag start or end actions in MediaControlPanelElement.
 
719
    if (event->type() == eventNames().mousedownEvent || event->type() == eventNames().mouseupEvent)
 
720
        event->setDefaultHandled();
 
721
}
 
722
 
 
723
void MediaControlSeekButtonElement::setActive(bool flag, bool pause)
 
724
{
 
725
    if (flag == active())
 
726
        return;
 
727
 
 
728
    if (flag)
 
729
        startTimer();
 
730
    else
 
731
        stopTimer();
 
732
 
 
733
    MediaControlInputElement::setActive(flag, pause);
 
734
}
 
735
 
 
736
void MediaControlSeekButtonElement::startTimer()
 
737
{
 
738
    m_seekType = mediaController()->supportsScanning() ? Scan : Skip;
 
739
 
 
740
    if (m_seekType == Skip) {
 
741
        // Seeking by skipping requires the video to be paused during seeking.
 
742
        m_actionOnStop = mediaController()->paused() ? Nothing : Play;
 
743
        mediaController()->pause();
 
744
    } else {
 
745
        // Seeking by scanning requires the video to be playing during seeking.
 
746
        m_actionOnStop = mediaController()->paused() ? Pause : Nothing;
 
747
        mediaController()->play();
 
748
        mediaController()->setPlaybackRate(nextRate());
 
749
    }
 
750
 
 
751
    m_seekTimer.start(0, m_seekType == Skip ? cSkipRepeatDelay : cScanRepeatDelay);
 
752
}
 
753
 
 
754
void MediaControlSeekButtonElement::stopTimer()
 
755
{
 
756
    if (m_seekType == Scan)
 
757
        mediaController()->setPlaybackRate(mediaController()->defaultPlaybackRate());
 
758
 
 
759
    if (m_actionOnStop == Play)
 
760
        mediaController()->play();
 
761
    else if (m_actionOnStop == Pause)
 
762
        mediaController()->pause();
 
763
 
 
764
    if (m_seekTimer.isActive())
 
765
        m_seekTimer.stop();
 
766
}
 
767
 
 
768
float MediaControlSeekButtonElement::nextRate() const
 
769
{
 
770
    float rate = std::min(cScanMaximumRate, fabsf(mediaController()->playbackRate() * 2));
 
771
    if (!isForwardButton())
 
772
        rate *= -1;
 
773
    return rate;
 
774
}
 
775
 
 
776
void MediaControlSeekButtonElement::seekTimerFired(Timer<MediaControlSeekButtonElement>*)
 
777
{
 
778
    if (m_seekType == Skip) {
 
779
        ExceptionCode ec;
 
780
        float skipTime = isForwardButton() ? cSkipTime : -cSkipTime;
 
781
        mediaController()->setCurrentTime(mediaController()->currentTime() + skipTime, ec);
 
782
    } else
 
783
        mediaController()->setPlaybackRate(nextRate());
 
784
}
 
785
 
 
786
// ----------------------------
 
787
 
 
788
inline MediaControlSeekForwardButtonElement::MediaControlSeekForwardButtonElement(Document* document)
 
789
    : MediaControlSeekButtonElement(document, MediaSeekForwardButton)
 
790
{
 
791
}
 
792
 
 
793
PassRefPtr<MediaControlSeekForwardButtonElement> MediaControlSeekForwardButtonElement::create(Document* document)
 
794
{
 
795
    RefPtr<MediaControlSeekForwardButtonElement> button = adoptRef(new MediaControlSeekForwardButtonElement(document));
 
796
    button->createShadowSubtree();
 
797
    button->setType("button");
 
798
    return button.release();
 
799
}
 
800
 
 
801
const AtomicString& MediaControlSeekForwardButtonElement::shadowPseudoId() const
 
802
{
 
803
    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-seek-forward-button", AtomicString::ConstructFromLiteral));
 
804
    return id;
 
805
}
 
806
 
 
807
// ----------------------------
 
808
 
 
809
inline MediaControlSeekBackButtonElement::MediaControlSeekBackButtonElement(Document* document)
 
810
    : MediaControlSeekButtonElement(document, MediaSeekBackButton)
 
811
{
 
812
}
 
813
 
 
814
PassRefPtr<MediaControlSeekBackButtonElement> MediaControlSeekBackButtonElement::create(Document* document)
 
815
{
 
816
    RefPtr<MediaControlSeekBackButtonElement> button = adoptRef(new MediaControlSeekBackButtonElement(document));
 
817
    button->createShadowSubtree();
 
818
    button->setType("button");
 
819
    return button.release();
 
820
}
 
821
 
 
822
const AtomicString& MediaControlSeekBackButtonElement::shadowPseudoId() const
 
823
{
 
824
    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-seek-back-button", AtomicString::ConstructFromLiteral));
 
825
    return id;
 
826
}
 
827
 
 
828
// ----------------------------
 
829
 
 
830
inline MediaControlRewindButtonElement::MediaControlRewindButtonElement(Document* document)
 
831
    : MediaControlInputElement(document, MediaRewindButton)
 
832
{
 
833
}
 
834
 
 
835
PassRefPtr<MediaControlRewindButtonElement> MediaControlRewindButtonElement::create(Document* document)
 
836
{
 
837
    RefPtr<MediaControlRewindButtonElement> button = adoptRef(new MediaControlRewindButtonElement(document));
 
838
    button->createShadowSubtree();
 
839
    button->setType("button");
 
840
    return button.release();
 
841
}
 
842
 
 
843
void MediaControlRewindButtonElement::defaultEventHandler(Event* event)
 
844
{
 
845
    if (event->type() == eventNames().clickEvent) {
 
846
        ExceptionCode ignoredCode;
 
847
        mediaController()->setCurrentTime(max(0.0f, mediaController()->currentTime() - 30), ignoredCode);
 
848
        event->setDefaultHandled();
 
849
    }    
 
850
    HTMLInputElement::defaultEventHandler(event);
 
851
}
 
852
 
 
853
const AtomicString& MediaControlRewindButtonElement::shadowPseudoId() const
 
854
{
 
855
    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-rewind-button", AtomicString::ConstructFromLiteral));
 
856
    return id;
 
857
}
 
858
 
 
859
// ----------------------------
 
860
 
 
861
inline MediaControlReturnToRealtimeButtonElement::MediaControlReturnToRealtimeButtonElement(Document* document)
 
862
    : MediaControlInputElement(document, MediaReturnToRealtimeButton)
 
863
{
 
864
}
 
865
 
 
866
PassRefPtr<MediaControlReturnToRealtimeButtonElement> MediaControlReturnToRealtimeButtonElement::create(Document* document)
 
867
{
 
868
    RefPtr<MediaControlReturnToRealtimeButtonElement> button = adoptRef(new MediaControlReturnToRealtimeButtonElement(document));
 
869
    button->createShadowSubtree();
 
870
    button->setType("button");
 
871
    button->hide();
 
872
    return button.release();
 
873
}
 
874
 
 
875
void MediaControlReturnToRealtimeButtonElement::defaultEventHandler(Event* event)
 
876
{
 
877
    if (event->type() == eventNames().clickEvent) {
 
878
        mediaController()->returnToRealtime();
 
879
        event->setDefaultHandled();
 
880
    }
 
881
    HTMLInputElement::defaultEventHandler(event);
 
882
}
 
883
 
 
884
const AtomicString& MediaControlReturnToRealtimeButtonElement::shadowPseudoId() const
 
885
{
 
886
    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-return-to-realtime-button", AtomicString::ConstructFromLiteral));
 
887
    return id;
 
888
}
 
889
 
 
890
// ----------------------------
 
891
 
 
892
inline MediaControlClosedCaptionsContainerElement::MediaControlClosedCaptionsContainerElement(Document* document)
 
893
    : MediaControlElement(document)
 
894
{
 
895
}
 
896
 
 
897
PassRefPtr<MediaControlClosedCaptionsContainerElement> MediaControlClosedCaptionsContainerElement::create(Document* document)
 
898
{
 
899
    RefPtr<MediaControlClosedCaptionsContainerElement> element = adoptRef(new MediaControlClosedCaptionsContainerElement(document));
 
900
    element->hide();
 
901
    return element.release();
 
902
}
 
903
 
 
904
const AtomicString& MediaControlClosedCaptionsContainerElement::shadowPseudoId() const
 
905
{
 
906
    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-closed-captions-container", AtomicString::ConstructFromLiteral));
 
907
    return id;
 
908
}
 
909
 
 
910
// ----------------------------
 
911
 
 
912
inline MediaControlToggleClosedCaptionsButtonElement::MediaControlToggleClosedCaptionsButtonElement(Document* document, MediaControls* controls)
 
913
    : MediaControlInputElement(document, MediaShowClosedCaptionsButton)
 
914
#if PLATFORM(MAC)
 
915
    , m_controls(controls)
 
916
#endif
 
917
{
 
918
#if !PLATFORM(MAC)
 
919
    UNUSED_PARAM(controls);
 
920
#endif
 
921
}
 
922
 
 
923
PassRefPtr<MediaControlToggleClosedCaptionsButtonElement> MediaControlToggleClosedCaptionsButtonElement::create(Document* document, MediaControls* controls)
 
924
{
 
925
    ASSERT(controls);
 
926
 
 
927
    RefPtr<MediaControlToggleClosedCaptionsButtonElement> button = adoptRef(new MediaControlToggleClosedCaptionsButtonElement(document, controls));
 
928
    button->createShadowSubtree();
 
929
    button->setType("button");
 
930
    button->hide();
 
931
    return button.release();
 
932
}
 
933
 
 
934
void MediaControlToggleClosedCaptionsButtonElement::updateDisplayType()
 
935
{
 
936
    bool captionsVisible = mediaController()->closedCaptionsVisible();
 
937
    setDisplayType(captionsVisible ? MediaHideClosedCaptionsButton : MediaShowClosedCaptionsButton);
 
938
    setChecked(captionsVisible);
 
939
}
 
940
 
 
941
void MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler(Event* event)
 
942
{
 
943
    if (event->type() == eventNames().clickEvent) {
 
944
        // FIXME: It's not great that the shared code is dictating behavior of platform-specific
 
945
        // UI. Not all ports may want the closed captions button to toggle a list of tracks, so
 
946
        // we have to use #if.
 
947
        // https://bugs.webkit.org/show_bug.cgi?id=101877
 
948
#if !PLATFORM(MAC)
 
949
        mediaController()->setClosedCaptionsVisible(!mediaController()->closedCaptionsVisible());
 
950
        setChecked(mediaController()->closedCaptionsVisible());
 
951
        updateDisplayType();
 
952
#else
 
953
        m_controls->toggleClosedCaptionTrackList();
 
954
#endif
 
955
        event->setDefaultHandled();
 
956
    }
 
957
 
 
958
    HTMLInputElement::defaultEventHandler(event);
 
959
}
 
960
 
 
961
const AtomicString& MediaControlToggleClosedCaptionsButtonElement::shadowPseudoId() const
 
962
{
 
963
    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-toggle-closed-captions-button", AtomicString::ConstructFromLiteral));
 
964
    return id;
 
965
}
 
966
 
 
967
// ----------------------------
 
968
 
 
969
inline MediaControlClosedCaptionsTrackListElement::MediaControlClosedCaptionsTrackListElement(Document* document, MediaControls* controls)
 
970
    : MediaControlElement(document)
 
971
    , m_controls(controls)
 
972
{
 
973
}
 
974
 
 
975
PassRefPtr<MediaControlClosedCaptionsTrackListElement> MediaControlClosedCaptionsTrackListElement::create(Document* document, MediaControls* controls)
 
976
{
 
977
    ASSERT(controls);
 
978
    RefPtr<MediaControlClosedCaptionsTrackListElement> element = adoptRef(new MediaControlClosedCaptionsTrackListElement(document, controls));
 
979
    return element.release();
 
980
}
 
981
 
 
982
void MediaControlClosedCaptionsTrackListElement::defaultEventHandler(Event* event)
 
983
{
 
984
#if ENABLE(VIDEO_TRACK)
 
985
    if (event->type() == eventNames().clickEvent) {
 
986
        // FIXME: Add modifier key for exclusivity override.
 
987
        // http://webkit.org/b/103361
 
988
 
 
989
        Node* target = event->target()->toNode();
 
990
        if (!target || !target->isElementNode())
 
991
            return;
 
992
 
 
993
        // When we created the elements in the track list, we gave them a custom
 
994
        // attribute representing the index in the HTMLMediaElement's list of tracks.
 
995
        // Check if the event target has such a custom element and, if so,
 
996
        // tell the HTMLMediaElement to enable that track.
 
997
 
 
998
        int trackIndex = trackListIndexForElement(toElement(target));
 
999
        if (trackIndex == textTracksIndexNotFound)
 
1000
            return;
 
1001
        
 
1002
        HTMLMediaElement* mediaElement = toParentMediaElement(this);
 
1003
        if (!mediaElement)
 
1004
            return;
 
1005
 
 
1006
        mediaElement->toggleTrackAtIndex(trackIndex);
 
1007
 
 
1008
        // We've selected a track to display, so we can now close the menu.
 
1009
        m_controls->toggleClosedCaptionTrackList();
 
1010
        updateDisplay();
 
1011
    }
 
1012
 
 
1013
    MediaControlElement::defaultEventHandler(event);
 
1014
#endif
 
1015
}
 
1016
 
 
1017
const AtomicString& MediaControlClosedCaptionsTrackListElement::shadowPseudoId() const
 
1018
{
 
1019
    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-closed-captions-track-list", AtomicString::ConstructFromLiteral));
 
1020
    return id;
 
1021
}
 
1022
 
 
1023
void MediaControlClosedCaptionsTrackListElement::updateDisplay()
 
1024
{
 
1025
#if ENABLE(VIDEO_TRACK)
 
1026
    DEFINE_STATIC_LOCAL(AtomicString, selectedClassValue, ("selected", AtomicString::ConstructFromLiteral));
 
1027
 
 
1028
    if (!mediaController()->hasClosedCaptions())
 
1029
        return;
 
1030
 
 
1031
    HTMLMediaElement* mediaElement = toParentMediaElement(this);
 
1032
    if (!mediaElement)
 
1033
        return;
 
1034
 
 
1035
    TextTrackList* trackList = mediaElement->textTracks();
 
1036
 
 
1037
    if (!trackList || !trackList->length())
 
1038
        return;
 
1039
 
 
1040
    bool captionsVisible = mediaElement->closedCaptionsVisible();
 
1041
    for (unsigned i = 0, length = menuItems.size(); i < length; ++i) {
 
1042
        RefPtr<Element> trackItem = menuItems[i];
 
1043
        int trackIndex = trackListIndexForElement(trackItem.get());
 
1044
        if (trackIndex != textTracksIndexNotFound) {
 
1045
            if (trackIndex == HTMLMediaElement::textTracksOffIndex()) {
 
1046
                if (captionsVisible)
 
1047
                    trackItem->classList()->remove(selectedClassValue, ASSERT_NO_EXCEPTION);
 
1048
                else
 
1049
                    trackItem->classList()->add(selectedClassValue, ASSERT_NO_EXCEPTION);
 
1050
            } else {
 
1051
                TextTrack* track = trackList->item(trackIndex);
 
1052
                if (!track)
 
1053
                    continue;
 
1054
                if (track->mode() == TextTrack::showingKeyword())
 
1055
                    trackItem->classList()->add(selectedClassValue, ASSERT_NO_EXCEPTION);
 
1056
                else
 
1057
                    trackItem->classList()->remove(selectedClassValue, ASSERT_NO_EXCEPTION);
 
1058
            }
 
1059
        }
 
1060
    }
 
1061
#endif
 
1062
}
 
1063
 
 
1064
void MediaControlClosedCaptionsTrackListElement::resetTrackListMenu()
 
1065
{
 
1066
#if ENABLE(VIDEO_TRACK)
 
1067
    // Remove any existing content.
 
1068
    removeChildren();
 
1069
    menuItems.clear();
 
1070
 
 
1071
    if (!mediaController()->hasClosedCaptions())
 
1072
        return;
 
1073
 
 
1074
    HTMLMediaElement* mediaElement = toParentMediaElement(this);
 
1075
    if (!mediaElement)
 
1076
        return;
 
1077
 
 
1078
    TextTrackList* trackList = mediaElement->textTracks();
 
1079
 
 
1080
    if (!trackList || !trackList->length())
 
1081
        return;
 
1082
 
 
1083
    Document* doc = document();
 
1084
 
 
1085
    RefPtr<Element> captionsSection = doc->createElement(sectionTag, ASSERT_NO_EXCEPTION);
 
1086
    RefPtr<Element> captionsHeader = doc->createElement(h3Tag, ASSERT_NO_EXCEPTION);
 
1087
    captionsHeader->appendChild(doc->createTextNode("Closed Captions"));
 
1088
    captionsSection->appendChild(captionsHeader);
 
1089
    RefPtr<Element> captionsList = doc->createElement(ulTag, ASSERT_NO_EXCEPTION);
 
1090
 
 
1091
    RefPtr<Element> subtitlesSection = doc->createElement(sectionTag, ASSERT_NO_EXCEPTION);
 
1092
    RefPtr<Element> subtitlesHeader = doc->createElement(h3Tag, ASSERT_NO_EXCEPTION);
 
1093
    subtitlesHeader->appendChild(doc->createTextNode("Subtitles"));
 
1094
    subtitlesSection->appendChild(subtitlesHeader);
 
1095
    RefPtr<Element> subtitlesList = doc->createElement(ulTag, ASSERT_NO_EXCEPTION);
 
1096
 
 
1097
    RefPtr<Element> trackItem;
 
1098
 
 
1099
    trackItem = doc->createElement(liTag, ASSERT_NO_EXCEPTION);
 
1100
    trackItem->appendChild(doc->createTextNode("Off"));
 
1101
    trackItem->setAttribute(trackIndexAttributeName(), textTracksOffAttrValue, ASSERT_NO_EXCEPTION);
 
1102
    captionsList->appendChild(trackItem);
 
1103
    menuItems.append(trackItem);
 
1104
 
 
1105
    trackItem = doc->createElement(liTag, ASSERT_NO_EXCEPTION);
 
1106
    trackItem->appendChild(doc->createTextNode("Off"));
 
1107
    trackItem->setAttribute(trackIndexAttributeName(), textTracksOffAttrValue, ASSERT_NO_EXCEPTION);
 
1108
    subtitlesList->appendChild(trackItem);
 
1109
    menuItems.append(trackItem);
 
1110
 
 
1111
    bool hasCaptions = false;
 
1112
    bool hasSubtitles = false;
 
1113
 
 
1114
    for (unsigned i = 0, length = trackList->length(); i < length; ++i) {
 
1115
        TextTrack* track = trackList->item(i);
 
1116
        trackItem = doc->createElement(liTag, ASSERT_NO_EXCEPTION);
 
1117
 
 
1118
        // Add a custom attribute to the <li> element which will allow
 
1119
        // us to easily associate the user tapping here with the
 
1120
        // track. Since this list is rebuilt if the tracks change, we
 
1121
        // should always be in sync.
 
1122
        trackItem->setAttribute(trackIndexAttributeName(), String::number(i), ASSERT_NO_EXCEPTION);
 
1123
 
 
1124
        AtomicString labelText = track->label();
 
1125
        if (labelText.isNull() || labelText.isEmpty())
 
1126
            labelText = displayNameForLanguageLocale(track->language());
 
1127
        if (labelText.isNull() || labelText.isEmpty())
 
1128
            labelText = "No Label";
 
1129
 
 
1130
        if (track->kind() == track->captionsKeyword()) {
 
1131
            hasCaptions = true;
 
1132
            captionsList->appendChild(trackItem);
 
1133
        }
 
1134
        if (track->kind() == track->subtitlesKeyword()) {
 
1135
            hasSubtitles = true;
 
1136
            subtitlesList->appendChild(trackItem);
 
1137
        }
 
1138
        trackItem->appendChild(doc->createTextNode(labelText));
 
1139
        menuItems.append(trackItem);
 
1140
    }
 
1141
 
 
1142
    captionsSection->appendChild(captionsList);
 
1143
    subtitlesSection->appendChild(subtitlesList);
 
1144
 
 
1145
    if (hasCaptions)
 
1146
        appendChild(captionsSection);
 
1147
    if (hasSubtitles)
 
1148
        appendChild(subtitlesSection);
 
1149
 
 
1150
    updateDisplay();
 
1151
#endif
 
1152
}
 
1153
 
 
1154
// ----------------------------
 
1155
 
 
1156
MediaControlTimelineElement::MediaControlTimelineElement(Document* document, MediaControls* controls)
 
1157
    : MediaControlInputElement(document, MediaSlider)
 
1158
    , m_controls(controls)
 
1159
{
 
1160
}
 
1161
 
 
1162
PassRefPtr<MediaControlTimelineElement> MediaControlTimelineElement::create(Document* document, MediaControls* controls)
 
1163
{
 
1164
    ASSERT(controls);
 
1165
 
 
1166
    RefPtr<MediaControlTimelineElement> timeline = adoptRef(new MediaControlTimelineElement(document, controls));
 
1167
    timeline->createShadowSubtree();
 
1168
    timeline->setType("range");
 
1169
    timeline->setAttribute(precisionAttr, "float");
 
1170
    return timeline.release();
 
1171
}
 
1172
 
 
1173
void MediaControlTimelineElement::defaultEventHandler(Event* event)
 
1174
{
 
1175
    // Left button is 0. Rejects mouse events not from left button.
 
1176
    if (event->isMouseEvent() && static_cast<MouseEvent*>(event)->button())
 
1177
        return;
 
1178
 
 
1179
    if (!attached())
 
1180
        return;
 
1181
 
 
1182
    if (event->type() == eventNames().mousedownEvent)
 
1183
        mediaController()->beginScrubbing();
 
1184
 
 
1185
    if (event->type() == eventNames().mouseupEvent)
 
1186
        mediaController()->endScrubbing();
 
1187
 
 
1188
    MediaControlInputElement::defaultEventHandler(event);
 
1189
 
 
1190
    if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent)
 
1191
        return;
 
1192
 
 
1193
    float time = narrowPrecisionToFloat(value().toDouble());
 
1194
    if (event->type() == eventNames().inputEvent && time != mediaController()->currentTime()) {
 
1195
        ExceptionCode ec;
 
1196
        mediaController()->setCurrentTime(time, ec);
 
1197
    }
 
1198
 
 
1199
    RenderSlider* slider = toRenderSlider(renderer());
 
1200
    if (slider && slider->inDragMode())
 
1201
        m_controls->updateCurrentTimeDisplay();
 
1202
}
 
1203
 
 
1204
bool MediaControlTimelineElement::willRespondToMouseClickEvents()
 
1205
{
 
1206
    if (!attached())
 
1207
        return false;
 
1208
 
 
1209
    return true;
 
1210
}
 
1211
 
 
1212
void MediaControlTimelineElement::setPosition(float currentTime)
 
1213
{
 
1214
    setValue(String::number(currentTime));
 
1215
}
 
1216
 
 
1217
void MediaControlTimelineElement::setDuration(float duration)
 
1218
{
 
1219
    setAttribute(maxAttr, String::number(isfinite(duration) ? duration : 0));
 
1220
}
 
1221
 
 
1222
 
 
1223
const AtomicString& MediaControlTimelineElement::shadowPseudoId() const
 
1224
{
 
1225
    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-timeline", AtomicString::ConstructFromLiteral));
 
1226
    return id;
 
1227
}
 
1228
 
 
1229
// ----------------------------
 
1230
 
 
1231
inline MediaControlVolumeSliderElement::MediaControlVolumeSliderElement(Document* document)
 
1232
    : MediaControlInputElement(document, MediaVolumeSlider)
 
1233
    , m_clearMutedOnUserInteraction(false)
 
1234
{
 
1235
}
 
1236
 
 
1237
PassRefPtr<MediaControlVolumeSliderElement> MediaControlVolumeSliderElement::create(Document* document)
 
1238
{
 
1239
    RefPtr<MediaControlVolumeSliderElement> slider = adoptRef(new MediaControlVolumeSliderElement(document));
 
1240
    slider->createShadowSubtree();
 
1241
    slider->setType("range");
 
1242
    slider->setAttribute(precisionAttr, "float");
 
1243
    slider->setAttribute(maxAttr, "1");
 
1244
    return slider.release();
 
1245
}
 
1246
 
 
1247
void MediaControlVolumeSliderElement::defaultEventHandler(Event* event)
 
1248
{
 
1249
    // Left button is 0. Rejects mouse events not from left button.
 
1250
    if (event->isMouseEvent() && static_cast<MouseEvent*>(event)->button())
 
1251
        return;
 
1252
 
 
1253
    if (!attached())
 
1254
        return;
 
1255
 
 
1256
    MediaControlInputElement::defaultEventHandler(event);
 
1257
 
 
1258
    if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent)
 
1259
        return;
 
1260
 
 
1261
    float volume = narrowPrecisionToFloat(value().toDouble());
 
1262
    if (volume != mediaController()->volume()) {
 
1263
        ExceptionCode ec = 0;
 
1264
        mediaController()->setVolume(volume, ec);
 
1265
        ASSERT(!ec);
 
1266
    }
 
1267
    if (m_clearMutedOnUserInteraction)
 
1268
        mediaController()->setMuted(false);
 
1269
}
 
1270
 
 
1271
bool MediaControlVolumeSliderElement::willRespondToMouseMoveEvents()
 
1272
{
 
1273
    if (!attached())
 
1274
        return false;
 
1275
 
 
1276
    return MediaControlInputElement::willRespondToMouseMoveEvents();
 
1277
}
 
1278
 
 
1279
bool MediaControlVolumeSliderElement::willRespondToMouseClickEvents()
 
1280
{
 
1281
    if (!attached())
 
1282
        return false;
 
1283
 
 
1284
    return MediaControlInputElement::willRespondToMouseClickEvents();
 
1285
}
 
1286
 
 
1287
void MediaControlVolumeSliderElement::setVolume(float volume)
 
1288
{
 
1289
    if (value().toFloat() != volume)
 
1290
        setValue(String::number(volume));
 
1291
}
 
1292
 
 
1293
void MediaControlVolumeSliderElement::setClearMutedOnUserInteraction(bool clearMute)
 
1294
{
 
1295
    m_clearMutedOnUserInteraction = clearMute;
 
1296
}
 
1297
 
 
1298
const AtomicString& MediaControlVolumeSliderElement::shadowPseudoId() const
 
1299
{
 
1300
    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-volume-slider", AtomicString::ConstructFromLiteral));
 
1301
    return id;
 
1302
}
 
1303
 
 
1304
// ----------------------------
 
1305
 
 
1306
inline MediaControlFullscreenVolumeSliderElement::MediaControlFullscreenVolumeSliderElement(Document* document)
 
1307
    : MediaControlVolumeSliderElement(document)
 
1308
{
 
1309
}
 
1310
 
 
1311
PassRefPtr<MediaControlFullscreenVolumeSliderElement> MediaControlFullscreenVolumeSliderElement::create(Document* document)
 
1312
{
 
1313
    RefPtr<MediaControlFullscreenVolumeSliderElement> slider = adoptRef(new MediaControlFullscreenVolumeSliderElement(document));
 
1314
    slider->createShadowSubtree();
 
1315
    slider->setType("range");
 
1316
    slider->setAttribute(precisionAttr, "float");
 
1317
    slider->setAttribute(maxAttr, "1");
 
1318
    return slider.release();
 
1319
}
 
1320
 
 
1321
const AtomicString& MediaControlFullscreenVolumeSliderElement::shadowPseudoId() const
 
1322
{
 
1323
    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-volume-slider", AtomicString::ConstructFromLiteral));
 
1324
    return id;
 
1325
}
 
1326
 
 
1327
// ----------------------------
 
1328
 
 
1329
inline MediaControlFullscreenButtonElement::MediaControlFullscreenButtonElement(Document* document, MediaControls*)
 
1330
    : MediaControlInputElement(document, MediaEnterFullscreenButton)
 
1331
{
 
1332
}
 
1333
 
 
1334
PassRefPtr<MediaControlFullscreenButtonElement> MediaControlFullscreenButtonElement::create(Document* document, MediaControls* controls)
 
1335
{
 
1336
    ASSERT(controls);
 
1337
 
 
1338
    RefPtr<MediaControlFullscreenButtonElement> button = adoptRef(new MediaControlFullscreenButtonElement(document, controls));
 
1339
    button->createShadowSubtree();
 
1340
    button->setType("button");
 
1341
    button->hide();
 
1342
    return button.release();
 
1343
}
 
1344
 
 
1345
void MediaControlFullscreenButtonElement::defaultEventHandler(Event* event)
 
1346
{
 
1347
    if (event->type() == eventNames().clickEvent) {
 
1348
#if ENABLE(FULLSCREEN_API)
 
1349
        // Only use the new full screen API if the fullScreenEnabled setting has 
 
1350
        // been explicitly enabled. Otherwise, use the old fullscreen API. This
 
1351
        // allows apps which embed a WebView to retain the existing full screen
 
1352
        // video implementation without requiring them to implement their own full 
 
1353
        // screen behavior.
 
1354
        if (document()->settings() && document()->settings()->fullScreenEnabled()) {
 
1355
            if (document()->webkitIsFullScreen() && document()->webkitCurrentFullScreenElement() == toParentMediaElement(this))
 
1356
                document()->webkitCancelFullScreen();
 
1357
            else
 
1358
                document()->requestFullScreenForElement(toParentMediaElement(this), 0, Document::ExemptIFrameAllowFullScreenRequirement);
 
1359
        } else
 
1360
#endif
 
1361
            mediaController()->enterFullscreen();
 
1362
        event->setDefaultHandled();
 
1363
    }
 
1364
    HTMLInputElement::defaultEventHandler(event);
 
1365
}
 
1366
 
 
1367
const AtomicString& MediaControlFullscreenButtonElement::shadowPseudoId() const
 
1368
{
 
1369
    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-button", AtomicString::ConstructFromLiteral));
 
1370
    return id;
 
1371
}
 
1372
 
 
1373
void MediaControlFullscreenButtonElement::setIsFullscreen(bool isFullscreen)
 
1374
{
 
1375
    setDisplayType(isFullscreen ? MediaExitFullscreenButton : MediaEnterFullscreenButton);
 
1376
}
 
1377
 
 
1378
// ----------------------------
 
1379
 
 
1380
inline MediaControlFullscreenVolumeMinButtonElement::MediaControlFullscreenVolumeMinButtonElement(Document* document)
 
1381
    : MediaControlInputElement(document, MediaUnMuteButton)
 
1382
{
 
1383
}
 
1384
 
 
1385
PassRefPtr<MediaControlFullscreenVolumeMinButtonElement> MediaControlFullscreenVolumeMinButtonElement::create(Document* document)
 
1386
{
 
1387
    RefPtr<MediaControlFullscreenVolumeMinButtonElement> button = adoptRef(new MediaControlFullscreenVolumeMinButtonElement(document));
 
1388
    button->createShadowSubtree();
 
1389
    button->setType("button");
 
1390
    return button.release();
 
1391
}
 
1392
 
 
1393
void MediaControlFullscreenVolumeMinButtonElement::defaultEventHandler(Event* event)
 
1394
{
 
1395
    if (event->type() == eventNames().clickEvent) {
 
1396
        ExceptionCode code = 0;
 
1397
        mediaController()->setVolume(0, code);
 
1398
        event->setDefaultHandled();
 
1399
    }
 
1400
    HTMLInputElement::defaultEventHandler(event);
 
1401
}
 
1402
 
 
1403
const AtomicString& MediaControlFullscreenVolumeMinButtonElement::shadowPseudoId() const
 
1404
{
 
1405
    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-volume-min-button", AtomicString::ConstructFromLiteral));
 
1406
    return id;
 
1407
}
 
1408
 
 
1409
// ----------------------------
 
1410
 
 
1411
inline MediaControlFullscreenVolumeMaxButtonElement::MediaControlFullscreenVolumeMaxButtonElement(Document* document)
 
1412
: MediaControlInputElement(document, MediaMuteButton)
 
1413
{
 
1414
}
 
1415
 
 
1416
PassRefPtr<MediaControlFullscreenVolumeMaxButtonElement> MediaControlFullscreenVolumeMaxButtonElement::create(Document* document)
 
1417
{
 
1418
    RefPtr<MediaControlFullscreenVolumeMaxButtonElement> button = adoptRef(new MediaControlFullscreenVolumeMaxButtonElement(document));
 
1419
    button->createShadowSubtree();
 
1420
    button->setType("button");
 
1421
    return button.release();
 
1422
}
 
1423
 
 
1424
void MediaControlFullscreenVolumeMaxButtonElement::defaultEventHandler(Event* event)
 
1425
{
 
1426
    if (event->type() == eventNames().clickEvent) {
 
1427
        ExceptionCode code = 0;
 
1428
        mediaController()->setVolume(1, code);
 
1429
        event->setDefaultHandled();
 
1430
    }
 
1431
    HTMLInputElement::defaultEventHandler(event);
 
1432
}
 
1433
 
 
1434
const AtomicString& MediaControlFullscreenVolumeMaxButtonElement::shadowPseudoId() const
 
1435
{
 
1436
    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-volume-max-button", AtomicString::ConstructFromLiteral));
 
1437
    return id;
 
1438
}
 
1439
 
 
1440
// ----------------------------
 
1441
 
 
1442
class RenderMediaControlTimeDisplay : public RenderDeprecatedFlexibleBox {
 
1443
public:
 
1444
    RenderMediaControlTimeDisplay(Node*);
 
1445
 
 
1446
private:
 
1447
    virtual void layout();
 
1448
};
 
1449
 
 
1450
RenderMediaControlTimeDisplay::RenderMediaControlTimeDisplay(Node* node)
 
1451
    : RenderDeprecatedFlexibleBox(node)
 
1452
{
 
1453
}
 
1454
 
 
1455
// We want the timeline slider to be at least 100 pixels wide.
 
1456
// FIXME: Eliminate hard-coded widths altogether.
 
1457
static const int minWidthToDisplayTimeDisplays = 45 + 100 + 45;
 
1458
 
 
1459
void RenderMediaControlTimeDisplay::layout()
 
1460
{
 
1461
    RenderDeprecatedFlexibleBox::layout();
 
1462
    RenderBox* timelineContainerBox = parentBox();
 
1463
    while (timelineContainerBox && timelineContainerBox->isAnonymous())
 
1464
        timelineContainerBox = timelineContainerBox->parentBox();
 
1465
 
 
1466
    if (timelineContainerBox && timelineContainerBox->width() < minWidthToDisplayTimeDisplays)
 
1467
        setWidth(0);
 
1468
}
 
1469
 
 
1470
inline MediaControlTimeDisplayElement::MediaControlTimeDisplayElement(Document* document)
 
1471
    : MediaControlElement(document)
 
1472
    , m_currentValue(0)
 
1473
{
 
1474
}
 
1475
 
 
1476
void MediaControlTimeDisplayElement::setCurrentValue(float time)
 
1477
{
 
1478
    m_currentValue = time;
 
1479
}
 
1480
 
 
1481
RenderObject* MediaControlTimeDisplayElement::createRenderer(RenderArena* arena, RenderStyle*)
 
1482
{
 
1483
    return new (arena) RenderMediaControlTimeDisplay(this);
 
1484
}
 
1485
 
 
1486
// ----------------------------
 
1487
 
 
1488
PassRefPtr<MediaControlTimeRemainingDisplayElement> MediaControlTimeRemainingDisplayElement::create(Document* document)
 
1489
{
 
1490
    return adoptRef(new MediaControlTimeRemainingDisplayElement(document));
 
1491
}
 
1492
 
 
1493
MediaControlTimeRemainingDisplayElement::MediaControlTimeRemainingDisplayElement(Document* document)
 
1494
    : MediaControlTimeDisplayElement(document)
 
1495
{
 
1496
}
 
1497
 
 
1498
MediaControlElementType MediaControlTimeRemainingDisplayElement::displayType() const
 
1499
{
 
1500
    return MediaTimeRemainingDisplay;
 
1501
}
 
1502
 
 
1503
const AtomicString& MediaControlTimeRemainingDisplayElement::shadowPseudoId() const
 
1504
{
 
1505
    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-time-remaining-display", AtomicString::ConstructFromLiteral));
 
1506
    return id;
 
1507
}
 
1508
 
 
1509
// ----------------------------
 
1510
 
 
1511
PassRefPtr<MediaControlCurrentTimeDisplayElement> MediaControlCurrentTimeDisplayElement::create(Document* document)
 
1512
{
 
1513
    return adoptRef(new MediaControlCurrentTimeDisplayElement(document));
 
1514
}
 
1515
 
 
1516
MediaControlCurrentTimeDisplayElement::MediaControlCurrentTimeDisplayElement(Document* document)
 
1517
    : MediaControlTimeDisplayElement(document)
 
1518
{
 
1519
}
 
1520
 
 
1521
MediaControlElementType MediaControlCurrentTimeDisplayElement::displayType() const
 
1522
{
 
1523
    return MediaCurrentTimeDisplay;
 
1524
}
 
1525
 
 
1526
const AtomicString& MediaControlCurrentTimeDisplayElement::shadowPseudoId() const
 
1527
{
 
1528
    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-current-time-display", AtomicString::ConstructFromLiteral));
 
1529
    return id;
 
1530
}
 
1531
 
 
1532
// ----------------------------
 
1533
 
 
1534
#if ENABLE(VIDEO_TRACK)
 
1535
 
 
1536
class RenderTextTrackContainerElement : public RenderBlock {
 
1537
public:
 
1538
    RenderTextTrackContainerElement(Node*);
 
1539
 
 
1540
private:
 
1541
    virtual void layout();
 
1542
};
 
1543
 
 
1544
RenderTextTrackContainerElement::RenderTextTrackContainerElement(Node* node)
 
1545
    : RenderBlock(node)
 
1546
{
 
1547
}
 
1548
 
 
1549
void RenderTextTrackContainerElement::layout()
 
1550
{
 
1551
    RenderBlock::layout();
 
1552
    if (style()->display() == NONE)
 
1553
        return;
 
1554
 
 
1555
    ASSERT(mediaControlElementType(node()) == MediaTextTrackDisplayContainer);
 
1556
 
 
1557
    LayoutStateDisabler layoutStateDisabler(view());
 
1558
    static_cast<MediaControlTextTrackContainerElement*>(node())->updateSizes();
 
1559
}
 
1560
 
 
1561
inline MediaControlTextTrackContainerElement::MediaControlTextTrackContainerElement(Document* document)
 
1562
    : MediaControlElement(document)
 
1563
    , m_fontSize(0)
 
1564
{
 
1565
}
 
1566
 
 
1567
PassRefPtr<MediaControlTextTrackContainerElement> MediaControlTextTrackContainerElement::create(Document* document)
 
1568
{
 
1569
    RefPtr<MediaControlTextTrackContainerElement> element = adoptRef(new MediaControlTextTrackContainerElement(document));
 
1570
    element->hide();
 
1571
    return element.release();
 
1572
}
 
1573
 
 
1574
RenderObject* MediaControlTextTrackContainerElement::createRenderer(RenderArena* arena, RenderStyle*)
 
1575
{
 
1576
    return new (arena) RenderTextTrackContainerElement(this);
 
1577
}
 
1578
 
 
1579
const AtomicString& MediaControlTextTrackContainerElement::shadowPseudoId() const
 
1580
{
 
1581
    DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-text-track-container", AtomicString::ConstructFromLiteral));
 
1582
    return id;
 
1583
}
 
1584
 
 
1585
void MediaControlTextTrackContainerElement::updateDisplay()
 
1586
{
 
1587
    HTMLMediaElement* mediaElement = toParentMediaElement(this);
 
1588
 
 
1589
    // 1. If the media element is an audio element, or is another playback
 
1590
    // mechanism with no rendering area, abort these steps. There is nothing to
 
1591
    // render.
 
1592
    if (!mediaElement->isVideo())
 
1593
        return;
 
1594
 
 
1595
    // 2. Let video be the media element or other playback mechanism.
 
1596
    HTMLVideoElement* video = static_cast<HTMLVideoElement*>(mediaElement);
 
1597
 
 
1598
    // 3. Let output be an empty list of absolutely positioned CSS block boxes.
 
1599
    Vector<RefPtr<HTMLDivElement> > output;
 
1600
 
 
1601
    // 4. If the user agent is exposing a user interface for video, add to
 
1602
    // output one or more completely transparent positioned CSS block boxes that
 
1603
    // cover the same region as the user interface.
 
1604
 
 
1605
    // 5. If the last time these rules were run, the user agent was not exposing
 
1606
    // a user interface for video, but now it is, let reset be true. Otherwise,
 
1607
    // let reset be false.
 
1608
 
 
1609
    // There is nothing to be done explicitly for 4th and 5th steps, as
 
1610
    // everything is handled through CSS. The caption box is on top of the
 
1611
    // controls box, in a container set with the -webkit-box display property.
 
1612
 
 
1613
    // 6. Let tracks be the subset of video's list of text tracks that have as
 
1614
    // their rules for updating the text track rendering these rules for
 
1615
    // updating the display of WebVTT text tracks, and whose text track mode is
 
1616
    // showing or showing by default.
 
1617
    // 7. Let cues be an empty list of text track cues.
 
1618
    // 8. For each track track in tracks, append to cues all the cues from
 
1619
    // track's list of cues that have their text track cue active flag set.
 
1620
    CueList activeCues = video->currentlyActiveCues();
 
1621
 
 
1622
    // 9. If reset is false, then, for each text track cue cue in cues: if cue's
 
1623
    // text track cue display state has a set of CSS boxes, then add those boxes
 
1624
    // to output, and remove cue from cues.
 
1625
 
 
1626
    // There is nothing explicitly to be done here, as all the caching occurs
 
1627
    // within the TextTrackCue instance itself. If parameters of the cue change,
 
1628
    // the display tree is cleared.
 
1629
 
 
1630
    // 10. For each text track cue cue in cues that has not yet had
 
1631
    // corresponding CSS boxes added to output, in text track cue order, run the
 
1632
    // following substeps:
 
1633
    for (size_t i = 0; i < activeCues.size(); ++i) {
 
1634
        TextTrackCue* cue = activeCues[i].data();
 
1635
 
 
1636
        ASSERT(cue->isActive());
 
1637
        if (!cue->track() || !cue->track()->isRendered())
 
1638
            continue;
 
1639
 
 
1640
        RefPtr<TextTrackCueBox> displayBox = cue->getDisplayTree();
 
1641
 
 
1642
        if (displayBox->hasChildNodes() && !contains(static_cast<Node*>(displayBox.get())))
 
1643
            // Note: the display tree of a cue is removed when the active flag of the cue is unset.
 
1644
            appendChild(displayBox, ASSERT_NO_EXCEPTION, false);
 
1645
    }
 
1646
 
 
1647
    // 11. Return output.
 
1648
    hasChildNodes() ? show() : hide();
 
1649
}
 
1650
 
 
1651
void MediaControlTextTrackContainerElement::updateSizes()
 
1652
{
 
1653
    HTMLMediaElement* mediaElement = toParentMediaElement(this);
 
1654
    if (!mediaElement || !mediaElement->renderer() || !mediaElement->renderer()->isVideo())
 
1655
        return;
 
1656
 
 
1657
    if (!document()->page())
 
1658
        return;
 
1659
 
 
1660
    IntRect videoBox = toRenderVideo(mediaElement->renderer())->videoBox();
 
1661
 
 
1662
    float fontSize = videoBox.size().height() * (document()->page()->group().captionFontSizeScale());
 
1663
    if (fontSize != m_fontSize) {
 
1664
        m_fontSize = fontSize;
 
1665
        setInlineStyleProperty(CSSPropertyFontSize, String::number(fontSize) + "px");
 
1666
    }
 
1667
}
 
1668
 
 
1669
#endif // ENABLE(VIDEO_TRACK)
 
1670
 
 
1671
// ----------------------------
 
1672
 
 
1673
} // namespace WebCore
 
1674
 
 
1675
#endif // ENABLE(VIDEO)