Mypal/gfx/thebes/gfxGlyphExtents.h

152 lines
5.3 KiB
C++

/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* 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 "nsTHashtable.h"
#include "nsHashKeys.h"
#include "nsTArray.h"
#include "mozilla/MemoryReporting.h"
class gfxContext;
struct gfxRect;
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) {
MOZ_COUNT_CTOR(gfxGlyphExtents);
}
~gfxGlyphExtents();
enum { INVALID_WIDTH = 0xFFFF };
void NotifyGlyphsChanged() {
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 GetContainedGlyphWidthAppUnits(uint32_t aGlyphID) const {
return mContainedGlyphWidths.Get(aGlyphID);
}
bool IsGlyphKnown(uint32_t aGlyphID) const {
return mContainedGlyphWidths.Get(aGlyphID) != INVALID_WIDTH ||
mTightGlyphExtents.GetEntry(aGlyphID) != nullptr;
}
bool IsGlyphKnownWithTightExtents(uint32_t aGlyphID) const {
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 GetTightGlyphExtentsAppUnits(gfxFont* aFont,
DrawTarget* aDrawTarget, uint32_t aGlyphID, gfxRect* aExtents);
void SetContainedGlyphWidthAppUnits(uint32_t aGlyphID, uint16_t aWidth) {
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) {}
HashEntry(const HashEntry& toCopy) : nsUint32HashKey(toCopy) {
x = toCopy.x; y = toCopy.y; width = toCopy.width; height = toCopy.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;
nsTHashtable<HashEntry> mTightGlyphExtents;
int32_t mAppUnitsPerDevUnit;
private:
// not implemented:
gfxGlyphExtents(const gfxGlyphExtents& aOther) = delete;
gfxGlyphExtents& operator=(const gfxGlyphExtents& aOther) = delete;
};
#endif