Index: modules/field/modules/text/text.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/field/modules/text/text.module,v
retrieving revision 1.68
diff -u -p -r1.68 text.module
--- modules/field/modules/text/text.module	13 Nov 2010 07:39:35 -0000	1.68
+++ modules/field/modules/text/text.module	20 Nov 2010 00:04:43 -0000
@@ -361,7 +361,7 @@ function text_summary($text, $format = N
     return $text;
   }
 
-  // If a valid delimiter has been specified, use it to chop off the summary.
+  // If the delimiter is present, use it to chop off the summary.
   if ($delimiter !== FALSE) {
     return substr($text, 0, $delimiter);
   }
@@ -376,18 +376,37 @@ function text_summary($text, $format = N
     }
   }
 
-  // If we have a short body, the entire body is the summary.
+  // If we have a short text, the entire text is the summary.
   if (drupal_strlen($text) <= $size) {
     return $text;
   }
 
+  // First, retrieve the initial substring corresponding to the first $size
+  // characters of the actual text content; i.e. excluding HTML markup.
+
+  // Split tags from text.
+  // $chunks will always consist of alternating literals (which can be the
+  // empty string) and delimiters, and begin and end with a literal.
+  $chunks = preg_split('@(<(?:[a-zA-Z/][^>]*|!--.*?--)>)@', $text, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_OFFSET_CAPTURE);
+
+  $cumulative_length = 0;
+  for ($i = 0; $i <= count($chunks); $i += 2) {
+    $chunk_length = drupal_strlen($chunks[$i][0]);
+    $cumulative_length += $chunk_length;
+    if ($cumulative_length > $size) {
+      break;
+    }
+  }
+  // Use the entire text, if it is within the size limit.
+  if ($cumulative_length <= $size) {
+    return $text;
+  }
+  $summary = drupal_substr($text, 0, $chunks[$i][1]) . drupal_substr($chunks[$i][0], 0, $size - ($cumulative_length - $chunk_length));
+
   // If the delimiter has not been specified, try to split at paragraph or
   // sentence boundaries.
 
-  // The summary may not be longer than maximum length specified. Initial slice.
-  $summary = truncate_utf8($text, $size);
-
-  // Store the actual length of the UTF8 string -- which might not be the same
+  // Store the actual length in bytes of the string, which might not be the same
   // as $size.
   $max_rpos = strlen($summary);
 
