1299 iContext->TranslateMonochromeGlyphBitmap(aFace->Face()->glyph,aGlyphData); |
1282 iContext->TranslateMonochromeGlyphBitmap(aFace->Face()->glyph,aGlyphData); |
1300 else |
1283 else |
1301 iContext->TranslateAntiAliasedGlyphBitmap(aFace->Face()->glyph,aGlyphData); |
1284 iContext->TranslateAntiAliasedGlyphBitmap(aFace->Face()->glyph,aGlyphData); |
1302 } |
1285 } |
1303 |
1286 |
1304 enum vg_commands { |
|
1305 VG_CMD_NONE = 0, |
|
1306 VG_CMD_MOVETO, |
|
1307 VG_CMD_LINETO, |
|
1308 VG_CMD_CONICTO, |
|
1309 VG_CMD_CUBICTO, |
|
1310 VG_CMD_CLOSE |
|
1311 }; |
|
1312 |
|
1313 |
|
1314 enum contour_states |
|
1315 { |
|
1316 CONTOUR_STATE_NOT_STARTED = 0, |
|
1317 CONTOUR_STATE_START, |
|
1318 CONTOUR_STATE_CONIC, |
|
1319 CONTOUR_STATE_CUBIC1, |
|
1320 CONTOUR_STATE_CUBIC2, |
|
1321 CONTOUR_STATE_MAX |
|
1322 }; |
|
1323 |
|
1324 static const TInt StateTransitions[CONTOUR_STATE_MAX][3] = |
|
1325 { |
|
1326 {CONTOUR_STATE_START, -1, -1}, |
|
1327 {CONTOUR_STATE_START, CONTOUR_STATE_CONIC, CONTOUR_STATE_CUBIC1}, |
|
1328 {CONTOUR_STATE_START, -1, -1}, |
|
1329 {-1, -1, CONTOUR_STATE_CUBIC2}, |
|
1330 {CONTOUR_STATE_START, -1, -1}, |
|
1331 }; |
|
1332 |
|
1333 static const TInt OutputCommands[CONTOUR_STATE_MAX][3] = |
|
1334 { |
|
1335 {VG_CMD_MOVETO, -1, -1}, |
|
1336 {VG_CMD_LINETO, VG_CMD_NONE, VG_CMD_NONE}, |
|
1337 {VG_CMD_CONICTO, -1, -1}, |
|
1338 {-1, -1, VG_CMD_NONE}, |
|
1339 {VG_CMD_CUBICTO, -1, -1}, |
|
1340 }; |
|
1341 |
|
1342 |
|
1343 class MVGCommandProcessor |
|
1344 { |
|
1345 public: |
|
1346 virtual TInt ProcessCommand(TInt8 cmd, FT_Vector &start, FT_Vector &end) = 0; |
|
1347 }; |
|
1348 |
|
1349 class COutlineStringBuilder: public MVGCommandProcessor, public CBase |
|
1350 { |
|
1351 private: |
|
1352 TUint8 *iBuffer; |
|
1353 TUint8 *iCur; |
|
1354 TInt iLen; |
|
1355 |
|
1356 |
|
1357 public: |
|
1358 COutlineStringBuilder():iBuffer(0), iLen(2000) |
|
1359 { |
|
1360 iBuffer = (TUint8 *)User::Alloc(iLen); |
|
1361 iCur = iBuffer; |
|
1362 } |
|
1363 |
|
1364 ~COutlineStringBuilder() |
|
1365 { |
|
1366 // ownership of the buffer is transferred to the caller. |
|
1367 } |
|
1368 |
|
1369 |
|
1370 TUint8 *GetBuffer(TInt &aLen) |
|
1371 { |
|
1372 aLen = iCur - iBuffer; |
|
1373 *iCur = '\0'; |
|
1374 return iBuffer; |
|
1375 } |
|
1376 |
|
1377 TInt AppendChar(char ch) |
|
1378 { |
|
1379 *(iCur++) = ch; |
|
1380 return 0; |
|
1381 } |
|
1382 |
|
1383 TInt AppendFTPos(FT_Pos n) |
|
1384 { |
|
1385 int divisor = 1; |
|
1386 FT_Pos tmp = (n > 0) ? n : (-n); |
|
1387 while (tmp/divisor >= 10) { |
|
1388 divisor *= 10; |
|
1389 } |
|
1390 |
|
1391 if (n < 0) |
|
1392 { |
|
1393 AppendChar('-'); |
|
1394 } |
|
1395 |
|
1396 for ( ; divisor >= 1; divisor /= 10) |
|
1397 { |
|
1398 AppendChar('0' + tmp/divisor); |
|
1399 tmp = tmp % divisor; |
|
1400 } |
|
1401 |
|
1402 return 0; |
|
1403 } |
|
1404 |
|
1405 TInt AppendCoord(FT_Pos x, FT_Pos y) |
|
1406 { |
|
1407 AppendFTPos(x); |
|
1408 AppendChar(','); |
|
1409 AppendFTPos(y); |
|
1410 AppendChar(' '); |
|
1411 return 0; |
|
1412 } |
|
1413 |
|
1414 TInt |
|
1415 ProcessCommand(TInt8 cmd, FT_Vector &start, FT_Vector &end) |
|
1416 { |
|
1417 FT_Vector *st = &start; |
|
1418 |
|
1419 if (iCur + 64 > iBuffer + iLen) |
|
1420 { |
|
1421 TUint distance = iCur - iBuffer; |
|
1422 iLen += 1000; |
|
1423 TUint8 *newBuffer = (TUint8 *)User::ReAlloc(iBuffer, iLen); |
|
1424 iBuffer = newBuffer; |
|
1425 iCur = iBuffer + distance; |
|
1426 } |
|
1427 |
|
1428 if (VG_CMD_MOVETO == cmd) |
|
1429 { |
|
1430 AppendChar('M'); |
|
1431 AppendCoord(start.x, start.y); |
|
1432 } |
|
1433 else if (VG_CMD_LINETO == cmd) |
|
1434 { |
|
1435 AppendChar('L'); |
|
1436 AppendCoord(end.x, end.y); |
|
1437 } |
|
1438 else if (VG_CMD_CONICTO == cmd) |
|
1439 { |
|
1440 AppendChar('Q'); |
|
1441 AppendCoord((st+1)->x, (st+1)->y); |
|
1442 AppendCoord(end.x, end.y); |
|
1443 } |
|
1444 else if (VG_CMD_CUBICTO == cmd) |
|
1445 { |
|
1446 AppendChar('Q'); |
|
1447 AppendCoord((st+1)->x, (st+1)->y); |
|
1448 AppendCoord((st+2)->x, (st+2)->y); |
|
1449 AppendCoord(end.x, end.y); |
|
1450 } |
|
1451 else if (VG_CMD_CLOSE == cmd) |
|
1452 { |
|
1453 AppendChar('Z'); |
|
1454 AppendChar(' '); |
|
1455 } |
|
1456 |
|
1457 return KErrNone; |
|
1458 } |
|
1459 }; |
|
1460 |
|
1461 |
|
1462 class COutlineConvDirector: public CBase { |
|
1463 private: |
|
1464 MVGCommandProcessor *iProcessor; |
|
1465 const FT_Outline *iOutline; |
|
1466 FT_Outline iNewOutline; |
|
1467 |
|
1468 |
|
1469 private: |
|
1470 char |
|
1471 GetNextPointType(char aTag) |
|
1472 { |
|
1473 char ret = FT_CURVE_TAG(aTag); |
|
1474 if (FT_CURVE_TAG_ON == ret) |
|
1475 { |
|
1476 ret = 0; |
|
1477 } |
|
1478 else if (FT_CURVE_TAG_CONIC == ret) |
|
1479 { |
|
1480 ret = 1; |
|
1481 } |
|
1482 else if (FT_CURVE_TAG_CUBIC == ret) |
|
1483 { |
|
1484 ret = 2; |
|
1485 } |
|
1486 else |
|
1487 { |
|
1488 __ASSERT_DEBUG(0, User::Panic(_L("IncorrectState"), -1)); |
|
1489 } |
|
1490 return ret; |
|
1491 } |
|
1492 |
|
1493 TInt SwapPoints(const TInt i1, const TInt i2) |
|
1494 { |
|
1495 FT_Vector tmpVector = iOutline->points[i1]; |
|
1496 char tmpTags = iOutline->tags[i1]; |
|
1497 iOutline->points[i1] = iOutline->points[i2]; |
|
1498 iOutline->tags[i1] = iOutline->tags[i2]; |
|
1499 iOutline->points[i2] = tmpVector; |
|
1500 iOutline->tags[i2] = tmpTags; |
|
1501 return 0; |
|
1502 } |
|
1503 |
|
1504 TInt MoveFirstOnPointToBeginning(const TInt aStartIndex, const TInt aEndIndex) |
|
1505 { |
|
1506 /* Contours of three or more points are valid, and single points |
|
1507 * (reference points, technically not contours) are also valid as |
|
1508 * special cases in TrueType. |
|
1509 */ |
|
1510 char curTag = FT_CURVE_TAG(iOutline->tags[aStartIndex]); |
|
1511 |
|
1512 // so a contour having only one point which is 'off' is invalid! |
|
1513 __ASSERT_DEBUG(!(aEndIndex - aStartIndex == 0 && FT_CURVE_TAG_ON != curTag), |
|
1514 User::Panic(_L("Contour consisting of 1 'off' point."), -1)); |
|
1515 |
|
1516 /* Contours consisting of two points are not a valid configuration. */ |
|
1517 __ASSERT_DEBUG(aEndIndex - aStartIndex != 1, |
|
1518 User::Panic(_L("Contour consisting of two points."), -1)); |
|
1519 |
|
1520 if (FT_CURVE_TAG_ON == curTag) |
|
1521 { |
|
1522 return KErrNone; |
|
1523 } |
|
1524 TInt firstOnIndex = -1; |
|
1525 TInt i = 0; |
|
1526 for (i = 1+aStartIndex; i < aEndIndex; ++i) |
|
1527 { |
|
1528 if (FT_CURVE_TAG_ON == FT_CURVE_TAG(iOutline->tags[i])) |
|
1529 { |
|
1530 firstOnIndex = i; |
|
1531 break; |
|
1532 } |
|
1533 } |
|
1534 __ASSERT_DEBUG(-1 != firstOnIndex, |
|
1535 User::Panic(_L("Contour containing no 'on' point."), -1)); |
|
1536 |
|
1537 for (i = firstOnIndex-1; i >= aStartIndex; --i) |
|
1538 { |
|
1539 for (TInt j = i; j < aEndIndex; ++j) |
|
1540 { |
|
1541 SwapPoints(j, j+1); |
|
1542 } |
|
1543 } |
|
1544 |
|
1545 return KErrNone; |
|
1546 } |
|
1547 |
|
1548 TInt |
|
1549 ConvertContour(const TInt aStartIndex, const TInt aEndIndex) |
|
1550 { |
|
1551 /* Contours consisting of two |
|
1552 * points are not a valid configuration. |
|
1553 */ |
|
1554 __ASSERT_DEBUG(aEndIndex - aStartIndex != 1, |
|
1555 User::Panic(_L("Contour consisting of two points."), -1)); |
|
1556 |
|
1557 TInt state = CONTOUR_STATE_NOT_STARTED, newState = -1; |
|
1558 TInt cmdStart = aStartIndex, cmdCur = 0, command = -1; |
|
1559 |
|
1560 char ptype = GetNextPointType(iNewOutline.tags[cmdStart]); |
|
1561 __ASSERT_DEBUG(0 == ptype, User::Panic(_L("IncorrectState"), -1)); |
|
1562 state = CONTOUR_STATE_START; |
|
1563 iProcessor->ProcessCommand(VG_CMD_MOVETO, |
|
1564 iNewOutline.points[aStartIndex], iNewOutline.points[aStartIndex]); |
|
1565 |
|
1566 |
|
1567 for (cmdCur = cmdStart + 1; cmdCur <= aEndIndex; ++cmdCur) |
|
1568 { |
|
1569 ptype = GetNextPointType(iNewOutline.tags[cmdCur]); |
|
1570 newState = StateTransitions[state][ptype]; |
|
1571 __ASSERT_DEBUG(-1 != newState, User::Panic(_L("IncorrectState"), -1)); |
|
1572 command = OutputCommands[state][ptype]; |
|
1573 __ASSERT_DEBUG(-1 != command, User::Panic(_L("IncorrectState"), -1)); |
|
1574 |
|
1575 if (VG_CMD_NONE != command) |
|
1576 { |
|
1577 iProcessor->ProcessCommand(command, |
|
1578 iNewOutline.points[cmdStart], iNewOutline.points[cmdCur]); |
|
1579 cmdStart = cmdCur; |
|
1580 } |
|
1581 state = newState; |
|
1582 } |
|
1583 |
|
1584 if (CONTOUR_STATE_CONIC == state) |
|
1585 { |
|
1586 iProcessor->ProcessCommand(VG_CMD_CONICTO, iNewOutline.points[cmdStart], |
|
1587 iNewOutline.points[aStartIndex]); |
|
1588 } |
|
1589 else if (CONTOUR_STATE_CUBIC2 == state) |
|
1590 { |
|
1591 iProcessor->ProcessCommand(VG_CMD_CUBICTO, iNewOutline.points[cmdStart], |
|
1592 iNewOutline.points[aStartIndex]); |
|
1593 } |
|
1594 iProcessor->ProcessCommand(VG_CMD_CLOSE, |
|
1595 iNewOutline.points[aStartIndex], iNewOutline.points[aStartIndex]); |
|
1596 |
|
1597 return KErrNone; |
|
1598 } |
|
1599 |
|
1600 |
|
1601 TInt Preprocess() |
|
1602 { |
|
1603 /* two successive conic "off" points forces the rasterizer to |
|
1604 * create (during the scan-line conversion process exclusively) a |
|
1605 * virtual "on" point amidst them, at their exact middle. |
|
1606 */ |
|
1607 char prevTag = FT_CURVE_TAG(iOutline->tags[0]), currentTag = 0; |
|
1608 TInt numNewPoints = 0; |
|
1609 TInt contourIndex = 0; |
|
1610 |
|
1611 iNewOutline.contours = 0; |
|
1612 iNewOutline.n_contours = iOutline->n_contours; |
|
1613 iNewOutline.contours = (short *) |
|
1614 User::Alloc(iNewOutline.n_contours * sizeof(short)); |
|
1615 |
|
1616 if (0 == iOutline->contours[0]) |
|
1617 { |
|
1618 iNewOutline.contours[0] = iOutline->contours[0]; // == 0 |
|
1619 ++contourIndex; |
|
1620 } |
|
1621 for (TInt i = 1; i < iOutline->n_points; ++i) |
|
1622 { |
|
1623 currentTag = FT_CURVE_TAG(iOutline->tags[i]); |
|
1624 if (FT_CURVE_TAG_CONIC == prevTag && prevTag == currentTag) |
|
1625 { |
|
1626 numNewPoints++; |
|
1627 } |
|
1628 prevTag = currentTag; |
|
1629 if (i == iOutline->contours[contourIndex]) |
|
1630 { |
|
1631 iNewOutline.contours[contourIndex] = |
|
1632 iOutline->contours[contourIndex] + numNewPoints; |
|
1633 ++contourIndex; |
|
1634 } |
|
1635 } |
|
1636 |
|
1637 |
|
1638 iNewOutline.n_points = iOutline->n_points + numNewPoints; |
|
1639 iNewOutline.flags = iOutline->flags; |
|
1640 |
|
1641 iNewOutline.points = 0; |
|
1642 iNewOutline.tags = 0; |
|
1643 |
|
1644 iNewOutline.points = (FT_Vector *) |
|
1645 User::Alloc(iNewOutline.n_points * sizeof(FT_Vector)); |
|
1646 |
|
1647 if (iNewOutline.contours) |
|
1648 { |
|
1649 iNewOutline.tags = (char *) |
|
1650 User::Alloc(iNewOutline.n_points * sizeof(char)); |
|
1651 } |
|
1652 |
|
1653 // copy the 'points' and 'tags' array, inserting new points |
|
1654 // when necessary. |
|
1655 TInt oldIndex = 0, newIndex = 0; |
|
1656 for ( ; oldIndex < iOutline->n_points; ++oldIndex) |
|
1657 { |
|
1658 char oldTag = FT_CURVE_TAG(iOutline->tags[oldIndex]); |
|
1659 iNewOutline.points[newIndex] = iOutline->points[oldIndex]; |
|
1660 iNewOutline.tags[newIndex] = iOutline->tags[oldIndex]; |
|
1661 |
|
1662 if (FT_CURVE_TAG_CONIC == oldTag && |
|
1663 oldIndex + 1 < iOutline->n_points) |
|
1664 { |
|
1665 char nextTag = FT_CURVE_TAG(iOutline->tags[oldIndex+1]); |
|
1666 // insert a new 'on' point when there are two consecutive |
|
1667 // 'conic off' points. |
|
1668 if (oldTag == nextTag) |
|
1669 { |
|
1670 newIndex++; |
|
1671 FT_Vector *cur = &(iOutline->points[oldIndex]); |
|
1672 FT_Vector *next = &(iOutline->points[oldIndex + 1]); |
|
1673 iNewOutline.points[newIndex].x = (cur->x + next->x)/2; |
|
1674 iNewOutline.points[newIndex].y = (cur->y + next->y)/2; |
|
1675 iNewOutline.tags[newIndex] = FT_CURVE_TAG_ON; |
|
1676 } |
|
1677 } |
|
1678 newIndex++; |
|
1679 } |
|
1680 |
|
1681 return 0; |
|
1682 } |
|
1683 |
|
1684 public: |
|
1685 COutlineConvDirector():iProcessor(0), iOutline(0) |
|
1686 { |
|
1687 // a null constructor |
|
1688 iNewOutline.contours = 0; |
|
1689 iNewOutline.tags = 0; |
|
1690 iNewOutline.points = 0; |
|
1691 } |
|
1692 |
|
1693 ~COutlineConvDirector() |
|
1694 { |
|
1695 User::Free(iNewOutline.contours); |
|
1696 User::Free(iNewOutline.points); |
|
1697 User::Free(iNewOutline.tags); |
|
1698 } |
|
1699 |
|
1700 TInt |
|
1701 ConvertOutline(const FT_Outline &aOutline, MVGCommandProcessor *aProcessor) |
|
1702 { |
|
1703 if (0 != aOutline.n_contours) |
|
1704 { |
|
1705 iProcessor = aProcessor; |
|
1706 iOutline = &aOutline; |
|
1707 |
|
1708 MoveFirstOnPointToBeginning(0, iOutline->contours[0]); |
|
1709 TInt i = 0; |
|
1710 for (i = 1; i < iOutline->n_contours; ++i) |
|
1711 { |
|
1712 MoveFirstOnPointToBeginning(iOutline->contours[i-1]+1, iOutline->contours[i]); |
|
1713 } |
|
1714 |
|
1715 Preprocess(); |
|
1716 |
|
1717 ConvertContour(0, iNewOutline.contours[0]); |
|
1718 for (i = 1; i < iNewOutline.n_contours; ++i) |
|
1719 { |
|
1720 ConvertContour(iNewOutline.contours[i-1]+1, iNewOutline.contours[i]); |
|
1721 } |
|
1722 } |
|
1723 else |
|
1724 { |
|
1725 RDebug::Printf("Zero contour in outline: missing glyph."); |
|
1726 FT_Vector dummyVector; |
|
1727 aProcessor->ProcessCommand(VG_CMD_CLOSE, dummyVector, dummyVector); |
|
1728 } |
|
1729 return KErrNone; |
|
1730 } |
|
1731 }; |
|
1732 |
|
1733 |
|
1734 TInt CFreeTypeFontFile::GetGlyphOutline(TInt aFaceIndex, TUint aCode, |
|
1735 TBool aIsGlyphId, TBool, TAny*& aOutline, TInt &aLength) |
|
1736 { |
|
1737 // The 4th param 'aHinted' is ignored in this reference implementation. |
|
1738 // Need to add it back and implement accordingly if freetype is used in |
|
1739 // production code. |
|
1740 CFaceListItem *faceList = LoadFaceL(aFaceIndex); |
|
1741 FT_Face face = faceList->Face(); |
|
1742 TUint code = aCode; |
|
1743 if (!aIsGlyphId) |
|
1744 { |
|
1745 code = FT_Get_Char_Index(face, aCode); |
|
1746 if (0 == code) |
|
1747 { |
|
1748 return KErrNotFound; |
|
1749 } |
|
1750 } |
|
1751 |
|
1752 TInt ret = FT_Load_Glyph(face, code, |
|
1753 FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_TRANSFORM); |
|
1754 |
|
1755 if (0 != ret) |
|
1756 { |
|
1757 return KErrUnknown; |
|
1758 } |
|
1759 |
|
1760 COutlineStringBuilder strBuilder; |
|
1761 if (0 != strBuilder.GetBuffer(aLength)) |
|
1762 { |
|
1763 FT_Outline &outline = face->glyph->outline; |
|
1764 |
|
1765 COutlineConvDirector d; |
|
1766 d.ConvertOutline(outline, &strBuilder); |
|
1767 } |
|
1768 else |
|
1769 { |
|
1770 return KErrNoMemory; |
|
1771 } |
|
1772 |
|
1773 TUint8 *buf = strBuilder.GetBuffer(aLength); |
|
1774 RDebug::Printf("length of buffer is %d\n", aLength); |
|
1775 RDebug::Printf("Outline for glyph %d: \n", aCode); |
|
1776 RDebug::Printf("%s", buf); |
|
1777 aOutline = (TAny*)buf; |
|
1778 |
|
1779 return KErrNone; |
|
1780 } |
|
1781 TAny* CFreeTypeFontFile::GetTrueTypeTable(TInt& aError, TInt aFaceIndex, |
1287 TAny* CFreeTypeFontFile::GetTrueTypeTable(TInt& aError, TInt aFaceIndex, |
1782 TUint32 aTag, TInt* aLength) |
1288 TUint32 aTag, TInt* aLength) |
1783 { |
1289 { |
1784 aError = KErrNone; |
1290 aError = KErrNone; |
1785 |
1291 |