aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorKenichi Handa2011-05-18 23:11:50 +0900
committerKenichi Handa2011-05-18 23:11:50 +0900
commita28d4396018e48479916fd624e2371aa1f75e6e7 (patch)
tree541383e75514ee6f0b71ab9fd55dc80dae1ee1de /src
parent7edd2093898ad14d78da23a3ea690df7de5616c4 (diff)
downloademacs-a28d4396018e48479916fd624e2371aa1f75e6e7.tar.gz
emacs-a28d4396018e48479916fd624e2371aa1f75e6e7.zip
Make find_automatic_composition more efficient.
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog6
-rw-r--r--src/composite.c279
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 @@
12011-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
12011-05-12 Drew Adams <drew.adams@oracle.com> 72011-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
1487static int 1490static int
1488find_automatic_composition (EMACS_INT pos, EMACS_INT limit, EMACS_INT *start, EMACS_INT *end, Lisp_Object *gstring, Lisp_Object string) 1491find_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}