1 /* 2 * Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013 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 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #ifndef HTMLMediaElement_h 27 #define HTMLMediaElement_h 28 29 #include "core/dom/ActiveDOMObject.h" 30 #include "core/events/GenericEventQueue.h" 31 #include "core/html/HTMLElement.h" 32 #include "core/html/MediaControllerInterface.h" 33 #include "core/html/track/TextTrack.h" 34 #include "core/html/track/TextTrackCue.h" 35 #include "core/html/track/vtt/VTTCue.h" 36 #include "platform/PODIntervalTree.h" 37 #include "platform/graphics/media/MediaPlayer.h" 38 #include "public/platform/WebMimeRegistry.h" 39 40 namespace blink { 41 class WebInbandTextTrack; 42 class WebLayer; 43 } 44 45 namespace WebCore { 46 47 #if ENABLE(WEB_AUDIO) 48 class AudioSourceProvider; 49 class MediaElementAudioSourceNode; 50 #endif 51 class ContentType; 52 class Event; 53 class ExceptionState; 54 class HTMLSourceElement; 55 class HTMLTrackElement; 56 class KURL; 57 class MediaController; 58 class MediaControls; 59 class MediaError; 60 class MediaKeys; 61 class HTMLMediaSource; 62 class TextTrackList; 63 class TimeRanges; 64 65 typedef PODIntervalTree<double, TextTrackCue*> CueIntervalTree; 66 typedef CueIntervalTree::IntervalType CueInterval; 67 typedef Vector<CueInterval> CueList; 68 69 // FIXME: The inheritance from MediaPlayerClient here should be private inheritance. 70 // But it can't be until the Chromium WebMediaPlayerClientImpl class is fixed so it 71 // no longer depends on typecasting a MediaPlayerClient to an HTMLMediaElement. 72 73 class HTMLMediaElement : public HTMLElement, public MediaPlayerClient, public ActiveDOMObject, public MediaControllerInterface 74 , private TextTrackClient 75 { 76 public: 77 static blink::WebMimeRegistry::SupportsType supportsType(const ContentType&, const String& keySystem = String()); 78 79 MediaPlayer* player() const { return m_player.get(); } 80 81 virtual bool isVideo() const = 0; 82 virtual bool hasVideo() const OVERRIDE { return false; } 83 virtual bool hasAudio() const OVERRIDE; 84 85 // Eventually overloaded in HTMLVideoElement 86 virtual bool supportsFullscreen() const OVERRIDE { return false; }; 87 88 bool supportsSave() const; 89 90 blink::WebLayer* platformLayer() const; 91 92 enum DelayedActionType { 93 LoadMediaResource = 1 << 0, 94 LoadTextTrackResource = 1 << 1, 95 TextTrackChangesNotification = 1 << 2 96 }; 97 void scheduleDelayedAction(DelayedActionType); 98 99 bool isActive() const { return m_active; } 100 101 // error state 102 PassRefPtr<MediaError> error() const; 103 104 // network state 105 void setSrc(const AtomicString&); 106 const KURL& currentSrc() const { return m_currentSrc; } 107 108 enum NetworkState { NETWORK_EMPTY, NETWORK_IDLE, NETWORK_LOADING, NETWORK_NO_SOURCE }; 109 NetworkState networkState() const; 110 111 String preload() const; 112 void setPreload(const String&); 113 114 PassRefPtr<TimeRanges> buffered() const; 115 void load(); 116 String canPlayType(const String& mimeType, const String& keySystem = String(), const KURL& = KURL()) const; 117 118 // ready state 119 ReadyState readyState() const; 120 bool seeking() const; 121 122 // playback state 123 double currentTime() const; 124 void setCurrentTime(double, ExceptionState&); 125 double duration() const; 126 bool paused() const; 127 double defaultPlaybackRate() const; 128 void setDefaultPlaybackRate(double); 129 double playbackRate() const; 130 void setPlaybackRate(double); 131 void updatePlaybackRate(); 132 PassRefPtr<TimeRanges> played(); 133 PassRefPtr<TimeRanges> seekable() const; 134 bool ended() const; 135 bool autoplay() const; 136 bool loop() const; 137 void setLoop(bool b); 138 void play(); 139 void pause(); 140 141 // statistics 142 unsigned webkitAudioDecodedByteCount() const; 143 unsigned webkitVideoDecodedByteCount() const; 144 145 // media source extensions 146 void closeMediaSource(); 147 void durationChanged(double duration); 148 149 // encrypted media extensions 150 void webkitGenerateKeyRequest(const String& keySystem, PassRefPtr<Uint8Array> initData, ExceptionState&); 151 void webkitGenerateKeyRequest(const String& keySystem, ExceptionState&); 152 void webkitAddKey(const String& keySystem, PassRefPtr<Uint8Array> key, PassRefPtr<Uint8Array> initData, const String& sessionId, ExceptionState&); 153 void webkitAddKey(const String& keySystem, PassRefPtr<Uint8Array> key, ExceptionState&); 154 void webkitCancelKeyRequest(const String& keySystem, const String& sessionId, ExceptionState&); 155 156 DEFINE_ATTRIBUTE_EVENT_LISTENER(webkitkeyadded); 157 DEFINE_ATTRIBUTE_EVENT_LISTENER(webkitkeyerror); 158 DEFINE_ATTRIBUTE_EVENT_LISTENER(webkitkeymessage); 159 DEFINE_ATTRIBUTE_EVENT_LISTENER(webkitneedkey); 160 161 MediaKeys* mediaKeys() const { return m_mediaKeys.get(); } 162 void setMediaKeys(MediaKeys*); 163 164 // controls 165 bool controls() const; 166 void setControls(bool); 167 double volume() const; 168 void setVolume(double, ExceptionState&); 169 bool muted() const; 170 void setMuted(bool); 171 172 void togglePlayState(); 173 void beginScrubbing(); 174 void endScrubbing(); 175 176 bool canPlay() const; 177 178 double percentLoaded() const; 179 180 PassRefPtr<TextTrack> addTextTrack(const String& kind, const String& label, const String& language, ExceptionState&); 181 PassRefPtr<TextTrack> addTextTrack(const String& kind, const String& label, ExceptionState& exceptionState) { return addTextTrack(kind, label, emptyString(), exceptionState); } 182 PassRefPtr<TextTrack> addTextTrack(const String& kind, ExceptionState& exceptionState) { return addTextTrack(kind, emptyString(), emptyString(), exceptionState); } 183 184 TextTrackList* textTracks(); 185 CueList currentlyActiveCues() const { return m_currentlyActiveCues; } 186 187 void addTrack(TextTrack*); 188 void removeTrack(TextTrack*); 189 void removeAllInbandTracks(); 190 void closeCaptionTracksChanged(); 191 void notifyMediaPlayerOfTextTrackChanges(); 192 193 void didAddTrack(HTMLTrackElement*); 194 void didRemoveTrack(HTMLTrackElement*); 195 196 virtual void mediaPlayerDidAddTrack(blink::WebInbandTextTrack*) OVERRIDE; 197 virtual void mediaPlayerDidRemoveTrack(blink::WebInbandTextTrack*) OVERRIDE; 198 199 struct TrackGroup { 200 enum GroupKind { CaptionsAndSubtitles, Description, Chapter, Metadata, Other }; 201 202 TrackGroup(GroupKind kind) 203 : visibleTrack(0) 204 , defaultTrack(0) 205 , kind(kind) 206 , hasSrcLang(false) 207 { 208 } 209 210 Vector<RefPtr<TextTrack> > tracks; 211 RefPtr<TextTrack> visibleTrack; 212 RefPtr<TextTrack> defaultTrack; 213 GroupKind kind; 214 bool hasSrcLang; 215 }; 216 217 void configureTextTrackGroupForLanguage(const TrackGroup&) const; 218 void configureTextTracks(); 219 void configureTextTrackGroup(const TrackGroup&); 220 221 bool textTracksAreReady() const; 222 enum VisibilityChangeAssumption { 223 AssumeNoVisibleChange, 224 AssumeVisibleChange 225 }; 226 void configureTextTrackDisplay(VisibilityChangeAssumption); 227 void updateTextTrackDisplay(); 228 void textTrackReadyStateChanged(TextTrack*); 229 230 // TextTrackClient 231 virtual void textTrackKindChanged(TextTrack*) OVERRIDE; 232 virtual void textTrackModeChanged(TextTrack*) OVERRIDE; 233 virtual void textTrackAddCues(TextTrack*, const TextTrackCueList*) OVERRIDE; 234 virtual void textTrackRemoveCues(TextTrack*, const TextTrackCueList*) OVERRIDE; 235 virtual void textTrackAddCue(TextTrack*, PassRefPtr<TextTrackCue>) OVERRIDE; 236 virtual void textTrackRemoveCue(TextTrack*, PassRefPtr<TextTrackCue>) OVERRIDE; 237 238 // EventTarget function. 239 // Both Node (via HTMLElement) and ActiveDOMObject define this method, which 240 // causes an ambiguity error at compile time. This class's constructor 241 // ensures that both implementations return document, so return the result 242 // of one of them here. 243 virtual ExecutionContext* executionContext() const OVERRIDE { return HTMLElement::executionContext(); } 244 245 bool hasSingleSecurityOrigin() const { return !m_player || m_player->hasSingleSecurityOrigin(); } 246 247 bool isFullscreen() const; 248 void enterFullscreen(); 249 void exitFullscreen(); 250 251 bool hasClosedCaptions() const; 252 bool closedCaptionsVisible() const; 253 void setClosedCaptionsVisible(bool); 254 255 MediaControls* mediaControls() const; 256 257 void sourceWasRemoved(HTMLSourceElement*); 258 void sourceWasAdded(HTMLSourceElement*); 259 260 bool isPlaying() const { return m_playing; } 261 262 // ActiveDOMObject functions. 263 virtual bool hasPendingActivity() const OVERRIDE; 264 virtual void contextDestroyed() OVERRIDE; 265 266 #if ENABLE(WEB_AUDIO) 267 MediaElementAudioSourceNode* audioSourceNode() { return m_audioSourceNode; } 268 void setAudioSourceNode(MediaElementAudioSourceNode*); 269 270 AudioSourceProvider* audioSourceProvider(); 271 #endif 272 273 enum InvalidURLAction { DoNothing, Complain }; 274 bool isSafeToLoadURL(const KURL&, InvalidURLAction); 275 276 MediaController* controller() const; 277 void setController(PassRefPtr<MediaController>); // Resets the MediaGroup and sets the MediaController. 278 279 protected: 280 HTMLMediaElement(const QualifiedName&, Document&, bool); 281 virtual ~HTMLMediaElement(); 282 283 virtual void parseAttribute(const QualifiedName&, const AtomicString&) OVERRIDE; 284 virtual void finishParsingChildren() OVERRIDE; 285 virtual bool isURLAttribute(const Attribute&) const OVERRIDE; 286 virtual void attach(const AttachContext& = AttachContext()) OVERRIDE; 287 288 virtual void didMoveToNewDocument(Document& oldDocument) OVERRIDE; 289 290 enum DisplayMode { Unknown, None, Poster, PosterWaitingForVideo, Video }; 291 DisplayMode displayMode() const { return m_displayMode; } 292 virtual void setDisplayMode(DisplayMode mode) { m_displayMode = mode; } 293 294 virtual bool isMediaElement() const OVERRIDE { return true; } 295 296 void setControllerInternal(PassRefPtr<MediaController>); 297 298 // Restrictions to change default behaviors. 299 enum BehaviorRestrictionFlags { 300 NoRestrictions = 0, 301 RequireUserGestureForLoadRestriction = 1 << 0, 302 RequireUserGestureForRateChangeRestriction = 1 << 1, 303 RequireUserGestureForFullscreenRestriction = 1 << 2, 304 RequirePageConsentToLoadMediaRestriction = 1 << 3, 305 }; 306 typedef unsigned BehaviorRestrictions; 307 308 bool userGestureRequiredForLoad() const { return m_restrictions & RequireUserGestureForLoadRestriction; } 309 bool userGestureRequiredForRateChange() const { return m_restrictions & RequireUserGestureForRateChangeRestriction; } 310 bool userGestureRequiredForFullscreen() const { return m_restrictions & RequireUserGestureForFullscreenRestriction; } 311 bool pageConsentRequiredForLoad() const { return m_restrictions & RequirePageConsentToLoadMediaRestriction; } 312 313 void addBehaviorRestriction(BehaviorRestrictions restriction) { m_restrictions |= restriction; } 314 void removeBehaviorRestriction(BehaviorRestrictions restriction) { m_restrictions &= ~restriction; } 315 316 bool ignoreTrackDisplayUpdateRequests() const { return m_ignoreTrackDisplayUpdate > 0; } 317 void beginIgnoringTrackDisplayUpdateRequests(); 318 void endIgnoringTrackDisplayUpdateRequests(); 319 320 private: 321 void createMediaPlayer(); 322 323 virtual bool alwaysCreateUserAgentShadowRoot() const OVERRIDE { return true; } 324 virtual bool areAuthorShadowsAllowed() const OVERRIDE { return false; } 325 326 virtual bool hasCustomFocusLogic() const OVERRIDE; 327 virtual bool supportsFocus() const OVERRIDE; 328 virtual bool isMouseFocusable() const OVERRIDE; 329 virtual bool rendererIsNeeded(const RenderStyle&) OVERRIDE; 330 virtual RenderObject* createRenderer(RenderStyle*) OVERRIDE; 331 virtual bool childShouldCreateRenderer(const Node& child) const OVERRIDE; 332 virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE; 333 virtual void removedFrom(ContainerNode*) OVERRIDE; 334 virtual void didRecalcStyle(StyleRecalcChange) OVERRIDE; 335 336 virtual void didBecomeFullscreenElement() OVERRIDE; 337 virtual void willStopBeingFullscreenElement() OVERRIDE; 338 virtual bool isInteractiveContent() const OVERRIDE; 339 340 // ActiveDOMObject functions. 341 virtual void stop() OVERRIDE; 342 343 virtual void updateDisplayState() { } 344 345 void setReadyState(MediaPlayer::ReadyState); 346 void setNetworkState(MediaPlayer::NetworkState); 347 348 virtual void mediaPlayerNetworkStateChanged() OVERRIDE; 349 virtual void mediaPlayerReadyStateChanged() OVERRIDE; 350 virtual void mediaPlayerTimeChanged() OVERRIDE; 351 virtual void mediaPlayerDurationChanged() OVERRIDE; 352 virtual void mediaPlayerPlaybackStateChanged() OVERRIDE; 353 virtual void mediaPlayerRequestFullscreen() OVERRIDE; 354 virtual void mediaPlayerRequestSeek(double) OVERRIDE; 355 virtual void mediaPlayerRepaint() OVERRIDE; 356 virtual void mediaPlayerSizeChanged() OVERRIDE; 357 358 virtual void mediaPlayerKeyAdded(const String& keySystem, const String& sessionId) OVERRIDE; 359 virtual void mediaPlayerKeyError(const String& keySystem, const String& sessionId, MediaPlayerClient::MediaKeyErrorCode, unsigned short systemCode) OVERRIDE; 360 virtual void mediaPlayerKeyMessage(const String& keySystem, const String& sessionId, const unsigned char* message, unsigned messageLength, const KURL& defaultURL) OVERRIDE; 361 virtual bool mediaPlayerKeyNeeded(const String& keySystem, const String& sessionId, const unsigned char* initData, unsigned initDataLength) OVERRIDE; 362 virtual bool mediaPlayerKeyNeeded(Uint8Array*) OVERRIDE; 363 364 virtual CORSMode mediaPlayerCORSMode() const OVERRIDE; 365 366 virtual void mediaPlayerSetWebLayer(blink::WebLayer*) OVERRIDE; 367 virtual void mediaPlayerSetOpaque(bool) OVERRIDE; 368 369 void loadTimerFired(Timer<HTMLMediaElement>*); 370 void progressEventTimerFired(Timer<HTMLMediaElement>*); 371 void playbackProgressTimerFired(Timer<HTMLMediaElement>*); 372 void startPlaybackProgressTimer(); 373 void startProgressEventTimer(); 374 void stopPeriodicTimers(); 375 376 void seek(double time, ExceptionState&); 377 void finishSeek(); 378 void checkIfSeekNeeded(); 379 void addPlayedRange(double start, double end); 380 381 void scheduleTimeupdateEvent(bool periodicEvent); 382 void scheduleEvent(const AtomicString& eventName); 383 384 // loading 385 void selectMediaResource(); 386 void loadResource(const KURL&, ContentType&, const String& keySystem); 387 void scheduleNextSourceChild(); 388 void loadNextSourceChild(); 389 void userCancelledLoad(); 390 void clearMediaPlayer(int flags); 391 void clearMediaPlayerAndAudioSourceProviderClient(); 392 bool havePotentialSourceChild(); 393 void noneSupported(); 394 void mediaEngineError(PassRefPtr<MediaError> err); 395 void cancelPendingEventsAndCallbacks(); 396 void waitForSourceChange(); 397 void prepareToPlay(); 398 399 KURL selectNextSourceChild(ContentType*, String* keySystem, InvalidURLAction); 400 401 void mediaLoadingFailed(MediaPlayer::NetworkState); 402 403 void updateActiveTextTrackCues(double); 404 HTMLTrackElement* showingTrackWithSameKind(HTMLTrackElement*) const; 405 406 void markCaptionAndSubtitleTracksAsUnconfigured(); 407 408 // These "internal" functions do not check user gesture restrictions. 409 void loadInternal(); 410 void playInternal(); 411 void pauseInternal(); 412 413 void prepareForLoad(); 414 void allowVideoRendering(); 415 416 void updateVolume(); 417 void updatePlayState(); 418 bool potentiallyPlaying() const; 419 bool endedPlayback() const; 420 bool stoppedDueToErrors() const; 421 bool pausedForUserInteraction() const; 422 bool couldPlayIfEnoughData() const; 423 424 // Pauses playback without changing any states or generating events 425 void setPausedInternal(bool); 426 427 void setPlaybackRateInternal(double); 428 429 void setShouldDelayLoadEvent(bool); 430 void invalidateCachedTime(); 431 void refreshCachedTime() const; 432 433 bool hasMediaControls() const; 434 bool createMediaControls(); 435 void configureMediaControls(); 436 437 void prepareMediaFragmentURI(); 438 void applyMediaFragmentURI(); 439 440 virtual void* preDispatchEventHandler(Event*) OVERRIDE; 441 442 void changeNetworkStateFromLoadingToIdle(); 443 444 void removeBehaviorsRestrictionsAfterFirstUserGesture(); 445 446 const AtomicString& mediaGroup() const; 447 void setMediaGroup(const AtomicString&); 448 void updateMediaController(); 449 bool isBlocked() const; 450 bool isBlockedOnMediaController() const; 451 bool hasCurrentSrc() const { return !m_currentSrc.isEmpty(); } 452 bool isAutoplaying() const { return m_autoplaying; } 453 454 Timer<HTMLMediaElement> m_loadTimer; 455 Timer<HTMLMediaElement> m_progressEventTimer; 456 Timer<HTMLMediaElement> m_playbackProgressTimer; 457 RefPtr<TimeRanges> m_playedTimeRanges; 458 OwnPtr<GenericEventQueue> m_asyncEventQueue; 459 460 double m_playbackRate; 461 double m_defaultPlaybackRate; 462 NetworkState m_networkState; 463 ReadyState m_readyState; 464 ReadyState m_readyStateMaximum; 465 KURL m_currentSrc; 466 467 RefPtr<MediaError> m_error; 468 469 double m_volume; 470 double m_lastSeekTime; 471 472 unsigned m_previousProgress; 473 double m_previousProgressTime; 474 475 // Cached duration to suppress duplicate events if duration unchanged. 476 double m_duration; 477 478 // The last time a timeupdate event was sent (wall clock). 479 double m_lastTimeUpdateEventWallTime; 480 481 // The last time a timeupdate event was sent in movie time. 482 double m_lastTimeUpdateEventMovieTime; 483 484 // Loading state. 485 enum LoadState { WaitingForSource, LoadingFromSrcAttr, LoadingFromSourceElement }; 486 LoadState m_loadState; 487 RefPtr<HTMLSourceElement> m_currentSourceNode; 488 RefPtr<Node> m_nextChildNodeToConsider; 489 490 OwnPtr<MediaPlayer> m_player; 491 blink::WebLayer* m_webLayer; 492 bool m_opaque; 493 494 BehaviorRestrictions m_restrictions; 495 496 MediaPlayer::Preload m_preload; 497 498 DisplayMode m_displayMode; 499 500 RefPtr<HTMLMediaSource> m_mediaSource; 501 502 mutable double m_cachedTime; 503 mutable double m_cachedTimeWallClockUpdateTime; 504 mutable double m_minimumWallClockTimeToCacheMediaTime; 505 506 double m_fragmentStartTime; 507 double m_fragmentEndTime; 508 509 typedef unsigned PendingActionFlags; 510 PendingActionFlags m_pendingActionFlags; 511 512 // FIXME: MediaElement has way too many state bits. 513 bool m_playing : 1; 514 bool m_shouldDelayLoadEvent : 1; 515 bool m_haveFiredLoadedData : 1; 516 bool m_active : 1; 517 bool m_autoplaying : 1; 518 bool m_muted : 1; 519 bool m_paused : 1; 520 bool m_seeking : 1; 521 522 // data has not been loaded since sending a "stalled" event 523 bool m_sentStalledEvent : 1; 524 525 // time has not changed since sending an "ended" event 526 bool m_sentEndEvent : 1; 527 528 bool m_pausedInternal : 1; 529 530 bool m_closedCaptionsVisible : 1; 531 532 bool m_loadInitiatedByUserGesture : 1; 533 bool m_completelyLoaded : 1; 534 bool m_havePreparedToPlay : 1; 535 bool m_parsingInProgress : 1; 536 537 bool m_tracksAreReady : 1; 538 bool m_haveVisibleTextTrack : 1; 539 bool m_processingPreferenceChange : 1; 540 double m_lastTextTrackUpdateTime; 541 542 RefPtr<TextTrackList> m_textTracks; 543 Vector<RefPtr<TextTrack> > m_textTracksWhenResourceSelectionBegan; 544 545 CueIntervalTree m_cueTree; 546 547 CueList m_currentlyActiveCues; 548 int m_ignoreTrackDisplayUpdate; 549 550 #if ENABLE(WEB_AUDIO) 551 // This is a weak reference, since m_audioSourceNode holds a reference to us. 552 // The value is set just after the MediaElementAudioSourceNode is created. 553 // The value is cleared in MediaElementAudioSourceNode::~MediaElementAudioSourceNode(). 554 MediaElementAudioSourceNode* m_audioSourceNode; 555 #endif 556 557 friend class MediaController; 558 RefPtr<MediaController> m_mediaController; 559 560 friend class TrackDisplayUpdateScope; 561 562 RefPtr<MediaKeys> m_mediaKeys; 563 }; 564 565 #ifndef NDEBUG 566 // Template specializations required by PodIntervalTree in debug mode. 567 template <> 568 struct ValueToString<double> { 569 static String string(const double value) 570 { 571 return String::number(value); 572 } 573 }; 574 575 template <> 576 struct ValueToString<TextTrackCue*> { 577 static String string(TextTrackCue* const& cue) 578 { 579 return cue->toString(); 580 } 581 }; 582 #endif 583 584 inline bool isHTMLMediaElement(Node* node) 585 { 586 return node && node->isElementNode() && toElement(node)->isMediaElement(); 587 } 588 589 inline bool isHTMLMediaElement(const Node& node) 590 { 591 return node.isElementNode() && toElement(node).isMediaElement(); 592 } 593 594 DEFINE_NODE_TYPE_CASTS_WITH_FUNCTION(HTMLMediaElement); 595 596 } //namespace 597 598 #endif 599