1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef GFX_GLYPHEXTENTS_H
7 #define GFX_GLYPHEXTENTS_H
11 #include "nsTHashtable.h"
12 #include "nsHashKeys.h"
14 #include "mozilla/MemoryReporting.h"
15 #include "mozilla/RWLock.h"
23 } // namespace mozilla
26 * This stores glyph bounds information for a particular gfxFont, at
27 * a particular appunits-per-dev-pixel ratio (because the compressed glyph
28 * width array is stored in appunits).
30 * We store a hashtable from glyph IDs to float bounding rects. For the
31 * common case where the glyph has no horizontal left bearing, and no
32 * y overflow above the font ascent or below the font descent, and tight
33 * bounding boxes are not required, we avoid storing the glyph ID in the
34 * hashtable and instead consult an array of 16-bit glyph XMost values (in
35 * appunits). This array always has an entry for the font's space glyph --- the
36 * width is assumed to be zero.
38 class gfxGlyphExtents
{
39 typedef mozilla::gfx::DrawTarget DrawTarget
;
42 explicit gfxGlyphExtents(int32_t aAppUnitsPerDevUnit
)
43 : mAppUnitsPerDevUnit(aAppUnitsPerDevUnit
),
44 mLock("gfxGlyphExtents lock") {
45 MOZ_COUNT_CTOR(gfxGlyphExtents
);
49 enum { INVALID_WIDTH
= 0xFFFF };
51 void NotifyGlyphsChanged() {
52 mozilla::AutoWriteLock
lock(mLock
);
53 mTightGlyphExtents
.Clear();
56 // returns INVALID_WIDTH => not a contained glyph
57 // Otherwise the glyph has no before-bearing or vertical bearings,
58 // and the result is its width measured from the baseline origin, in
60 uint16_t GetContainedGlyphWidthAppUnitsLocked(uint32_t aGlyphID
) const
61 MOZ_REQUIRES_SHARED(mLock
) {
62 return mContainedGlyphWidths
.Get(aGlyphID
);
65 bool IsGlyphKnownLocked(uint32_t aGlyphID
) const MOZ_REQUIRES_SHARED(mLock
) {
66 return mContainedGlyphWidths
.Get(aGlyphID
) != INVALID_WIDTH
||
67 mTightGlyphExtents
.GetEntry(aGlyphID
) != nullptr;
70 bool IsGlyphKnownWithTightExtentsLocked(uint32_t aGlyphID
) const
71 MOZ_REQUIRES_SHARED(mLock
) {
72 return mTightGlyphExtents
.GetEntry(aGlyphID
) != nullptr;
75 // Get glyph extents; a rectangle relative to the left baseline origin
76 // Returns true on success. Can fail on OOM or when aContext is null
77 // and extents were not (successfully) prefetched.
78 bool GetTightGlyphExtentsAppUnitsLocked(gfxFont
* aFont
,
79 DrawTarget
* aDrawTarget
,
80 uint32_t aGlyphID
, gfxRect
* aExtents
)
81 MOZ_REQUIRES_SHARED(mLock
);
82 bool GetTightGlyphExtentsAppUnits(gfxFont
* aFont
, DrawTarget
* aDrawTarget
,
83 uint32_t aGlyphID
, gfxRect
* aExtents
) {
84 mozilla::AutoReadLock
lock(mLock
);
85 return GetTightGlyphExtentsAppUnitsLocked(aFont
, aDrawTarget
, aGlyphID
,
89 void SetContainedGlyphWidthAppUnits(uint32_t aGlyphID
, uint16_t aWidth
) {
90 mozilla::AutoWriteLock
lock(mLock
);
91 mContainedGlyphWidths
.Set(aGlyphID
, aWidth
);
93 void SetTightGlyphExtents(uint32_t aGlyphID
, const gfxRect
& aExtentsAppUnits
);
95 int32_t GetAppUnitsPerDevUnit() { return mAppUnitsPerDevUnit
; }
97 size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf
) const;
98 size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf
) const;
101 class HashEntry
: public nsUint32HashKey
{
103 // When constructing a new entry in the hashtable, we'll leave this
104 // blank. The caller of Put() will fill this in.
105 explicit HashEntry(KeyTypePointer aPtr
)
106 : nsUint32HashKey(aPtr
), x(0.0), y(0.0), width(0.0), height(0.0) {}
107 HashEntry(HashEntry
&& aOther
)
108 : nsUint32HashKey(std::move(aOther
)),
112 height(aOther
.height
) {}
114 float x
, y
, width
, height
;
119 BLOCK_SIZE
= 1 << BLOCK_SIZE_BITS
120 }; // 128-glyph blocks
124 void Set(uint32_t aIndex
, uint16_t aValue
);
125 uint16_t Get(uint32_t aIndex
) const {
126 uint32_t block
= aIndex
>> BLOCK_SIZE_BITS
;
127 if (block
>= mBlocks
.Length()) return INVALID_WIDTH
;
128 uintptr_t bits
= mBlocks
[block
];
129 if (!bits
) return INVALID_WIDTH
;
130 uint32_t indexInBlock
= aIndex
& (BLOCK_SIZE
- 1);
132 if (GetGlyphOffset(bits
) != indexInBlock
) return INVALID_WIDTH
;
133 return GetWidth(bits
);
135 uint16_t* widths
= reinterpret_cast<uint16_t*>(bits
);
136 return widths
[indexInBlock
];
139 uint32_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf
) const;
144 static uint32_t GetGlyphOffset(uintptr_t aBits
) {
145 NS_ASSERTION(aBits
& 0x1, "This is really a pointer...");
146 return (aBits
>> 1) & ((1 << BLOCK_SIZE_BITS
) - 1);
148 static uint32_t GetWidth(uintptr_t aBits
) {
149 NS_ASSERTION(aBits
& 0x1, "This is really a pointer...");
150 return aBits
>> (1 + BLOCK_SIZE_BITS
);
152 static uintptr_t MakeSingle(uint32_t aGlyphOffset
, uint16_t aWidth
) {
153 return (aWidth
<< (1 + BLOCK_SIZE_BITS
)) + (aGlyphOffset
<< 1) + 1;
156 nsTArray
<uintptr_t> mBlocks
;
159 GlyphWidths mContainedGlyphWidths
MOZ_GUARDED_BY(mLock
);
160 nsTHashtable
<HashEntry
> mTightGlyphExtents
MOZ_GUARDED_BY(mLock
);
161 const int32_t mAppUnitsPerDevUnit
;
164 mutable mozilla::RWLock mLock
;
168 gfxGlyphExtents(const gfxGlyphExtents
& aOther
) = delete;
169 gfxGlyphExtents
& operator=(const gfxGlyphExtents
& aOther
) = delete;