/* -*- 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/. */ #include "gfxGlyphExtents.h" #include "gfxTextRun.h" using namespace mozilla; #ifdef DEBUG_roc #define DEBUG_TEXT_RUN_STORAGE_METRICS #endif #ifdef DEBUG_TEXT_RUN_STORAGE_METRICS extern uint32_t gTextRunStorageHighWaterMark; extern uint32_t gTextRunStorage; extern uint32_t gFontCount; extern uint32_t gGlyphExtentsCount; extern uint32_t gGlyphExtentsWidthsTotalSize; extern uint32_t gGlyphExtentsSetupEagerSimple; extern uint32_t gGlyphExtentsSetupEagerTight; extern uint32_t gGlyphExtentsSetupLazyTight; extern uint32_t gGlyphExtentsSetupFallBackToTight; #endif gfxGlyphExtents::~gfxGlyphExtents() { #ifdef DEBUG_TEXT_RUN_STORAGE_METRICS gGlyphExtentsWidthsTotalSize += mContainedGlyphWidths.SizeOfExcludingThis(&FontCacheMallocSizeOf); gGlyphExtentsCount++; #endif MOZ_COUNT_DTOR(gfxGlyphExtents); } bool gfxGlyphExtents::GetTightGlyphExtentsAppUnits(gfxFont* aFont, DrawTarget* aDrawTarget, uint32_t aGlyphID, gfxRect* aExtents) { HashEntry *entry = mTightGlyphExtents.GetEntry(aGlyphID); if (!entry) { // Some functions higher up in the call chain deliberately pass in a // nullptr DrawTarget, e.g. GetBaselinePosition() passes nullptr to // gfxTextRun::MeasureText() and that nullptr reaches here. if (!aDrawTarget) { NS_WARNING("Could not get glyph extents (no aDrawTarget)"); return false; } if (aFont->SetupCairoFont(aDrawTarget)) { #ifdef DEBUG_TEXT_RUN_STORAGE_METRICS ++gGlyphExtentsSetupLazyTight; #endif aFont->SetupGlyphExtents(aDrawTarget, aGlyphID, true, this); entry = mTightGlyphExtents.GetEntry(aGlyphID); } if (!entry) { NS_WARNING("Could not get glyph extents"); return false; } } *aExtents = gfxRect(entry->x, entry->y, entry->width, entry->height); return true; } gfxGlyphExtents::GlyphWidths::~GlyphWidths() { uint32_t i, count = mBlocks.Length(); for (i = 0; i < count; ++i) { uintptr_t bits = mBlocks[i]; if (bits && !(bits & 0x1)) { delete[] reinterpret_cast(bits); } } } uint32_t gfxGlyphExtents::GlyphWidths::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const { uint32_t i; uint32_t size = mBlocks.ShallowSizeOfExcludingThis(aMallocSizeOf); for (i = 0; i < mBlocks.Length(); ++i) { uintptr_t bits = mBlocks[i]; if (bits && !(bits & 0x1)) { size += aMallocSizeOf(reinterpret_cast(bits)); } } return size; } void gfxGlyphExtents::GlyphWidths::Set(uint32_t aGlyphID, uint16_t aWidth) { uint32_t block = aGlyphID >> BLOCK_SIZE_BITS; uint32_t len = mBlocks.Length(); if (block >= len) { uintptr_t *elems = mBlocks.AppendElements(block + 1 - len); if (!elems) return; memset(elems, 0, sizeof(uintptr_t)*(block + 1 - len)); } uintptr_t bits = mBlocks[block]; uint32_t glyphOffset = aGlyphID & (BLOCK_SIZE - 1); if (!bits) { mBlocks[block] = MakeSingle(glyphOffset, aWidth); return; } uint16_t *newBlock; if (bits & 0x1) { // Expand the block to a real block. We could avoid this by checking // glyphOffset == GetGlyphOffset(bits), but that never happens so don't bother newBlock = new uint16_t[BLOCK_SIZE]; if (!newBlock) return; uint32_t i; for (i = 0; i < BLOCK_SIZE; ++i) { newBlock[i] = INVALID_WIDTH; } newBlock[GetGlyphOffset(bits)] = GetWidth(bits); mBlocks[block] = reinterpret_cast(newBlock); } else { newBlock = reinterpret_cast(bits); } newBlock[glyphOffset] = aWidth; } void gfxGlyphExtents::SetTightGlyphExtents(uint32_t aGlyphID, const gfxRect& aExtentsAppUnits) { HashEntry *entry = mTightGlyphExtents.PutEntry(aGlyphID); if (!entry) return; entry->x = aExtentsAppUnits.X(); entry->y = aExtentsAppUnits.Y(); entry->width = aExtentsAppUnits.Width(); entry->height = aExtentsAppUnits.Height(); } size_t gfxGlyphExtents::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const { return mContainedGlyphWidths.SizeOfExcludingThis(aMallocSizeOf) + mTightGlyphExtents.ShallowSizeOfExcludingThis(aMallocSizeOf); } size_t gfxGlyphExtents::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const { return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); }