1/*
2 * Copyright (C) 2006, 2009 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 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Inc. ("Apple") nor the names of
14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#ifndef GlyphMetricsMap_h
30#define GlyphMetricsMap_h
31
32#include "Glyph.h"
33#include "Path.h"
34#include <array>
35#include <wtf/HashMap.h>
36
37namespace WebCore {
38
39const float cGlyphSizeUnknown = -1;
40
41template<class T> class GlyphMetricsMap {
42 WTF_MAKE_FAST_ALLOCATED;
43public:
44 T metricsForGlyph(Glyph glyph)
45 {
46 return locatePage(glyph / GlyphMetricsPage::size).metricsForGlyph(glyph);
47 }
48
49 const T& existingMetricsForGlyph(Glyph glyph)
50 {
51 return locatePage(glyph / GlyphMetricsPage::size).existingMetricsForGlyph(glyph);
52 }
53
54 void setMetricsForGlyph(Glyph glyph, const T& metrics)
55 {
56 locatePage(glyph / GlyphMetricsPage::size).setMetricsForGlyph(glyph, metrics);
57 }
58
59private:
60 class GlyphMetricsPage {
61 WTF_MAKE_FAST_ALLOCATED;
62 public:
63 static const size_t size = 16;
64
65 GlyphMetricsPage() = default;
66 explicit GlyphMetricsPage(const T& initialValue)
67 {
68 fill(initialValue);
69 }
70
71 void fill(const T& value)
72 {
73 m_metrics.fill(value);
74 }
75
76 T metricsForGlyph(Glyph glyph) const { return m_metrics[glyph % size]; }
77 const T& existingMetricsForGlyph(Glyph glyph) const { return m_metrics[glyph % size]; }
78 void setMetricsForGlyph(Glyph glyph, const T& metrics)
79 {
80 setMetricsForIndex(glyph % size, metrics);
81 }
82
83 private:
84 void setMetricsForIndex(unsigned index, const T& metrics)
85 {
86 m_metrics[index] = metrics;
87 }
88
89 std::array<T, size> m_metrics;
90 };
91
92 GlyphMetricsPage& locatePage(unsigned pageNumber)
93 {
94 if (!pageNumber && m_filledPrimaryPage)
95 return m_primaryPage;
96 return locatePageSlowCase(pageNumber);
97 }
98
99 GlyphMetricsPage& locatePageSlowCase(unsigned pageNumber);
100
101 static T unknownMetrics();
102
103 bool m_filledPrimaryPage { false };
104 GlyphMetricsPage m_primaryPage; // We optimize for the page that contains glyph indices 0-255.
105 std::unique_ptr<HashMap<int, std::unique_ptr<GlyphMetricsPage>>> m_pages;
106};
107
108template<> inline float GlyphMetricsMap<float>::unknownMetrics()
109{
110 return cGlyphSizeUnknown;
111}
112
113template<> inline FloatRect GlyphMetricsMap<FloatRect>::unknownMetrics()
114{
115 return FloatRect(0, 0, cGlyphSizeUnknown, cGlyphSizeUnknown);
116}
117
118template<> inline Optional<Path> GlyphMetricsMap<Optional<Path>>::unknownMetrics()
119{
120 return WTF::nullopt;
121}
122
123template<class T> typename GlyphMetricsMap<T>::GlyphMetricsPage& GlyphMetricsMap<T>::locatePageSlowCase(unsigned pageNumber)
124{
125 if (!pageNumber) {
126 ASSERT(!m_filledPrimaryPage);
127 m_primaryPage.fill(unknownMetrics());
128 m_filledPrimaryPage = true;
129 return m_primaryPage;
130 }
131
132 if (!m_pages)
133 m_pages = std::make_unique<HashMap<int, std::unique_ptr<GlyphMetricsPage>>>();
134
135 auto& page = m_pages->ensure(pageNumber, [] {
136 return std::make_unique<GlyphMetricsPage>(unknownMetrics());
137 }).iterator->value;
138 return *page;
139}
140
141} // namespace WebCore
142
143#endif
144