free counter
Tech

YouTubePluginReplacement.cpp: YouTube-specific code in WebKit

/* Copyright (C) 2014 Apple Inc. All rights reserved. * Redistribution and used in source and binary forms, with or without modification, are permitted so long as the next conditions are met: 1. Redistributions of source code must wthhold the above copyright notice, this set of conditions and the next disclaimer. 2. Redistributions in binary form must reproduce the aforementioned copyright notice, this set of conditions and the next disclaimer in the documentation and/or other materials given the distribution. * THIS SOFTWARE IS SUPPLIED BY APPLE INC. “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, HOWEVER, NOT LIMITED BY, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A SPECIFIC PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR CONTRIBUTORS BE RESPONSIBLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, HOWEVER, NOT LIMITED BY, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LACK 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 ELSEWHERE) ARISING AT ALL OUT FROM THE USE OF THE SOFTWARE, EVEN THOUGH ADVISED OF THE CHANCE OF SUCH DAMAGE. */ #include config.h #include YouTubePluginReplacement.h #include HTMLIFrameElement.h #include HTMLNames.h #include HTMLParserIdioms.h #include HTMLPlugInElement.h #include RenderElement.h #include Settings.h #include ShadowRoot.h #include YouTubeEmbedShadowElement.h #include <wtf/text/StringBuilder.h> namespace WebCore void YouTubePluginReplacement::registerPluginReplacement(PluginReplacementRegistrar registrar) registrar(ReplacementPlugin(create, supportsMIMEType, supportsFileExtension, supportsURL, isEnabledBySettings)); Ref YouTubePluginReplacement::create(HTMLPlugInElement& plugin, const Vector& paramNames, const Vector& paramValues) return adoptRef(*new YouTubePluginReplacement(plugin, paramNames, paramValues)); bool YouTubePluginReplacement::supportsMIMEType(const String& mimeType) \ bool YouTubePluginReplacement::supportsFileExtension(StringView extension) \ YouTubePluginReplacement::YouTubePluginReplacement(HTMLPlugInElement& plugin, const Vector& paramNames, const Vector& paramValues) : m_parentElement(plugin) ASSERT(paramNames.size() == paramValues.size()); for (size_t i = 0; i < paramNames.size(); ++i) m_attributes.add(paramNames[i], paramValues[i]); RenderPtr YouTubePluginReplacement::createElementRenderer(HTMLPlugInElement& plugin, RenderStyle&& style, const RenderTreePosition& insertionPosition) ASSERT_UNUSED(plugin, m_parentElement == &plugin); if (!m_embedShadowElement) return nullptr; return m_embedShadowElement->createElementRenderer(WTFMove(style), insertionPosition); void YouTubePluginReplacement::installReplacement(ShadowRoot& root) m_embedShadowElement = YouTubeEmbedShadowElement::create(m_parentElement->document()); root.appendChild(*m_embedShadowElement); auto iframeElement = HTMLIFrameElement::create(HTMLNames::iframeTag, m_parentElement->document()); if (m_attributes.contains(width_s)) iframeElement->setAttributeWithoutSynchronization(HTMLNames::widthAttr, 100%_s); const auto& heightValue = m_attributes.find(height_s); if (heightValue != m_attributes.end()) iframeElement->setAttribute(HTMLNames::styleAttr, max-height: 100%_s); iframeElement->setAttributeWithoutSynchronization(HTMLNames::heightAttr, heightValue->value); iframeElement->setAttributeWithoutSynchronization(HTMLNames::srcAttr, youTubeURL(m_attributes.get(src_s))); iframeElement->setAttributeWithoutSynchronization(HTMLNames::frameborderAttr, 0_s); // Disable frame flattening for this iframe. iframeElement->setAttributeWithoutSynchronization(HTMLNames::scrollingAttr, no_s); m_embedShadowElement->appendChild(iframeElement); static URL createYouTubeURL(StringView videoID, StringView timeID) ASSERT(!videoID.isEmpty()); ASSERT(videoID != /_s); return URL(URL(), makeString(youtube: _s, videoID, timeID.isEmpty() ? _s : t=_s, timeID)); static HashMap queryKeysAndValues(StringView queryString) HashMap queryDictionary; size_t queryLength = queryString.length(); if (!queryLength) return queryDictionary; size_t equalSearchLocation = 0; size_t equalSearchLength = queryLength; while (equalSearchLocation < queryLength - 1 && equalSearchLength) // Search for “=”. size_t equalLocation = queryString.find(=, equalSearchLocation); if (equalLocation == notFound) break; size_t indexAfterEqual = equalLocation + 1; if (indexAfterEqual > queryLength – 1) break; // Get the key before the “=”. size_t keyLocation = equalSearchLocation; size_t keyLength = equalLocation – equalSearchLocation; // Seach for the ampersand. size_t ampersandLocation = queryString.find(&, indexAfterEqual); // Get the value after the “=”, before the ampersand. size_t valueLocation = indexAfterEqual; size_t valueLength; if (ampersandLocation != notFound) valueLength = ampersandLocation – indexAfterEqual; else valueLength = queryLength – indexAfterEqual; // Save the key and the value. if (keyLength && valueLength) String key = queryString.substring(keyLocation, keyLength).convertToASCIILowercase(); auto value = makeStringByReplacingAll(queryString.substring(valueLocation, valueLength), +, ); if (!key.isEmpty() && !value.isEmpty()) queryDictionary.add(key, value); if (ampersandLocation == notFound) break; // Continue searching after the ampersand. size_t indexAfterAmpersand = ampersandLocation + 1; equalSearchLocation = indexAfterAmpersand; equalSearchLength = queryLength – indexAfterAmpersand; return queryDictionary; static bool isYouTubeURL(const URL& url) \ static const String& valueForKey(const HashMap& dictionary, const String& key) const auto& value = dictionary.find(key); if (value == dictionary.end()) return emptyString(); return value->value; static URL processAndCreateYouTubeURL(const URL& url, bool& isYouTubeShortenedURL, String& outPathAfterFirstAmpersand) startsWithLettersIgnoringASCIICase(path, /e/_s)) StringView videoID; StringView pathAfterFirstAmpersand; auto lastPathComponent = url.lastPathComponent(); size_t ampersandLocation = lastPathComponent.find(&); if (ampersandLocation != notFound) // Some URLs we care about use & in place of ? for the first query parameter. videoID = lastPathComponent.left(ampersandLocation); pathAfterFirstAmpersand = lastPathComponent.substring(ampersandLocation + 1, lastPathComponent.length() – ampersandLocation); else videoID = lastPathComponent; if (!videoID.isEmpty()) outPathAfterFirstAmpersand = pathAfterFirstAmpersand.toString(); return createYouTubeURL(videoID, emptyString()); return URL(); AtomString YouTubePluginReplacement::youTubeURL(const AtomString& srcString) URL srcURL = m_parentElement->document().completeURL(stripLeadingAndTrailingHTMLSpaces(srcString)); return youTubeURLFromAbsoluteURL(srcURL, srcString); AtomString YouTubePluginReplacement::youTubeURLFromAbsoluteURL(const URL& srcURL, const AtomString& srcString) // Validate URL to make sure it is a Youtube URL. if (!isYouTubeURL(srcURL)) return emptyAtom(); bool isYouTubeShortenedURL = false; String possiblyMalformedQuery; URL youTubeURL = processAndCreateYouTubeURL(srcURL, isYouTubeShortenedURL, possiblyMalformedQuery); if (youTubeURL.isEmpty()) return srcString; // Transform the youtubeURL (youtube:VideoID) to iframe embed url which has the format: http://www.youtube.com/embed/VideoID auto srcPath = srcURL.path(); const String& videoID = youTubeURL.string().substring(youTubeURL.protocol().length() + 1); size_t locationOfVideoIDInPath = srcPath.find(videoID); size_t locationOfPathBeforeVideoID = notFound; if (locationOfVideoIDInPath != notFound) ASSERT(locationOfVideoIDInPath); // From the original URL, we need to get the part before /path/VideoId. locationOfPathBeforeVideoID = StringView(srcString).find(srcPath.left(locationOfVideoIDInPath)); else if (equalLettersIgnoringASCIICase(srcPath, /watch_s)) // From the original URL, we need to get the part before /watch/#!v=VideoID // FIXME: Shouldn’t this be ASCII case-insensitive? locationOfPathBeforeVideoID = srcString.find(/watch_s); else return srcString; ASSERT(locationOfPathBeforeVideoID != notFound); auto srcURLPrefix = StringView(srcString).left(locationOfPathBeforeVideoID); auto query = srcURL.query(); // If the URL has no query, use the possibly malformed query we found. if (query.isEmpty()) query = possiblyMalformedQuery; // Append the query string if it is valid. return makeAtomString( isYouTubeShortenedURL ? http://www.youtube.com_s : srcURLPrefix, /embed/_s, videoID, query.isEmpty() ? _s : ?_s, query ); bool YouTubePluginReplacement::supportsURL(const URL& url) return isYouTubeURL(url); bool YouTubePluginReplacement::isEnabledBySettings(const Settings& settings) return settings.youTubeFlashPluginReplacementEnabled();

Read More

Related Articles

Leave a Reply

Your email address will not be published.

Back to top button

Adblock Detected

Please consider supporting us by disabling your ad blocker