#ifndef GlyphPage_h
#define GlyphPage_h
#include "Glyph.h"
#include <string.h>
#include <unicode/utypes.h>
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
#include <wtf/RefPtr.h>
namespace WebCore {
class Font;
struct GlyphData {
GlyphData(Glyph g = 0, const Font* f = 0)
: glyph(g)
, font(f)
{
}
Glyph glyph;
const Font* font;
};
#if COMPILER(MSVC)
#pragma warning(push)
#pragma warning(disable: 4200) // Disable "zero-sized array in struct/union" warning
#endif
class GlyphPage : public RefCounted<GlyphPage> {
public:
static PassRefPtr<GlyphPage> createForMixedFonts()
{
void* slot = fastMalloc(sizeof(GlyphPage) + sizeof(Font*) * GlyphPage::size);
return adoptRef(new (NotNull, slot) GlyphPage(nullptr));
}
static PassRefPtr<GlyphPage> createCopyForMixedFonts(const GlyphPage& original)
{
RefPtr<GlyphPage> page = createForMixedFonts();
for (unsigned i = 0; i < GlyphPage::size; ++i)
page->setGlyphDataForIndex(i, original.glyphDataForIndex(i));
return page.release();
}
static PassRefPtr<GlyphPage> createForSingleFont(const Font* font)
{
ASSERT(font);
return adoptRef(new GlyphPage(font));
}
~GlyphPage()
{
--s_count;
}
bool isImmutable() const { return m_isImmutable; }
void setImmutable() { m_isImmutable = true; }
static unsigned count() { return s_count; }
static const size_t size = 256; static_assert((!(0xD800 % size)) && (!(0xDC00 % size)) && (!(0xE000 % size)), "GlyphPages must never straddle code-unit length boundaries");
static unsigned indexForCharacter(UChar32 c) { return c % GlyphPage::size; }
ALWAYS_INLINE GlyphData glyphDataForCharacter(UChar32 c) const
{
return glyphDataForIndex(indexForCharacter(c));
}
ALWAYS_INLINE GlyphData glyphDataForIndex(unsigned index) const
{
ASSERT_WITH_SECURITY_IMPLICATION(index < size);
Glyph glyph = m_glyphs[index];
if (hasPerGlyphFontData())
return GlyphData(glyph, m_perGlyphFontData[index]);
return GlyphData(glyph, glyph ? m_fontForAllGlyphs : 0);
}
ALWAYS_INLINE Glyph glyphAt(unsigned index) const
{
ASSERT_WITH_SECURITY_IMPLICATION(index < size);
return m_glyphs[index];
}
ALWAYS_INLINE const Font* fontForCharacter(UChar32 c) const
{
unsigned index = indexForCharacter(c);
if (hasPerGlyphFontData())
return m_perGlyphFontData[index];
return m_glyphs[index] ? m_fontForAllGlyphs : 0;
}
void setGlyphDataForCharacter(UChar32 c, Glyph g, const Font* f)
{
setGlyphDataForIndex(indexForCharacter(c), g, f);
}
void setGlyphDataForIndex(unsigned index, Glyph glyph, const Font* font)
{
ASSERT_WITH_SECURITY_IMPLICATION(index < size);
ASSERT(!m_isImmutable);
m_glyphs[index] = glyph;
if (hasPerGlyphFontData()) {
m_perGlyphFontData[index] = glyph ? font : 0;
return;
}
ASSERT(!glyph || font == m_fontForAllGlyphs);
}
void setGlyphDataForIndex(unsigned index, const GlyphData& glyphData)
{
setGlyphDataForIndex(index, glyphData.glyph, glyphData.font);
}
bool fill(unsigned offset, unsigned length, UChar* characterBuffer, unsigned bufferLength, const Font*);
#if PLATFORM(COCOA)
static bool mayUseMixedFontsWhenFilling(const UChar* characterBuffer, unsigned bufferLength, const Font*);
#else
static bool mayUseMixedFontsWhenFilling(const UChar*, unsigned, const Font*) { return false; }
#endif
private:
explicit GlyphPage(const Font* fontForAllGlyphs)
: m_fontForAllGlyphs(fontForAllGlyphs)
{
memset(m_glyphs, 0, sizeof(m_glyphs));
if (hasPerGlyphFontData())
memset(m_perGlyphFontData, 0, sizeof(Font*) * GlyphPage::size);
++s_count;
}
bool hasPerGlyphFontData() const { return !m_fontForAllGlyphs; }
const Font* m_fontForAllGlyphs;
Glyph m_glyphs[size];
bool m_isImmutable { false };
const Font* m_perGlyphFontData[0];
WEBCORE_EXPORT static unsigned s_count;
};
#if COMPILER(MSVC)
#pragma warning(pop)
#endif
}
#endif // GlyphPage_h