diff options
| author | Kenichi Handa | 2011-05-18 23:11:50 +0900 |
|---|---|---|
| committer | Kenichi Handa | 2011-05-18 23:11:50 +0900 |
| commit | a28d4396018e48479916fd624e2371aa1f75e6e7 (patch) | |
| tree | 541383e75514ee6f0b71ab9fd55dc80dae1ee1de /src | |
| parent | 7edd2093898ad14d78da23a3ea690df7de5616c4 (diff) | |
| download | emacs-a28d4396018e48479916fd624e2371aa1f75e6e7.tar.gz emacs-a28d4396018e48479916fd624e2371aa1f75e6e7.zip | |
Make find_automatic_composition more efficient.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 6 | ||||
| -rw-r--r-- | src/composite.c | 279 |
2 files changed, 156 insertions, 129 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index ceb45afebc5..fd6f42acb91 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,9 @@ | |||
| 1 | 2011-05-18 Kenichi Handa <handa@m17n.org> | ||
| 2 | |||
| 3 | * composite.c (CHAR_COMPOSABLE_P): Add more check for efficiency. | ||
| 4 | (BACKWARD_CHAR): Wrap the arg STOP by parenthesis. | ||
| 5 | (find_automatic_composition): Mostly rewrite for efficiency. | ||
| 6 | |||
| 1 | 2011-05-12 Drew Adams <drew.adams@oracle.com> | 7 | 2011-05-12 Drew Adams <drew.adams@oracle.com> |
| 2 | 8 | ||
| 3 | * textprop.c (Fprevious_single_char_property_change): Doc fix (bug#8655). | 9 | * textprop.c (Fprevious_single_char_property_change): Doc fix (bug#8655). |
diff --git a/src/composite.c b/src/composite.c index f069acce1c0..8f8878e46a9 100644 --- a/src/composite.c +++ b/src/composite.c | |||
| @@ -972,11 +972,12 @@ static int _work_char; | |||
| 972 | category Z? or C? are not composable except for ZWNJ and ZWJ. */ | 972 | category Z? or C? are not composable except for ZWNJ and ZWJ. */ |
| 973 | 973 | ||
| 974 | #define CHAR_COMPOSABLE_P(C) \ | 974 | #define CHAR_COMPOSABLE_P(C) \ |
| 975 | ((C) == 0x200C || (C) == 0x200D \ | 975 | ((C) > ' ' \ |
| 976 | || (_work_val = CHAR_TABLE_REF (Vunicode_category_table, (C)), \ | 976 | && ((C) == 0x200C || (C) == 0x200D \ |
| 977 | (SYMBOLP (_work_val) \ | 977 | || (_work_val = CHAR_TABLE_REF (Vunicode_category_table, (C)), \ |
| 978 | && (_work_char = SDATA (SYMBOL_NAME (_work_val))[0]) != 'C' \ | 978 | (SYMBOLP (_work_val) \ |
| 979 | && _work_char != 'Z'))) | 979 | && (_work_char = SDATA (SYMBOL_NAME (_work_val))[0]) != 'C' \ |
| 980 | && _work_char != 'Z')))) | ||
| 980 | 981 | ||
| 981 | /* Update cmp_it->stop_pos to the next position after CHARPOS (and | 982 | /* Update cmp_it->stop_pos to the next position after CHARPOS (and |
| 982 | BYTEPOS) where character composition may happen. If BYTEPOS is | 983 | BYTEPOS) where character composition may happen. If BYTEPOS is |
| @@ -1471,7 +1472,7 @@ struct position_record | |||
| 1471 | /* Update the members of POSITION to the previous character boundary. */ | 1472 | /* Update the members of POSITION to the previous character boundary. */ |
| 1472 | #define BACKWARD_CHAR(POSITION, STOP) \ | 1473 | #define BACKWARD_CHAR(POSITION, STOP) \ |
| 1473 | do { \ | 1474 | do { \ |
| 1474 | if ((POSITION).pos == STOP) \ | 1475 | if ((POSITION).pos == (STOP)) \ |
| 1475 | (POSITION).p = GPT_ADDR; \ | 1476 | (POSITION).p = GPT_ADDR; \ |
| 1476 | do { \ | 1477 | do { \ |
| 1477 | (POSITION).pos_byte--; \ | 1478 | (POSITION).pos_byte--; \ |
| @@ -1481,178 +1482,198 @@ struct position_record | |||
| 1481 | } while (0) | 1482 | } while (0) |
| 1482 | 1483 | ||
| 1483 | /* This is like find_composition, but find an automatic composition | 1484 | /* This is like find_composition, but find an automatic composition |
| 1484 | instead. If found, set *GSTRING to the glyph-string representing | 1485 | instead. It is assured that POS is not within a static |
| 1485 | the composition, and return 1. Otherwise, return 0. */ | 1486 | composition. If found, set *GSTRING to the glyph-string |
| 1487 | representing the composition, and return 1. Otherwise, *GSTRING to | ||
| 1488 | Qnil, and return 0. */ | ||
| 1486 | 1489 | ||
| 1487 | static int | 1490 | static int |
| 1488 | find_automatic_composition (EMACS_INT pos, EMACS_INT limit, EMACS_INT *start, EMACS_INT *end, Lisp_Object *gstring, Lisp_Object string) | 1491 | find_automatic_composition (EMACS_INT pos, EMACS_INT limit, |
| 1492 | EMACS_INT *start, EMACS_INT *end, | ||
| 1493 | Lisp_Object *gstring, Lisp_Object string) | ||
| 1489 | { | 1494 | { |
| 1490 | EMACS_INT head, tail, stop; | 1495 | EMACS_INT head, tail, stop; |
| 1491 | /* Limit to check a composition after POS. */ | 1496 | /* Forward limit position of checking a composition taking a |
| 1497 | looking-back count into account. */ | ||
| 1492 | EMACS_INT fore_check_limit; | 1498 | EMACS_INT fore_check_limit; |
| 1493 | struct position_record orig, cur; | 1499 | struct position_record cur, prev; |
| 1494 | |||
| 1495 | /* FIXME: It's not obvious whether these two variables need initialization. | ||
| 1496 | If they do, please supply initial values. | ||
| 1497 | If not, please remove this comment. */ | ||
| 1498 | struct position_record check IF_LINT (= {0}), prev IF_LINT (= {0}); | ||
| 1499 | |||
| 1500 | Lisp_Object check_val, val, elt; | ||
| 1501 | int c; | 1500 | int c; |
| 1502 | Lisp_Object window; | 1501 | Lisp_Object window; |
| 1503 | struct window *w; | 1502 | struct window *w; |
| 1503 | int need_adjustment = 0; | ||
| 1504 | 1504 | ||
| 1505 | window = Fget_buffer_window (Fcurrent_buffer (), Qnil); | 1505 | window = Fget_buffer_window (Fcurrent_buffer (), Qnil); |
| 1506 | if (NILP (window)) | 1506 | if (NILP (window)) |
| 1507 | return 0; | 1507 | return 0; |
| 1508 | w = XWINDOW (window); | 1508 | w = XWINDOW (window); |
| 1509 | 1509 | ||
| 1510 | orig.pos = pos; | 1510 | cur.pos = pos; |
| 1511 | if (NILP (string)) | 1511 | if (NILP (string)) |
| 1512 | { | 1512 | { |
| 1513 | head = BEGV, tail = ZV, stop = GPT; | 1513 | head = BEGV, tail = ZV, stop = GPT; |
| 1514 | orig.pos_byte = CHAR_TO_BYTE (orig.pos); | 1514 | cur.pos_byte = CHAR_TO_BYTE (cur.pos); |
| 1515 | orig.p = BYTE_POS_ADDR (orig.pos_byte); | 1515 | cur.p = BYTE_POS_ADDR (cur.pos_byte); |
| 1516 | } | 1516 | } |
| 1517 | else | 1517 | else |
| 1518 | { | 1518 | { |
| 1519 | head = 0, tail = SCHARS (string), stop = -1; | 1519 | head = 0, tail = SCHARS (string), stop = -1; |
| 1520 | orig.pos_byte = string_char_to_byte (string, orig.pos); | 1520 | cur.pos_byte = string_char_to_byte (string, cur.pos); |
| 1521 | orig.p = SDATA (string) + orig.pos_byte; | 1521 | cur.p = SDATA (string) + cur.pos_byte; |
| 1522 | } | 1522 | } |
| 1523 | if (limit < pos) | 1523 | if (limit < 0) |
| 1524 | fore_check_limit = min (tail, pos + MAX_AUTO_COMPOSITION_LOOKBACK); | 1524 | /* Finding a composition covering the character after POS is the |
| 1525 | same as setting LIMIT to POS. */ | ||
| 1526 | limit = pos; | ||
| 1527 | if (limit <= pos) | ||
| 1528 | fore_check_limit = min (tail, pos + 1 + MAX_AUTO_COMPOSITION_LOOKBACK); | ||
| 1525 | else | 1529 | else |
| 1526 | fore_check_limit = min (tail, limit + MAX_AUTO_COMPOSITION_LOOKBACK); | 1530 | fore_check_limit = min (tail, limit + MAX_AUTO_COMPOSITION_LOOKBACK); |
| 1527 | cur = orig; | ||
| 1528 | 1531 | ||
| 1529 | retry: | 1532 | /* Provided that we have these possible compositions now: |
| 1530 | check_val = Qnil; | ||
| 1531 | /* At first, check if POS is composable. */ | ||
| 1532 | c = STRING_CHAR (cur.p); | ||
| 1533 | if (! CHAR_COMPOSABLE_P (c)) | ||
| 1534 | { | ||
| 1535 | if (limit < 0) | ||
| 1536 | return 0; | ||
| 1537 | if (limit >= cur.pos) | ||
| 1538 | goto search_forward; | ||
| 1539 | } | ||
| 1540 | else | ||
| 1541 | { | ||
| 1542 | val = CHAR_TABLE_REF (Vcomposition_function_table, c); | ||
| 1543 | if (! NILP (val)) | ||
| 1544 | check_val = val, check = cur; | ||
| 1545 | else | ||
| 1546 | while (cur.pos + 1 < fore_check_limit) | ||
| 1547 | { | ||
| 1548 | EMACS_INT b, e; | ||
| 1549 | 1533 | ||
| 1550 | FORWARD_CHAR (cur, stop); | 1534 | POS: 1 2 3 4 5 6 7 8 9 |
| 1551 | if (get_property_and_range (cur.pos, Qcomposition, &val, &b, &e, | 1535 | |-A-| |
| 1552 | Qnil) | 1536 | |-B-|-C-|--D--| |
| 1553 | && COMPOSITION_VALID_P (b, e, val)) | ||
| 1554 | { | ||
| 1555 | fore_check_limit = cur.pos; | ||
| 1556 | break; | ||
| 1557 | } | ||
| 1558 | c = STRING_CHAR (cur.p); | ||
| 1559 | if (! CHAR_COMPOSABLE_P (c)) | ||
| 1560 | break; | ||
| 1561 | val = CHAR_TABLE_REF (Vcomposition_function_table, c); | ||
| 1562 | if (NILP (val)) | ||
| 1563 | continue; | ||
| 1564 | check_val = val, check = cur; | ||
| 1565 | break; | ||
| 1566 | } | ||
| 1567 | cur = orig; | ||
| 1568 | } | ||
| 1569 | /* Rewind back to the position where we can safely search forward | ||
| 1570 | for compositions. */ | ||
| 1571 | while (cur.pos > head) | ||
| 1572 | { | ||
| 1573 | EMACS_INT b, e; | ||
| 1574 | 1537 | ||
| 1575 | BACKWARD_CHAR (cur, stop); | 1538 | Here, it is known that characters after positions 1 and 9 can |
| 1576 | if (get_property_and_range (cur.pos, Qcomposition, &val, &b, &e, Qnil) | 1539 | never be composed (i.e. ! CHAR_COMPOSABLE_P (CH)), and |
| 1577 | && COMPOSITION_VALID_P (b, e, val)) | 1540 | composition A is an invalid one because it's partially covered by |
| 1578 | break; | 1541 | the valid composition C. And to know whether a composition is |
| 1542 | valid or not, the only way is to start searching forward from a | ||
| 1543 | position that can not be a tail part of composition (it's 2 in | ||
| 1544 | the above case). | ||
| 1545 | |||
| 1546 | Now we have these cases (1 through 4): | ||
| 1547 | |||
| 1548 | -- character after POS is ... -- | ||
| 1549 | not composable composable | ||
| 1550 | LIMIT <= POS (1) (3) | ||
| 1551 | POS < LIMIT (2) (4) | ||
| 1552 | |||
| 1553 | Among them, in case (2), we simply search forward from POS. | ||
| 1554 | |||
| 1555 | In the other cases, we at first rewind back to the position where | ||
| 1556 | the previous character is not composable or the beginning of | ||
| 1557 | buffer (string), then search compositions forward. In case (1) | ||
| 1558 | and (3) we repeat this process until a composition is found. */ | ||
| 1559 | |||
| 1560 | while (1) | ||
| 1561 | { | ||
| 1579 | c = STRING_CHAR (cur.p); | 1562 | c = STRING_CHAR (cur.p); |
| 1580 | if (! CHAR_COMPOSABLE_P (c)) | 1563 | if (! CHAR_COMPOSABLE_P (c)) |
| 1581 | break; | ||
| 1582 | val = CHAR_TABLE_REF (Vcomposition_function_table, c); | ||
| 1583 | if (! NILP (val)) | ||
| 1584 | check_val = val, check = cur; | ||
| 1585 | } | ||
| 1586 | prev = cur; | ||
| 1587 | /* Now search forward. */ | ||
| 1588 | search_forward: | ||
| 1589 | *gstring = Qnil; | ||
| 1590 | if (! NILP (check_val) || limit >= orig.pos) | ||
| 1591 | { | ||
| 1592 | if (NILP (check_val)) | ||
| 1593 | cur = orig; | ||
| 1594 | else | ||
| 1595 | cur = check; | ||
| 1596 | while (cur.pos < fore_check_limit) | ||
| 1597 | { | 1564 | { |
| 1598 | int need_adjustment = 0; | 1565 | if (limit <= pos) /* case (1) */ |
| 1566 | { | ||
| 1567 | do { | ||
| 1568 | if (cur.pos == limit) | ||
| 1569 | return 0; | ||
| 1570 | BACKWARD_CHAR (cur, stop); | ||
| 1571 | c = STRING_CHAR (cur.p); | ||
| 1572 | } while (! CHAR_COMPOSABLE_P (c)); | ||
| 1573 | fore_check_limit = cur.pos + 1; | ||
| 1574 | } | ||
| 1575 | else /* case (2) */ | ||
| 1576 | /* No need of rewinding back. */ | ||
| 1577 | goto search_forward; | ||
| 1578 | } | ||
| 1599 | 1579 | ||
| 1600 | if (NILP (check_val)) | 1580 | /* Rewind back to the position where we can safely search |
| 1581 | forward for compositions. It is assured that the character | ||
| 1582 | at cur.pos is composable. */ | ||
| 1583 | while (head < cur.pos) | ||
| 1584 | { | ||
| 1585 | prev = cur; | ||
| 1586 | BACKWARD_CHAR (cur, stop); | ||
| 1587 | c = STRING_CHAR (cur.p); | ||
| 1588 | if (! CHAR_COMPOSABLE_P (c)) | ||
| 1601 | { | 1589 | { |
| 1602 | c = STRING_CHAR (cur.p); | 1590 | cur = prev; |
| 1603 | check_val = CHAR_TABLE_REF (Vcomposition_function_table, c); | 1591 | break; |
| 1604 | } | 1592 | } |
| 1605 | for (; CONSP (check_val); check_val = XCDR (check_val)) | 1593 | } |
| 1594 | |||
| 1595 | search_forward: | ||
| 1596 | /* Now search forward. */ | ||
| 1597 | *gstring = Qnil; | ||
| 1598 | prev = cur; /* remember the start of searching position. */ | ||
| 1599 | while (cur.pos < fore_check_limit) | ||
| 1600 | { | ||
| 1601 | Lisp_Object val; | ||
| 1602 | |||
| 1603 | c = STRING_CHAR (cur.p); | ||
| 1604 | for (val = CHAR_TABLE_REF (Vcomposition_function_table, c); | ||
| 1605 | CONSP (val); val = XCDR (val)) | ||
| 1606 | { | 1606 | { |
| 1607 | elt = XCAR (check_val); | 1607 | Lisp_Object elt = XCAR (val); |
| 1608 | if (VECTORP (elt) && ASIZE (elt) == 3 && NATNUMP (AREF (elt, 1)) | 1608 | |
| 1609 | && cur.pos - XFASTINT (AREF (elt, 1)) >= head) | 1609 | if (VECTORP (elt) && ASIZE (elt) == 3 && NATNUMP (AREF (elt, 1))) |
| 1610 | { | 1610 | { |
| 1611 | check.pos = cur.pos - XFASTINT (AREF (elt, 1)); | 1611 | EMACS_INT check_pos = cur.pos - XFASTINT (AREF (elt, 1)); |
| 1612 | if (check.pos == cur.pos) | 1612 | struct position_record check; |
| 1613 | check.pos_byte = cur.pos_byte; | 1613 | |
| 1614 | else | 1614 | if (check_pos < head |
| 1615 | check.pos_byte = CHAR_TO_BYTE (check.pos); | 1615 | || (limit <= pos ? pos < check_pos |
| 1616 | val = autocmp_chars (elt, check.pos, check.pos_byte, | 1616 | : limit <= check_pos)) |
| 1617 | tail, w, NULL, string); | 1617 | continue; |
| 1618 | for (check = cur; check_pos < check.pos; ) | ||
| 1619 | BACKWARD_CHAR (check, stop); | ||
| 1620 | *gstring = autocmp_chars (elt, check.pos, check.pos_byte, | ||
| 1621 | tail, w, NULL, string); | ||
| 1618 | need_adjustment = 1; | 1622 | need_adjustment = 1; |
| 1619 | if (! NILP (val)) | 1623 | if (NILP (*gstring)) |
| 1620 | { | 1624 | { |
| 1621 | *gstring = val; | 1625 | /* As we have called Lisp, there's a possibility |
| 1626 | that buffer/string is relocated. */ | ||
| 1627 | if (NILP (string)) | ||
| 1628 | cur.p = BYTE_POS_ADDR (cur.pos_byte); | ||
| 1629 | else | ||
| 1630 | cur.p = SDATA (string) + cur.pos_byte; | ||
| 1631 | } | ||
| 1632 | else | ||
| 1633 | { | ||
| 1634 | /* We found a candidate of a target composition. */ | ||
| 1622 | *start = check.pos; | 1635 | *start = check.pos; |
| 1623 | *end = check.pos + LGSTRING_CHAR_LEN (*gstring); | 1636 | *end = check.pos + LGSTRING_CHAR_LEN (*gstring); |
| 1624 | if (*start <= orig.pos ? *end > orig.pos | 1637 | if (pos < limit |
| 1625 | : limit >= orig.pos) | 1638 | ? pos < *end |
| 1639 | : *start <= pos && pos < *end) | ||
| 1640 | /* This is the target composition. */ | ||
| 1626 | return 1; | 1641 | return 1; |
| 1627 | cur.pos = *end; | 1642 | cur.pos = *end; |
| 1628 | cur.pos_byte = CHAR_TO_BYTE (cur.pos); | 1643 | if (NILP (string)) |
| 1644 | { | ||
| 1645 | cur.pos_byte = CHAR_TO_BYTE (cur.pos); | ||
| 1646 | cur.p = BYTE_POS_ADDR (cur.pos_byte); | ||
| 1647 | } | ||
| 1648 | else | ||
| 1649 | { | ||
| 1650 | cur.pos_byte = string_char_to_byte (string, cur.pos); | ||
| 1651 | cur.p = SDATA (string) + cur.pos_byte; | ||
| 1652 | } | ||
| 1629 | break; | 1653 | break; |
| 1630 | } | 1654 | } |
| 1631 | } | 1655 | } |
| 1632 | } | 1656 | } |
| 1633 | if (need_adjustment) | 1657 | if (! CONSP (val)) |
| 1634 | { | 1658 | /* We found no composition here. */ |
| 1635 | /* As we have called Lisp, there's a possibility that | ||
| 1636 | buffer/string is relocated. */ | ||
| 1637 | if (NILP (string)) | ||
| 1638 | cur.p = BYTE_POS_ADDR (cur.pos_byte); | ||
| 1639 | else | ||
| 1640 | cur.p = SDATA (string) + cur.pos_byte; | ||
| 1641 | } | ||
| 1642 | if (! CONSP (check_val)) | ||
| 1643 | FORWARD_CHAR (cur, stop); | 1659 | FORWARD_CHAR (cur, stop); |
| 1644 | check_val = Qnil; | ||
| 1645 | } | 1660 | } |
| 1646 | } | 1661 | |
| 1647 | if (! NILP (*gstring)) | 1662 | if (pos < limit) /* case (2) and (4)*/ |
| 1648 | return (limit >= 0 || (*start <= orig.pos && *end > orig.pos)); | 1663 | return 0; |
| 1649 | if (limit >= 0 && limit < orig.pos && prev.pos > head) | 1664 | if (! NILP (*gstring)) |
| 1650 | { | 1665 | return 1; |
| 1666 | if (prev.pos == head) | ||
| 1667 | return 0; | ||
| 1651 | cur = prev; | 1668 | cur = prev; |
| 1669 | if (need_adjustment) | ||
| 1670 | { | ||
| 1671 | if (NILP (string)) | ||
| 1672 | cur.p = BYTE_POS_ADDR (cur.pos_byte); | ||
| 1673 | else | ||
| 1674 | cur.p = SDATA (string) + cur.pos_byte; | ||
| 1675 | } | ||
| 1652 | BACKWARD_CHAR (cur, stop); | 1676 | BACKWARD_CHAR (cur, stop); |
| 1653 | orig = cur; | ||
| 1654 | fore_check_limit = orig.pos; | ||
| 1655 | goto retry; | ||
| 1656 | } | 1677 | } |
| 1657 | return 0; | 1678 | return 0; |
| 1658 | } | 1679 | } |