private void shapeContextually(char[] text, int start, int count, Range ctxKey) {
    // if we don't support the specified context, then don't shape.
    if (ctxKey == null || !rangeSet.contains(ctxKey)) {
      ctxKey = Range.EUROPEAN;
    }

    Range lastKey = ctxKey;
    int base = ctxKey.getDigitBase();
    char minDigit = (char) ('0' + ctxKey.getNumericBase());
    final int end = start + count;
    for (int i = start; i < end; ++i) {
      char c = text[i];
      if (c >= minDigit && c <= '9') {
        text[i] = (char) (c + base);
        continue;
      }
      if (isStrongDirectional(c)) {
        ctxKey = rangeForCodePoint(c);
        if (ctxKey != lastKey) {
          lastKey = ctxKey;
          base = ctxKey.getDigitBase();
          minDigit = (char) ('0' + ctxKey.getNumericBase());
        }
      }
    }
  }
 /** Perform non-contextual shaping. */
 private void shapeNonContextually(char[] text, int start, int count) {
   int base;
   char minDigit = '0';
   if (shapingRange != null) {
     base = shapingRange.getDigitBase();
     minDigit += shapingRange.getNumericBase();
   } else {
     base = bases[key];
     if (key == ETHIOPIC_KEY) {
       minDigit++; // Ethiopic doesn't use decimal zero
     }
   }
   for (int i = start, e = start + count; i < e; ++i) {
     char c = text[i];
     if (c >= minDigit && c <= '\u0039') {
       text[i] = (char) (c + base);
     }
   }
 }