| /* |
| ****************************************************************************** |
| * |
| * Copyright (C) 2000-2004, International Business Machines |
| * Corporation and others. All Rights Reserved. |
| * Copyright (C) 2007 Apple Inc. All rights reserved. |
| * |
| * 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, and/or sell copies of the Software, and to permit persons |
| * to whom the Software is furnished to do so, provided that the above copyright notice(s) |
| * and this permission notice appear in all copies of the Software and that both the above |
| * copyright notice(s) and this permission notice appear in supporting documentation. |
| * |
| * 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 OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER |
| * OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR |
| * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR |
| * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING |
| * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| * |
| * Except as contained in this notice, the name of a copyright holder shall not be used in |
| * advertising or otherwise to promote the sale, use or other dealings in this Software |
| * without prior written authorization of the copyright holder. |
| * |
| ****************************************************************************** |
| * |
| * Arabic letter shaping implemented by Ayman Roshdy |
| */ |
| |
| #include "config.h" |
| |
| #if USE(ATSUI) |
| |
| #include "ShapeArabic.h" |
| |
| #include <stdbool.h> |
| #include <string.h> |
| #include <unicode/utypes.h> |
| #include <unicode/uchar.h> |
| #include <unicode/ustring.h> |
| #include <unicode/ushape.h> |
| #include <wtf/Assertions.h> |
| |
| /* |
| * ### TODO in general for letter shaping: |
| * - the letter shaping code is UTF-16-unaware; needs update |
| * + especially invertBuffer()?! |
| * - needs to handle the "Arabic Tail" that is used in some legacy codepages |
| * as a glyph fragment of wide-glyph letters |
| * + IBM Unicode conversion tables map it to U+200B (ZWSP) |
| * + IBM Egypt has proposed to encode the tail in Unicode among Arabic Presentation Forms |
| */ |
| |
| /* definitions for Arabic letter shaping ------------------------------------ */ |
| |
| #define IRRELEVANT 4 |
| #define LAMTYPE 16 |
| #define ALEFTYPE 32 |
| #define LINKR 1 |
| #define LINKL 2 |
| |
| static const UChar IrrelevantPos[] = { |
| 0x0, 0x2, 0x4, 0x6, |
| 0x8, 0xA, 0xC, 0xE, |
| }; |
| |
| static const UChar araLink[178]= |
| { |
| 1 + 32 + 256 * 0x11,/*0x0622*/ |
| 1 + 32 + 256 * 0x13,/*0x0623*/ |
| 1 + 256 * 0x15,/*0x0624*/ |
| 1 + 32 + 256 * 0x17,/*0x0625*/ |
| 1 + 2 + 256 * 0x19,/*0x0626*/ |
| 1 + 32 + 256 * 0x1D,/*0x0627*/ |
| 1 + 2 + 256 * 0x1F,/*0x0628*/ |
| 1 + 256 * 0x23,/*0x0629*/ |
| 1 + 2 + 256 * 0x25,/*0x062A*/ |
| 1 + 2 + 256 * 0x29,/*0x062B*/ |
| 1 + 2 + 256 * 0x2D,/*0x062C*/ |
| 1 + 2 + 256 * 0x31,/*0x062D*/ |
| 1 + 2 + 256 * 0x35,/*0x062E*/ |
| 1 + 256 * 0x39,/*0x062F*/ |
| 1 + 256 * 0x3B,/*0x0630*/ |
| 1 + 256 * 0x3D,/*0x0631*/ |
| 1 + 256 * 0x3F,/*0x0632*/ |
| 1 + 2 + 256 * 0x41,/*0x0633*/ |
| 1 + 2 + 256 * 0x45,/*0x0634*/ |
| 1 + 2 + 256 * 0x49,/*0x0635*/ |
| 1 + 2 + 256 * 0x4D,/*0x0636*/ |
| 1 + 2 + 256 * 0x51,/*0x0637*/ |
| 1 + 2 + 256 * 0x55,/*0x0638*/ |
| 1 + 2 + 256 * 0x59,/*0x0639*/ |
| 1 + 2 + 256 * 0x5D,/*0x063A*/ |
| 0, 0, 0, 0, 0, /*0x063B-0x063F*/ |
| 1 + 2, /*0x0640*/ |
| 1 + 2 + 256 * 0x61,/*0x0641*/ |
| 1 + 2 + 256 * 0x65,/*0x0642*/ |
| 1 + 2 + 256 * 0x69,/*0x0643*/ |
| 1 + 2 + 16 + 256 * 0x6D,/*0x0644*/ |
| 1 + 2 + 256 * 0x71,/*0x0645*/ |
| 1 + 2 + 256 * 0x75,/*0x0646*/ |
| 1 + 2 + 256 * 0x79,/*0x0647*/ |
| 1 + 256 * 0x7D,/*0x0648*/ |
| 1 + 256 * 0x7F,/*0x0649*/ |
| 1 + 2 + 256 * 0x81,/*0x064A*/ |
| 4, 4, 4, 4, /*0x064B-0x064E*/ |
| 4, 4, 4, 4, /*0x064F-0x0652*/ |
| 4, 4, 4, 0, 0, /*0x0653-0x0657*/ |
| 0, 0, 0, 0, /*0x0658-0x065B*/ |
| 1 + 256 * 0x85,/*0x065C*/ |
| 1 + 256 * 0x87,/*0x065D*/ |
| 1 + 256 * 0x89,/*0x065E*/ |
| 1 + 256 * 0x8B,/*0x065F*/ |
| 0, 0, 0, 0, 0, /*0x0660-0x0664*/ |
| 0, 0, 0, 0, 0, /*0x0665-0x0669*/ |
| 0, 0, 0, 0, 0, 0, /*0x066A-0x066F*/ |
| 4, /*0x0670*/ |
| 0, /*0x0671*/ |
| 1 + 32, /*0x0672*/ |
| 1 + 32, /*0x0673*/ |
| 0, /*0x0674*/ |
| 1 + 32, /*0x0675*/ |
| 1, 1, /*0x0676-0x0677*/ |
| 1+2, /*0x0678*/ |
| 1+2 + 256 * 0x16,/*0x0679*/ |
| 1+2 + 256 * 0x0E,/*0x067A*/ |
| 1+2 + 256 * 0x02,/*0x067B*/ |
| 1+2, 1+2, /*0x067C-0x067D*/ |
| 1+2 + 256 * 0x06,/*0x067E*/ |
| 1+2 + 256 * 0x12,/*0x067F*/ |
| 1+2 + 256 * 0x0A,/*0x0680*/ |
| 1+2, 1+2, /*0x0681-0x0682*/ |
| 1+2 + 256 * 0x26,/*0x0683*/ |
| 1+2 + 256 * 0x22,/*0x0684*/ |
| 1+2, /*0x0685*/ |
| 1+2 + 256 * 0x2A,/*0x0686*/ |
| 1+2 + 256 * 0x2E,/*0x0687*/ |
| 1 + 256 * 0x38,/*0x0688*/ |
| 1, 1, 1, /*0x0689-0x068B*/ |
| 1 + 256 * 0x34,/*0x068C*/ |
| 1 + 256 * 0x32,/*0x068D*/ |
| 1 + 256 * 0x36,/*0x068E*/ |
| 1, 1, /*0x068F-0x0690*/ |
| 1 + 256 * 0x3C,/*0x0691*/ |
| 1, 1, 1, 1, 1, 1, /*0x0692-0x0697*/ |
| 1 + 256 * 0x3A,/*0x0698*/ |
| 1, /*0x0699*/ |
| 1+2, 1+2, 1+2, 1+2, 1+2, 1+2, /*0x069A-0x069F*/ |
| 1+2, 1+2, 1+2, 1+2, /*0x06A0-0x06A3*/ |
| 1+2 + 256 * 0x2E,/*0x06A4*/ |
| 1+2, /*0x06A5*/ |
| 1+2 + 256 * 0x1E,/*0x06A6*/ |
| 1+2, 1+2, /*0x06A7-0x06A8*/ |
| 1+2 + 256 * 0x3E,/*0x06A9*/ |
| 1+2, 1+2, 1+2, /*0x06AA-0x06AC*/ |
| 1+2 + 256 * 0x83,/*0x06AD*/ |
| 1+2, /*0x06AE*/ |
| 1+2 + 256 * 0x42,/*0x06AF*/ |
| 1+2, /*0x06B0*/ |
| 1+2 + 256 * 0x4A,/*0x06B1*/ |
| 1+2, /*0x06B2*/ |
| 1+2 + 256 * 0x46,/*0x06B3*/ |
| 1+2, 1+2, 1+2, 1+2, 1+2, 1+2, /*0x06B4-0x06B9*/ |
| 1+2, /*0x06BA*/ // FIXME: Seems to have a final form |
| 1+2 + 256 * 0x50,/*0x06BB*/ |
| 1+2, 1+2, /*0x06BC-0x06BD*/ |
| 1+2 + 256 * 0x5A,/*0x06BE*/ |
| 1+2, /*0x06BF*/ |
| 1, /*0x06C0*/ |
| 1+2 + 256 * 0x56,/*0x06C1*/ |
| 1+2, /*0x06C2*/ |
| 1, 1, /*0x06C3-0x06C4*/ |
| 1 + 256 * 0x90,/*0x06C5*/ |
| 1 + 256 * 0x89,/*0x06C6*/ |
| 1 + 256 * 0x87,/*0x06C7*/ |
| 1 + 256 * 0x8B,/*0x06C8*/ |
| 1 + 256 * 0x92,/*0x06C9*/ |
| 1, /*0x06CA*/ |
| 1 + 256 * 0x8E,/*0x06CB*/ |
| 1+2 + 256 * 0xAC,/*0x06CC*/ |
| 1, /*0x06CD*/ |
| 1+2, /*0x06CE*/ |
| 1, /*0x06CF*/ |
| 1+2 + 256 * 0x94,/*0x06D0*/ |
| 1+2, /*0x06D1*/ |
| 1 + 256 * 0x5E,/*0x06D2*/ |
| 1 + 256 * 0x60 /*0x06D3*/ |
| }; |
| |
| static const UChar presLink[141]= |
| { |
| 1 + 2, /*0xFE70*/ |
| 1 + 2, /*0xFE71*/ |
| 1 + 2, 0, 1+ 2, 0, 1+ 2, /*0xFE72-0xFE76*/ |
| 1 + 2, /*0xFE77*/ |
| 1+ 2, 1 + 2, 1+2, 1 + 2, /*0xFE78-0xFE81*/ |
| 1+ 2, 1 + 2, 1+2, 1 + 2, /*0xFE82-0xFE85*/ |
| 0, 0 + 32, 1 + 32, 0 + 32, /*0xFE86-0xFE89*/ |
| 1 + 32, 0, 1, 0 + 32, /*0xFE8A-0xFE8D*/ |
| 1 + 32, 0, 2, 1 + 2, /*0xFE8E-0xFE91*/ |
| 1, 0 + 32, 1 + 32, 0, /*0xFE92-0xFE95*/ |
| 2, 1 + 2, 1, 0, /*0xFE96-0xFE99*/ |
| 1, 0, 2, 1 + 2, /*0xFE9A-0xFE9D*/ |
| 1, 0, 2, 1 + 2, /*0xFE9E-0xFEA1*/ |
| 1, 0, 2, 1 + 2, /*0xFEA2-0xFEA5*/ |
| 1, 0, 2, 1 + 2, /*0xFEA6-0xFEA9*/ |
| 1, 0, 2, 1 + 2, /*0xFEAA-0xFEAD*/ |
| 1, 0, 1, 0, /*0xFEAE-0xFEB1*/ |
| 1, 0, 1, 0, /*0xFEB2-0xFEB5*/ |
| 1, 0, 2, 1+2, /*0xFEB6-0xFEB9*/ |
| 1, 0, 2, 1+2, /*0xFEBA-0xFEBD*/ |
| 1, 0, 2, 1+2, /*0xFEBE-0xFEC1*/ |
| 1, 0, 2, 1+2, /*0xFEC2-0xFEC5*/ |
| 1, 0, 2, 1+2, /*0xFEC6-0xFEC9*/ |
| 1, 0, 2, 1+2, /*0xFECA-0xFECD*/ |
| 1, 0, 2, 1+2, /*0xFECE-0xFED1*/ |
| 1, 0, 2, 1+2, /*0xFED2-0xFED5*/ |
| 1, 0, 2, 1+2, /*0xFED6-0xFED9*/ |
| 1, 0, 2, 1+2, /*0xFEDA-0xFEDD*/ |
| 1, 0, 2, 1+2, /*0xFEDE-0xFEE1*/ |
| 1, 0 + 16, 2 + 16, 1 + 2 +16, /*0xFEE2-0xFEE5*/ |
| 1 + 16, 0, 2, 1+2, /*0xFEE6-0xFEE9*/ |
| 1, 0, 2, 1+2, /*0xFEEA-0xFEED*/ |
| 1, 0, 2, 1+2, /*0xFEEE-0xFEF1*/ |
| 1, 0, 1, 0, /*0xFEF2-0xFEF5*/ |
| 1, 0, 2, 1+2, /*0xFEF6-0xFEF9*/ |
| 1, 0, 1, 0, /*0xFEFA-0xFEFD*/ |
| 1, 0, 1, 0, |
| 1 |
| }; |
| |
| static const UChar convertFEto06[] = |
| { |
| /***********0******1******2******3******4******5******6******7******8******9******A******B******C******D******E******F***/ |
| /*FE7*/ 0x64B, 0x64B, 0x64C, 0x64C, 0x64D, 0x64D, 0x64E, 0x64E, 0x64F, 0x64F, 0x650, 0x650, 0x651, 0x651, 0x652, 0x652, |
| /*FE8*/ 0x621, 0x622, 0x622, 0x623, 0x623, 0x624, 0x624, 0x625, 0x625, 0x626, 0x626, 0x626, 0x626, 0x627, 0x627, 0x628, |
| /*FE9*/ 0x628, 0x628, 0x628, 0x629, 0x629, 0x62A, 0x62A, 0x62A, 0x62A, 0x62B, 0x62B, 0x62B, 0x62B, 0x62C, 0x62C, 0x62C, |
| /*FEA*/ 0x62C, 0x62D, 0x62D, 0x62D, 0x62D, 0x62E, 0x62E, 0x62E, 0x62E, 0x62F, 0x62F, 0x630, 0x630, 0x631, 0x631, 0x632, |
| /*FEB*/ 0x632, 0x633, 0x633, 0x633, 0x633, 0x634, 0x634, 0x634, 0x634, 0x635, 0x635, 0x635, 0x635, 0x636, 0x636, 0x636, |
| /*FEC*/ 0x636, 0x637, 0x637, 0x637, 0x637, 0x638, 0x638, 0x638, 0x638, 0x639, 0x639, 0x639, 0x639, 0x63A, 0x63A, 0x63A, |
| /*FED*/ 0x63A, 0x641, 0x641, 0x641, 0x641, 0x642, 0x642, 0x642, 0x642, 0x643, 0x643, 0x643, 0x643, 0x644, 0x644, 0x644, |
| /*FEE*/ 0x644, 0x645, 0x645, 0x645, 0x645, 0x646, 0x646, 0x646, 0x646, 0x647, 0x647, 0x647, 0x647, 0x648, 0x648, 0x649, |
| /*FEF*/ 0x649, 0x64A, 0x64A, 0x64A, 0x64A, 0x65C, 0x65C, 0x65D, 0x65D, 0x65E, 0x65E, 0x65F, 0x65F |
| }; |
| |
| static const UChar shapeTable[4][4][4]= |
| { |
| { {0,0,0,0}, {0,0,0,0}, {0,1,0,3}, {0,1,0,1} }, |
| { {0,0,2,2}, {0,0,1,2}, {0,1,1,2}, {0,1,1,3} }, |
| { {0,0,0,0}, {0,0,0,0}, {0,1,0,3}, {0,1,0,3} }, |
| { {0,0,1,2}, {0,0,1,2}, {0,1,1,2}, {0,1,1,3} } |
| }; |
| |
| /* |
| *Name : changeLamAlef |
| *Function : Converts the Alef characters into an equivalent |
| * LamAlef location in the 0x06xx Range, this is an |
| * intermediate stage in the operation of the program |
| * later it'll be converted into the 0xFExx LamAlefs |
| * in the shaping function. |
| */ |
| static UChar |
| changeLamAlef(UChar ch) { |
| |
| switch(ch) { |
| case 0x0622 : |
| return(0x065C); |
| break; |
| case 0x0623 : |
| return(0x065D); |
| break; |
| case 0x0625 : |
| return(0x065E); |
| break; |
| case 0x0627 : |
| return(0x065F); |
| break; |
| default : |
| return(0); |
| break; |
| } |
| } |
| |
| /* |
| *Name : specialChar |
| *Function : Special Arabic characters need special handling in the shapeUnicode |
| * function, this function returns 1 or 2 for these special characters |
| */ |
| static int32_t |
| specialChar(UChar ch) { |
| |
| if( (ch>0x0621 && ch<0x0626)||(ch==0x0627)||(ch>0x062e && ch<0x0633)|| |
| (ch>0x0647 && ch<0x064a)||(ch==0x0629) ) { |
| return (1); |
| } |
| else |
| if( ch>=0x064B && ch<= 0x0652 ) |
| return (2); |
| else |
| if( (ch>=0x0653 && ch<= 0x0655) || ch == 0x0670 || |
| (ch>=0xFE70 && ch<= 0xFE7F) ) |
| return (3); |
| else |
| return (0); |
| } |
| |
| /* |
| *Name : getLink |
| *Function : Resolves the link between the characters as |
| * Arabic characters have four forms : |
| * Isolated, Initial, Middle and Final Form |
| */ |
| static UChar |
| getLink(UChar ch) { |
| |
| if(ch >= 0x0622 && ch <= 0x06D3) { |
| return(araLink[ch-0x0622]); |
| } else if(ch == 0x200D) { |
| return(3); |
| } else if(ch >= 0x206D && ch <= 0x206F) { |
| return(4); |
| } else if(ch >= 0xFE70 && ch <= 0xFEFC) { |
| return(presLink[ch-0xFE70]); |
| } else { |
| return(0); |
| } |
| } |
| |
| /* |
| *Name : isTashkeelChar |
| *Function : Returns 1 for Tashkeel characters else return 0 |
| */ |
| static int32_t |
| isTashkeelChar(UChar ch) { |
| |
| if( ch>=0x064B && ch<= 0x0652 ) |
| return (1); |
| else |
| return (0); |
| } |
| |
| /* |
| *Name : shapeUnicode |
| *Function : Converts an Arabic Unicode buffer in 06xx Range into a shaped |
| * arabic Unicode buffer in FExx Range |
| */ |
| static int32_t |
| shapeUnicode(UChar *dest, int32_t sourceLength, |
| int32_t destSize, |
| int tashkeelFlag) { |
| |
| int32_t i, iend; |
| int32_t prevPos, lastPos,Nx, Nw; |
| unsigned int Shape; |
| int32_t flag; |
| int32_t lamalef_found = 0; |
| UChar prevLink = 0, lastLink = 0, currLink, nextLink = 0; |
| UChar wLamalef; |
| |
| /* |
| * Converts the input buffer from FExx Range into 06xx Range |
| * to make sure that all characters are in the 06xx range |
| * even the lamalef is converted to the special region in |
| * the 06xx range |
| */ |
| for (i = 0; i < sourceLength; i++) { |
| UChar inputChar = dest[i]; |
| if ( (inputChar >= 0xFE70) && (inputChar <= 0xFEFC)) { |
| dest[i] = convertFEto06 [ (inputChar - 0xFE70) ] ; |
| } |
| } |
| |
| /* sets the index to the end of the buffer, together with the step point to -1 */ |
| i = 0; |
| iend = sourceLength; |
| |
| /* |
| * This function resolves the link between the characters . |
| * Arabic characters have four forms : |
| * Isolated Form, Initial Form, Middle Form and Final Form |
| */ |
| currLink = getLink(dest[i]); |
| |
| prevPos = i; |
| lastPos = i; |
| Nx = sourceLength + 2, Nw = 0; |
| |
| while (i != iend) { |
| /* If high byte of currLink > 0 then more than one shape */ |
| if ((currLink & 0xFF00) > 0 || isTashkeelChar(dest[i])) { |
| Nw = i + 1; |
| while (Nx >= sourceLength) { /* we need to know about next char */ |
| if(Nw == iend) { |
| nextLink = 0; |
| Nx = -1; |
| } else { |
| nextLink = getLink(dest[Nw]); |
| if((nextLink & IRRELEVANT) == 0) { |
| Nx = Nw; |
| } else { |
| Nw = Nw + 1; |
| } |
| } |
| } |
| |
| if ( ((currLink & ALEFTYPE) > 0) && ((lastLink & LAMTYPE) > 0) ) { |
| lamalef_found = 1; |
| wLamalef = changeLamAlef(dest[i]); /*get from 0x065C-0x065f */ |
| if ( wLamalef != 0) { |
| dest[i] = ' '; /* The default case is to drop the Alef and replace */ |
| dest[lastPos] =wLamalef; /* it by a space. */ |
| i=lastPos; |
| } |
| lastLink = prevLink; |
| currLink = getLink(wLamalef); |
| } |
| /* |
| * get the proper shape according to link ability of neighbors |
| * and of character; depends on the order of the shapes |
| * (isolated, initial, middle, final) in the compatibility area |
| */ |
| flag = specialChar(dest[i]); |
| |
| Shape = shapeTable[nextLink & (LINKR + LINKL)] |
| [lastLink & (LINKR + LINKL)] |
| [currLink & (LINKR + LINKL)]; |
| |
| if (flag == 1) { |
| Shape = (Shape == 1 || Shape == 3) ? 1 : 0; |
| } |
| else |
| if(flag == 2) { |
| if( (lastLink & LINKL) && (nextLink & LINKR) && (tashkeelFlag == 1) && |
| dest[i] != 0x064C && dest[i] != 0x064D ) { |
| Shape = 1; |
| if( (nextLink&ALEFTYPE) == ALEFTYPE && (lastLink&LAMTYPE) == LAMTYPE ) |
| Shape = 0; |
| } |
| else { |
| Shape = 0; |
| } |
| } |
| |
| if(flag == 2) { |
| dest[i] = 0xFE70 + IrrelevantPos[(dest[i] - 0x064B)] + Shape; |
| } |
| else |
| dest[i] = (UChar)((dest[i] < 0x0670 ? 0xFE70 : 0xFB50) + (currLink >> 8) + Shape); |
| } |
| |
| /* move one notch forward */ |
| if ((currLink & IRRELEVANT) == 0) { |
| prevLink = lastLink; |
| lastLink = currLink; |
| prevPos = lastPos; |
| lastPos = i; |
| } |
| |
| i++; |
| if (i == Nx) { |
| currLink = nextLink; |
| Nx = sourceLength + 2; |
| } |
| else if(i != iend) { |
| currLink = getLink(dest[i]); |
| } |
| } |
| |
| destSize = sourceLength; |
| |
| return destSize; |
| } |
| |
| int32_t shapeArabic(const UChar *source, int32_t sourceLength, UChar *dest, int32_t destCapacity, uint32_t options, UErrorCode *pErrorCode) { |
| int32_t destLength; |
| |
| /* usual error checking */ |
| if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { |
| return 0; |
| } |
| |
| /* make sure that no reserved options values are used; allow dest==NULL only for preflighting */ |
| if( source==NULL || sourceLength<-1 || |
| (dest==NULL && destCapacity!=0) || destCapacity<0 || |
| options>=U_SHAPE_DIGIT_TYPE_RESERVED || |
| (options&U_SHAPE_DIGITS_MASK)>=U_SHAPE_DIGITS_RESERVED |
| ) { |
| *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; |
| return 0; |
| } |
| |
| /* determine the source length */ |
| if(sourceLength==-1) { |
| sourceLength=u_strlen(source); |
| } |
| if(sourceLength==0) { |
| return 0; |
| } |
| |
| /* check that source and destination do not overlap */ |
| if( dest!=NULL && |
| ((source<=dest && dest<source+sourceLength) || |
| (dest<=source && source<dest+destCapacity)) |
| ) { |
| *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; |
| return 0; |
| } |
| |
| if((options&U_SHAPE_LETTERS_MASK)!=U_SHAPE_LETTERS_NOOP) { |
| int32_t outputSize = sourceLength; |
| |
| /* calculate destination size */ |
| /* TODO: do we ever need to do this pure preflighting? */ |
| ASSERT((options&U_SHAPE_LENGTH_MASK) != U_SHAPE_LENGTH_GROW_SHRINK); |
| |
| if(outputSize>destCapacity) { |
| *pErrorCode=U_BUFFER_OVERFLOW_ERROR; |
| return outputSize; |
| } |
| |
| /* Start of Arabic letter shaping part */ |
| memcpy(dest, source, sourceLength*U_SIZEOF_UCHAR); |
| |
| ASSERT((options&U_SHAPE_TEXT_DIRECTION_MASK) == U_SHAPE_TEXT_DIRECTION_LOGICAL); |
| |
| switch(options&U_SHAPE_LETTERS_MASK) { |
| case U_SHAPE_LETTERS_SHAPE : |
| /* Call the shaping function with tashkeel flag == 1 */ |
| destLength = shapeUnicode(dest,sourceLength,destCapacity,1); |
| break; |
| case U_SHAPE_LETTERS_SHAPE_TASHKEEL_ISOLATED : |
| /* Call the shaping function with tashkeel flag == 0 */ |
| destLength = shapeUnicode(dest,sourceLength,destCapacity,0); |
| break; |
| case U_SHAPE_LETTERS_UNSHAPE : |
| ASSERT_NOT_REACHED(); |
| break; |
| default : |
| /* will never occur because of validity checks above */ |
| destLength = 0; |
| break; |
| } |
| |
| /* End of Arabic letter shaping part */ |
| } else |
| ASSERT_NOT_REACHED(); |
| |
| ASSERT((options & U_SHAPE_DIGITS_MASK) == U_SHAPE_DIGITS_NOOP); |
| |
| return sourceLength; |
| } |
| |
| #endif // USE(ATSUI) |