FindControllerIOS.mm   [plain text]


/*
 * 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)

#import "FindController.h"
#import "FindIndicatorOverlayClientIOS.h"
#import "WebCoreArgumentCoders.h"
#import "WebPage.h"
#import "WebPageProxyMessages.h"
#import <WebCore/FrameView.h>
#import <WebCore/GraphicsContext.h>
#import <WebCore/MainFrame.h>
#import <WebCore/Page.h>

using namespace WebCore;

const int cornerRadius = 3;
const int totalHorizontalMargin = 2;
const int totalVerticalMargin = 1;

const double maximumFindIndicatorZoom = 1.6;

static Color highlightColor()
{
    return Color(255, 228, 56, 255);
}

namespace WebKit {

void FindIndicatorOverlayClientIOS::drawRect(PageOverlay* overlay, WebCore::GraphicsContext& context, const WebCore::IntRect& dirtyRect)
{
    // FIXME: Support multiple text rects.

    IntRect overlayFrame = overlay->frame();
    IntRect overlayBounds = overlay->bounds();

    {
        GraphicsContextStateSaver stateSaver(context);
        Path clipPath;
        clipPath.addRoundedRect(overlayBounds, FloatSize(cornerRadius, cornerRadius));
        context.clip(clipPath);
        context.setFillColor(highlightColor(), ColorSpaceDeviceRGB);
        context.fillRect(overlayBounds);
    }

    {
        GraphicsContextStateSaver stateSaver(context);
        context.translate(-overlayFrame.x(), -overlayFrame.y());
        m_frame.view()->setPaintBehavior(PaintBehaviorSelectionOnly | PaintBehaviorForceBlackText | PaintBehaviorFlattenCompositingLayers);
        m_frame.view()->paintContents(&context, overlayFrame);
        m_frame.view()->setPaintBehavior(PaintBehaviorNormal);
    }
}

bool FindController::updateFindIndicator(Frame& selectedFrame, bool isShowingOverlay, bool shouldAnimate)
{
    IntRect matchRect = enclosingIntRect(selectedFrame.selection().selectionBounds(false));
    matchRect = selectedFrame.view()->contentsToRootView(matchRect);
    matchRect.inflateX(totalHorizontalMargin);
    matchRect.inflateY(totalVerticalMargin);

    if (m_findIndicatorOverlay)
        m_webPage->uninstallPageOverlay(m_findIndicatorOverlay.get());

    m_findIndicatorOverlayClient = std::make_unique<FindIndicatorOverlayClientIOS>(selectedFrame);
    m_findIndicatorOverlay = PageOverlay::create(m_findIndicatorOverlayClient.get(), PageOverlay::OverlayType::Document);
    m_webPage->installPageOverlay(m_findIndicatorOverlay);

    m_findIndicatorOverlay->setFrame(matchRect);
    m_findIndicatorOverlay->setNeedsDisplay();

    m_webPage->zoomToRect(matchRect, m_webPage->minimumPageScaleFactor(), std::min(m_webPage->maximumPageScaleFactor(), maximumFindIndicatorZoom));
    m_findIndicatorRect = matchRect;
    m_isShowingFindIndicator = true;
    
    return true;
}

void FindController::hideFindIndicator()
{
    if (!m_isShowingFindIndicator)
        return;

    m_webPage->uninstallPageOverlay(m_findIndicatorOverlay.get());
    m_findIndicatorOverlay = nullptr;
    m_isShowingFindIndicator = false;
    m_foundStringMatchIndex = -1;
    didHideFindIndicator();
}

void FindController::willFindString()
{
    for (Frame* coreFrame = m_webPage->mainFrame(); coreFrame; coreFrame = coreFrame->tree().traverseNext()) {
        coreFrame->editor().setIgnoreCompositionSelectionChange(true);
        coreFrame->selection().setUpdateAppearanceEnabled(true);
    }
}

void FindController::didFailToFindString()
{
    for (Frame* coreFrame = m_webPage->mainFrame(); coreFrame; coreFrame = coreFrame->tree().traverseNext()) {
        coreFrame->selection().setUpdateAppearanceEnabled(false);
        coreFrame->editor().setIgnoreCompositionSelectionChange(false);
    }
}

void FindController::didHideFindIndicator()
{
    for (Frame* coreFrame = m_webPage->mainFrame(); coreFrame; coreFrame = coreFrame->tree().traverseNext()) {
        coreFrame->selection().setUpdateAppearanceEnabled(false);
        coreFrame->editor().setIgnoreCompositionSelectionChange(false);
    }
}

} // namespace WebKit

#endif