GlyphMap.cpp   [plain text]


/*
 * 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;
    UChar 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)
        m_filledPrimaryPage = true;
    else {
        if (!m_pages)
            m_pages = new HashMap<int, GlyphPage*>;
        m_pages->set(pageNumber, page);
    }

    return page;
}

}