1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/. */
5 
6 #include "gfxGlyphExtents.h"
7 #include "gfxTextRun.h"
8 
9 using namespace mozilla;
10 
11 #ifdef DEBUG_roc
12 #define DEBUG_TEXT_RUN_STORAGE_METRICS
13 #endif
14 
15 #ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
16 extern uint32_t gTextRunStorageHighWaterMark;
17 extern uint32_t gTextRunStorage;
18 extern uint32_t gFontCount;
19 extern uint32_t gGlyphExtentsCount;
20 extern uint32_t gGlyphExtentsWidthsTotalSize;
21 extern uint32_t gGlyphExtentsSetupEagerSimple;
22 extern uint32_t gGlyphExtentsSetupEagerTight;
23 extern uint32_t gGlyphExtentsSetupLazyTight;
24 extern uint32_t gGlyphExtentsSetupFallBackToTight;
25 #endif
26 
~gfxGlyphExtents()27 gfxGlyphExtents::~gfxGlyphExtents()
28 {
29 #ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
30     gGlyphExtentsWidthsTotalSize +=
31         mContainedGlyphWidths.SizeOfExcludingThis(&FontCacheMallocSizeOf);
32     gGlyphExtentsCount++;
33 #endif
34     MOZ_COUNT_DTOR(gfxGlyphExtents);
35 }
36 
37 bool
GetTightGlyphExtentsAppUnits(gfxFont * aFont,DrawTarget * aDrawTarget,uint32_t aGlyphID,gfxRect * aExtents)38 gfxGlyphExtents::GetTightGlyphExtentsAppUnits(gfxFont* aFont,
39     DrawTarget* aDrawTarget, uint32_t aGlyphID, gfxRect* aExtents)
40 {
41     HashEntry *entry = mTightGlyphExtents.GetEntry(aGlyphID);
42     if (!entry) {
43         // Some functions higher up in the call chain deliberately pass in a
44         // nullptr DrawTarget, e.g. GetBaselinePosition() passes nullptr to
45         // gfxTextRun::MeasureText() and that nullptr reaches here.
46         if (!aDrawTarget) {
47             NS_WARNING("Could not get glyph extents (no aDrawTarget)");
48             return false;
49         }
50 
51         if (aFont->SetupCairoFont(aDrawTarget)) {
52 #ifdef DEBUG_TEXT_RUN_STORAGE_METRICS
53             ++gGlyphExtentsSetupLazyTight;
54 #endif
55             aFont->SetupGlyphExtents(aDrawTarget, aGlyphID, true, this);
56             entry = mTightGlyphExtents.GetEntry(aGlyphID);
57         }
58         if (!entry) {
59             NS_WARNING("Could not get glyph extents");
60             return false;
61         }
62     }
63 
64     *aExtents = gfxRect(entry->x, entry->y, entry->width, entry->height);
65     return true;
66 }
67 
~GlyphWidths()68 gfxGlyphExtents::GlyphWidths::~GlyphWidths()
69 {
70     uint32_t i, count = mBlocks.Length();
71     for (i = 0; i < count; ++i) {
72         uintptr_t bits = mBlocks[i];
73         if (bits && !(bits & 0x1)) {
74             delete[] reinterpret_cast<uint16_t *>(bits);
75         }
76     }
77 }
78 
79 uint32_t
SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const80 gfxGlyphExtents::GlyphWidths::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
81 {
82     uint32_t i;
83     uint32_t size = mBlocks.ShallowSizeOfExcludingThis(aMallocSizeOf);
84     for (i = 0; i < mBlocks.Length(); ++i) {
85         uintptr_t bits = mBlocks[i];
86         if (bits && !(bits & 0x1)) {
87             size += aMallocSizeOf(reinterpret_cast<void*>(bits));
88         }
89     }
90     return size;
91 }
92 
93 void
Set(uint32_t aGlyphID,uint16_t aWidth)94 gfxGlyphExtents::GlyphWidths::Set(uint32_t aGlyphID, uint16_t aWidth)
95 {
96     uint32_t block = aGlyphID >> BLOCK_SIZE_BITS;
97     uint32_t len = mBlocks.Length();
98     if (block >= len) {
99         uintptr_t *elems = mBlocks.AppendElements(block + 1 - len);
100         if (!elems)
101             return;
102         memset(elems, 0, sizeof(uintptr_t)*(block + 1 - len));
103     }
104 
105     uintptr_t bits = mBlocks[block];
106     uint32_t glyphOffset = aGlyphID & (BLOCK_SIZE - 1);
107     if (!bits) {
108         mBlocks[block] = MakeSingle(glyphOffset, aWidth);
109         return;
110     }
111 
112     uint16_t *newBlock;
113     if (bits & 0x1) {
114         // Expand the block to a real block. We could avoid this by checking
115         // glyphOffset == GetGlyphOffset(bits), but that never happens so don't bother
116         newBlock = new uint16_t[BLOCK_SIZE];
117         if (!newBlock)
118             return;
119         uint32_t i;
120         for (i = 0; i < BLOCK_SIZE; ++i) {
121             newBlock[i] = INVALID_WIDTH;
122         }
123         newBlock[GetGlyphOffset(bits)] = GetWidth(bits);
124         mBlocks[block] = reinterpret_cast<uintptr_t>(newBlock);
125     } else {
126         newBlock = reinterpret_cast<uint16_t *>(bits);
127     }
128     newBlock[glyphOffset] = aWidth;
129 }
130 
131 void
SetTightGlyphExtents(uint32_t aGlyphID,const gfxRect & aExtentsAppUnits)132 gfxGlyphExtents::SetTightGlyphExtents(uint32_t aGlyphID, const gfxRect& aExtentsAppUnits)
133 {
134     HashEntry *entry = mTightGlyphExtents.PutEntry(aGlyphID);
135     if (!entry)
136         return;
137     entry->x = aExtentsAppUnits.X();
138     entry->y = aExtentsAppUnits.Y();
139     entry->width = aExtentsAppUnits.Width();
140     entry->height = aExtentsAppUnits.Height();
141 }
142 
143 size_t
SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const144 gfxGlyphExtents::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
145 {
146     return mContainedGlyphWidths.SizeOfExcludingThis(aMallocSizeOf) +
147         mTightGlyphExtents.ShallowSizeOfExcludingThis(aMallocSizeOf);
148 }
149 
150 size_t
SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const151 gfxGlyphExtents::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
152 {
153     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
154 }
155