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
36namespace WebCore {
37
38CSSCursorImageValue::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
49CSSCursorImageValue::~CSSCursorImageValue()
50{
51 for (auto* element : m_cursorElements)
52 element->removeClient(*this);
53}
54
55String 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?
69SVGCursorElement* 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
86void CSSCursorImageValue::cursorElementRemoved(SVGCursorElement& cursorElement)
87{
88 m_cursorElements.remove(&cursorElement);
89}
90
91void 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
103std::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
116bool 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
123