33a529e81266073135693e0d747d5d12e9de1602
[WebKit.git] / Source / WebCore / css / CSSCursorImageValue.cpp
1 /*
2  * Copyright (C) 2006 Rob Buis <buis@kde.org>
3  *           (C) 2008 Nikolas Zimmermann <zimmermann@kde.org>
4  * Copyright (C) 2008 Apple Inc. All rights reserved.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public License
17  * along with this library; see the file COPYING.LIB.  If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21
22 #include "config.h"
23 #include "CSSCursorImageValue.h"
24
25 #include "CSSImageSetValue.h"
26 #include "CSSImageValue.h"
27 #include "CachedImage.h"
28 #include "CachedResourceLoader.h"
29 #include "SVGCursorElement.h"
30 #include "SVGLengthContext.h"
31 #include "SVGURIReference.h"
32 #include <wtf/MathExtras.h>
33 #include <wtf/text/StringBuilder.h>
34 #include <wtf/text/WTFString.h>
35
36 namespace WebCore {
37
38 CSSCursorImageValue::CSSCursorImageValue(Ref<CSSValue>&& imageValue, bool hasHotSpot, const IntPoint& hotSpot, LoadedFromOpaqueSource loadedFromOpaqueSource)
39     : CSSValue(CursorImageClass)
40     , m_imageValue(WTFMove(imageValue))
41     , m_hasHotSpot(hasHotSpot)
42     , m_hotSpot(hotSpot)
43     , m_loadedFromOpaqueSource(loadedFromOpaqueSource)
44 {
45     if (is<CSSImageValue>(m_imageValue.get()))
46         m_originalURL = downcast<CSSImageValue>(m_imageValue.get()).url();
47 }
48
49 CSSCursorImageValue::~CSSCursorImageValue()
50 {
51     for (auto* element : m_cursorElements)
52         element->removeClient(*this);
53 }
54
55 String CSSCursorImageValue::customCSSText() const
56 {
57     StringBuilder result;
58     result.append(m_imageValue.get().cssText());
59     if (m_hasHotSpot) {
60         result.append(' ');
61         result.appendNumber(m_hotSpot.x());
62         result.append(' ');
63         result.appendNumber(m_hotSpot.y());
64     }
65     return result.toString();
66 }
67
68 // FIXME: Should this function take a TreeScope instead?
69 SVGCursorElement* CSSCursorImageValue::updateCursorElement(const Document& document)
70 {
71     if (!m_originalURL.hasFragmentIdentifier())
72         return nullptr;
73
74     auto element = SVGURIReference::targetElementFromIRIString(m_originalURL, document).element;
75     if (!is<SVGCursorElement>(element))
76         return nullptr;
77
78     auto& cursorElement = downcast<SVGCursorElement>(*element);
79     if (m_cursorElements.add(&cursorElement).isNewEntry) {
80         cursorElementChanged(cursorElement);
81         cursorElement.addClient(*this);
82     }
83     return &cursorElement;
84 }
85
86 void CSSCursorImageValue::cursorElementRemoved(SVGCursorElement& cursorElement)
87 {
88     m_cursorElements.remove(&cursorElement);
89 }
90
91 void CSSCursorImageValue::cursorElementChanged(SVGCursorElement& cursorElement)
92 {
93     // FIXME: This will override hot spot specified in CSS, which is probably incorrect.
94     SVGLengthContext lengthContext(nullptr);
95     m_hasHotSpot = true;
96     float x = std::round(cursorElement.x().value(lengthContext));
97     m_hotSpot.setX(static_cast<int>(x));
98
99     float y = std::round(cursorElement.y().value(lengthContext));
100     m_hotSpot.setY(static_cast<int>(y));
101 }
102
103 std::pair<CachedImage*, float> CSSCursorImageValue::loadImage(CachedResourceLoader& loader, const ResourceLoaderOptions& options)
104 {
105     if (is<CSSImageSetValue>(m_imageValue.get()))
106         return downcast<CSSImageSetValue>(m_imageValue.get()).loadBestFitImage(loader, options);
107
108     if (auto* cursorElement = updateCursorElement(*loader.document())) {
109         if (cursorElement->href() != downcast<CSSImageValue>(m_imageValue.get()).url())
110             m_imageValue = CSSImageValue::create(loader.document()->completeURL(cursorElement->href()), m_loadedFromOpaqueSource);
111     }
112
113     return { downcast<CSSImageValue>(m_imageValue.get()).loadImage(loader, options), 1 };
114 }
115
116 bool CSSCursorImageValue::equals(const CSSCursorImageValue& other) const
117 {
118     return m_hasHotSpot ? other.m_hasHotSpot && m_hotSpot == other.m_hotSpot : !other.m_hasHotSpot
119         && compareCSSValue(m_imageValue, other.m_imageValue);
120 }
121
122 } // namespace WebCore