mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-27 14:52:16 +00:00
501b73a6f1
Differential Revision: https://phabricator.services.mozilla.com/D155340
173 lines
5.9 KiB
C++
173 lines
5.9 KiB
C++
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#ifndef GFX_GLYPHEXTENTS_H
|
|
#define GFX_GLYPHEXTENTS_H
|
|
|
|
#include "gfxFont.h"
|
|
#include "gfxRect.h"
|
|
#include "nsTHashtable.h"
|
|
#include "nsHashKeys.h"
|
|
#include "nsTArray.h"
|
|
#include "mozilla/MemoryReporting.h"
|
|
#include "mozilla/RWLock.h"
|
|
|
|
class gfxContext;
|
|
|
|
namespace mozilla {
|
|
namespace gfx {
|
|
class DrawTarget;
|
|
} // namespace gfx
|
|
} // namespace mozilla
|
|
|
|
/**
|
|
* This stores glyph bounds information for a particular gfxFont, at
|
|
* a particular appunits-per-dev-pixel ratio (because the compressed glyph
|
|
* width array is stored in appunits).
|
|
*
|
|
* We store a hashtable from glyph IDs to float bounding rects. For the
|
|
* common case where the glyph has no horizontal left bearing, and no
|
|
* y overflow above the font ascent or below the font descent, and tight
|
|
* bounding boxes are not required, we avoid storing the glyph ID in the
|
|
* hashtable and instead consult an array of 16-bit glyph XMost values (in
|
|
* appunits). This array always has an entry for the font's space glyph --- the
|
|
* width is assumed to be zero.
|
|
*/
|
|
class gfxGlyphExtents {
|
|
typedef mozilla::gfx::DrawTarget DrawTarget;
|
|
|
|
public:
|
|
explicit gfxGlyphExtents(int32_t aAppUnitsPerDevUnit)
|
|
: mAppUnitsPerDevUnit(aAppUnitsPerDevUnit),
|
|
mLock("gfxGlyphExtents lock") {
|
|
MOZ_COUNT_CTOR(gfxGlyphExtents);
|
|
}
|
|
~gfxGlyphExtents();
|
|
|
|
enum { INVALID_WIDTH = 0xFFFF };
|
|
|
|
void NotifyGlyphsChanged() {
|
|
mozilla::AutoWriteLock lock(mLock);
|
|
mTightGlyphExtents.Clear();
|
|
}
|
|
|
|
// returns INVALID_WIDTH => not a contained glyph
|
|
// Otherwise the glyph has no before-bearing or vertical bearings,
|
|
// and the result is its width measured from the baseline origin, in
|
|
// appunits.
|
|
uint16_t GetContainedGlyphWidthAppUnitsLocked(uint32_t aGlyphID) const
|
|
MOZ_REQUIRES_SHARED(mLock) {
|
|
return mContainedGlyphWidths.Get(aGlyphID);
|
|
}
|
|
|
|
bool IsGlyphKnownLocked(uint32_t aGlyphID) const MOZ_REQUIRES_SHARED(mLock) {
|
|
return mContainedGlyphWidths.Get(aGlyphID) != INVALID_WIDTH ||
|
|
mTightGlyphExtents.GetEntry(aGlyphID) != nullptr;
|
|
}
|
|
|
|
bool IsGlyphKnownWithTightExtentsLocked(uint32_t aGlyphID) const
|
|
MOZ_REQUIRES_SHARED(mLock) {
|
|
return mTightGlyphExtents.GetEntry(aGlyphID) != nullptr;
|
|
}
|
|
|
|
// Get glyph extents; a rectangle relative to the left baseline origin
|
|
// Returns true on success. Can fail on OOM or when aContext is null
|
|
// and extents were not (successfully) prefetched.
|
|
bool GetTightGlyphExtentsAppUnitsLocked(gfxFont* aFont,
|
|
DrawTarget* aDrawTarget,
|
|
uint32_t aGlyphID, gfxRect* aExtents)
|
|
MOZ_REQUIRES_SHARED(mLock);
|
|
bool GetTightGlyphExtentsAppUnits(gfxFont* aFont, DrawTarget* aDrawTarget,
|
|
uint32_t aGlyphID, gfxRect* aExtents) {
|
|
mozilla::AutoReadLock lock(mLock);
|
|
return GetTightGlyphExtentsAppUnitsLocked(aFont, aDrawTarget, aGlyphID,
|
|
aExtents);
|
|
}
|
|
|
|
void SetContainedGlyphWidthAppUnits(uint32_t aGlyphID, uint16_t aWidth) {
|
|
mozilla::AutoWriteLock lock(mLock);
|
|
mContainedGlyphWidths.Set(aGlyphID, aWidth);
|
|
}
|
|
void SetTightGlyphExtents(uint32_t aGlyphID, const gfxRect& aExtentsAppUnits);
|
|
|
|
int32_t GetAppUnitsPerDevUnit() { return mAppUnitsPerDevUnit; }
|
|
|
|
size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
|
|
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
|
|
|
|
private:
|
|
class HashEntry : public nsUint32HashKey {
|
|
public:
|
|
// When constructing a new entry in the hashtable, we'll leave this
|
|
// blank. The caller of Put() will fill this in.
|
|
explicit HashEntry(KeyTypePointer aPtr)
|
|
: nsUint32HashKey(aPtr), x(0.0), y(0.0), width(0.0), height(0.0) {}
|
|
HashEntry(HashEntry&& aOther)
|
|
: nsUint32HashKey(std::move(aOther)),
|
|
x(aOther.x),
|
|
y(aOther.y),
|
|
width(aOther.width),
|
|
height(aOther.height) {}
|
|
|
|
float x, y, width, height;
|
|
};
|
|
|
|
enum {
|
|
BLOCK_SIZE_BITS = 7,
|
|
BLOCK_SIZE = 1 << BLOCK_SIZE_BITS
|
|
}; // 128-glyph blocks
|
|
|
|
class GlyphWidths {
|
|
public:
|
|
void Set(uint32_t aIndex, uint16_t aValue);
|
|
uint16_t Get(uint32_t aIndex) const {
|
|
uint32_t block = aIndex >> BLOCK_SIZE_BITS;
|
|
if (block >= mBlocks.Length()) return INVALID_WIDTH;
|
|
uintptr_t bits = mBlocks[block];
|
|
if (!bits) return INVALID_WIDTH;
|
|
uint32_t indexInBlock = aIndex & (BLOCK_SIZE - 1);
|
|
if (bits & 0x1) {
|
|
if (GetGlyphOffset(bits) != indexInBlock) return INVALID_WIDTH;
|
|
return GetWidth(bits);
|
|
}
|
|
uint16_t* widths = reinterpret_cast<uint16_t*>(bits);
|
|
return widths[indexInBlock];
|
|
}
|
|
|
|
uint32_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
|
|
|
|
~GlyphWidths();
|
|
|
|
private:
|
|
static uint32_t GetGlyphOffset(uintptr_t aBits) {
|
|
NS_ASSERTION(aBits & 0x1, "This is really a pointer...");
|
|
return (aBits >> 1) & ((1 << BLOCK_SIZE_BITS) - 1);
|
|
}
|
|
static uint32_t GetWidth(uintptr_t aBits) {
|
|
NS_ASSERTION(aBits & 0x1, "This is really a pointer...");
|
|
return aBits >> (1 + BLOCK_SIZE_BITS);
|
|
}
|
|
static uintptr_t MakeSingle(uint32_t aGlyphOffset, uint16_t aWidth) {
|
|
return (aWidth << (1 + BLOCK_SIZE_BITS)) + (aGlyphOffset << 1) + 1;
|
|
}
|
|
|
|
nsTArray<uintptr_t> mBlocks;
|
|
};
|
|
|
|
GlyphWidths mContainedGlyphWidths MOZ_GUARDED_BY(mLock);
|
|
nsTHashtable<HashEntry> mTightGlyphExtents MOZ_GUARDED_BY(mLock);
|
|
const int32_t mAppUnitsPerDevUnit;
|
|
|
|
public:
|
|
mutable mozilla::RWLock mLock;
|
|
|
|
private:
|
|
// not implemented:
|
|
gfxGlyphExtents(const gfxGlyphExtents& aOther) = delete;
|
|
gfxGlyphExtents& operator=(const gfxGlyphExtents& aOther) = delete;
|
|
};
|
|
|
|
#endif
|