📄 htmlmediaelement.cpp
字号:
/* * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */#include "config.h"#if ENABLE(VIDEO)#include "HTMLMediaElement.h"#include "ContentType.h"#include "CSSHelper.h"#include "CSSPropertyNames.h"#include "CSSValueKeywords.h"#include "Event.h"#include "EventNames.h"#include "ExceptionCode.h"#include "Frame.h"#include "FrameLoader.h"#include "HTMLDocument.h"#include "HTMLNames.h"#include "HTMLSourceElement.h"#include "HTMLVideoElement.h"#include <limits>#include "MediaError.h"#include "MediaList.h"#include "MediaQueryEvaluator.h"#include "MIMETypeRegistry.h"#include "MediaPlayer.h"#include "Page.h"#include "RenderVideo.h"#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)#include "RenderPartObject.h"#endif#include "TimeRanges.h"#if ENABLE(PLUGIN_PROXY_FOR_VIDEO)#include "Widget.h"#endif#include <wtf/CurrentTime.h>#include <wtf/MathExtras.h>using namespace std;namespace WebCore {using namespace HTMLNames;HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document* doc) : HTMLElement(tagName, doc) , m_loadTimer(this, &HTMLMediaElement::loadTimerFired) , m_asyncEventTimer(this, &HTMLMediaElement::asyncEventTimerFired) , m_progressEventTimer(this, &HTMLMediaElement::progressEventTimerFired) , m_defaultPlaybackRate(1.0f) , m_networkState(EMPTY) , m_readyState(DATA_UNAVAILABLE) , m_begun(false) , m_loadedFirstFrame(false) , m_autoplaying(true) , m_volume(1.0f) , m_muted(false) , m_paused(true) , m_seeking(false) , m_currentTimeDuringSeek(0) , m_previousProgress(0) , m_previousProgressTime(numeric_limits<double>::max()) , m_sentStalledEvent(false) , m_loadNestingLevel(0) , m_terminateLoadBelowNestingLevel(0) , m_pausedInternal(false) , m_inActiveDocument(true) , m_player(0) , m_restrictions(NoRestrictions) , m_processingMediaPlayerCallback(0) , m_sendProgressEvents(true)#if ENABLE(PLUGIN_PROXY_FOR_VIDEO) , m_needWidgetUpdate(false)#endif{ document()->registerForDocumentActivationCallbacks(this); document()->registerForMediaVolumeCallbacks(this);}HTMLMediaElement::~HTMLMediaElement(){ document()->unregisterForDocumentActivationCallbacks(this); document()->unregisterForMediaVolumeCallbacks(this);}bool HTMLMediaElement::checkDTD(const Node* newChild){ return newChild->hasTagName(sourceTag) || HTMLElement::checkDTD(newChild);}void HTMLMediaElement::attributeChanged(Attribute* attr, bool preserveDecls){ HTMLElement::attributeChanged(attr, preserveDecls); const QualifiedName& attrName = attr->name(); if (attrName == srcAttr) { // 3.14.9.2. // change to src attribute triggers load() if (inDocument() && m_networkState == EMPTY) scheduleLoad(); } #if !ENABLE(PLUGIN_PROXY_FOR_VIDEO) else if (attrName == controlsAttr) { if (!isVideo() && attached() && (controls() != (renderer() != 0))) { detach(); attach(); } if (renderer()) renderer()->updateFromElement(); }#endif} bool HTMLMediaElement::rendererIsNeeded(RenderStyle* style){#if ENABLE(PLUGIN_PROXY_FOR_VIDEO) UNUSED_PARAM(style); Frame* frame = document()->frame(); if (!frame) return false; return true;#else return controls() ? HTMLElement::rendererIsNeeded(style) : false;#endif}RenderObject* HTMLMediaElement::createRenderer(RenderArena* arena, RenderStyle*){#if ENABLE(PLUGIN_PROXY_FOR_VIDEO) return new (arena) RenderPartObject(this);#else return new (arena) RenderMedia(this);#endif} void HTMLMediaElement::insertedIntoDocument(){ HTMLElement::insertedIntoDocument(); if (!src().isEmpty()) scheduleLoad();}void HTMLMediaElement::removedFromDocument(){ if (networkState() != EMPTY) { ExceptionCode ec; pause(ec); } HTMLElement::removedFromDocument();}void HTMLMediaElement::attach(){ ASSERT(!attached());#if ENABLE(PLUGIN_PROXY_FOR_VIDEO) m_needWidgetUpdate = true;#endif HTMLElement::attach(); if (renderer()) renderer()->updateFromElement();}void HTMLMediaElement::recalcStyle(StyleChange change){ HTMLElement::recalcStyle(change); if (renderer()) renderer()->updateFromElement();}void HTMLMediaElement::scheduleLoad(){ m_loadTimer.startOneShot(0);}void HTMLMediaElement::initAndDispatchProgressEvent(const AtomicString& eventName){ if (!m_sendProgressEvents) return; bool totalKnown = m_player && m_player->totalBytesKnown(); unsigned loaded = m_player ? m_player->bytesLoaded() : 0; unsigned total = m_player ? m_player->totalBytes() : 0; dispatchProgressEvent(eventName, totalKnown, loaded, total); if (renderer()) renderer()->updateFromElement();}void HTMLMediaElement::dispatchEventAsync(const AtomicString& eventName){ m_asyncEventsToDispatch.append(eventName); if (!m_asyncEventTimer.isActive()) m_asyncEventTimer.startOneShot(0);}void HTMLMediaElement::loadTimerFired(Timer<HTMLMediaElement>*){ ExceptionCode ec; loadInternal(ec);}void HTMLMediaElement::asyncEventTimerFired(Timer<HTMLMediaElement>*){ Vector<AtomicString> asyncEventsToDispatch; m_asyncEventsToDispatch.swap(asyncEventsToDispatch); unsigned count = asyncEventsToDispatch.size(); for (unsigned n = 0; n < count; ++n) dispatchEventForType(asyncEventsToDispatch[n], false, true);}static String serializeTimeOffset(float time){ String timeString = String::number(time); // FIXME serialize time offset values properly (format not specified yet) timeString.append("s"); return timeString;}static float parseTimeOffset(const String& timeString, bool* ok = 0){ const UChar* characters = timeString.characters(); unsigned length = timeString.length(); if (length && characters[length - 1] == 's') length--; // FIXME parse time offset values (format not specified yet) float val = charactersToFloat(characters, length, ok); return val;}float HTMLMediaElement::getTimeOffsetAttribute(const QualifiedName& name, float valueOnError) const{ bool ok; String timeString = getAttribute(name); float result = parseTimeOffset(timeString, &ok); if (ok) return result; return valueOnError;}void HTMLMediaElement::setTimeOffsetAttribute(const QualifiedName& name, float value){ setAttribute(name, serializeTimeOffset(value));}PassRefPtr<MediaError> HTMLMediaElement::error() const { return m_error;}KURL HTMLMediaElement::src() const{ return document()->completeURL(getAttribute(srcAttr));}void HTMLMediaElement::setSrc(const String& url){ setAttribute(srcAttr, url);}String HTMLMediaElement::currentSrc() const{ return m_currentSrc;}HTMLMediaElement::NetworkState HTMLMediaElement::networkState() const{ return m_networkState;}String HTMLMediaElement::canPlayType(const String& mimeType) const{ MediaPlayer::SupportsType support = MediaPlayer::supportsType(ContentType(mimeType)); String canPlay; // 4.8.10.3 switch (support) { case MediaPlayer::IsNotSupported: canPlay = "no"; break; case MediaPlayer::MayBeSupported: canPlay = "maybe"; break; case MediaPlayer::IsSupported: canPlay = "probably"; break; } return canPlay;}void HTMLMediaElement::load(ExceptionCode& ec){ if (m_restrictions & RequireUserGestureForLoadRestriction && !processingUserGesture()) { ec = INVALID_STATE_ERR; return; } loadInternal(ec);}void HTMLMediaElement::loadInternal(ExceptionCode& ec){ String mediaSrc; ContentType contentType(""); // 3.14.9.4. Loading the media resource // 1 // if an event generated during load() ends up re-entering load(), terminate previous instances m_loadNestingLevel++; m_terminateLoadBelowNestingLevel = m_loadNestingLevel; m_progressEventTimer.stop(); m_sentStalledEvent = false; m_loadTimer.stop(); // 2 if (m_begun) { m_begun = false; m_error = MediaError::create(MediaError::MEDIA_ERR_ABORTED); if (m_sendProgressEvents) initAndDispatchProgressEvent(eventNames().abortEvent); if (m_loadNestingLevel < m_terminateLoadBelowNestingLevel) goto end; } // 3 m_error = 0; m_loadedFirstFrame = false; m_autoplaying = true; // 4 setPlaybackRate(defaultPlaybackRate(), ec); // 5 if (networkState() != EMPTY) { m_networkState = EMPTY; m_readyState = DATA_UNAVAILABLE; m_paused = true; m_seeking = false; if (m_player) { m_player->pause(); m_player->seek(0); } dispatchEventForType(eventNames().emptiedEvent, false, true); if (m_loadNestingLevel < m_terminateLoadBelowNestingLevel) goto end; } // 6 mediaSrc = selectMediaURL(contentType); if (mediaSrc.isEmpty()) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -