Mozilla/mozilla/intl/ctl/src/nsULE.cpp
bryner%brianryner.com 23af8f3c42 Fix build on gcc 3.4 by removing extra semicolons (bug 218551). r/sr=dbaron, a=brendan.
git-svn-id: svn://10.0.0.236/trunk@146618 18797224-902f-48f8-a5cc-f745e15eee43
2003-09-07 22:24:21 +00:00

467 lines
13 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* XPCTL : nsULE.cpp
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
* The Initial Developer of the Original Code is Sun Microsystems,
* Inc. Portions created by SUN are Copyright (C) 2000 SUN
* Microsystems, Inc. All Rights Reserved.
*
* This module 'XPCTL Interface' is based on Pango (www.pango.org)
* by Red Hat Software. Portions created by Redhat are Copyright (C)
* 1999 Red Hat Software.
*
* Contributor(s):
* Prabhat Hegde (prabhat.hegde@sun.com)
*/
#include "nsULE.h"
#include "nsString.h"
#include "pango-types.h"
#include "pango-glyph.h"
#include "pango-modules.h"
#include "pango-utils.h"
/*
* To Do: (Last Updated by prabhat - 08/24/02)
* A> Extend shapers to support ASCII + Script
* B> Eliminate Separate Script
* C> Look at improving the speed of cursor handling logic
*
*/
#define CLEAN_RUN \
aPtr = aRun.head; \
for (int ct=0; (ct < aRun.numRuns); ct++) { \
aTmpPtr = aPtr; \
aPtr = aPtr->next; \
delete(aTmpPtr); \
}
/*
* Start of nsULE Public Functions
*/
nsULE::nsULE() {
}
nsULE::~nsULE() {
// No data to cleanup.
}
NS_IMPL_ISUPPORTS1(nsULE, nsILE)
/* Caller needs to ensure that GetEngine is called with valid state */
PangoliteEngineShape*
nsULE::GetShaper(const PRUnichar *inBuf,
PRUint32 aLength,
const char *lang)
{
PangoliteEngineShape *aEngine = NULL;
PangoliteMap *aMap = NULL;
guint engine_type_id = 0, render_type_id = 0;
PRUnichar wc = inBuf[0];
if ((inBuf == (PRUnichar*)NULL) || (aLength <= 0)) {
aEngine = (PangoliteEngineShape*)NULL;
}
else {
if (engine_type_id == 0) {
engine_type_id = g_quark_from_static_string(PANGO_ENGINE_TYPE_SHAPE);
render_type_id = g_quark_from_static_string(PANGO_RENDER_TYPE_X);
}
// Do not care about lang for now
aMap = pangolite_find_map("en_US", engine_type_id, render_type_id);
aEngine = (PangoliteEngineShape*)pangolite_map_get_engine(aMap, (PRUint32)wc);
}
return aEngine;
}
PRInt32
nsULE::ScriptsByRun(const PRUnichar *aSrcBuf,
PRInt32 aSrcLen,
textRunList *aRunList)
{
int ct = 0, start = 0;
PRBool sameCtlRun = PR_FALSE;
struct textRun *tmpChunk;
PangoliteEngineShape *curEngine = NULL, *prevEngine = NULL;
PangoliteMap *aMap = NULL;
guint engine_type_id = 0, render_type_id = 0;
engine_type_id = g_quark_from_static_string(PANGO_ENGINE_TYPE_SHAPE);
render_type_id = g_quark_from_static_string(PANGO_RENDER_TYPE_X);
aMap = pangolite_find_map("en_US", engine_type_id, render_type_id);
for (ct = 0; ct < aSrcLen;) {
tmpChunk = new textRun;
if (aRunList->numRuns == 0)
aRunList->head = tmpChunk;
else
aRunList->cur->next = tmpChunk;
aRunList->cur = tmpChunk;
aRunList->numRuns++;
tmpChunk->start = &aSrcBuf[ct];
start = ct;
curEngine = (PangoliteEngineShape*)
pangolite_map_get_engine(aMap, (PRUint32)aSrcBuf[ct]);
sameCtlRun = (curEngine != NULL);
prevEngine = curEngine;
if (sameCtlRun) {
while (sameCtlRun && ct < aSrcLen) {
curEngine = (PangoliteEngineShape*)
pangolite_map_get_engine(aMap, (PRUint32)aSrcBuf[ct]);
sameCtlRun = ((curEngine != NULL) && (curEngine == prevEngine));
if (sameCtlRun)
ct++;
}
tmpChunk->isOther = PR_FALSE;
}
else {
while (!sameCtlRun && ct < aSrcLen) {
curEngine = (PangoliteEngineShape*)
pangolite_map_get_engine(aMap, (PRUint32)aSrcBuf[ct]);
sameCtlRun = (curEngine != NULL);
if (!sameCtlRun)
ct++;
}
tmpChunk->isOther = PR_TRUE;
}
tmpChunk->length = ct - start;
}
return (PRInt32)aRunList->numRuns;
}
// Default font encoding by code-range
// At the moment pangoliteLite only supports 2 shapers/scripts
const char*
nsULE::GetDefaultFont(const PRUnichar aString)
{
if ((aString >= 0x0e01) && (aString <= 0x0e5b))
return "tis620-2";
else if ((aString >= 0x0901) && (aString <= 0x0970))
return "sun.unicode.india-0";
else
return "iso8859-1";
}
// Analysis needs to have valid direction
PRInt32
nsULE::GetCtlData(const PRUnichar *aString,
PRUint32 aLength,
PangoliteGlyphString *aGlyphs,
const char *fontCharset)
{
PangoliteEngineShape *aShaper = GetShaper(aString, aLength, (const char*)NULL);
PangoliteAnalysis aAnalysis;
aAnalysis.shape_engine = aShaper;
aAnalysis.aDir = PANGO_DIRECTION_LTR;
// Maybe find a better way to handle font encodings
if (fontCharset == NULL)
aAnalysis.fontCharset = strdup(GetDefaultFont(aString[0]));
else
aAnalysis.fontCharset = strdup(fontCharset);
if (aShaper != NULL) {
aShaper->script_shape(aAnalysis.fontCharset, aString, aLength,
&aAnalysis, aGlyphs);
nsMemory::Free(aAnalysis.fontCharset);
}
else {
/* No Shaper - Copy Input to output */
return 0;
}
return aGlyphs->num_glyphs;
}
NS_IMETHODIMP
nsULE::GetPresentationForm(const PRUnichar *aString,
PRUint32 aLength,
const char *fontCharset,
char *aGlyphs,
PRSize *aOutLength)
{
PangoliteGlyphString *tmpGlyphs = pangolite_glyph_string_new();
GetCtlData(aString, aLength, tmpGlyphs, fontCharset);
if (tmpGlyphs->num_glyphs > 0) {
guint i = 0, glyphCt = 0;
for (i = 0; i < tmpGlyphs->num_glyphs; i++, glyphCt++) {
if (tmpGlyphs->glyphs[i].glyph > 0xFF) {
aGlyphs[glyphCt]=(unsigned char)((tmpGlyphs->glyphs[i].glyph & 0xFF00) >> 8);
glyphCt++;
}
aGlyphs[glyphCt]=(unsigned char)(tmpGlyphs->glyphs[i].glyph & 0x00FF);
}
*aOutLength = (PRSize)glyphCt;
}
else {
/* No Shaper - Copy Input to output */
}
return NS_OK;
}
// This routine returns the string index of the next cluster
// corresponding to the cluster at string index 'aIndex'
// Note : Index returned is the end-offset
// Cursor position iterates between 0 and (position - 1)
NS_IMETHODIMP
nsULE::NextCluster(const PRUnichar *aString,
PRUint32 aLength,
const PRInt32 aIndex,
PRInt32 *nextOffset)
{
textRunList aRun;
textRun *aPtr, *aTmpPtr;
PRInt32 aStrCt=0;
PRBool isBoundary=PR_FALSE;
PangoliteGlyphString *aGlyphData=pangolite_glyph_string_new();
if (aIndex >= aLength-1) {
*nextOffset = aLength; // End
return NS_OK;
}
aRun.numRuns = 0;
ScriptsByRun(aString, aLength, &aRun);
aPtr = aRun.head;
for (int i=0; (i < aRun.numRuns); i++) {
PRInt32 runLen=0;
runLen = aPtr->length;
if ((aStrCt+runLen) < aIndex) /* Skip Run and continue */
aStrCt += runLen;
else if ((aStrCt+runLen) == aIndex) {
isBoundary = PR_TRUE;/* Script Boundary - Skip a cell in next iteration */
aStrCt += runLen;
}
else {
if (aPtr->isOther) {
*nextOffset = aIndex+1;
CLEAN_RUN
return NS_OK;
}
else { /* CTL Cell Movement */
PRInt32 j, startCt, beg, end, numCur;
startCt=aStrCt;
GetCtlData(aPtr->start, runLen, aGlyphData);
numCur=beg=0;
for (j=0; j<aGlyphData->num_glyphs; j++) {
while ((!aGlyphData->glyphs[j].attr.is_cluster_start) &&
j<aGlyphData->num_glyphs)
j++;
if (j>=aGlyphData->num_glyphs)
end=runLen;
else
end=aGlyphData->log_clusters[j];
numCur += end-beg;
if (startCt+numCur > aIndex)
break;
else
beg=end;
}
// Found Cluster - Start of Next == End Of Current
*nextOffset = startCt+numCur;
CLEAN_RUN
return NS_OK;
}
}
aPtr = aPtr->next;
}
/* UNUSED */
CLEAN_RUN
}
// This routine returns the end-offset of the previous block
// corresponding to string index 'aIndex'
NS_IMETHODIMP
nsULE::PrevCluster(const PRUnichar *aString,
PRUint32 aLength,
const PRInt32 aIndex,
PRInt32 *prevOffset)
{
textRunList aRun;
textRun *aPtr, *aTmpPtr;
PRInt32 aStrCt=0, startCt=0, glyphct=0;
PangoliteGlyphString *aGlyphData=pangolite_glyph_string_new();
if (aIndex<=1) {
*prevOffset=0; // End
return NS_OK;
}
aRun.numRuns=0;
ScriptsByRun(aString, aLength, &aRun);
// Get the index of current cluster
aPtr=aRun.head;
for (int i=0; i<aRun.numRuns; i++) {
PRInt32 runLen=aPtr->length;
if ((aStrCt+runLen) < aIndex) /* Skip Run */
aStrCt += runLen;
else if ((aStrCt+runLen) == aIndex) {
if (aPtr->isOther) {
*prevOffset=aIndex-1;
CLEAN_RUN
return NS_OK;
}
else { /* Move back a cluster */
startCt=aStrCt;
GetCtlData(aPtr->start, runLen, aGlyphData);
glyphct=aGlyphData->num_glyphs-1;
while (glyphct > 0) {
if (aGlyphData->glyphs[glyphct].attr.is_cluster_start) {
*prevOffset=startCt+aGlyphData->log_clusters[glyphct];
CLEAN_RUN
return NS_OK;
}
--glyphct;
}
*prevOffset=startCt;
CLEAN_RUN
return NS_OK;
}
}
else {
if (aPtr->isOther) {
*prevOffset=aIndex-1;
CLEAN_RUN
return NS_OK;
}
else {
PRInt32 j,beg,end,numPrev,numCur;
startCt=aStrCt;
GetCtlData(aPtr->start, runLen, aGlyphData);
numPrev=numCur=beg=0;
for (j=1; j<aGlyphData->num_glyphs; j++) {
while ((!aGlyphData->glyphs[j].attr.is_cluster_start) &&
j<aGlyphData->num_glyphs)
j++;
if (j>=aGlyphData->num_glyphs)
end=runLen;
else
end=aGlyphData->log_clusters[j];
numCur += end-beg;
if (numCur+startCt >= aIndex)
break;
else {
beg=end;
numPrev=numCur;
}
}
*prevOffset=startCt+numPrev;
CLEAN_RUN
return NS_OK;
}
}
aPtr=aPtr->next;
}
/* UNUSED */
CLEAN_RUN
}
// This routine returns the end-offset of the previous block
// corresponding to string index 'aIndex'
NS_IMETHODIMP
nsULE::GetRangeOfCluster(const PRUnichar *aString,
PRUint32 aLength,
const PRInt32 aIndex,
PRInt32 *aStart,
PRInt32 *aEnd)
{
textRunList aRun;
textRun *aPtr, *aTmpPtr;
PRInt32 aStrCt=0, startCt=0,j;
PangoliteGlyphString *aGlyphData=pangolite_glyph_string_new();
*aStart = *aEnd = 0;
aRun.numRuns=0;
ScriptsByRun(aString, aLength, &aRun);
// Get the index of current cluster
aPtr=aRun.head;
for (int i=0; i<aRun.numRuns; i++) {
PRInt32 runLen=aPtr->length;
if ((aStrCt+runLen) < aIndex) /* Skip Run */
aStrCt += runLen;
else {
if (aPtr->isOther) {
*aStart = *aEnd = aIndex;
CLEAN_RUN
return NS_OK;
}
else {
PRInt32 beg,end,numCur;
startCt=aStrCt;
GetCtlData(aPtr->start, runLen, aGlyphData);
numCur=beg=0;
for (j=1; j<aGlyphData->num_glyphs; j++) {
while ((!aGlyphData->glyphs[j].attr.is_cluster_start) &&
j<aGlyphData->num_glyphs)
j++;
if (j>=aGlyphData->num_glyphs)
end=runLen;
else
end=aGlyphData->log_clusters[j];
numCur += end-beg;
if (numCur+startCt >= aIndex)
break;
else
beg=end;
}
*aEnd = startCt+numCur;
if (beg == 0)
*aStart = beg;
else {
if ((end-beg) == 1) /* n=n Condition */
*aStart = *aEnd;
else
*aStart = startCt+beg+1; /* Maintain Mozilla Convention */
}
CLEAN_RUN
return NS_OK;
}
}
aPtr=aPtr->next;
}
CLEAN_RUN
/* UNUSED */
}