+2006-05-17 David Hyatt <hyatt@apple.com>
+
+ Fix for 8954, separate the glyph map out into its own files and make it
+ cross-platform.
+
+ Reviewed by darin
+
+ * WebCore.xcodeproj/project.pbxproj:
+ * platform/Font.cpp:
+ (WebCore::WidthIterator::advance):
+ * platform/FontData.h:
+ (WebCore::FontData::glyphDataForCharacter):
+ (WebCore::FontData::setGlyphDataForCharacter):
+ * platform/GlyphMap.cpp: Added.
+ (WebCore::GlyphMap::glyphDataForCharacter):
+ (WebCore::GlyphMap::setGlyphDataForCharacter):
+ (WebCore::GlyphMap::locatePage):
+ * platform/GlyphMap.h: Added.
+ (WebCore::GlyphMap::GlyphMap):
+ (WebCore::GlyphMap::~GlyphMap):
+ (WebCore::GlyphMap::GlyphPage::glyphDataForCharacter):
+ (WebCore::GlyphMap::GlyphPage::setGlyphDataForCharacter):
+ (WebCore::GlyphMap::GlyphPage::setGlyphDataForIndex):
+ * platform/mac/FontData.mm:
+ (-[NSFont WebCore]):
+ (WidthMap::m_ATSUMirrors):
+ (WidthMap::FontData::~FontData):
+ (WidthMap::FontData::xHeight):
+ (WidthMap::FontData::platformInit):
+ (WidthMap::extendWidthMap):
+ * platform/mac/GlyphMapMac.cpp: Added.
+ (WebCore::GlyphMap::fillPage):
+ * platform/mac/WebCoreSystemInterface.h:
+
2006-05-17 Anders Carlsson <acarlsson@apple.com>
Reviewed by Maciej.
BC6DABF30A19015700E5CD14 /* FontCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC6DABF20A19015700E5CD14 /* FontCache.cpp */; };
BC6DADEF0A195FDF00E5CD14 /* WebFontCache.h in Headers */ = {isa = PBXBuildFile; fileRef = BC6DADEE0A195FDF00E5CD14 /* WebFontCache.h */; };
BC6DADFA0A19602B00E5CD14 /* WebFontCache.mm in Sources */ = {isa = PBXBuildFile; fileRef = BC6DADF90A19602B00E5CD14 /* WebFontCache.mm */; };
+ BC6DB3690A1A7CB700E5CD14 /* GlyphMap.h in Headers */ = {isa = PBXBuildFile; fileRef = BC6DB3680A1A7CB700E5CD14 /* GlyphMap.h */; };
+ BC6DB4740A1A90FB00E5CD14 /* GlyphMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC6DB4730A1A90FB00E5CD14 /* GlyphMap.cpp */; };
+ BC6DB4D40A1AFEEF00E5CD14 /* GlyphMapMac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC6DB4D30A1AFEEF00E5CD14 /* GlyphMapMac.cpp */; };
BC73E25D0978682700EDFF8A /* FloatSize.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC73E25B0978682700EDFF8A /* FloatSize.cpp */; };
BC73E25E0978682700EDFF8A /* FloatSize.h in Headers */ = {isa = PBXBuildFile; fileRef = BC73E25C0978682700EDFF8A /* FloatSize.h */; };
BC73E2FF0978AF9C00EDFF8A /* IntPointArray.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC73E2FC0978AF9C00EDFF8A /* IntPointArray.cpp */; };
BC6DABF20A19015700E5CD14 /* FontCache.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = FontCache.cpp; sourceTree = "<group>"; };
BC6DADEE0A195FDF00E5CD14 /* WebFontCache.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = WebFontCache.h; sourceTree = "<group>"; };
BC6DADF90A19602B00E5CD14 /* WebFontCache.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; path = WebFontCache.mm; sourceTree = "<group>"; };
+ BC6DB3680A1A7CB700E5CD14 /* GlyphMap.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = GlyphMap.h; sourceTree = "<group>"; };
+ BC6DB4730A1A90FB00E5CD14 /* GlyphMap.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = GlyphMap.cpp; sourceTree = "<group>"; };
+ BC6DB4D30A1AFEEF00E5CD14 /* GlyphMapMac.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = GlyphMapMac.cpp; sourceTree = "<group>"; };
BC73E25B0978682700EDFF8A /* FloatSize.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = FloatSize.cpp; sourceTree = "<group>"; };
BC73E25C0978682700EDFF8A /* FloatSize.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = FloatSize.h; sourceTree = "<group>"; };
BC73E2FC0978AF9C00EDFF8A /* IntPointArray.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = IntPointArray.cpp; sourceTree = "<group>"; };
6582A14809999D6C00BEEB6D /* mac */ = {
isa = PBXGroup;
children = (
+ BC6DB4D30A1AFEEF00E5CD14 /* GlyphMapMac.cpp */,
65A640F00533BB1F0085E777 /* BlockExceptions.h */,
65F80697054D9F86008BF776 /* BlockExceptions.mm */,
2D90660B0665D937006B6F1A /* ClipboardMac.h */,
BCC47E2409A3D6F100ADB771 /* FontFamily.cpp */,
BCC47E2509A3D6F100ADB771 /* FontFamily.h */,
BCC71A120A0FF94D0014EE6E /* GlyphBuffer.h */,
+ BC6DB3680A1A7CB700E5CD14 /* GlyphMap.h */,
+ BC6DB4730A1A90FB00E5CD14 /* GlyphMap.cpp */,
A823A75B09B6E53900B60641 /* GraphicsContext.cpp */,
935367E409AF77DD00D35CD6 /* GraphicsContext.h */,
938E685309F0BE04008A48EC /* GraphicsTypes.cpp */,
A80E73500A199C77007FB8C5 /* StyleBase.h in Headers */,
A80E73510A199C77007FB8C5 /* StyleList.h in Headers */,
A80E73520A199C77007FB8C5 /* CSSSelector.h in Headers */,
+ BC6DB3690A1A7CB700E5CD14 /* GlyphMap.h in Headers */,
A80E7A180A19C3D6007FB8C5 /* JSHTMLMetaElement.h in Headers */,
A80E7B0C0A19D606007FB8C5 /* JSHTMLTitleElement.h in Headers */,
A80E7B0D0A19D606007FB8C5 /* JSHTMLLinkElement.h in Headers */,
A80E7B120A19D606007FB8C5 /* JSHTMLBaseElement.cpp in Sources */,
A80E7B130A19D606007FB8C5 /* JSHTMLTitleElement.cpp in Sources */,
A80E7B140A19D606007FB8C5 /* JSHTMLHeadElement.cpp in Sources */,
+ BC6DB4740A1A90FB00E5CD14 /* GlyphMap.cpp in Sources */,
+ BC6DB4D40A1AFEEF00E5CD14 /* GlyphMapMac.cpp in Sources */,
1A9EF4570A1B957D00332B63 /* JSCanvasRenderingContext2DCustom.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
}
// FIXME: Should go through fallback list eventually when we rework the glyph map.
- Glyph glyph = fontData->glyphForCharacter(&fontData, c);
+ const GlyphData& glyphData = fontData->glyphDataForCharacter(c);
+ Glyph glyph = glyphData.glyph;
+ fontData = glyphData.fontData;
// Try to find a substitute font if this font didn't have a glyph for a character in the
// string. If one isn't found we end up drawing and measuring the 0 glyph, usually a box.
if (localGlyphBuffer.size() == 1) {
assert(substituteFontData == localGlyphBuffer.fontDataAt(0));
glyph = localGlyphBuffer.glyphAt(0);
- fontData->updateGlyphMapEntry(c, glyph, substituteFontData);
+ fontData->setGlyphDataForCharacter(c, glyph, substituteFontData);
fontData = substituteFontData;
}
}
// FIXME: This is going to be cross-platform eventually, but for now we just compile on OS X.
#include "FontPlatformData.h"
-#include "GlyphBuffer.h"
+#include "GlyphMap.h"
+#include <wtf/Noncopyable.h>
// FIXME: Temporary. Only needed to support API that's going to move.
#include <unicode/umachine.h>
class FontDescription;
-typedef struct WidthMap WidthMap;
-typedef struct GlyphMap GlyphMap;
+class WidthMap;
-class FontData
+class FontData : Noncopyable
{
public:
FontData(const FontPlatformData& f);
float xHeight() const;
- // FIXME: These are temporary API and will eventually move to the fallback list.
- Glyph glyphForCharacter(const FontData **renderer, unsigned c) const;
- void updateGlyphMapEntry(UChar c, Glyph glyph, const FontData *substituteRenderer) const;
- // End temporary API
-
float widthForGlyph(Glyph glyph) const;
bool containsCharacters(const UChar* characters, int length) const;
void determinePitch();
Pitch pitch() const { return m_treatAsFixedPitch ? FixedPitch : VariablePitch; }
+ // FIXME: Should go away when we pull the glyph map out of the FontData.
+ GlyphData glyphDataForCharacter(UChar32 c) const { return m_characterToGlyphMap.glyphDataForCharacter(c, this); }
+ void setGlyphDataForCharacter(UChar32 c, Glyph glyph, const FontData* fontData) const { m_characterToGlyphMap.setGlyphDataForCharacter(c, glyph, fontData); }
+
#if __APPLE__
NSFont* getNSFont() const { return m_font.font; }
#endif
+private:
+ bool platformInit();
+
public:
int m_ascent;
int m_descent;
void* m_styleGroup;
FontPlatformData m_font;
- mutable GlyphMap* m_characterToGlyphMap;
+ mutable GlyphMap m_characterToGlyphMap;
mutable WidthMap* m_glyphToWidthMap;
bool m_treatAsFixedPitch;
--- /dev/null
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "GlyphMap.h"
+#include "FontData.h"
+
+#include <unicode/uchar.h>
+
+#define NO_BREAK_SPACE 0x00A0
+#define ZERO_WIDTH_SPACE 0x200B
+
+namespace WebCore
+{
+
+GlyphData GlyphMap::glyphDataForCharacter(UChar32 c, const FontData* fontData)
+{
+ unsigned pageNumber = (c / cGlyphPageSize);
+ GlyphPage* page = locatePage(pageNumber, fontData);
+ if (page)
+ return page->glyphDataForCharacter(c);
+ GlyphData data = { 0, fontData };
+ return data;
+}
+
+void GlyphMap::setGlyphDataForCharacter(UChar32 c, Glyph glyph, const FontData* fontData)
+{
+ unsigned pageNumber = (c / cGlyphPageSize);
+ GlyphPage* page = locatePage(pageNumber, fontData);
+ if (page)
+ page->setGlyphDataForCharacter(c, glyph, fontData);
+}
+
+inline GlyphMap::GlyphPage* GlyphMap::locatePage(unsigned pageNumber, const FontData* fontData)
+{
+ GlyphPage* page;
+ if (pageNumber == 0) {
+ if (m_filledPrimaryPage)
+ return &m_primaryPage;
+ page = &m_primaryPage;
+ } else {
+ if (m_pages) {
+ GlyphPage* result = m_pages->get(pageNumber);
+ if (result)
+ return result;
+ }
+ page = new GlyphPage;
+ }
+
+ unsigned start = pageNumber * cGlyphPageSize;
+ unsigned short buffer[cGlyphPageSize * 2 + 2];
+ unsigned bufferLength;
+ unsigned i;
+
+ // Fill in a buffer with the entire "page" of characters that we want to look up glyphs for.
+ if (start < 0x10000) {
+ bufferLength = cGlyphPageSize;
+ for (i = 0; i < cGlyphPageSize; i++)
+ buffer[i] = start + i;
+
+ if (start == 0) {
+ // Control characters must not render at all.
+ for (i = 0; i < 0x20; ++i)
+ buffer[i] = ZERO_WIDTH_SPACE;
+ for (i = 0x7F; i < 0xA0; i++)
+ buffer[i] = ZERO_WIDTH_SPACE;
+
+ // \n, \t, and nonbreaking space must render as a space.
+ buffer[(int)'\n'] = ' ';
+ buffer[(int)'\t'] = ' ';
+ buffer[NO_BREAK_SPACE] = ' ';
+ }
+ } else {
+ bufferLength = cGlyphPageSize * 2;
+ for (i = 0; i < cGlyphPageSize; i++) {
+ int c = i + start;
+ buffer[i * 2] = U16_LEAD(c);
+ buffer[i * 2 + 1] = U16_TRAIL(c);
+ }
+ }
+
+ // Now that we have a buffer full of characters, we want to get back an array
+ // of glyph indices. This part involves calling into the platform-specific
+ // routine of our glyph map for actually filling in the page with the glyphs.
+ bool success = fillPage(page, buffer, bufferLength, fontData);
+ if (!success) {
+ if (pageNumber != 0)
+ delete page;
+ return 0;
+ }
+
+ if (pageNumber != 0) {
+ if (!m_pages)
+ m_pages = new HashMap<int, GlyphPage*>;
+ m_pages->set(pageNumber, page);
+ }
+
+ return page;
+}
+
+}
--- /dev/null
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef GLYPH_MAP_H
+#define GLYPH_MAP_H
+
+#include <unicode/umachine.h>
+#include "GlyphBuffer.h"
+#include <wtf/Noncopyable.h>
+#include <wtf/HashMap.h>
+
+namespace WebCore {
+
+// Covers Latin-1.
+const unsigned cGlyphPageSize = 256;
+
+class FontData;
+
+struct GlyphData
+{
+ Glyph glyph;
+ const FontData* fontData;
+};
+
+class GlyphMap : Noncopyable
+{
+public:
+ GlyphMap() : m_filledPrimaryPage(false), m_pages(0) {}
+ ~GlyphMap() { deleteAllValues(*m_pages); delete m_pages; }
+
+ GlyphData glyphDataForCharacter(UChar32, const FontData*);
+ void setGlyphDataForCharacter(UChar32, Glyph, const FontData*);
+
+private:
+ struct GlyphPage {
+ GlyphData m_glyphs[cGlyphPageSize];
+
+ const GlyphData& glyphDataForCharacter(UChar32 c) const { return m_glyphs[c % cGlyphPageSize]; }
+ void setGlyphDataForCharacter(UChar32 c, Glyph g, const FontData* f)
+ {
+ setGlyphDataForIndex(c % cGlyphPageSize, g, f);
+ }
+
+ void setGlyphDataForIndex(unsigned index, Glyph g, const FontData* f) {
+ m_glyphs[index].glyph = g;
+ m_glyphs[index].fontData = f;
+ }
+ };
+
+ GlyphPage* locatePage(unsigned page, const FontData* fontData);
+ bool fillPage(GlyphPage*, UChar* characterBuffer, unsigned bufferLength, const FontData* fontData);
+
+ bool m_filledPrimaryPage;
+ GlyphPage m_primaryPage; // We optimize for the page that contains Latin1.
+ HashMap<int, GlyphPage*>* m_pages;
+};
+
+}
+#endif
namespace WebCore
{
-// FIXME: FATAL seems like a bad idea; lets stop using it.
-
#define SMALLCAPS_FONTSIZE_MULTIPLIER 0.7f
-#define SYNTHETIC_OBLIQUE_ANGLE 14
-
-// Should be more than enough for normal usage.
-#define NUM_SUBSTITUTE_FONT_MAPS 10
-
#define SPACE 0x0020
-#define NO_BREAK_SPACE 0x00A0
-#define ZERO_WIDTH_SPACE 0x200B
-#define POP_DIRECTIONAL_FORMATTING 0x202C
-#define LEFT_TO_RIGHT_OVERRIDE 0x202D
-#define RIGHT_TO_LEFT_OVERRIDE 0x202E
-
-// MAX_GLYPH_EXPANSION is the maximum numbers of glyphs that may be
-// use to represent a single Unicode code point.
-#define MAX_GLYPH_EXPANSION 4
-#define LOCAL_BUFFER_SIZE 2048
-
-// Covers Latin-1.
-#define INITIAL_BLOCK_SIZE 0x200
-
-// Get additional blocks of glyphs and widths in bigger chunks.
-// This will typically be for other character sets.
-#define INCREMENTAL_BLOCK_SIZE 0x400
-
#define CONTEXT_DPI (72.0)
#define SCALE_EM_TO_UNITS(X, U_PER_EM) (X * ((1.0 * CONTEXT_DPI) / (CONTEXT_DPI * U_PER_EM)))
-#define WKGlyphVectorSize (50 * 32)
-
typedef float WebGlyphWidth;
struct WidthMap {
WebGlyphWidth *widths;
};
-typedef struct GlyphEntry {
- Glyph glyph;
- const FontData *renderer;
-} GlyphEntry;
-
-struct GlyphMap {
- UChar startRange;
- UChar endRange;
- GlyphMap *next;
- GlyphEntry *glyphs;
-};
-
static WidthMap *extendWidthMap(const FontData *, ATSGlyphRef);
-static ATSGlyphRef extendGlyphMap(const FontData *, UChar32);
static void freeWidthMap(WidthMap *);
-static void freeGlyphMap(GlyphMap *);
-
-static bool setUpFont(FontData *);
-
-static bool fillStyleWithAttributes(ATSUStyle style, NSFont *theFont);
#if !ERROR_DISABLED
static NSString *pathFromFont(NSFont *font);
}
FontData::FontData(const FontPlatformData& f)
-:m_styleGroup(0), m_font(f), m_characterToGlyphMap(0), m_glyphToWidthMap(0), m_treatAsFixedPitch(false),
+:m_styleGroup(0), m_font(f), m_glyphToWidthMap(0), m_treatAsFixedPitch(false),
m_smallCapsFontData(0), m_ATSUStyleInitialized(false), m_ATSUMirrors(false)
{
m_font = f;
m_syntheticBoldOffset = f.syntheticBold ? ceilf([f.font pointSize] / 24.0f) : 0.f;
bool failedSetup = false;
- if (!setUpFont(this)) {
+ if (!platformInit()) {
// Ack! Something very bad happened, like a corrupt font.
// Try looking for an alternate 'base' font for this renderer.
if (!filePath)
filePath = @"not known";
#endif
- if (!setUpFont(this)) {
+ if (!platformInit()) {
if ([fallbackFontFamily isEqual:@"Times New Roman"]) {
// OK, couldn't setup Times New Roman as an alternate to Times, fallback
// on the system font. If this fails we have no alternative left.
m_font.font = [[NSFontManager sharedFontManager] convertFont:m_font.font toFamily:webFallbackFontFamily()];
- if (!setUpFont(this)) {
+ if (!platformInit()) {
// We tried, Times, Times New Roman, and the system font. No joy. We have to give up.
LOG_ERROR("unable to initialize with font %@ at %@", initialFont, filePath);
failedSetup = true;
if (failedSetup) {
m_font.font = [NSFont systemFontOfSize:[m_font.font pointSize]];
LOG_ERROR("failed to set up font, using system font %s", m_font.font);
- setUpFont(this);
+ platformInit();
}
int iAscent;
wkReleaseStyleGroup(m_styleGroup);
freeWidthMap(m_glyphToWidthMap);
- freeGlyphMap(m_characterToGlyphMap);
if (m_ATSUStyleInitialized)
ATSUDisposeStyle(m_ATSUStyle);
{
// Measure the actual character "x", because AppKit synthesizes X height rather than getting it from the font.
// Unfortunately, NSFont will round this for us so we don't quite get the right value.
- const FontData *renderer = this;
- NSGlyph xGlyph = glyphForCharacter(&renderer, 'x');
+ NSGlyph xGlyph = m_characterToGlyphMap.glyphDataForCharacter('x', this).glyph;
if (xGlyph) {
NSRect xBox = [m_font.font boundingRectForGlyph:xGlyph];
// Use the maximum of either width or height because "x" is nearly square
return result;
}
-// Nasty hack to determine if we should round or ceil space widths.
-// If the font is monospace or fake monospace we ceil to ensure that
-// every character and the space are the same width. Otherwise we round.
-static bool computeWidthForSpace(FontData *renderer)
-{
- renderer->m_spaceGlyph = extendGlyphMap(renderer, SPACE);
- if (renderer->m_spaceGlyph == 0)
- return false;
-
- float width = renderer->widthForGlyph(renderer->m_spaceGlyph);
-
- renderer->m_spaceWidth = width;
-
- renderer->determinePitch();
- renderer->m_adjustedSpaceWidth = renderer->m_treatAsFixedPitch ? ceilf(width) : roundf(width);
-
- return true;
-}
-
-static bool setUpFont(FontData *renderer)
+bool FontData::platformInit()
{
ATSUStyle fontStyle;
if (ATSUCreateStyle(&fontStyle) != noErr)
return false;
+
+ ATSUFontID fontId = wkGetNSFontATSUFontId(m_font.font);
+ if (!fontId) {
+ ATSUDisposeStyle(fontStyle);
+ return false;
+ }
- if (!fillStyleWithAttributes(fontStyle, renderer->m_font.font)) {
+ ATSUAttributeTag tag = kATSUFontTag;
+ ByteCount size = sizeof(ATSUFontID);
+ ATSUFontID *valueArray[1] = {&fontId};
+ OSStatus status = ATSUSetAttributes(fontStyle, 1, &tag, &size, (void* const*)valueArray);
+ if (status != noErr) {
ATSUDisposeStyle(fontStyle);
return false;
}
- if (wkGetATSStyleGroup(fontStyle, &renderer->m_styleGroup) != noErr) {
+ if (wkGetATSStyleGroup(fontStyle, &m_styleGroup) != noErr) {
ATSUDisposeStyle(fontStyle);
return false;
}
ATSUDisposeStyle(fontStyle);
- if (!computeWidthForSpace(renderer)) {
- freeGlyphMap(renderer->m_characterToGlyphMap);
- renderer->m_characterToGlyphMap = 0;
- wkReleaseStyleGroup(renderer->m_styleGroup);
- renderer->m_styleGroup = 0;
+ // Nasty hack to determine if we should round or ceil space widths.
+ // If the font is monospace or fake monospace we ceil to ensure that
+ // every character and the space are the same width. Otherwise we round.
+ m_spaceGlyph = m_characterToGlyphMap.glyphDataForCharacter(SPACE, this).glyph;
+ if (m_spaceGlyph == 0) {
+ wkReleaseStyleGroup(m_styleGroup);
+ m_styleGroup = 0;
return false;
}
+
+ float width = widthForGlyph(m_spaceGlyph);
+
+ m_spaceWidth = width;
+
+ determinePitch();
+ m_adjustedSpaceWidth = m_treatAsFixedPitch ? ceilf(width) : roundf(width);
return true;
}
#endif
-void FontData::updateGlyphMapEntry(UChar c, ATSGlyphRef glyph, const FontData *substituteRenderer) const
-{
- GlyphMap *map;
- for (map = m_characterToGlyphMap; map; map = map->next) {
- UChar32 start = map->startRange;
- if (c >= start && c <= map->endRange) {
- int i = c - start;
- map->glyphs[i].glyph = glyph;
- // This renderer will leak.
- // No problem though; we want it to stick around forever.
- // Max theoretical retain counts applied here will be num_fonts_on_system * num_glyphs_in_font.
- map->glyphs[i].renderer = substituteRenderer;
- break;
- }
- }
-}
-
-static ATSGlyphRef extendGlyphMap(const FontData *renderer, UChar32 c)
-{
- GlyphMap *map = new GlyphMap;
- ATSLayoutRecord *glyphRecord;
- char glyphVector[WKGlyphVectorSize];
- UChar32 end, start;
- unsigned blockSize;
-
- if (renderer->m_characterToGlyphMap == 0)
- blockSize = INITIAL_BLOCK_SIZE;
- else
- blockSize = INCREMENTAL_BLOCK_SIZE;
- start = (c / blockSize) * blockSize;
- end = start + (blockSize - 1);
-
- map->startRange = start;
- map->endRange = end;
- map->next = 0;
-
- unsigned i;
- unsigned count = end - start + 1;
- unsigned short buffer[INCREMENTAL_BLOCK_SIZE * 2 + 2];
- unsigned bufferLength;
-
- if (start < 0x10000) {
- bufferLength = count;
- for (i = 0; i < count; i++)
- buffer[i] = i + start;
-
- if (start == 0) {
- // Control characters must not render at all.
- for (i = 0; i < 0x20; ++i)
- buffer[i] = ZERO_WIDTH_SPACE;
- buffer[0x7F] = ZERO_WIDTH_SPACE;
-
- // But \n, \t, and nonbreaking space must render as a space.
- buffer[(int)'\n'] = ' ';
- buffer[(int)'\t'] = ' ';
- buffer[NO_BREAK_SPACE] = ' ';
- }
- } else {
- bufferLength = count * 2;
- for (i = 0; i < count; i++) {
- int c = i + start;
- buffer[i * 2] = U16_LEAD(c);
- buffer[i * 2 + 1] = U16_TRAIL(c);
- }
- }
-
- OSStatus status = wkInitializeGlyphVector(count, &glyphVector);
- if (status != noErr) {
- // This should never happen, perhaps indicates a bad font! If it does the
- // font substitution code will find an alternate font.
- delete map;
- return 0;
- }
-
- wkConvertCharToGlyphs(renderer->m_styleGroup, &buffer[0], bufferLength, &glyphVector);
- unsigned numGlyphs = wkGetGlyphVectorNumGlyphs(&glyphVector);
- if (numGlyphs != count) {
- // This should never happen, perhaps indicates a bad font?
- // If it does happen, the font substitution code will find an alternate font.
- wkClearGlyphVector(&glyphVector);
- delete map;
- return 0;
- }
-
- map->glyphs = new GlyphEntry[count];
- glyphRecord = (ATSLayoutRecord *)wkGetGlyphVectorFirstRecord(glyphVector);
- for (i = 0; i < count; i++) {
- map->glyphs[i].glyph = glyphRecord->glyphID;
- map->glyphs[i].renderer = renderer;
- glyphRecord = (ATSLayoutRecord *)((char *)glyphRecord + wkGetGlyphVectorRecordSize(glyphVector));
- }
- wkClearGlyphVector(&glyphVector);
-
- if (renderer->m_characterToGlyphMap == 0)
- renderer->m_characterToGlyphMap = map;
- else {
- GlyphMap *lastMap = renderer->m_characterToGlyphMap;
- while (lastMap->next != 0)
- lastMap = lastMap->next;
- lastMap->next = map;
- }
-
- ATSGlyphRef glyph = map->glyphs[c - start].glyph;
-
- // Special case for characters 007F-00A0.
- if (glyph == 0 && c >= 0x7F && c <= 0xA0) {
- glyph = wkGetDefaultGlyphForChar(renderer->m_font.font, c);
- map->glyphs[c - start].glyph = glyph;
- }
-
- return glyph;
-}
-
static WidthMap *extendWidthMap(const FontData *renderer, ATSGlyphRef glyph)
{
WidthMap *map = new WidthMap;
unsigned i, count;
NSFont *f = renderer->m_font.font;
- if (renderer->m_glyphToWidthMap == 0) {
- if ([f numberOfGlyphs] < INITIAL_BLOCK_SIZE)
- blockSize = [f numberOfGlyphs];
- else
- blockSize = INITIAL_BLOCK_SIZE;
- } else {
- blockSize = INCREMENTAL_BLOCK_SIZE;
- }
- if (blockSize == 0) {
+ if (renderer->m_glyphToWidthMap == 0 && [f numberOfGlyphs] < cGlyphPageSize)
+ blockSize = [f numberOfGlyphs];
+ else
+ blockSize = cGlyphPageSize;
+
+ if (blockSize == 0)
start = 0;
- } else {
+ else
start = (glyph / blockSize) * blockSize;
- }
+
end = ((unsigned)start) + blockSize;
map->startRange = start;
}
}
-static void freeGlyphMap(GlyphMap *map)
-{
- while (map) {
- GlyphMap *next = map->next;
- delete []map->glyphs;
- delete map;
- map = next;
- }
-}
-
-Glyph FontData::glyphForCharacter(const FontData **renderer, unsigned c) const
-{
- // this loop is hot, so it is written to avoid LSU stalls
- GlyphMap *map;
- GlyphMap *nextMap;
- for (map = (*renderer)->m_characterToGlyphMap; map; map = nextMap) {
- UChar start = map->startRange;
- nextMap = map->next;
- if (c >= start && c <= map->endRange) {
- GlyphEntry *ge = &map->glyphs[c - start];
- *renderer = ge->renderer;
- return ge->glyph;
- }
- }
-
- return extendGlyphMap(*renderer, c);
-}
-
-static bool fillStyleWithAttributes(ATSUStyle style, NSFont *theFont)
-{
- if (!theFont)
- return false;
- ATSUFontID fontId = wkGetNSFontATSUFontId(theFont);
- if (!fontId)
- return false;
- ATSUAttributeTag tag = kATSUFontTag;
- ByteCount size = sizeof(ATSUFontID);
- ATSUFontID *valueArray[1] = {&fontId};
- OSStatus status = ATSUSetAttributes(style, 1, &tag, &size, (void* const*)valueArray);
- if (status != noErr)
- return false;
- return true;
-}
-
void FontData::determinePitch()
{
NSFont* f = m_font.font;
--- /dev/null
+/*
+ * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "GlyphMap.h"
+#include "FontData.h"
+#include "WebCoreSystemInterface.h"
+
+namespace WebCore
+{
+
+bool GlyphMap::fillPage(GlyphPage* page, UChar* buffer, unsigned bufferLength, const FontData* fontData)
+{
+ // Use an array of long so we get good enough alignment.
+ long glyphVector[(GLYPH_VECTOR_SIZE + sizeof(long) - 1) / sizeof(long)];
+
+ OSStatus status = wkInitializeGlyphVector(cGlyphPageSize, &glyphVector);
+ if (status != noErr)
+ // This should never happen, perhaps indicates a bad font! If it does the
+ // font substitution code will find an alternate font.
+ return false;
+
+ wkConvertCharToGlyphs(fontData->m_styleGroup, buffer, bufferLength, &glyphVector);
+
+ unsigned numGlyphs = wkGetGlyphVectorNumGlyphs(&glyphVector);
+ if (numGlyphs != cGlyphPageSize) {
+ // This should never happen, perhaps indicates a bad font?
+ // If it does happen, the font substitution code will find an alternate font.
+ wkClearGlyphVector(&glyphVector);
+ return false;
+ }
+
+ ATSLayoutRecord* glyphRecord = (ATSLayoutRecord*)wkGetGlyphVectorFirstRecord(glyphVector);
+ for (unsigned i = 0; i < cGlyphPageSize; i++) {
+ page->setGlyphDataForIndex(i, glyphRecord->glyphID, fontData);
+ glyphRecord = (ATSLayoutRecord *)((char *)glyphRecord + wkGetGlyphVectorRecordSize(glyphVector));
+ }
+ wkClearGlyphVector(&glyphVector);
+
+ return true;
+}
+
+}
\ No newline at end of file
#define WebCoreSystemInterface_h
typedef signed char BOOL;
+typedef struct _NSPoint NSPoint;
typedef struct _NSRange NSRange;
+typedef struct _NSRect NSRect;
+
+#ifndef __OBJC__
+class NSImage;
+class NSString;
+#endif
#ifdef __cplusplus
extern "C" {
#endif
+#define GLYPH_VECTOR_SIZE (50 * 32)
+
// In alphabetical order.
extern BOOL (*wkCGContextGetShouldSmoothFonts)(CGContextRef);