3b7457281b
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@4606 a95241bf-73f2-0310-859d-f6bbb57e9c96
511 lines
12 KiB
C++
511 lines
12 KiB
C++
//------------------------------------------------------------------------------
|
|
// Copyright (c) 2001-2002, OpenBeOS
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
|
// copy of this software and associated documentation files (the "Software"),
|
|
// to deal in the Software without restriction, including without limitation
|
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
// and/or sell copies of the Software, and to permit persons to whom the
|
|
// Software is furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in
|
|
// all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
// DEALINGS IN THE SOFTWARE.
|
|
//
|
|
// File Name: FontServer.cpp
|
|
// Author: DarkWyrm <bpmagic@columbus.rr.com>
|
|
// Description: Handles the largest part of the font subsystem
|
|
//
|
|
//------------------------------------------------------------------------------
|
|
#include <String.h>
|
|
#include <Directory.h>
|
|
#include <Entry.h>
|
|
#include <storage/Path.h> // specified to be able to build under Dano
|
|
#include <File.h>
|
|
#include <Message.h>
|
|
#include <String.h>
|
|
|
|
#include <FontServer.h>
|
|
#include <FontFamily.h>
|
|
#include <ServerFont.h>
|
|
#include "ServerConfig.h"
|
|
|
|
extern FTC_Manager ftmanager;
|
|
FT_Library ftlib;
|
|
FontServer *fontserver;
|
|
|
|
//#define PRINT_FONT_LIST
|
|
|
|
/*!
|
|
\brief Access function to request a face via the FreeType font cache
|
|
*/
|
|
static FT_Error face_requester(FTC_FaceID face_id, FT_Library library,
|
|
FT_Pointer request_data, FT_Face *aface)
|
|
{
|
|
CachedFace face = (CachedFace) face_id;
|
|
return FT_New_Face(ftlib,face->file_path.String(),face->face_index,aface);
|
|
}
|
|
|
|
//! Does basic set up so that directories can be scanned
|
|
FontServer::FontServer(void)
|
|
{
|
|
lock=create_sem(1,"fontserver_lock");
|
|
init=(FT_Init_FreeType(&ftlib)==0)?true:false;
|
|
|
|
/*
|
|
Fire up the font caching subsystem.
|
|
The three zeros tell FreeType to use the defaults, which are 2 faces,
|
|
4 face sizes, and a maximum of 200000 bytes. I will probably change
|
|
these numbers in the future to maximize performance for your "average"
|
|
application.
|
|
*/
|
|
if(FTC_Manager_New(ftlib,0,0,0,&face_requester,NULL,&ftmanager)!=0
|
|
&& init)
|
|
init=false;
|
|
|
|
families=new BList(0);
|
|
plain=NULL;
|
|
bold=NULL;
|
|
fixed=NULL;
|
|
}
|
|
|
|
//! Frees items allocated in the constructor and shuts down FreeType
|
|
FontServer::~FontServer(void)
|
|
{
|
|
delete_sem(lock);
|
|
delete families;
|
|
FTC_Manager_Done(ftmanager);
|
|
FT_Done_FreeType(ftlib);
|
|
}
|
|
|
|
//! Locks access to the font server
|
|
void FontServer::Lock(void)
|
|
{
|
|
acquire_sem(lock);
|
|
}
|
|
|
|
//! Unlocks access to the font server
|
|
void FontServer::Unlock(void)
|
|
{
|
|
release_sem(lock);
|
|
}
|
|
|
|
/*!
|
|
\brief Counts the number of font families available
|
|
\return The number of unique font families currently available
|
|
*/
|
|
int32 FontServer::CountFamilies(void)
|
|
{
|
|
if(init)
|
|
return families->CountItems();
|
|
return 0;
|
|
}
|
|
|
|
/*!
|
|
\brief Counts the number of styles available in a font family
|
|
\param family Name of the font family to scan
|
|
\return The number of font styles currently available for the font family
|
|
*/
|
|
int32 FontServer::CountStyles(const char *family)
|
|
{
|
|
FontFamily *f=_FindFamily(family);
|
|
if(f)
|
|
{
|
|
return f->CountStyles();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*!
|
|
\brief Removes a font family from the font list
|
|
\param family The family to remove
|
|
*/
|
|
void FontServer::RemoveFamily(const char *family)
|
|
{
|
|
FontFamily *f=_FindFamily(family);
|
|
if(f)
|
|
{
|
|
families->RemoveItem(f);
|
|
delete f;
|
|
}
|
|
}
|
|
|
|
/*!
|
|
\brief Protected function which locates a FontFamily object
|
|
\param name The family to find
|
|
\return Pointer to the specified family or NULL if not found.
|
|
|
|
Do NOT delete the FontFamily returned by this function.
|
|
*/
|
|
FontFamily *FontServer::_FindFamily(const char *name)
|
|
{
|
|
if(!init)
|
|
return NULL;
|
|
int32 count=families->CountItems(), i;
|
|
FontFamily *family;
|
|
for(i=0; i<count; i++)
|
|
{
|
|
family=(FontFamily*)families->ItemAt(i);
|
|
if(strcmp(family->Name(),name)==0)
|
|
return family;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*!
|
|
\brief Scan a folder for all valid fonts
|
|
\param fontspath Path of the folder to scan.
|
|
\return
|
|
- \c B_OK Success
|
|
- \c B_NAME_TOO_LONG The path specified is too long
|
|
- \c B_ENTRY_NOT_FOUND The path does not exist
|
|
- \c B_LINK_LIMIT A cyclic loop was detected in the file system
|
|
- \c B_BAD_VALUE Invalid input specified
|
|
- \c B_NO_MEMORY Insufficient memory to open the folder for reading
|
|
- \c B_BUSY A busy node could not be accessed
|
|
- \c B_FILE_ERROR An invalid file prevented the operation.
|
|
- \c B_NO_MORE_FDS All file descriptors are in use (too many open files).
|
|
*/
|
|
status_t FontServer::ScanDirectory(const char *fontspath)
|
|
{
|
|
// This bad boy does all the real work. It loads each entry in the
|
|
// directory. If a valid font file, it adds both the family and the style.
|
|
// Both family and style are stored internally as BStrings. Once everything
|
|
|
|
BDirectory dir;
|
|
BEntry entry;
|
|
BPath path;
|
|
entry_ref ref;
|
|
status_t stat;
|
|
int32 refcount,i, validcount=0;
|
|
FT_Face face;
|
|
FT_Error error;
|
|
FT_CharMap charmap;
|
|
FontFamily *family;
|
|
|
|
stat=dir.SetTo(fontspath);
|
|
if(stat!=B_OK)
|
|
return stat;
|
|
|
|
refcount=dir.CountEntries();
|
|
|
|
for(i=0;i<refcount;i++)
|
|
{
|
|
if(dir.GetNextEntry(&entry)==B_ENTRY_NOT_FOUND)
|
|
break;
|
|
|
|
stat=entry.GetPath(&path);
|
|
if(stat!=B_OK)
|
|
continue;
|
|
|
|
error=FT_New_Face(ftlib,path.Path(),0,&face);
|
|
|
|
if (error!=0)
|
|
continue;
|
|
|
|
charmap=_GetSupportedCharmap(face);
|
|
if(!charmap)
|
|
{
|
|
FT_Done_Face(face);
|
|
continue;
|
|
}
|
|
|
|
face->charmap=charmap;
|
|
|
|
family=_FindFamily(face->family_name);
|
|
|
|
if(!family)
|
|
{
|
|
#ifdef PRINT_FONT_LIST
|
|
printf("Font Family: %s\n",face->family_name);
|
|
#endif
|
|
|
|
family=new FontFamily(face->family_name);
|
|
families->AddItem(family);
|
|
}
|
|
|
|
if(family->HasStyle(face->style_name))
|
|
{
|
|
FT_Done_Face(face);
|
|
continue;
|
|
}
|
|
|
|
#ifdef PRINT_FONT_LIST
|
|
printf("\tFont Style: %s\n",face->style_name);
|
|
#endif
|
|
|
|
// Has vertical metrics?
|
|
family->AddStyle(path.Path(),face);
|
|
validcount++;
|
|
|
|
FT_Done_Face(face);
|
|
} // end for(i<refcount)
|
|
|
|
dir.Unset();
|
|
|
|
need_update=true;
|
|
return B_OK;
|
|
}
|
|
|
|
/*!
|
|
\brief Finds and returns the first valid charmap in a font
|
|
|
|
\param face Font handle obtained from FT_Load_Face()
|
|
\return An FT_CharMap or NULL if unsuccessful
|
|
*/
|
|
FT_CharMap FontServer::_GetSupportedCharmap(const FT_Face &face)
|
|
{
|
|
int32 i;
|
|
FT_CharMap charmap;
|
|
for(i=0; i< face->num_charmaps; i++)
|
|
{
|
|
charmap=face->charmaps[i];
|
|
switch(charmap->platform_id)
|
|
{
|
|
case 3:
|
|
{
|
|
// if Windows Symbol or Windows Unicode
|
|
if(charmap->encoding_id==0 || charmap->encoding_id==1)
|
|
return charmap;
|
|
break;
|
|
}
|
|
case 1:
|
|
{
|
|
// if Apple Unicode
|
|
if(charmap->encoding_id==0)
|
|
return charmap;
|
|
break;
|
|
}
|
|
case 0:
|
|
{
|
|
// if Apple Roman
|
|
if(charmap->encoding_id==0)
|
|
return charmap;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return NULL;
|
|
|
|
}
|
|
|
|
/*!
|
|
\brief This saves all family names and styles to the file specified in
|
|
ServerConfig.h as SERVER_FONT_LIST as a flattened BMessage.
|
|
|
|
This operation is not done very often because the access to disk adds a significant
|
|
performance hit.
|
|
|
|
The format for storage consists of two things: an array of strings with the name 'family'
|
|
and a number of small string arrays which have the name of the font family. These are
|
|
the style lists.
|
|
|
|
Additionally, any fonts which have bitmap strikes contained in them or any fonts which
|
|
are fixed-width are named in the arrays 'tuned' and 'fixed'.
|
|
*/
|
|
void FontServer::SaveList(void)
|
|
{
|
|
int32 famcount=0, stycount=0,i=0,j=0;
|
|
FontFamily *fam;
|
|
FontStyle *sty;
|
|
BMessage fontmsg, familymsg('FONT');
|
|
BString famname, styname, extraname;
|
|
bool fixed,tuned;
|
|
|
|
famcount=families->CountItems();
|
|
for(i=0; i<famcount; i++)
|
|
{
|
|
fam=(FontFamily*)families->ItemAt(i);
|
|
fixed=false;
|
|
tuned=false;
|
|
if(!fam)
|
|
continue;
|
|
|
|
famname=fam->Name();
|
|
|
|
// Add the family to the message
|
|
familymsg.AddString("name",famname);
|
|
|
|
stycount=fam->CountStyles();
|
|
for(j=0;j<stycount;j++)
|
|
{
|
|
styname.SetTo(fam->GetStyle(j));
|
|
if(styname.CountChars()>0)
|
|
{
|
|
// Add to list
|
|
familymsg.AddString("styles", styname);
|
|
|
|
// Check to see if it has prerendered strikes (has "tuned" fonts)
|
|
sty=fam->GetStyle(styname.String());
|
|
if(!sty)
|
|
continue;
|
|
|
|
if(sty->HasTuned() && sty->IsScalable())
|
|
tuned=true;
|
|
|
|
// Check to see if it is fixed-width
|
|
if(sty->IsFixedWidth())
|
|
fixed=true;
|
|
}
|
|
}
|
|
if(tuned)
|
|
familymsg.AddBool("tuned",true);
|
|
if(fixed)
|
|
familymsg.AddBool("fixed",true);
|
|
|
|
fontmsg.AddMessage("family",&familymsg);
|
|
familymsg.MakeEmpty();
|
|
}
|
|
|
|
BFile file(SERVER_FONT_LIST,B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE);
|
|
if(file.InitCheck()==B_OK)
|
|
fontmsg.Flatten(&file);
|
|
}
|
|
|
|
/*!
|
|
\brief Retrieves the FontStyle object
|
|
\param family The font's family
|
|
\param face The font's style
|
|
\return The FontStyle having those attributes or NULL if not available
|
|
*/
|
|
FontStyle *FontServer::GetStyle(font_family family, font_style face)
|
|
{
|
|
FontFamily *ffam=_FindFamily(family);
|
|
|
|
if(ffam)
|
|
{
|
|
FontStyle *fsty=ffam->GetStyle(face);
|
|
return fsty;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*!
|
|
\brief Returns the current object used for the regular style
|
|
\return A ServerFont pointer which is the plain font.
|
|
|
|
Do NOT delete this object. If you access it, make a copy of it.
|
|
*/
|
|
ServerFont *FontServer::GetSystemPlain(void)
|
|
{
|
|
if(plain)
|
|
{
|
|
ServerFont *f=new ServerFont(*plain);
|
|
return f;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*!
|
|
\brief Returns the current object used for the bold style
|
|
\return A ServerFont pointer which is the bold font.
|
|
|
|
Do NOT delete this object. If you access it, make a copy of it.
|
|
*/
|
|
ServerFont *FontServer::GetSystemBold(void)
|
|
{
|
|
if(bold)
|
|
{
|
|
ServerFont *f=new ServerFont(*bold);
|
|
return f;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*!
|
|
\brief Returns the current object used for the fixed style
|
|
\return A ServerFont pointer which is the fixed font.
|
|
|
|
Do NOT delete this object. If you access it, make a copy of it.
|
|
*/
|
|
ServerFont *FontServer::GetSystemFixed(void)
|
|
{
|
|
if(fixed)
|
|
{
|
|
ServerFont *f=new ServerFont(*fixed);
|
|
return f;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*!
|
|
\brief Sets the system's plain font to the specified family and style
|
|
\param family Name of the font's family
|
|
\param style Name of the style desired
|
|
\param size Size desired
|
|
\return true if successful, false if not.
|
|
|
|
*/
|
|
bool FontServer::SetSystemPlain(const char *family, const char *style, float size)
|
|
{
|
|
FontFamily *fam=_FindFamily(family);
|
|
if(!fam)
|
|
return false;
|
|
FontStyle *sty=fam->GetStyle(style);
|
|
if(!sty)
|
|
return false;
|
|
|
|
if(plain)
|
|
delete plain;
|
|
plain=sty->Instantiate(size);
|
|
return true;
|
|
}
|
|
|
|
/*!
|
|
\brief Sets the system's bold font to the specified family and style
|
|
\param family Name of the font's family
|
|
\param style Name of the style desired
|
|
\param size Size desired
|
|
\return true if successful, false if not.
|
|
|
|
*/
|
|
bool FontServer::SetSystemBold(const char *family, const char *style, float size)
|
|
{
|
|
FontFamily *fam=_FindFamily(family);
|
|
if(!fam)
|
|
return false;
|
|
FontStyle *sty=fam->GetStyle(style);
|
|
if(!sty)
|
|
return false;
|
|
|
|
if(bold)
|
|
delete bold;
|
|
bold=sty->Instantiate(size);
|
|
return true;
|
|
}
|
|
|
|
/*!
|
|
\brief Sets the system's fixed font to the specified family and style
|
|
\param family Name of the font's family
|
|
\param style Name of the style desired
|
|
\param size Size desired
|
|
\return true if successful, false if not.
|
|
|
|
*/
|
|
bool FontServer::SetSystemFixed(const char *family, const char *style, float size)
|
|
{
|
|
FontFamily *fam=_FindFamily(family);
|
|
if(!fam)
|
|
return false;
|
|
FontStyle *sty=fam->GetStyle(style);
|
|
if(!sty)
|
|
return false;
|
|
|
|
if(fixed)
|
|
delete fixed;
|
|
fixed=sty->Instantiate(size);
|
|
return true;
|
|
}
|
|
|