blob: d12b98a958401f0c3d9f2caacc55b40b2a61b764 [file] [log] [blame]
/*
* Copyright (C) 2016-2019 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 INC. AND ITS CONTRIBUTORS ``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 INC. OR ITS 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.
*/
#import "config.h"
#import "WebPage.h"
#import "AttributedString.h"
#import "LoadParameters.h"
#import "PluginView.h"
#import "RemoteObjectRegistry.h"
#import "WKAccessibilityWebPageObjectBase.h"
#import "WebPageProxyMessages.h"
#import "WebPaymentCoordinator.h"
#import <WebCore/DictionaryLookup.h>
#import <WebCore/Editor.h>
#import <WebCore/EventHandler.h>
#import <WebCore/FocusController.h>
#import <WebCore/HTMLConverter.h>
#import <WebCore/HitTestResult.h>
#import <WebCore/NodeRenderStyle.h>
#import <WebCore/PaymentCoordinator.h>
#import <WebCore/PlatformMediaSessionManager.h>
#import <WebCore/RenderElement.h>
#import <WebCore/RenderObject.h>
#import <WebCore/TextIterator.h>
#if PLATFORM(COCOA)
namespace WebKit {
using namespace WebCore;
void WebPage::platformDidReceiveLoadParameters(const LoadParameters& loadParameters)
{
m_dataDetectionContext = loadParameters.dataDetectionContext;
}
void WebPage::requestActiveNowPlayingSessionInfo(CallbackID callbackID)
{
bool hasActiveSession = false;
String title = emptyString();
double duration = NAN;
double elapsedTime = NAN;
uint64_t uniqueIdentifier = 0;
bool registeredAsNowPlayingApplication = false;
if (auto* sharedManager = WebCore::PlatformMediaSessionManager::sharedManagerIfExists()) {
hasActiveSession = sharedManager->hasActiveNowPlayingSession();
title = sharedManager->lastUpdatedNowPlayingTitle();
duration = sharedManager->lastUpdatedNowPlayingDuration();
elapsedTime = sharedManager->lastUpdatedNowPlayingElapsedTime();
uniqueIdentifier = sharedManager->lastUpdatedNowPlayingInfoUniqueIdentifier();
registeredAsNowPlayingApplication = sharedManager->registeredAsNowPlayingApplication();
}
send(Messages::WebPageProxy::NowPlayingInfoCallback(hasActiveSession, registeredAsNowPlayingApplication, title, duration, elapsedTime, uniqueIdentifier, callbackID));
}
void WebPage::performDictionaryLookupAtLocation(const FloatPoint& floatPoint)
{
if (auto* pluginView = pluginViewForFrame(&m_page->mainFrame())) {
if (pluginView->performDictionaryLookupAtLocation(floatPoint))
return;
}
// Find the frame the point is over.
HitTestResult result = m_page->mainFrame().eventHandler().hitTestResultAtPoint(m_page->mainFrame().view()->windowToContents(roundedIntPoint(floatPoint)), HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::DisallowUserAgentShadowContent | HitTestRequest::AllowChildFrameContent);
auto [range, options] = DictionaryLookup::rangeAtHitTestResult(result);
if (!range)
return;
auto* frame = result.innerNonSharedNode() ? result.innerNonSharedNode()->document().frame() : &m_page->focusController().focusedOrMainFrame();
if (!frame)
return;
performDictionaryLookupForRange(*frame, *range, options, TextIndicatorPresentationTransition::Bounce);
}
void WebPage::performDictionaryLookupForSelection(Frame& frame, const VisibleSelection& selection, TextIndicatorPresentationTransition presentationTransition)
{
auto [selectedRange, options] = DictionaryLookup::rangeForSelection(selection);
if (selectedRange)
performDictionaryLookupForRange(frame, *selectedRange, options, presentationTransition);
}
void WebPage::performDictionaryLookupOfCurrentSelection()
{
auto& frame = m_page->focusController().focusedOrMainFrame();
performDictionaryLookupForSelection(frame, frame.selection().selection(), TextIndicatorPresentationTransition::BounceAndCrossfade);
}
void WebPage::performDictionaryLookupForRange(Frame& frame, Range& range, NSDictionary *options, TextIndicatorPresentationTransition presentationTransition)
{
send(Messages::WebPageProxy::DidPerformDictionaryLookup(dictionaryPopupInfoForRange(frame, range, options, presentationTransition)));
}
DictionaryPopupInfo WebPage::dictionaryPopupInfoForRange(Frame& frame, Range& range, NSDictionary *options, TextIndicatorPresentationTransition presentationTransition)
{
Editor& editor = frame.editor();
editor.setIsGettingDictionaryPopupInfo(true);
DictionaryPopupInfo dictionaryPopupInfo;
if (range.text().stripWhiteSpace().isEmpty()) {
editor.setIsGettingDictionaryPopupInfo(false);
return dictionaryPopupInfo;
}
Vector<FloatQuad> quads;
range.absoluteTextQuads(quads);
if (quads.isEmpty()) {
editor.setIsGettingDictionaryPopupInfo(false);
return dictionaryPopupInfo;
}
IntRect rangeRect = frame.view()->contentsToWindow(quads[0].enclosingBoundingBox());
const RenderStyle* style = range.startContainer().renderStyle();
float scaledAscent = style ? style->fontMetrics().ascent() * pageScaleFactor() : 0;
dictionaryPopupInfo.origin = FloatPoint(rangeRect.x(), rangeRect.y() + scaledAscent);
dictionaryPopupInfo.options = options;
#if PLATFORM(MAC)
NSAttributedString *nsAttributedString = editingAttributedStringFromRange(range, IncludeImagesInAttributedString::No);
RetainPtr<NSMutableAttributedString> scaledNSAttributedString = adoptNS([[NSMutableAttributedString alloc] initWithString:[nsAttributedString string]]);
NSFontManager *fontManager = [NSFontManager sharedFontManager];
[nsAttributedString enumerateAttributesInRange:NSMakeRange(0, [nsAttributedString length]) options:0 usingBlock:^(NSDictionary *attributes, NSRange range, BOOL *stop) {
RetainPtr<NSMutableDictionary> scaledAttributes = adoptNS([attributes mutableCopy]);
NSFont *font = [scaledAttributes objectForKey:NSFontAttributeName];
if (font)
font = [fontManager convertFont:font toSize:font.pointSize * pageScaleFactor()];
if (font)
[scaledAttributes setObject:font forKey:NSFontAttributeName];
[scaledNSAttributedString addAttributes:scaledAttributes.get() range:range];
}];
#endif // PLATFORM(MAC)
TextIndicatorOptions indicatorOptions = TextIndicatorOptionUseBoundingRectAndPaintAllContentForComplexRanges;
if (presentationTransition == TextIndicatorPresentationTransition::BounceAndCrossfade)
indicatorOptions |= TextIndicatorOptionIncludeSnapshotWithSelectionHighlight;
auto textIndicator = TextIndicator::createWithRange(range, indicatorOptions, presentationTransition);
if (!textIndicator) {
editor.setIsGettingDictionaryPopupInfo(false);
return dictionaryPopupInfo;
}
dictionaryPopupInfo.textIndicator = textIndicator->data();
#if PLATFORM(MAC)
dictionaryPopupInfo.attributedString = scaledNSAttributedString;
#endif // PLATFORM(MAC)
#if PLATFORM(MACCATALYST)
dictionaryPopupInfo.attributedString = adoptNS([[NSMutableAttributedString alloc] initWithString:range.text()]);
#endif // PLATFORM(MACCATALYST)
editor.setIsGettingDictionaryPopupInfo(false);
return dictionaryPopupInfo;
}
void WebPage::accessibilityTransferRemoteToken(RetainPtr<NSData> remoteToken)
{
IPC::DataReference dataToken = IPC::DataReference(reinterpret_cast<const uint8_t*>([remoteToken bytes]), [remoteToken length]);
send(Messages::WebPageProxy::RegisterWebProcessAccessibilityToken(dataToken));
}
#if ENABLE(APPLE_PAY)
WebPaymentCoordinator* WebPage::paymentCoordinator()
{
if (!m_page)
return nullptr;
auto& client = m_page->paymentCoordinator().client();
return is<WebPaymentCoordinator>(client) ? downcast<WebPaymentCoordinator>(&client) : nullptr;
}
#endif
void WebPage::getContentsAsAttributedString(CompletionHandler<void(const AttributedString&)>&& completionHandler)
{
auto* documentElement = m_page->mainFrame().document()->documentElement();
if (!documentElement) {
completionHandler({ });
return;
}
NSDictionary* documentAttributes = nil;
AttributedString result;
result.string = attributedStringFromRange(rangeOfContents(*documentElement), &documentAttributes);
result.documentAttributes = documentAttributes;
completionHandler({ result });
}
void WebPage::setRemoteObjectRegistry(RemoteObjectRegistry& registry)
{
m_remoteObjectRegistry = makeWeakPtr(registry);
}
void WebPage::updateMockAccessibilityElementAfterCommittingLoad()
{
auto* document = mainFrame()->document();
[m_mockAccessibilityElement setHasMainFramePlugin:document ? document->isPluginDocument() : false];
}
} // namespace WebKit
#endif // PLATFORM(COCOA)