blob: 9abb2a79299d596b91e6ef61ca43ef86190a9049 [file] [log] [blame]
/*
* Copyright (C) 2014 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>
#if PLATFORM(IOS_FAMILY)
#import "FindController.h"
#import "FindIndicatorOverlayClientIOS.h"
#import "SmartMagnificationControllerMessages.h"
#import "WebCoreArgumentCoders.h"
#import "WebPage.h"
#import "WebPageProxyMessages.h"
#import <WebCore/Editor.h>
#import <WebCore/FocusController.h>
#import <WebCore/Frame.h>
#import <WebCore/FrameView.h>
#import <WebCore/GraphicsContext.h>
#import <WebCore/Page.h>
#import <WebCore/PageOverlayController.h>
#import <WebCore/PathUtilities.h>
#import <WebCore/Settings.h>
#import <WebCore/TextIndicator.h>
namespace WebKit {
using namespace WebCore;
const int cornerRadius = 3;
const int totalHorizontalMargin = 1;
const int totalVerticalMargin = 1;
const TextIndicatorOptions findTextIndicatorOptions = TextIndicatorOptionIncludeMarginIfRangeMatchesSelection | TextIndicatorOptionDoNotClipToVisibleRect;
static Color highlightColor()
{
return Color(255, 228, 56, 255);
}
void FindIndicatorOverlayClientIOS::drawRect(PageOverlay& overlay, GraphicsContext& context, const IntRect& dirtyRect)
{
float scaleFactor = m_frame.page()->deviceScaleFactor();
if (m_frame.settings().delegatesPageScaling())
scaleFactor *= m_frame.page()->pageScaleFactor();
// If the page scale changed, we need to paint a new TextIndicator.
if (m_textIndicator->contentImageScaleFactor() != scaleFactor)
m_textIndicator = TextIndicator::createWithSelectionInFrame(m_frame, findTextIndicatorOptions, TextIndicatorPresentationTransition::None, FloatSize(totalHorizontalMargin, totalVerticalMargin));
if (!m_textIndicator)
return;
Image* indicatorImage = m_textIndicator->contentImage();
if (!indicatorImage)
return;
Vector<FloatRect> textRectsInBoundingRectCoordinates = m_textIndicator->textRectsInBoundingRectCoordinates();
Vector<Path> paths = PathUtilities::pathsWithShrinkWrappedRects(textRectsInBoundingRectCoordinates, cornerRadius);
context.setFillColor(highlightColor());
for (const auto& path : paths)
context.fillPath(path);
context.drawImage(*indicatorImage, overlay.bounds());
}
bool FindController::updateFindIndicator(Frame& selectedFrame, bool isShowingOverlay, bool shouldAnimate)
{
if (m_findIndicatorOverlay) {
m_webPage->corePage()->pageOverlayController().uninstallPageOverlay(*m_findIndicatorOverlay, PageOverlay::FadeMode::DoNotFade);
m_findIndicatorOverlay = nullptr;
m_isShowingFindIndicator = false;
}
auto textIndicator = TextIndicator::createWithSelectionInFrame(selectedFrame, findTextIndicatorOptions, TextIndicatorPresentationTransition::None, FloatSize(totalHorizontalMargin, totalVerticalMargin));
if (!textIndicator)
return false;
m_findIndicatorOverlayClient = std::make_unique<FindIndicatorOverlayClientIOS>(selectedFrame, textIndicator.get());
m_findIndicatorRect = enclosingIntRect(textIndicator->selectionRectInRootViewCoordinates());
m_findIndicatorOverlay = PageOverlay::create(*m_findIndicatorOverlayClient, PageOverlay::OverlayType::Document);
m_webPage->corePage()->pageOverlayController().installPageOverlay(*m_findIndicatorOverlay, PageOverlay::FadeMode::DoNotFade);
m_findIndicatorOverlay->setFrame(enclosingIntRect(textIndicator->textBoundingRectInRootViewCoordinates()));
m_findIndicatorOverlay->setNeedsDisplay();
if (shouldAnimate) {
bool isReplaced;
const VisibleSelection& visibleSelection = selectedFrame.selection().selection();
FloatRect renderRect = visibleSelection.start().containerNode()->renderRect(&isReplaced);
IntRect startRect = visibleSelection.visibleStart().absoluteCaretBounds();
m_webPage->send(Messages::SmartMagnificationController::ScrollToRect(startRect.center(), renderRect));
}
m_isShowingFindIndicator = true;
return true;
}
void FindController::hideFindIndicator()
{
if (!m_isShowingFindIndicator)
return;
m_webPage->corePage()->pageOverlayController().uninstallPageOverlay(*m_findIndicatorOverlay, PageOverlay::FadeMode::DoNotFade);
m_findIndicatorOverlay = nullptr;
m_isShowingFindIndicator = false;
m_foundStringMatchIndex = -1;
didHideFindIndicator();
}
static void setSelectionChangeUpdatesEnabledInAllFrames(WebPage& page, bool enabled)
{
for (Frame* coreFrame = page.mainFrame(); coreFrame; coreFrame = coreFrame->tree().traverseNext())
coreFrame->editor().setIgnoreSelectionChanges(enabled);
}
void FindController::willFindString()
{
setSelectionChangeUpdatesEnabledInAllFrames(*m_webPage, true);
}
void FindController::didFindString()
{
// If the selection before we enabled appearance updates is equal to the
// range that we just found, setSelection will bail and fail to actually call
// updateAppearance, so the selection won't have been pushed to the render tree.
// Therefore, we need to force an update no matter what.
Frame& frame = m_webPage->corePage()->focusController().focusedOrMainFrame();
frame.selection().setUpdateAppearanceEnabled(true);
frame.selection().updateAppearance();
frame.selection().setUpdateAppearanceEnabled(false);
// Scrolling the main frame is handled by the SmartMagnificationController class but we still
// need to consider overflow nodes and subframes here.
// Many sites have overlay headers or footers that may overlap with the highlighted
// text, so we reveal the text at the center of the viewport.
// FIXME: Find a better way to estimate the obscured area (https://webkit.org/b/183889).
frame.selection().revealSelection(SelectionRevealMode::RevealUpToMainFrame, ScrollAlignment::alignCenterAlways, WebCore::DoNotRevealExtent);
}
void FindController::didFailToFindString()
{
setSelectionChangeUpdatesEnabledInAllFrames(*m_webPage, false);
}
void FindController::didHideFindIndicator()
{
setSelectionChangeUpdatesEnabledInAllFrames(*m_webPage, false);
}
unsigned FindController::findIndicatorRadius() const
{
return cornerRadius;
}
bool FindController::shouldHideFindIndicatorOnScroll() const
{
return false;
}
} // namespace WebKit
#endif