1/*
2 * Copyright (C) 2013 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "PageBanner.h"
28
29#include "WebPage.h"
30#include <WebCore/FrameView.h>
31#include <WebCore/GraphicsLayer.h>
32
33using namespace WebCore;
34
35namespace WebKit {
36
37PassRefPtr<PageBanner> PageBanner::create(CALayer *layer, int height, Client* client)
38{
39    return adoptRef(new PageBanner(layer, height, client));
40}
41
42PageBanner::PageBanner(CALayer *layer, int height, Client* client)
43    : m_type(NotSet)
44    , m_client(client)
45    , m_webPage(0)
46    , m_mouseDownInBanner(false)
47    , m_isHidden(false)
48    , m_layer(layer)
49    , m_height(height)
50{
51}
52
53void PageBanner::addToPage(Type type, WebPage* webPage)
54{
55    m_type = type;
56    m_webPage = webPage;
57
58    ASSERT(m_type != NotSet);
59    ASSERT(m_webPage);
60
61    switch (m_type) {
62    case Header:
63        m_webPage->corePage()->addHeaderWithHeight(m_height);
64        break;
65    case Footer:
66        m_webPage->corePage()->addFooterWithHeight(m_height);
67        break;
68    case NotSet:
69        ASSERT_NOT_REACHED();
70    }
71}
72
73void PageBanner::didAddParentLayer(GraphicsLayer* parentLayer)
74{
75    if (!parentLayer)
76        return;
77
78    m_layer.get().bounds = CGRectMake(0, 0, parentLayer->size().width(), parentLayer->size().height());
79    [parentLayer->platformLayer() addSublayer:m_layer.get()];
80}
81
82void PageBanner::detachFromPage()
83{
84    if (!m_webPage)
85        return;
86
87    // m_webPage->corePage() can be null when this is called from WebPage::~WebPage() after
88    // the web page has been closed.
89    if (m_webPage->corePage()) {
90        // We can hide the banner by removing the parent layer that hosts it.
91        if (m_type == Header)
92            m_webPage->corePage()->addHeaderWithHeight(0);
93        else if (m_type == Footer)
94            m_webPage->corePage()->addFooterWithHeight(0);
95    }
96
97    m_type = NotSet;
98    m_webPage = 0;
99}
100
101void PageBanner::hide()
102{
103    // We can hide the banner by removing the parent layer that hosts it.
104    if (m_type == Header)
105        m_webPage->corePage()->addHeaderWithHeight(0);
106    else if (m_type == Footer)
107        m_webPage->corePage()->addFooterWithHeight(0);
108
109    m_isHidden = true;
110}
111
112void PageBanner::showIfHidden()
113{
114    if (!m_isHidden)
115        return;
116    m_isHidden = false;
117
118    // This will re-create a parent layer in the WebCore layer tree, and we will re-add
119    // m_layer as a child of it.
120    addToPage(m_type, m_webPage);
121}
122
123void PageBanner::didChangeDeviceScaleFactor(float scaleFactor)
124{
125    m_layer.get().contentsScale = scaleFactor;
126    [m_layer.get() setNeedsDisplay];
127}
128
129bool PageBanner::mouseEvent(const WebMouseEvent& mouseEvent)
130{
131    if (m_isHidden)
132        return false;
133
134    FrameView* frameView = m_webPage->mainFrameView();
135    if (!frameView)
136        return false;
137
138    IntPoint positionInBannerSpace;
139
140    switch (m_type) {
141    case Header: {
142        positionInBannerSpace = frameView->rootViewToTotalContents(mouseEvent.position());
143        break;
144    }
145    case Footer: {
146        positionInBannerSpace = frameView->rootViewToTotalContents(mouseEvent.position()) - IntSize(0, frameView->totalContentsSize().height() - m_height);
147        break;
148    }
149    case NotSet:
150        ASSERT_NOT_REACHED();
151    }
152
153    if (!m_mouseDownInBanner && (positionInBannerSpace.y() < 0 || positionInBannerSpace.y() > m_height))
154        return false;
155
156    if (mouseEvent.type() == WebEvent::MouseDown)
157        m_mouseDownInBanner = true;
158    else if (mouseEvent.type() == WebEvent::MouseUp)
159        m_mouseDownInBanner = false;
160
161    return m_client->mouseEvent(this, mouseEvent.type(), mouseEvent.button(), positionInBannerSpace);
162}
163
164CALayer *PageBanner::layer()
165{
166    return m_layer.get();
167}
168
169} // namespace WebKit
170