blob: bd8f102454a32cad8cdd8b591ceb4e95afc50b99 [file] [log] [blame]
/*
* Copyright 2006 The Android Open Source Project
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkFontHost.h"
#include "SkDescriptor.h"
#include "SkString.h"
#include "SkStream.h"
#include <stdio.h>
/* define this if we can use mmap() to access fonts from the filesystem */
#define SK_CAN_USE_MMAP
#ifndef SK_FONTPATH
#define SK_FONTPATH "the complete path for a font file"
#endif
struct FontFaceRec {
const char* fFileName;
uint8_t fFamilyIndex;
SkBool8 fBold;
SkBool8 fItalic;
static const FontFaceRec& FindFace(const FontFaceRec rec[], int count,
int isBold, int isItalic);
};
struct FontFamilyRec {
const FontFaceRec* fFaces;
int fFaceCount;
};
const FontFaceRec& FontFaceRec::FindFace(const FontFaceRec rec[], int count,
int isBold, int isItalic)
{
SkASSERT(count > 0);
int i;
// look for an exact match
for (i = 0; i < count; i++) {
if (rec[i].fBold == isBold && rec[i].fItalic == isItalic)
return rec[i];
}
// look for a match in the bold field
for (i = 0; i < count; i++) {
if (rec[i].fBold == isBold)
return rec[i];
}
// look for a normal/regular face
for (i = 0; i < count; i++) {
if (!rec[i].fBold && !rec[i].fItalic)
return rec[i];
}
// give up
return rec[0];
}
enum {
DEFAULT_FAMILY_INDEX,
FAMILY_INDEX_COUNT
};
static const FontFaceRec gDefaultFaces[] = {
{ SK_FONTPATH, DEFAULT_FAMILY_INDEX, 0, 0 }
};
// This table must be in the same order as the ..._FAMILY_INDEX enum specifies
static const FontFamilyRec gFamilies[] = {
{ gDefaultFaces, SK_ARRAY_COUNT(gDefaultFaces) }
};
#define DEFAULT_FAMILY_INDEX DEFAULT_FAMILY_INDEX
#define DEFAULT_FAMILY_FACE_INDEX 0
///////////////////////////////////////////////////////////////////////////////
/* map common "web" font names to our font list */
struct FontFamilyMatchRec {
const char* fLCName;
int fFamilyIndex;
};
/* This is a table of synonyms for collapsing font names
down to their pseudo-equivalents (i.e. in terms of fonts
we actually have.)
Keep this sorted by the first field so we can do a binary search.
If this gets big, we could switch to a hash...
*/
static const FontFamilyMatchRec gMatches[] = {
#if 0
{ "Ahem", Ahem_FAMILY_INDEX },
{ "arial", SANS_FAMILY_INDEX },
{ "courier", MONO_FAMILY_INDEX },
{ "courier new", MONO_FAMILY_INDEX },
{ "cursive", SERIF_FAMILY_INDEX },
{ "fantasy", SERIF_FAMILY_INDEX },
{ "georgia", SERIF_FAMILY_INDEX },
{ "goudy", SERIF_FAMILY_INDEX },
{ "helvetica", SANS_FAMILY_INDEX },
{ "palatino", SERIF_FAMILY_INDEX },
{ "tahoma", SANS_FAMILY_INDEX },
{ "sans-serif", SANS_FAMILY_INDEX },
{ "serif", SERIF_FAMILY_INDEX },
{ "times", SERIF_FAMILY_INDEX },
{ "times new roman", SERIF_FAMILY_INDEX },
{ "verdana", SANS_FAMILY_INDEX }
#endif
};
///////////////////////////////////////////////////////////////////////////////
#include "SkTSearch.h"
static bool contains_only_ascii(const char s[])
{
for (;;)
{
int c = *s++;
if (c == 0)
break;
if ((c >> 7) != 0)
return false;
}
return true;
}
#define TRACE_FONT_NAME(code)
//#define TRACE_FONT_NAME(code) code
const FontFamilyRec* find_family_rec(const char target[])
{
int index;
// If we're asked for a font name that contains non-ascii,
// 1) SkStrLCSearch can't handle it
// 2) All of our fonts are have ascii names, so...
TRACE_FONT_NAME(printf("----------------- font request <%s>", target);)
if (contains_only_ascii(target))
{
// Search for the font by matching the entire name
index = SkStrLCSearch(&gMatches[0].fLCName, SK_ARRAY_COUNT(gMatches),
target, sizeof(gMatches[0]));
if (index >= 0)
{
TRACE_FONT_NAME(printf(" found %d\n", index);)
return &gFamilies[gMatches[index].fFamilyIndex];
}
}
// Sniff for key words...
#if 0
if (strstr(target, "sans") || strstr(target, "Sans"))
{
TRACE_FONT_NAME(printf(" found sans\n");)
return &gFamilies[SANS_FAMILY_INDEX];
}
if (strstr(target, "serif") || strstr(target, "Serif"))
{
TRACE_FONT_NAME(printf(" found serif\n");)
return &gFamilies[SERIF_FAMILY_INDEX];
}
if (strstr(target, "mono") || strstr(target, "Mono"))
{
TRACE_FONT_NAME(printf(" found mono\n");)
return &gFamilies[MONO_FAMILY_INDEX];
}
#endif
TRACE_FONT_NAME(printf(" use default\n");)
// we give up, just give them the default font
return &gFamilies[DEFAULT_FAMILY_INDEX];
}
///////////////////////////////////////////////////////////////////////////////
static const FontFaceRec* get_default_face()
{
return &gFamilies[DEFAULT_FAMILY_INDEX].fFaces[DEFAULT_FAMILY_FACE_INDEX];
}
static SkTypeface::Style get_style(const FontFaceRec& face) {
int style = 0;
if (face.fBold) {
style |= SkTypeface::kBold;
}
if (face.fItalic) {
style |= SkTypeface::kItalic;
}
return static_cast<SkTypeface::Style>(style);
}
// This global const reference completely identifies the face
static uint32_t get_id(const FontFaceRec& face) {
uintptr_t id = reinterpret_cast<uintptr_t>(&face);
return static_cast<uint32_t>(id);
}
class FontFaceRec_Typeface : public SkTypeface {
public:
FontFaceRec_Typeface(const FontFaceRec& face) :
SkTypeface(get_style(face), get_id(face)),
fFace(face)
{
}
// This global const reference completely identifies the face
const FontFaceRec& fFace;
};
static const FontFaceRec* get_typeface_rec(const SkTypeface* face)
{
const FontFaceRec_Typeface* f = (FontFaceRec_Typeface*)face;
return f ? &f->fFace : get_default_face();
}
static uint32_t ptr2uint32(const void* p)
{
// cast so we avoid warnings on 64bit machines that a ptr difference
// which might be 64bits is being trucated from 64 to 32
return (uint32_t)((char*)p - (char*)0);
}
SkTypeface* SkFontHost::CreateTypeface(const SkTypeface* familyFace,
const char familyName[],
const void* data, size_t bytelength,
SkTypeface::Style style)
{
const FontFamilyRec* family;
if (familyFace)
family = &gFamilies[
((FontFaceRec_Typeface*)familyFace)->fFace.fFamilyIndex];
else if (familyName)
family = find_family_rec(familyName);
else
family = &gFamilies[DEFAULT_FAMILY_INDEX];
const FontFaceRec& face = FontFaceRec::FindFace(family->fFaces,
family->fFaceCount,
(style & SkTypeface::kBold) != 0,
(style & SkTypeface::kItalic) != 0);
// if we're returning our input parameter, no need to create a new instance
if (familyFace != NULL &&
&((FontFaceRec_Typeface*)familyFace)->fFace == &face)
{
familyFace->ref();
return (SkTypeface*)familyFace;
}
return SkNEW_ARGS(FontFaceRec_Typeface, (face));
}
// static
SkAdvancedTypefaceMetrics* SkFontHost::GetAdvancedTypefaceMetrics(
uint32_t fontID,
SkAdvancedTypefaceMetrics::PerGlyphInfo perGlyphInfo) {
sk_throw(); // not implemented
return NULL;
}
SkTypeface* SkFontHost::CreateTypefaceFromStream(SkStream* stream) {
sk_throw(); // not implemented
return NULL;
}
SkTypeface* SkFontHost::CreateTypefaceFromFile(const char path[]) {
sk_throw(); // not implemented
return NULL;
}
SkStream* SkFontHost::OpenStream(uint32_t fontID) {
sk_throw(); // not implemented
return NULL;
}
size_t SkFontHost::GetFileName(SkFontID fontID, char path[], size_t length,
int32_t* index) {
SkDebugf("SkFontHost::GetFileName unimplemented\n");
return 0;
}
void SkFontHost::Serialize(const SkTypeface* tface, SkWStream* stream) {
const FontFaceRec* face = &((const FontFaceRec_Typeface*)tface)->fFace;
stream->write(face, sizeof(face));
}
SkTypeface* SkFontHost::Deserialize(SkStream* stream) {
const FontFaceRec* face;
stream->read(&face, sizeof(face));
return new FontFaceRec_Typeface(*face);
}
SkScalerContext* SkFontHost::CreateFallbackScalerContext(
const SkScalerContext::Rec& rec)
{
const FontFaceRec* face = get_default_face();
SkAutoDescriptor ad(sizeof(rec) + sizeof(face) +
SkDescriptor::ComputeOverhead(2));
SkDescriptor* desc = ad.getDesc();
SkScalerContext::Rec* newRec;
desc->init();
newRec = reinterpret_cast<SkScalerContext::Rec*>(
desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec));
newRec->fFontID = get_id(*face);
desc->computeChecksum();
return SkFontHost::CreateScalerContext(desc);
}