WebCore:
authordarin <darin@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 8 Feb 2004 22:40:10 +0000 (22:40 +0000)
committerdarin <darin@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 8 Feb 2004 22:40:10 +0000 (22:40 +0000)
        Reviewed by Dave.

        - fixed things seen in the profile, for a total speedup of 4% on cvs-base
        - fixed some layout regressions from my last speedup due to text measurement inconsistencies

        * WebCorePrefix.h: Add a workaround for a bug in our system headers that prevents the <ctype.h>
        macros from working right in C++ code that uses the <cctype> header.

        * khtml/css/cssstyleselector.cpp:
        (khtml::checkPseudoState): Use prepend instead of operator + here. Will probably be obviated if
        someone fixes the checkPseudoState problem.
        (khtml::colorForCSSValue): Get rid of all the code that uses QPalette; it wasn't doing any good
        in Safari. Instead, hardcode the UI colors.

        * kwq/KWQChar.mm:
        (QChar::isDigitNonASCII): Non-inline part. The ASCII case is handled with an inline now.
        (QChar::isLetterNonASCII): Ditto.
        (QChar::isNumberNonASCII): Ditto.
        (QChar::isLetterOrNumberNonASCII): Ditto.
        (QChar::lowerNonASCII): Ditto.
        (QChar::upperNonASCII): Ditto.
        (QChar::digitValueNonASCII): Ditto.

        * kwq/KWQColorGroup.mm: Put all roles base inside #if, since we don't need them, and copying
        the color group and palette was making things slow.

        * kwq/KWQComboBox.h: Remove KWQComboBoxAdapter, not needed any more.
        * kwq/KWQComboBox.mm:
        (QComboBox::QComboBox): Remove KWQComboBoxAdapter, not needed any more.
        (QComboBox::~QComboBox): Ditto.
        (QComboBox::sizeHint): Turn off rounding; we use that in web text, but not in widgets.
        (-[KWQPopUpButton action:]): Moved the action method here.

        * kwq/KWQLineEdit.mm: (QLineEdit::sizeForCharacterWidth): Turn off rounding. We use it in web
        page text, but not in widgets.
        * kwq/KWQListBox.mm:
        (QListBox::sizeForNumberOfLines): Ditto.
        (-[KWQTableView drawRow:clipRect:]): Ditto.

        * kwq/KWQKURL.mm:
        (KURL::KURL): Added code to put the "file:" in front of a path without making a QString.
        (hasSlashDotOrDotDot): Added. Faster than two calls to strstr.
        (matchLetter): Added. Faster than tolower calls on each letter.
        (KURL::parse): Changed to use matchLetter and hasSlashDotOrDotDot.

        * kwq/KWQPalette.h: Remove all roles except base, and all groups except active, since we don't
        need them, and copying the color group and palette was making things slow.
        * kwq/KWQPalette.mm: Ditto.

        * kwq/KWQRegExp.mm: (QRegExp::match): Fixed logic so we don't create and destroy a QCString
        in the fast case. Also avoid UTF-8/UTF-16 offset mapping.

        * kwq/KWQString.h:
        (QChar::isDigit): Add inline section for ASCII.
        (QChar::isLetter): Ditto.
        (QChar::isNumber): Ditto.
        (QChar::isLetterOrNumber): Ditto.
        (QChar::digitValue): Ditto.
        (QChar::lower): Ditto.
        (QChar::upper): Ditto.
        (QString::utf8): Add a new version that returns the length; used by QRegExp.
        (QString::operator+=): Call a new append function.
        * kwq/KWQString.mm:
        (ucstrcmp): Made this function inline.
        (equal): Added, replacing various strcmp functions.
        (equalCaseInsensitive): Ditto.
        (ok_in_base): Changed to use <ctype.h> isdigit and isalpha instead of QChar functions.
        (QString::detachInternal): Moved up so it will be inlined.
        (QString::~QString): Streamlined a little.
        (QString::utf8): Changed to return the length.
        (QString::find): Use unicode() instead of cell() in various places. Also refined a faster
        version of the one that takes a char *.
        (QString::contains): Changed all of the overloads to have structure that's more similar,
        and made them slightly faster too.
        (QString::isAllLatin1): Added.
        (QString::copyLatin1): Added. Lets you get the string as a char * buffer without changing
        the string itself into that format.
        (QString::toLong): Changed to use <ctype.h> isdigit instead of QChar function.
        (QString::toULong): Ditto.
        (QString::setUnicode): Call the new detachAndDiscardCharacters; not implemented yet.
        (QString::setLatin1): Call the new detachAndDiscardCharacters; not implemented yet.
        (QString::sprintf): Call the new detachAndDiscardCharacters; not implemented yet.
        (QString::insert): Remove one memmove call for the case that appends at the end.
        (QString::detach): Change code to use the internal data if we can; saves at destructor time.
        (QString::detachAndDiscardCharacters): Added. Placeholder for now that just calls detach().
        (QString::setLength): Optimize the setLength(0) case.
        (QString::fill): Call the new detachAndDiscardCharacters; not implemented yet.
        (QString::append): Renamed from operator+=, which now simply calls append().
        (QString::reserve): Added. Useful when building up a string, like in QTextCodec.

        * WebCore-tests.exp: Added new function names for QChar.
        * WebCore-combined.exp: Updated.

        * kwq/KWQTextCodec.mm:
        (KWQTextDecoder::convertLatin1): Added. Since this is the most common encoding, and very
        easy to decode (built into QString, in fact), best to do it as a special case, not with TEC.
        (KWQTextDecoder::convertUTF16): Added a reserve() call for better performance and made the
        stack buffer larger.
        (KWQTextDecoder::convertUsingTEC): Added a reserve() call for better performance and made the
        stack buffer larger.
        (KWQTextDecoder::convert): Added a switch statement and convertLatin1 case.

        * kwq/KWQView.h: Removed the KWQView class.
        * kwq/KWQView.mm: Removed.
        * WebCore.pbproj/project.pbxproj: Removed KWQView.mm.

        * kwq/KWQWidget.h: Changed name of QWidgetPrivate to KWQWidgetPrivate.
        * kwq/KWQWidget.mm:
        (QWidget::QWidget): Got rid of code that makes a KWQView when no view is passed in. We were
        creating and destroying extra views because of this.
        (QWidget::setFrameGeometry): Only call getOuterView() once, not three times. Also, don't do
        any work at all if the frame is already correct.
        * khtml/khtmlview.cpp: (KHTMLView::init): Removed a call that will hit an assertion due to the
        way a new KHTMLView does not yet have an NSView.

        * kwq/WebCoreTextRenderer.h: Broke applyRounding into applyRunRounding and applyWordRounding.
        * kwq/WebCoreTextRendererFactory.m: (WebCoreInitializeEmptyTextStyle): Initialize both rounding
        flags on.

WebKit:

        Reviewed by Dave.

        - fixed things seen in the profile, for a total speedup of 4% on cvs-base
        - fixed some layout regressions from my last speedup due to text measurement inconsistencies by adding
          a flag to control whether word rounding is done or not
        - fixed text measurement to be used with AppKit to match AppKit again, as it did at some point in the past

        * WebCoreSupport.subproj/WebTextRenderer.h: Remove some unused fields, and added a field to say whether we
        treat this font as fixed pitch.
        * WebCoreSupport.subproj/WebTextRenderer.m:
        (getUncachedWidth): Remove space width hack from this level. There was already a width hack up at the higher
        level for space itself, so there's not a significant speed benefit, and the higher level can make a more
        intelligent choice based on the current rounding setting since it's not cached.
        (-[WebTextRenderer _computeWidthForSpace]): Don't store so many widths; just the adjusted width we will
        actually use.
        (widthForNextCharacter): Use two different rules for when to adjust space widths, based on whether this is
        a fixed pitch font or not. Also, don't do any adjusting of space widths if applyWordRounding is false.

        * Misc.subproj/WebKitNSStringExtras.m:
        (-[NSString _web_drawAtPoint:font:textColor:]): Turn off rounding, so we get the kind of spacing AppKit would normally give.
        (-[NSString _web_widthWithFont:]): Ditto.
        * Misc.subproj/WebStringTruncator.m: (stringWidth): Ditto.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@6052 268f45cc-cd09-0410-ab3c-d52691b4dbfc

34 files changed:
LayoutTests/fast/overflow/005-expected.txt [new file with mode: 0644]
WebCore/ChangeLog-2005-08-23
WebCore/WebCore-combined.exp
WebCore/WebCore-tests.exp
WebCore/WebCore.pbproj/project.pbxproj
WebCore/WebCorePrefix.h
WebCore/khtml/css/cssstyleselector.cpp
WebCore/khtml/khtmlview.cpp
WebCore/kwq/KWQChar.mm
WebCore/kwq/KWQColorGroup.mm
WebCore/kwq/KWQComboBox.h
WebCore/kwq/KWQComboBox.mm
WebCore/kwq/KWQKURL.mm
WebCore/kwq/KWQLineEdit.mm
WebCore/kwq/KWQListBox.mm
WebCore/kwq/KWQPalette.h
WebCore/kwq/KWQPalette.mm
WebCore/kwq/KWQRegExp.mm
WebCore/kwq/KWQString.h
WebCore/kwq/KWQString.mm
WebCore/kwq/KWQTextCodec.mm
WebCore/kwq/KWQView.h
WebCore/kwq/KWQView.mm [deleted file]
WebCore/kwq/KWQWidget.h
WebCore/kwq/KWQWidget.mm
WebCore/kwq/WebCoreTextRenderer.h
WebCore/kwq/WebCoreTextRendererFactory.m
WebCore/kwq/WebCoreTextRendererFactory.mm
WebKit/ChangeLog
WebKit/Misc.subproj/WebKitNSStringExtras.m
WebKit/Misc.subproj/WebNSURLExtras.m
WebKit/Misc.subproj/WebStringTruncator.m
WebKit/WebCoreSupport.subproj/WebTextRenderer.h
WebKit/WebCoreSupport.subproj/WebTextRenderer.m

diff --git a/LayoutTests/fast/overflow/005-expected.txt b/LayoutTests/fast/overflow/005-expected.txt
new file mode 100644 (file)
index 0000000..c7bc8d7
--- /dev/null
@@ -0,0 +1,10 @@
+layer at (0,0) size 800x600
+  RenderCanvas at (0,0) size 800x600
+layer at (0,0) size 800x66
+  RenderBlock {HTML} at (0,0) size 800x66
+    RenderBody {BODY} at (8,8) size 784x45
+layer at (8,8) size 300x45 clip at (8,8) size 300x30
+  RenderBlock {PRE} at (0,0) size 300x45
+    RenderText {TEXT} at (0,0) size 312x30
+      text run at (0,0) width 312: "This is a test to see if this messes up"
+      text run at (0,15) width 240: "the way I think it's going to."
index 5d4f722..0c6db94 100644 (file)
@@ -1,3 +1,124 @@
+2004-02-08  Darin Adler  <darin@apple.com>
+
+        Reviewed by Dave.
+
+        - fixed things seen in the profile, for a total speedup of 4% on cvs-base
+        - fixed some layout regressions from my last speedup due to text measurement inconsistencies
+
+        * WebCorePrefix.h: Add a workaround for a bug in our system headers that prevents the <ctype.h>
+        macros from working right in C++ code that uses the <cctype> header.
+
+        * khtml/css/cssstyleselector.cpp:
+        (khtml::checkPseudoState): Use prepend instead of operator + here. Will probably be obviated if
+        someone fixes the checkPseudoState problem.
+        (khtml::colorForCSSValue): Get rid of all the code that uses QPalette; it wasn't doing any good
+        in Safari. Instead, hardcode the UI colors.
+
+        * kwq/KWQChar.mm:
+        (QChar::isDigitNonASCII): Non-inline part. The ASCII case is handled with an inline now.
+        (QChar::isLetterNonASCII): Ditto.
+        (QChar::isNumberNonASCII): Ditto.
+        (QChar::isLetterOrNumberNonASCII): Ditto.
+        (QChar::lowerNonASCII): Ditto.
+        (QChar::upperNonASCII): Ditto.
+        (QChar::digitValueNonASCII): Ditto.
+
+        * kwq/KWQColorGroup.mm: Put all roles base inside #if, since we don't need them, and copying
+        the color group and palette was making things slow.
+
+        * kwq/KWQComboBox.h: Remove KWQComboBoxAdapter, not needed any more.
+        * kwq/KWQComboBox.mm:
+        (QComboBox::QComboBox): Remove KWQComboBoxAdapter, not needed any more.
+        (QComboBox::~QComboBox): Ditto.
+        (QComboBox::sizeHint): Turn off rounding; we use that in web text, but not in widgets.
+        (-[KWQPopUpButton action:]): Moved the action method here.
+
+        * kwq/KWQLineEdit.mm: (QLineEdit::sizeForCharacterWidth): Turn off rounding. We use it in web
+        page text, but not in widgets.
+        * kwq/KWQListBox.mm:
+        (QListBox::sizeForNumberOfLines): Ditto.
+        (-[KWQTableView drawRow:clipRect:]): Ditto.
+
+        * kwq/KWQKURL.mm:
+        (KURL::KURL): Added code to put the "file:" in front of a path without making a QString.
+        (hasSlashDotOrDotDot): Added. Faster than two calls to strstr.
+        (matchLetter): Added. Faster than tolower calls on each letter.
+        (KURL::parse): Changed to use matchLetter and hasSlashDotOrDotDot.
+
+        * kwq/KWQPalette.h: Remove all roles except base, and all groups except active, since we don't
+        need them, and copying the color group and palette was making things slow.
+        * kwq/KWQPalette.mm: Ditto.
+
+        * kwq/KWQRegExp.mm: (QRegExp::match): Fixed logic so we don't create and destroy a QCString
+        in the fast case. Also avoid UTF-8/UTF-16 offset mapping.
+
+        * kwq/KWQString.h:
+        (QChar::isDigit): Add inline section for ASCII.
+        (QChar::isLetter): Ditto.
+        (QChar::isNumber): Ditto.
+        (QChar::isLetterOrNumber): Ditto.
+        (QChar::digitValue): Ditto.
+        (QChar::lower): Ditto.
+        (QChar::upper): Ditto.
+        (QString::utf8): Add a new version that returns the length; used by QRegExp.
+        (QString::operator+=): Call a new append function.
+        * kwq/KWQString.mm:
+        (ucstrcmp): Made this function inline.
+        (equal): Added, replacing various strcmp functions.
+        (equalCaseInsensitive): Ditto.
+        (ok_in_base): Changed to use <ctype.h> isdigit and isalpha instead of QChar functions.
+        (QString::detachInternal): Moved up so it will be inlined.
+        (QString::~QString): Streamlined a little.
+        (QString::utf8): Changed to return the length.
+        (QString::find): Use unicode() instead of cell() in various places. Also refined a faster
+        version of the one that takes a char *.
+        (QString::contains): Changed all of the overloads to have structure that's more similar,
+        and made them slightly faster too.
+        (QString::isAllLatin1): Added.
+        (QString::copyLatin1): Added. Lets you get the string as a char * buffer without changing
+        the string itself into that format.
+        (QString::toLong): Changed to use <ctype.h> isdigit instead of QChar function.
+        (QString::toULong): Ditto.
+        (QString::setUnicode): Call the new detachAndDiscardCharacters; not implemented yet.
+        (QString::setLatin1): Call the new detachAndDiscardCharacters; not implemented yet.
+        (QString::sprintf): Call the new detachAndDiscardCharacters; not implemented yet.
+        (QString::insert): Remove one memmove call for the case that appends at the end.
+        (QString::detach): Change code to use the internal data if we can; saves at destructor time.
+        (QString::detachAndDiscardCharacters): Added. Placeholder for now that just calls detach().
+        (QString::setLength): Optimize the setLength(0) case.
+        (QString::fill): Call the new detachAndDiscardCharacters; not implemented yet.
+        (QString::append): Renamed from operator+=, which now simply calls append().
+        (QString::reserve): Added. Useful when building up a string, like in QTextCodec.
+
+        * WebCore-tests.exp: Added new function names for QChar.
+        * WebCore-combined.exp: Updated.
+
+        * kwq/KWQTextCodec.mm:
+        (KWQTextDecoder::convertLatin1): Added. Since this is the most common encoding, and very
+        easy to decode (built into QString, in fact), best to do it as a special case, not with TEC.
+        (KWQTextDecoder::convertUTF16): Added a reserve() call for better performance and made the
+        stack buffer larger.
+        (KWQTextDecoder::convertUsingTEC): Added a reserve() call for better performance and made the
+        stack buffer larger.
+        (KWQTextDecoder::convert): Added a switch statement and convertLatin1 case.
+
+        * kwq/KWQView.h: Removed the KWQView class.
+        * kwq/KWQView.mm: Removed.
+        * WebCore.pbproj/project.pbxproj: Removed KWQView.mm.
+
+        * kwq/KWQWidget.h: Changed name of QWidgetPrivate to KWQWidgetPrivate.
+        * kwq/KWQWidget.mm:
+        (QWidget::QWidget): Got rid of code that makes a KWQView when no view is passed in. We were
+        creating and destroying extra views because of this.
+        (QWidget::setFrameGeometry): Only call getOuterView() once, not three times. Also, don't do
+        any work at all if the frame is already correct.
+        * khtml/khtmlview.cpp: (KHTMLView::init): Removed a call that will hit an assertion due to the
+        way a new KHTMLView does not yet have an NSView.
+
+        * kwq/WebCoreTextRenderer.h: Broke applyRounding into applyRunRounding and applyWordRounding.
+        * kwq/WebCoreTextRendererFactory.m: (WebCoreInitializeEmptyTextStyle): Initialize both rounding
+        flags on.
+
 2004-02-07  Darin Adler  <darin@apple.com>
 
         Reviewed by Dave.
index 1eab8a1..940439d 100644 (file)
@@ -146,6 +146,10 @@ __ZN4KURLC1ERKS_
 __ZN4KURLC1ERKS_RK7QStringPK10QTextCodec
 __ZN4KURLC1Ev
 __ZN4KURLD1Ev
+__ZN5QChar13lowerNonASCIIEt
+__ZN5QChar13upperNonASCIIEt
+__ZN5QChar15isDigitNonASCIIEt
+__ZN5QChar24isLetterOrNumberNonASCIIEt
 __ZN5QDateC1Eiii
 __ZN5QFile4openEi
 __ZN5QFile5closeEv
@@ -169,7 +173,9 @@ __ZN7QRegExpC1EPKc
 __ZN7QRegExpC1ERK7QStringbb
 __ZN7QRegExpD1Ev
 __ZN7QString4fillE5QChari
+__ZN7QString6appendE5QChar
 __ZN7QString6appendERKS_
+__ZN7QString6appendEc
 __ZN7QString6insertEj5QChar
 __ZN7QString6insertEjRKS_
 __ZN7QString6insertEjc
index 07d0efe..92b3b2f 100644 (file)
@@ -112,6 +112,10 @@ __ZN4KURLC1ERKS_
 __ZN4KURLC1ERKS_RK7QStringPK10QTextCodec
 __ZN4KURLC1Ev
 __ZN4KURLD1Ev
+__ZN5QChar13lowerNonASCIIEt
+__ZN5QChar13upperNonASCIIEt
+__ZN5QChar15isDigitNonASCIIEt
+__ZN5QChar24isLetterOrNumberNonASCIIEt
 __ZN5QDateC1Eiii
 __ZN5QFile4openEi
 __ZN5QFile5closeEv
@@ -135,7 +139,9 @@ __ZN7QRegExpC1EPKc
 __ZN7QRegExpC1ERK7QStringbb
 __ZN7QRegExpD1Ev
 __ZN7QString4fillE5QChari
+__ZN7QString6appendE5QChar
 __ZN7QString6appendERKS_
+__ZN7QString6appendEc
 __ZN7QString6insertEj5QChar
 __ZN7QString6insertEjRKS_
 __ZN7QString6insertEjc
index 83f472f..c609a6d 100644 (file)
                                F58785CE02DE375901EA4122,
                                F58785CF02DE375901EA4122,
                                F58785D102DE375901EA4122,
-                               F58785D302DE375901EA4122,
                                F58785D402DE375901EA4122,
                                F58785D602DE375901EA4122,
                                F58785DA02DE375901EA4122,
                                F587851B02DE375901EA4122,
                                F587851C02DE375901EA4122,
                                F587854002DE375901EA4122,
-                               F587854102DE375901EA4122,
                                F587854302DE375901EA4122,
                                F587854402DE375901EA4122,
                                BC7B2AF80450824100A8000F,
                        refType = 4;
                        sourceTree = "<group>";
                };
-               F587854102DE375901EA4122 = {
-                       fileEncoding = 30;
-                       isa = PBXFileReference;
-                       lastKnownFileType = sourcecode.cpp.objcpp;
-                       path = KWQView.mm;
-                       refType = 4;
-                       sourceTree = "<group>";
-               };
                F587854202DE375901EA4122 = {
                        fileEncoding = 30;
                        isa = PBXFileReference;
                        settings = {
                        };
                };
-               F58785D302DE375901EA4122 = {
-                       fileRef = F587854102DE375901EA4122;
-                       isa = PBXBuildFile;
-                       settings = {
-                       };
-               };
                F58785D402DE375901EA4122 = {
                        fileRef = F587854202DE375901EA4122;
                        isa = PBXBuildFile;
index 8d4208c..f8e190a 100644 (file)
 #include <ostream>
 #endif
 
+// Work around bug 3553309 by re-including <ctype.h>.
+#include <cctype>
+#define isalnum(c)      __istype((c), (_CTYPE_A|_CTYPE_D))
+#define isalpha(c)      __istype((c), _CTYPE_A)
+#define iscntrl(c)      __istype((c), _CTYPE_C)
+#define isdigit(c)      __isctype((c), _CTYPE_D)       /* ANSI -- locale independent */
+#define isgraph(c)      __istype((c), _CTYPE_G)
+#define islower(c)      __istype((c), _CTYPE_L)
+#define isprint(c)      __istype((c), _CTYPE_R)
+#define ispunct(c)      __istype((c), _CTYPE_P)
+#define isspace(c)      __istype((c), _CTYPE_S)
+#define isupper(c)      __istype((c), _CTYPE_U)
+#define isxdigit(c)     __isctype((c), _CTYPE_X)       /* ANSI -- locale independent */
+#define tolower(c)      __tolower(c)
+#define toupper(c)      __toupper(c)
+
 #endif
 
 #include <sys/types.h>
index 2f2f3eb..59331ac 100644 (file)
@@ -2,7 +2,7 @@
  * This file is part of the CSS implementation for KDE.
  *
  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
- * Copyright (C) 2003 Apple Computer, Inc.
+ * Copyright (C) 2004 Apple Computer, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -756,11 +756,11 @@ static void checkPseudoState( DOM::ElementImpl *e, bool checkVisited = true )
     QString u = cu.string();
     if ( !u.contains("://") ) {
         if ( u[0] == '/' )
-            u = encodedurl->host + u;
+            u.prepend(encodedurl->host);
         else if ( u[0] == '#' )
-            u = encodedurl->file + u;
+            u.prepend(encodedurl->file);
         else
-            u = encodedurl->path + u;
+            u.prepend(encodedurl->path);
         cleanpath( u );
     }
     //completeURL( attr.string() );
@@ -1321,10 +1321,42 @@ static const colorMap cmap[] = {
     { CSS_VAL_YELLOW, 0xFFFFFF00 },
     { CSS_VAL_INVERT, invertedColor },
     { CSS_VAL_TRANSPARENT, transparentColor },
-    { CSS_VAL_GREY, 0xff808080 },
+    { CSS_VAL_GREY, 0xFF808080 },
+#if APPLE_CHANGES
+    { CSS_VAL_ACTIVEBORDER, 0xFFE0E0E0 },
+    { CSS_VAL_ACTIVECAPTION, 0xFF000000 },
+    { CSS_VAL_APPWORKSPACE, 0xFF000000 },
+    { CSS_VAL_BUTTONFACE, 0xFFC0C0C0 },
+    { CSS_VAL_BUTTONHIGHLIGHT, 0xFFE0E0E0 },
+    { CSS_VAL_BUTTONSHADOW, 0xFFFFFFFF },
+    { CSS_VAL_BUTTONTEXT, 0xFF000000 },
+    { CSS_VAL_CAPTIONTEXT, 0xFF000000 },
+    { CSS_VAL_GRAYTEXT, 0xFF000000 },
+    { CSS_VAL_HIGHLIGHT, 0xFFFFFFFF },
+    { CSS_VAL_HIGHLIGHTTEXT, 0xFFFFFFFF },
+    { CSS_VAL_INACTIVEBORDER, 0xFFFFFFFF },
+    { CSS_VAL_INACTIVECAPTION, 0xFFFFFFFF },
+    { CSS_VAL_INACTIVECAPTIONTEXT, 0xFF000000 },
+    { CSS_VAL_INFOBACKGROUND, 0xFF000000 },
+    { CSS_VAL_INFOTEXT, 0xFF000000 },
+    { CSS_VAL_MENU, 0xFFFFFFFF },
+    { CSS_VAL_MENUTEXT, 0xFFFFFFFF },
+    { CSS_VAL_SCROLLBAR, 0xFFFFFFFF },
+    { CSS_VAL_TEXT, 0xFF000000 },
+    { CSS_VAL_THREEDDARKSHADOW, 0xFF404040 },
+    { CSS_VAL_THREEDFACE, 0xFFC0C0C0 },
+    { CSS_VAL_THREEDHIGHLIGHT, 0xFFE0E0E0 },
+    { CSS_VAL_THREEDLIGHTSHADOW, 0xFFC0C0C0 },
+    { CSS_VAL_THREEDSHADOW, 0xFFFFFFFF },
+    { CSS_VAL_WINDOW, 0xFFFFFFFF },
+    { CSS_VAL_WINDOWFRAME, 0xFFFFFFFF },
+    { CSS_VAL_WINDOWTEXT, 0xFF000000 },
+#endif
     { 0, 0 }
 };
 
+#if !APPLE_CHANGES
+
 struct uiColors {
     int css_value;
     const char * configGroup;
@@ -1400,6 +1432,8 @@ static const uiColors uimap[] = {
     { 0, 0, 0, QPalette::NColorGroups, QColorGroup::NColorRoles }
 };
 
+#endif // !APPLE_CHANGES
+
 static QColor colorForCSSValue( int css_value )
 {
     // try the regular ones first
@@ -1409,10 +1443,12 @@ static QColor colorForCSSValue( int css_value )
     if ( col->css_value )
         return col->color;
 
+#if APPLE_CHANGES
+    return QColor();
+#else
     const uiColors *uicol = uimap;
     while ( uicol->css_value && uicol->css_value != css_value )
         ++uicol;
-#if !APPLE_CHANGES
     if ( !uicol->css_value ) {
         if ( css_value == CSS_VAL_INFOBACKGROUND )
             return QToolTip::palette().inactive().background();
@@ -1426,20 +1462,18 @@ static QColor colorForCSSValue( int css_value )
         }
         return khtml::invalidColor;
     }
-#endif
     
     const QPalette &pal = qApp->palette();
     QColor c = pal.color( uicol->group, uicol->role );
-#if !APPLE_CHANGES
     if ( uicol->configEntry ) {
         KConfig *globalConfig = KGlobal::config();
         globalConfig->setGroup( uicol->configGroup );
         c = globalConfig->readColorEntry( uicol->configEntry, &c );
     }
-#endif
     
     return c;
-};
+#endif
+}
 
 void CSSStyleSelector::applyDeclarations(bool applyFirst, bool isImportant,
                                          int startIndex, int endIndex)
index 97d0450..041b5ab 100644 (file)
@@ -323,7 +323,9 @@ void KHTMLView::init()
 
     setAcceptDrops(true);
     
+#if !APPLE_CHANGES
     resizeContents(visibleWidth(), visibleHeight());
+#endif
 }
 
 void KHTMLView::clear()
index 5defaa0..63cd6da 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2003 Apple Computer, Inc.  All rights reserved.
+ * Copyright (C) 2004 Apple Computer, Inc.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 
 #import <Foundation/Foundation.h>
 
-bool QChar::isDigit() const
+bool QChar::isDigitNonASCII(UniChar c)
 {
     static CFCharacterSetRef set = CFCharacterSetGetPredefined(kCFCharacterSetDecimalDigit);
     return CFCharacterSetIsCharacterMember(set, c);
 }
 
-bool QChar::isLetter() const
+bool QChar::isLetterNonASCII(UniChar c)
 {
     static CFCharacterSetRef set = CFCharacterSetGetPredefined(kCFCharacterSetLetter);
     return CFCharacterSetIsCharacterMember(set, c);
 }
 
-bool QChar::isNumber() const
+bool QChar::isNumberNonASCII(UniChar c)
 {
-    return isLetterOrNumber() && !isLetter();
+    return isLetterOrNumberNonASCII(c) && !isLetterNonASCII(c);
 }
 
-bool QChar::isLetterOrNumber() const
+bool QChar::isLetterOrNumberNonASCII(UniChar c)
 {
     static CFCharacterSetRef set = CFCharacterSetGetPredefined(kCFCharacterSetAlphaNumeric);
     return CFCharacterSetIsCharacterMember(set, c);
@@ -58,14 +58,14 @@ bool QChar::isPunct() const
     return CFCharacterSetIsCharacterMember(set, c);
 }
 
-QChar QChar::lower() const
+UniChar QChar::lowerNonASCII(UniChar c)
 {
-    return (UniChar)WebCoreUnicodeLowerFunction(c);
+    return WebCoreUnicodeLowerFunction(c);
 }
 
-QChar QChar::upper() const
+UniChar QChar::upperNonASCII(UniChar c)
 {
-    return (UniChar)WebCoreUnicodeUpperFunction(c);
+    return WebCoreUnicodeUpperFunction(c);
 }
 
 bool QChar::mirrored() const
@@ -78,10 +78,8 @@ QChar QChar::mirroredChar() const
     return QChar((UniChar)WebCoreUnicodeMirroredCharFunction(c));
 }
 
-int QChar::digitValue() const
+int QChar::digitValueNonASCII(UniChar)
 {
-    if (c < '0' || c > '9')
-       return -1;
-    else
-       return c - '0';
+    // FIXME: This isn't right. Need Unicode-savvy version of this that matches isDigitNonASCII.
+    return -1;
 }
index 692b244..0d50bff 100644 (file)
 
 QColorGroup::QColorGroup()
 {
+#if KWQ_USE_PALETTES
     brushes[Foreground] = QColor(255,255,255);
     brushes[Shadow] = QColor(255,255,255);
     brushes[Light] = QColor(224,224,224);
     brushes[Midlight] = QColor(192,192,192);
     brushes[Mid] = QColor(128,128,128);
     brushes[Dark] = QColor(64,64,64);
+#endif
     brushes[Base] = QColor(255,255,255);
+#if KWQ_USE_PALETTES
     brushes[ButtonText] = QColor(0,0,0);
     brushes[Button] = QColor(192,192,192);
     brushes[Background] = QColor(255,255,255);
     brushes[Text] = QColor(0,0,0);
     brushes[Highlight] = QColor(64,64,64);
     brushes[HighlightedText] = QColor(0,0,0);
+#endif
 }
 
 const QBrush &QColorGroup::brush(ColorRole cr) const
@@ -57,6 +61,8 @@ void QColorGroup::setColor(QColorGroup::ColorRole cr, const QColor &color)
     brushes[cr].setColor(color);
 }
 
+#if KWQ_USE_PALETTES
+
 const QColor &QColorGroup::foreground() const
 {
     return brushes[Foreground].color();
@@ -82,11 +88,15 @@ const QColor &QColorGroup::dark() const
     return brushes[Dark].color();
 }
 
+#endif
+
 const QColor &QColorGroup::base() const
 {
     return brushes[Base].color();
 }
 
+#if KWQ_USE_PALETTES
+
 const QColor &QColorGroup::buttonText() const
 {
     return brushes[ButtonText].color();
@@ -117,6 +127,8 @@ const QColor &QColorGroup::highlightedText() const
     return brushes[HighlightedText].color();
 }
 
+#endif
+
 bool QColorGroup::operator==(const QColorGroup &other) const
 {
     for (int i = 0; i < NColorRoles; i++) {
index 1e6efb6..bf3a3a9 100644 (file)
@@ -68,8 +68,6 @@ public:
 private:
     const int *dimensions() const;
     
-    KWQComboBoxAdapter *_adapter;
-
     mutable int _width;
     mutable bool _widthGood;
 
index 74c1d7d..ab0bbf2 100644 (file)
@@ -49,14 +49,6 @@ enum {
     minimumTextWidth
 };
 
-@interface KWQComboBoxAdapter : NSObject
-{
-    QComboBox *box;
-}
-- (id)initWithQComboBox:(QComboBox *)b;
-- (void)action:(id)sender;
-@end
-
 @interface KWQPopUpButtonCell : NSPopUpButtonCell <KWQWidgetHolder>
 {
     QComboBox *box;
@@ -74,15 +66,13 @@ enum {
 @end
 
 QComboBox::QComboBox()
-    : _adapter(0)
-    , _widthGood(false)
+    : _widthGood(false)
     , _currentItem(0)
     , _menuPopulated(true)
     , _activated(this, SIGNAL(activated(int)))
 {
     KWQ_BLOCK_EXCEPTIONS;
 
-    _adapter = [[KWQComboBoxAdapter alloc] initWithQComboBox:this];
     KWQPopUpButton *button = [[KWQPopUpButton alloc] init];
     setView(button);
     [button release];
@@ -91,7 +81,7 @@ QComboBox::QComboBox()
     [button setCell:cell];
     [cell release];
 
-    [button setTarget:_adapter];
+    [button setTarget:button];
     [button setAction:@selector(action:)];
 
     [[button cell] setControlSize:NSSmallControlSize];
@@ -106,7 +96,6 @@ QComboBox::~QComboBox()
 
     KWQPopUpButton *button = (KWQPopUpButton *)getView();
     [button setTarget:nil];
-    [_adapter release];
 
     KWQ_UNBLOCK_EXCEPTIONS;
 }
@@ -147,6 +136,8 @@ QSize QComboBox::sizeHint() const
                 rendererWithFont:[button font] usingPrinterFont:![NSGraphicsContext currentContextDrawingToScreen]];
             WebCoreTextStyle style;
             WebCoreInitializeEmptyTextStyle(&style);
+            style.applyRunRounding = NO;
+            style.applyWordRounding = NO;
             do {
                 const QString &s = *i;
                 ++i;
@@ -329,21 +320,6 @@ void QComboBox::populateMenu()
     }
 }
 
-@implementation KWQComboBoxAdapter
-
-- (id)initWithQComboBox:(QComboBox *)b
-{
-    box = b;
-    return [super init];
-}
-
-- (void)action:(id)sender
-{
-    box->itemSelected();
-}
-
-@end
-
 @implementation KWQPopUpButtonCell
 
 - (id)initWithQComboBox:(QComboBox *)b
@@ -407,6 +383,11 @@ void QComboBox::populateMenu()
 
 @implementation KWQPopUpButton
 
+- (void)action:(id)sender
+{
+    static_cast<QComboBox *>([self widget])->itemSelected();
+}
+
 - (QWidget *)widget
 {
     return [(KWQPopUpButtonCell *)[self cell] widget];
index 2aad083..85a2387 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2003 Apple Computer, Inc.  All rights reserved.
+ * Copyright (C) 2004 Apple Computer, Inc.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -225,8 +225,25 @@ KURL::KURL() : m_isValid(false)
 KURL::KURL(const char *url)
 {
     if (url != NULL && url[0] == '/') {
-       QString qurl = QString("file:") + url;
-       parse(qurl.ascii(), &qurl);
+        char staticBuffer[2048];
+        char *buffer;
+        size_t urlLength = strlen(url) + 1;
+        size_t bufferLength = urlLength + 5; // 5 for "file:"
+        if (bufferLength > sizeof(staticBuffer)) {
+            buffer = (char *)malloc(bufferLength);
+        } else {
+            buffer = staticBuffer;
+        }
+        buffer[0] = 'f';
+        buffer[1] = 'i';
+        buffer[2] = 'l';
+        buffer[3] = 'e';
+        buffer[4] = ':';
+        memcpy(&buffer[5], url, urlLength);
+       parse(buffer, NULL);
+        if (buffer != staticBuffer) {
+            free(buffer);
+        }
     } else {
        parse(url, NULL);
     }
@@ -235,8 +252,24 @@ KURL::KURL(const char *url)
 KURL::KURL(const QString &url)
 {
     if (!url.isEmpty() && url[0] == '/') {
-       QString fileUrl = QString("file:") + url;
-       parse(fileUrl.ascii(), &fileUrl);
+        char staticBuffer[2048];
+        char *buffer;
+        size_t bufferLength = url.length() + 6; // 5 for "file:", 1 for terminator
+        if (bufferLength > sizeof(staticBuffer)) {
+            buffer = (char *)malloc(bufferLength);
+        } else {
+            buffer = staticBuffer;
+        }
+        buffer[0] = 'f';
+        buffer[1] = 'i';
+        buffer[2] = 'l';
+        buffer[3] = 'e';
+        buffer[4] = ':';
+        url.copyLatin1(&buffer[5]);
+       parse(buffer, NULL);
+        if (buffer != staticBuffer) {
+            free(buffer);
+        }
     } else {
        parse(url.ascii(), &url);
     }
@@ -245,17 +278,31 @@ KURL::KURL(const QString &url)
 KURL::KURL(NSURL *url)
 {
     if (url) {
-        CFIndex bufferLength = CFURLGetBytes((CFURLRef)url, NULL, 0);
-        char *bytes = new char [bufferLength + 1];
-        CFURLGetBytes((CFURLRef)url, (UInt8 *)bytes, bufferLength);
-       bytes[bufferLength] = '\0';
+        CFIndex bytesLength = CFURLGetBytes((CFURLRef)url, NULL, 0);
+        size_t bufferLength = bytesLength + 6; // 5 for "file:", 1 for NUL terminator
+        char staticBuffer[2048];
+        char *buffer;
+        if (bufferLength > sizeof(staticBuffer)) {
+            buffer = (char *)malloc(bufferLength);
+        } else {
+            buffer = staticBuffer;
+        }
+        char *bytes = &buffer[5];
+        CFURLGetBytes((CFURLRef)url, (UInt8 *)bytes, bytesLength);
+       bytes[bytesLength] = '\0';
         if (bytes[0] == '/') {
-            QString fileUrl = QString("file:") + bytes;
-            parse(fileUrl.ascii(), &fileUrl);
+            buffer[0] = 'f';
+            buffer[1] = 'i';
+            buffer[2] = 'l';
+            buffer[3] = 'e';
+            buffer[4] = ':';
+            parse(buffer, NULL);
         } else {
             parse(bytes, NULL);
         }
-        delete [] bytes;
+        if (buffer != staticBuffer) {
+            free(buffer);
+        }
     }
     else {
         parse("", NULL);
@@ -391,15 +438,15 @@ KURL::KURL(const KURL &base, const QString &relative, const QTextCodec *codec)
            {
                // must be relative-path reference
 
-               char static_buffer[2048];
+               char staticBuffer[2048];
                char *buffer;
                
                size_t bufferLength = base.pathEndPos + strlen(str) + 1;
 
-               if (bufferLength > sizeof(static_buffer)) {
+               if (bufferLength > sizeof(staticBuffer)) {
                    buffer = (char *)malloc(bufferLength);
                } else {
-                   buffer = static_buffer;
+                   buffer = staticBuffer;
                }
                
                char *bufferPos = buffer;
@@ -467,7 +514,7 @@ KURL::KURL(const KURL &base, const QString &relative, const QTextCodec *codec)
                 
                 ASSERT(strlen(buffer) + 1 <= bufferLength);
                
-               if (buffer != static_buffer) {
+               if (buffer != staticBuffer) {
                    free(buffer);
                }
                
@@ -930,6 +977,25 @@ static int copyPathRemovingDots(char *dst, const char *src, int srcStart, int sr
     return dst - bufferPathStart;
 }
 
+static inline bool hasSlashDotOrDotDot(const char *str)
+{
+    const char *p = str;
+    if (!*p)
+        return false;
+    char pc = *p;
+    while (char c = *++p) {
+        if (c == '.' && (pc == '/' || pc == '.'))
+            return true;
+        pc = c;
+    }
+    return false;
+}
+
+static inline bool matchLetter(char c, char lowercaseLetter)
+{
+    return (c | 0x20) == lowercaseLetter;
+}
+
 void KURL::parse(const char *url, const QString *originalString)
 {
     m_isValid = true;
@@ -1103,11 +1169,11 @@ void KURL::parse(const char *url, const QString *originalString)
 
     // assemble it all, remembering the real ranges
 
-    char static_buffer[4096];
+    char staticBuffer[4096];
     char *buffer;
     uint bufferLength = fragmentEnd * 3 + 1;
-    if (bufferLength <= sizeof(static_buffer)) {
-       buffer = static_buffer;
+    if (bufferLength <= sizeof(staticBuffer)) {
+       buffer = staticBuffer;
     } else {
        buffer = (char *)malloc(bufferLength);
     }
@@ -1123,28 +1189,28 @@ void KURL::parse(const char *url, const QString *originalString)
     schemeEndPos = p - buffer;
 
     // Check if we're http or https.
-    bool isHTTPorHTTPS = tolower(url[0]) == 'h'
-        && tolower(url[1]) == 't'
-        && tolower(url[2]) == 't'
-        && tolower(url[3]) == 'p'
+    bool isHTTPorHTTPS = matchLetter(url[0], 'h')
+        && matchLetter(url[1], 't')
+        && matchLetter(url[2], 't')
+        && matchLetter(url[3], 'p')
         && (url[4] == ':'
-            || (tolower(url[4]) == 's' && url[5] == ':'));
+            || (matchLetter(url[4], 's') && url[5] == ':'));
 
     bool hostIsLocalHost = portEnd - userStart == 9
-        && tolower(url[userStart]) == 'l'
-        && tolower(url[userStart+1]) == 'o'
-        && tolower(url[userStart+2]) == 'c'
-        && tolower(url[userStart+3]) == 'a'
-        && tolower(url[userStart+4]) == 'l'
-        && tolower(url[userStart+5]) == 'h'
-        && tolower(url[userStart+6]) == 'o'
-        && tolower(url[userStart+7]) == 's'
-        && tolower(url[userStart+8]) == 't';
-
-    bool isFile = tolower(url[0]) == 'f'
-        && tolower(url[1]) == 'i'
-        && tolower(url[2]) == 'l'
-        && tolower(url[3]) == 'e'
+        && matchLetter(url[userStart], 'l')
+        && matchLetter(url[userStart+1], 'o')
+        && matchLetter(url[userStart+2], 'c')
+        && matchLetter(url[userStart+3], 'a')
+        && matchLetter(url[userStart+4], 'l')
+        && matchLetter(url[userStart+5], 'h')
+        && matchLetter(url[userStart+6], 'o')
+        && matchLetter(url[userStart+7], 's')
+        && matchLetter(url[userStart+8], 't');
+
+    bool isFile = matchLetter(url[0], 'f')
+        && matchLetter(url[1], 'i')
+        && matchLetter(url[2], 'l')
+        && matchLetter(url[3], 'e')
         && url[4] == ':';
         
     // File URLs need a host part unless it is just file:// or file://localhost
@@ -1228,7 +1294,7 @@ void KURL::parse(const char *url, const QString *originalString)
        
     // add path, escaping bad characters
     
-    if (hierarchical && (strstr(url, "/.") || strstr(url, ".."))) {
+    if (hierarchical && hasSlashDotOrDotDot(url)) {
         char static_path_buffer[4096];
         char *path_buffer;
         uint pathBufferLength = pathEnd - pathStart + 1;
@@ -1271,7 +1337,7 @@ void KURL::parse(const char *url, const QString *originalString)
 
     ASSERT(p - buffer <= (int)bufferLength);
                
-    if (buffer != static_buffer) {
+    if (buffer != staticBuffer) {
        free(buffer);
     }
 }
@@ -1307,11 +1373,11 @@ QString KURL::encode_string(const QString& notEncodedString)
 {
     QCString asUTF8 = notEncodedString.utf8();
     
-    char static_buffer[4096];
+    char staticBuffer[4096];
     char *buffer;
     uint bufferLength = asUTF8.length() * 3 + 1;
-    if (bufferLength <= sizeof(static_buffer)) {
-       buffer = static_buffer;
+    if (bufferLength <= sizeof(staticBuffer)) {
+       buffer = staticBuffer;
     } else {
        buffer = (char *)malloc(bufferLength);
     }
@@ -1335,7 +1401,7 @@ QString KURL::encode_string(const QString& notEncodedString)
     
     ASSERT(p - buffer <= (int)bufferLength);
                
-    if (buffer != static_buffer) {
+    if (buffer != staticBuffer) {
        free(buffer);
     }
 
index 579ccc5..0bf42aa 100644 (file)
@@ -190,6 +190,8 @@ QSize QLineEdit::sizeForCharacterWidth(int numCharacters) const
 
     WebCoreTextStyle style;
     WebCoreInitializeEmptyTextStyle(&style);
+    style.applyRunRounding = NO;
+    style.applyWordRounding = NO;
 
     const UniChar zero = '0';
     WebCoreTextRun run;
index 6a270fe..5c9ccde 100644 (file)
@@ -256,6 +256,8 @@ QSize QListBox::sizeForNumberOfLines(int lines) const
             WebCoreTextStyle style;
             WebCoreInitializeEmptyTextStyle(&style);
             style.rtl = [tableView baseWritingDirection] == NSWritingDirectionRightToLeft;
+            style.applyRunRounding = NO;
+            style.applyWordRounding = NO;
             do {
                 const QString &s = (*i).string;
                 id <WebCoreTextRenderer> renderer = (*i).isGroupLabel ? groupLabelTextRenderer() : itemTextRenderer();
@@ -503,6 +505,8 @@ void QListBox::setWritingDirection(QPainter::TextDirection d)
     WebCoreTextStyle style;
     WebCoreInitializeEmptyTextStyle(&style);
     style.rtl = RTL;
+    style.applyRunRounding = NO;
+    style.applyWordRounding = NO;
     style.textColor = color;
 
     WebCoreTextRun run;
index d394e35..c9d9737 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2003 Apple Computer, Inc.  All rights reserved.
+ * Copyright (C) 2004 Apple Computer, Inc.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 #include "KWQColor.h"
 #include "KWQBrush.h"
 
+// We don't colorize widgets, so we don't need palettes.
+// And copying the palettes was taking a measurable amount of time.
+#define KWQ_USE_PALETTES 0
+
 class QColorGroupPrivate;
 class QPalettePrivate;
 
 class QColorGroup {
 public:
     enum ColorRole { 
-        Foreground, 
-        Shadow, 
-        Light, 
-        Midlight, 
-        Mid, 
-        Dark, 
-        Base, 
-        ButtonText, 
-        Button, 
-        Background, 
+#if KWQ_USE_PALETTES
+        Foreground,
+        Shadow,
+        Light,
+        Midlight,
+        Mid,
+        Dark,
+#endif
+        Base,
+#if KWQ_USE_PALETTES
+        ButtonText,
+        Button,
+        Background,
         Text,
         Highlight,
         HighlightedText,
+#endif
         NColorRoles
     };
 
@@ -58,18 +66,22 @@ public:
     const QColor &color(ColorRole) const;
     void setColor(ColorRole, const QColor &);
 
+#if KWQ_USE_PALETTES
     const QColor &foreground() const;
     const QColor &shadow() const;
     const QColor &light() const;
     const QColor &midlight() const;
     const QColor &dark() const;
+#endif
     const QColor &base() const;
+#if KWQ_USE_PALETTES
     const QColor &buttonText() const;
     const QColor &button() const;
     const QColor &text() const;
     const QColor &background() const;
     const QColor &highlight() const;
     const QColor &highlightedText() const;
+#endif
 
     bool operator==(const QColorGroup &) const;
 
@@ -82,8 +94,10 @@ class QPalette {
 public:
     enum ColorGroup { 
         Active, 
+#if KWQ_USE_PALETTES
         Inactive, 
         Disabled,
+#endif
         NColorGroups
     };
 
@@ -91,16 +105,20 @@ public:
     void setColor(ColorGroup, QColorGroup::ColorRole, const QColor &);
 
     const QColorGroup &active() const { return m_active; }
+#if KWQ_USE_PALETTES
     const QColorGroup &inactive() const { return m_inactive; }
     const QColorGroup &disabled() const { return m_disabled; }
     const QColorGroup &normal() const { return m_active; }
+#endif
 
     bool operator==(const QPalette &) const;
 
 private:
     QColorGroup m_active;  
+#if KWQ_USE_PALETTES
     QColorGroup m_inactive;  
     QColorGroup m_disabled;  
+#endif
 };
 
 #endif
index 8a2febf..e48db80 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2003 Apple Computer, Inc.  All rights reserved.
+ * Copyright (C) 2004 Apple Computer, Inc.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
 
 #import "KWQPalette.h"
 
+#import "KWQAssertions.h"
+
 const QColor& QPalette::color(ColorGroup cg, QColorGroup::ColorRole role) const
 {
     switch (cg) {
-    default: // keep GCC from complaining about NColorGroups
+    case NColorGroups:
+        break;
     case Active:
         return m_active.color(role);
+#if KWQ_USE_PALETTES
     case Inactive:
         return m_inactive.color(role);
     case Disabled:
         return m_disabled.color(role);
+#endif
     }
+    ASSERT(false);
+    return m_active.color(QColorGroup::Base);
 }
 
 void QPalette::setColor(ColorGroup cg, QColorGroup::ColorRole role, const QColor &color)
@@ -44,18 +51,25 @@ void QPalette::setColor(ColorGroup cg, QColorGroup::ColorRole role, const QColor
     case Active:
         m_active.setColor(role, color);
         break;
+#if KWQ_USE_PALETTES
     case Inactive:
         m_inactive.setColor(role, color);
         break;
     case Disabled:
         m_disabled.setColor(role, color);
         break;
-    default: // keep GCC from complaining about NColorGroups
+#endif
+    case NColorGroups:
+        ASSERT(false);
         break;
     }
 }
 
 bool QPalette::operator==(QPalette const &other) const
 {
-    return m_active == other.m_active && m_inactive == other.m_inactive && m_disabled == other.m_disabled;
+    return m_active == other.m_active
+#if KWQ_USE_PALETTES
+        && m_inactive == other.m_inactive && m_disabled == other.m_disabled
+#endif
+        ;
 }
index 26aa384..9da9548 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2003 Apple Computer, Inc.  All rights reserved.
+ * Copyright (C) 2004 Apple Computer, Inc.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -159,23 +159,25 @@ QString QRegExp::pattern() const
 }
 
 int QRegExp::match(const QString &str, int startFrom, int *matchLength) const
-{    
-    QCString asUTF8;
-    const char *cstring;
-    
+{
+    // First 2 offsets are start and end offsets; 3rd entry is used internally by pcre
+    int offsets[3];
+    int result;
+
     if (str.isAllASCII()) {
-        cstring = str.ascii();
+        result = pcre_exec(d->regex, NULL, str.ascii(), str.length(), startFrom, 
+                           startFrom == 0 ? 0 : PCRE_NOTBOL, offsets, 3);
     } else {
-        asUTF8 = str.utf8();
-        cstring = asUTF8;
-    }
-        
-    // first 2 offsets are start and end offsets; 3rd entry is used internally by pcre
-    int offsets[3];
-    convertUTF16OffsetsToUTF8Offsets(cstring, &startFrom, 1);
-    int result = pcre_exec(d->regex, NULL, cstring, strlen(cstring), startFrom, 
+        int length;
+        QCString asUTF8 = str.utf8(length);
+        convertUTF16OffsetsToUTF8Offsets(asUTF8, &startFrom, 1);
+        result = pcre_exec(d->regex, NULL, asUTF8, length, startFrom, 
                            startFrom == 0 ? 0 : PCRE_NOTBOL, offsets, 3);
-    
+        if (result >= 0) {
+            convertUTF8OffsetsToUTF16Offsets(asUTF8, offsets, 2);
+        }
+    }
+
     if (result < 0) {
         if (result != PCRE_ERROR_NOMATCH) {
             ERROR("KWQRegExp: pcre_exec() failed with result %d", result);
@@ -185,9 +187,8 @@ int QRegExp::match(const QString &str, int startFrom, int *matchLength) const
         return -1;
     }
     
+    // 1 means 1 match; 0 means more than one match. First match is recorded in offsets.
     ASSERT(result < 2);
-    // 1 means 1 match; 0 means more than one match, first one is recorded in offsets
-    convertUTF8OffsetsToUTF16Offsets(cstring, offsets, 2);
     d->lastMatchPos = offsets[0];
     d->lastMatchLength = offsets[1] - offsets[0];
     if (matchLength != NULL) {
index af42e9d..a1c087a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2003 Apple Computer, Inc.  All rights reserved.
+ * Copyright (C) 2004 Apple Computer, Inc.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -65,15 +65,7 @@ public:
     uchar row() const;
     char latin1() const;
     bool isNull() const;
-    bool isSpace() const
-    {
-        // Use isspace() for basic latin1.  This will include newlines, which
-        // aren't included in unicode DirWS.
-        if (c <= 0x7F) {
-            return isspace(c);
-        }
-        return direction() == DirWS;
-    }
+    bool isSpace() const;
     bool isDigit() const;
     bool isLetter() const;
     bool isNumber() const;
@@ -82,10 +74,7 @@ public:
     int digitValue() const;
     QChar lower() const;
     QChar upper() const;
-    Direction direction() const
-    {
-        return (Direction)WebCoreUnicodeDirectionFunction(c);
-    }
+    Direction direction() const;
 
     bool mirrored() const;
     QChar mirroredChar() const;
@@ -122,6 +111,13 @@ private:
     friend class QString;
     friend class QConstString;
 
+    static bool isDigitNonASCII(UniChar c);
+    static bool isLetterNonASCII(UniChar c);
+    static bool isNumberNonASCII(UniChar c);
+    static bool isLetterOrNumberNonASCII(UniChar c);
+    static int digitValueNonASCII(UniChar c);
+    static UniChar lowerNonASCII(UniChar c);
+    static UniChar upperNonASCII(UniChar c);
 };
 
 inline QChar::QChar() : c(0)
@@ -167,6 +163,53 @@ inline bool QChar::isNull() const
     return c == 0;
 }
 
+inline bool QChar::isSpace() const
+{
+    // Use isspace() for basic latin1.  This will include newlines, which
+    // aren't included in unicode DirWS.
+    return c <= 0x7F ? isspace(c) : direction() == DirWS;
+}
+
+inline bool QChar::isDigit() const
+{
+    return c <= 0x7F ? isdigit(c) : isDigitNonASCII(c);
+}
+
+inline bool QChar::isLetter() const
+{
+    return c <= 0x7F ? isalpha(c) : isLetterNonASCII(c);
+}
+
+inline bool QChar::isNumber() const
+{
+    return c <= 0x7F ? isdigit(c) : isNumberNonASCII(c);
+}
+
+inline bool QChar::isLetterOrNumber() const
+{
+    return c <= 0x7F ? isalnum(c) : isLetterOrNumberNonASCII(c);
+}
+
+inline int QChar::digitValue() const
+{
+    return c <= '9' ? c - '0' : digitValueNonASCII(c);
+}
+
+inline QChar QChar::lower() const
+{
+    return c <= 0x7F ? tolower(c) : lowerNonASCII(c);
+}
+
+inline QChar QChar::upper() const
+{
+    return c <= 0x7F ? toupper(c) : upperNonASCII(c);
+}
+
+inline QChar::Direction QChar::direction() const
+{
+    return static_cast<Direction>(WebCoreUnicodeDirectionFunction(c));
+}
+
 inline uchar QChar::row() const
 {
     return c >> 8;
@@ -366,7 +409,10 @@ public:
     const char *latin1() const;
     const char *ascii() const;
     bool isAllASCII() const;
-    QCString utf8() const;
+    bool isAllLatin1() const;
+    void copyLatin1(char *latin1) const;
+    QCString utf8() const { int length; return utf8(length); }
+    QCString utf8(int &length) const;
     QCString local8Bit() const;
 
     bool isNull() const;
@@ -452,47 +498,49 @@ public:
 
     QString &sprintf(const char *, ...) __attribute__ ((format (printf, 2, 3)));
 
-    QString &prepend(const QString &);
     QString &append(const QString &);
+    QString &append(QChar);
+    QString &append(char);
     QString &insert(uint, const QString &);
     QString &insert(uint, QChar);
     QString &insert(uint, char);
     QString &insert(uint index, const char *insertChars, uint insertLength);
+    QString &prepend(const QString &);
     QString &remove(uint, uint);
     QString &replace(uint index, uint len, const QString &s);
     QString &replace(const QRegExp &, const QString &);
     QString &replace(QChar, QChar);
 
-    void truncate(uint);
+    QString &append(const QChar *, uint length);
+    QString &append(const char *, uint length);
+    QString &insert(uint position, const QChar *, uint length);
+    QString &prepend(const QChar *, uint length);
+    
     void fill(QChar, int len=-1);
+    void truncate(uint);
 
-    void compose();
-    QString visual();
+    void reserve(uint);
 
-    CFStringRef getCFString() const;
-    NSString *getNSString() const;
+    uint hash() const;
 
     bool operator!() const;
 
     const QChar operator[](int) const;
 
-    QString &operator+=(const QString &);
-    QString &operator+=(QChar);
-    QString &operator+=(char);
+    QString &operator+=(const QString &s) { return append(s); }
+    QString &operator+=(QChar c) { return append(c); }
+    QString &operator+=(char c) { return append(c); }
+
+    CFStringRef getCFString() const;
+    NSString *getNSString() const;
 
     void setBufferFromCFString(CFStringRef);
     
-    QString &append(const char *, uint length);
-    QString &append(const QChar *, uint length);
-    QString &prepend(const QChar *, uint length);
-    QString &insert(uint position, const QChar *, uint length);
-    
-    uint hash() const;
-    
 private:
     // Used by QConstString.
     QString(KWQStringData *constData, bool /*dummy*/);
     void detach();
+    void detachAndDiscardCharacters();
     void detachIfInternal();
     void detachInternal();
     void deref();
index 80105bf..a79efec 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2003 Apple Computer, Inc.  All rights reserved.
+ * Copyright (C) 2004 Apple Computer, Inc.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -46,12 +46,13 @@ int malloc_good_size(int size);
 #define ALLOC_CHAR_GOOD_SIZE(X) (malloc_good_size(X))
 
 #ifdef QSTRING_DEBUG_ALLOCATIONS
+
 #import <pthread.h>
 #import <mach/mach_types.h>
 
-static CFMutableDictionaryRef _allocatedBuffers = 0;
+static CFMutableDictionaryRef allocatedBuffers = 0;
 #define ALLOCATION_HISTOGRAM_SIZE 128
-static uint _allocationHistogram[ALLOCATION_HISTOGRAM_SIZE];
+static uint allocationHistogram[ALLOCATION_HISTOGRAM_SIZE];
 
 static uint stackInstances = 0;
 static uint heapInstances = 0;
@@ -60,7 +61,8 @@ static uint stringDataHeapInstances = 0;
 static uint stringDataDetachments = 0;
 static uint handleInstances = 0;
 
-static bool _isOnStack(void *ptr){
+static bool isOnStack(void *ptr)
+{
     void *address;
     size_t size;
     pthread_t thisThread = pthread_self();
@@ -73,10 +75,9 @@ static bool _isOnStack(void *ptr){
     return false;
 }
 
-
 static void countInstance(void *ptr)
 {
-    if (_isOnStack(ptr))
+    if (isOnStack(ptr))
         stackInstances++;
     else
         heapInstances++;
@@ -84,35 +85,37 @@ static void countInstance(void *ptr)
 
 static CFMutableDictionaryRef allocatedBuffers()
 {
-    if (_allocatedBuffers == 0){
+    if (allocatedBuffers == 0){
         for (int i = 0; i < ALLOCATION_HISTOGRAM_SIZE; i++)
-            _allocationHistogram[i] = 0;
-        _allocatedBuffers = CFDictionaryCreateMutable (kCFAllocatorDefault, 1024*8, NULL, NULL);
+            allocationHistogram[i] = 0;
+        allocatedBuffers = CFDictionaryCreateMutable (kCFAllocatorDefault, 1024*8, NULL, NULL);
     }
-    return _allocatedBuffers;
+    return allocatedBuffers;
 }
 
-static char *ALLOC_CHAR(int n){
+static char *ALLOC_CHAR(int n)
+{
     char *ptr = (char *)malloc(n);
 
     CFDictionarySetValue (allocatedBuffers(), ptr, (void *)n);
     
     if (n >= ALLOCATION_HISTOGRAM_SIZE)
-        _allocationHistogram[ALLOCATION_HISTOGRAM_SIZE-1]++;
+        allocationHistogram[ALLOCATION_HISTOGRAM_SIZE-1]++;
     else
-        _allocationHistogram[n]++;
+        allocationHistogram[n]++;
     return ptr;
 }
 
-static char *REALLOC_CHAR(void *p, int n){
+static char *REALLOC_CHAR(void *p, int n)
+{
     char *ptr = (char *)realloc(p, n);
 
     CFDictionaryRemoveValue (allocatedBuffers(), p);
     CFDictionarySetValue (allocatedBuffers(), ptr, (const void *)(n));
     if (n >= ALLOCATION_HISTOGRAM_SIZE)
-        _allocationHistogram[ALLOCATION_HISTOGRAM_SIZE-1]++;
+        allocationHistogram[ALLOCATION_HISTOGRAM_SIZE-1]++;
     else
-        _allocationHistogram[n]++;
+        allocationHistogram[n]++;
     return ptr;
 }
 
@@ -122,28 +125,30 @@ static void DELETE_CHAR(void *p)
     free (p);
 }
 
-static QChar *ALLOC_QCHAR(int n){
+static QChar *ALLOC_QCHAR(int n)
+{
     size_t size = (sizeof(QChar)*( n ));
     QChar *ptr = (QChar *)malloc(size);
 
     CFDictionarySetValue (allocatedBuffers(), ptr, (const void *)size);
     if (size >= ALLOCATION_HISTOGRAM_SIZE)
-        _allocationHistogram[ALLOCATION_HISTOGRAM_SIZE-1]++;
+        allocationHistogram[ALLOCATION_HISTOGRAM_SIZE-1]++;
     else
-        _allocationHistogram[size]++;
+        allocationHistogram[size]++;
     return ptr;
 }
 
-static QChar *REALLOC_QCHAR(void *p, int n){
+static QChar *REALLOC_QCHAR(void *p, int n)
+{
     size_t size = (sizeof(QChar)*( n ));
     QChar *ptr = (QChar *)realloc(p, size);
 
     CFDictionaryRemoveValue (allocatedBuffers(), p);
     CFDictionarySetValue (allocatedBuffers(), ptr, (const void *)size);
     if (size >= ALLOCATION_HISTOGRAM_SIZE)
-        _allocationHistogram[ALLOCATION_HISTOGRAM_SIZE-1]++;
+        allocationHistogram[ALLOCATION_HISTOGRAM_SIZE-1]++;
     else
-        _allocationHistogram[size]++;
+        allocationHistogram[size]++;
         
     return ptr;
 }
@@ -183,9 +188,9 @@ void _printQStringAllocationStatistics()
     
     printf ("\nString size histogram:\n");
     for (i = 0; i < ALLOCATION_HISTOGRAM_SIZE; i++){
-        if (_allocationHistogram[i])
-            printf ("[%d] = %d\n", i, _allocationHistogram[i]);
-        totalAllocations += _allocationHistogram[i];
+        if (allocationHistogram[i])
+            printf ("[%d] = %d\n", i, allocationHistogram[i]);
+        totalAllocations += allocationHistogram[i];
     }
     printf ("Total allocations %d\n", totalAllocations);
     
@@ -200,6 +205,7 @@ void _printQStringAllocationStatistics()
     free(keys);
     free(values);
 }
+
 #else
 
 #define ALLOC_CHAR( N ) (char*) malloc(N)
@@ -209,13 +215,14 @@ void _printQStringAllocationStatistics()
 #define ALLOC_QCHAR( N ) (QChar*) malloc(sizeof(QChar)*( N ))
 #define REALLOC_QCHAR( P, N ) (QChar *) realloc(P,sizeof(QChar)*( N ))
 #define DELETE_QCHAR( P ) free( P )
+
 #endif // QSTRING_DEBUG_ALLOCATIONS
 
 #import <mach/vm_map.h>
 #import <mach/mach_init.h>
 
-static void *allocateHandle();
-static void freeHandle(void *free);
+static KWQStringData **allocateHandle();
+static void freeHandle(KWQStringData **);
 
 #define IS_ASCII_QCHAR(c) ((c).unicode() > 0 && (c).unicode() <= 0xff)
 
@@ -230,7 +237,7 @@ KWQStringData **QString::shared_null_handle = 0;
 // Utility functions
 // -------------------------------------------------------------------------
 
-static int ucstrcmp( const QString &as, const QString &bs )
+static inline int ucstrcmp( const QString &as, const QString &bs )
 {
     const QChar *a = as.unicode();
     const QChar *b = bs.unicode();
@@ -240,7 +247,7 @@ static int ucstrcmp( const QString &as, const QString &bs )
        return 1;
     if ( b == 0 )
        return -1;
-    int l = QMIN(as.length(), bs.length());
+    int l = kMin(as.length(), bs.length());
     while ( l-- && *a == *b )
        a++,b++;
     if ( l == -1 )
@@ -249,38 +256,75 @@ static int ucstrcmp( const QString &as, const QString &bs )
 }
 
 
-static int ucstrncmp( const QChar *a, const QChar *b, int l )
+static bool equal(const QChar *a, const char *b, int l)
 {
-    while ( l-- && *a == *b )
-       a++,b++;
-    if ( l == -1 )
-       return 0;
-    return a->unicode() - b->unicode();
+    ASSERT(l >= 0);
+    while (l--) {
+        if (*a != *b)
+            return false;
+       a++; b++;
+    }
+    return true;
 }
 
+// Not a "true" case insensitive compare; only insensitive for plain ASCII.
 
-static int ucstrnicmp( const QChar *a, const QChar *b, int l )
+static bool equalCaseInsensitive(const char *a, const char *b, int l)
 {
-    while ( l-- && a->lower() == b->lower() )
-       a++,b++;
-    if ( l == -1 )
-       return 0;
-    QChar al = a->lower();
-    QChar bl = b->lower();
-    return al.unicode() - bl.unicode();
+    ASSERT(l >= 0);
+    while (l--) {
+        if (tolower(*a) != tolower(*b))
+            return false;
+       a++; b++;
+    }
+    return true;
 }
 
+static bool equalCaseInsensitive(const QChar *a, const char *b, int l)
+{
+    ASSERT(l >= 0);
+    while (l--) {
+        if (tolower(a->unicode()) != tolower(*b))
+            return false;
+       a++; b++;
+    }
+    return true;
+}
 
-static bool ok_in_base( QChar c, int base )
+static bool equalCaseInsensitive(const QChar *a, const QChar *b, int l)
 {
-    if ( base <= 10 )
-       return c.isDigit() && c.digitValue() < base;
-    else
-       return c.isDigit() || (c >= 'a' && c < char('a' + base - 10))
-                          || (c >= 'A' && c < char('A' + base - 10));
+    ASSERT(l >= 0);
+    while (l--) {
+        if (tolower(a->unicode()) != tolower(b->unicode()))
+            return false;
+       a++; b++;
+    }
+    return true;
 }
 
+static inline bool equalCaseInsensitive(char c1, char c2)
+{
+    return tolower(c1) == tolower(c2);
+}
 
+static inline bool equalCaseInsensitive(QChar c1, char c2)
+{
+    return tolower(c1.unicode()) == tolower(static_cast<unsigned char>(c2));
+}
+
+static bool ok_in_base(QChar c, int base)
+{
+    int uc = c.unicode();
+    if (isdigit(uc))
+       return uc - '0' < base;
+    if (isalpha(uc)) {
+        if (base > 36)
+            base = 36;
+       return (uc >= 'a' && uc < 'a' + base - 10)
+            || (uc >= 'A' && uc < 'A' + base - 10);
+    }
+    return false;
+}
 
 // -------------------------------------------------------------------------
 // KWQStringData
@@ -436,7 +480,7 @@ KWQStringData *QString::makeSharedNull()
 KWQStringData **QString::makeSharedNullHandle()
 {
     if (!shared_null_handle) {
-        shared_null_handle = (KWQStringData **)allocateHandle();
+        shared_null_handle = allocateHandle();
         *shared_null_handle = makeSharedNull();
     }
     return shared_null_handle;
@@ -599,29 +643,6 @@ QChar *KWQStringData::makeUnicode()
 // -------------------------------------------------------------------------
 
 
-static inline bool compareIgnoringCaseForASCIIOnly(char c1, char c2)
-{
-    if (c2 >= 'a' && c2 <= 'z') {
-        return c1 == c2 || c1 == c2 - caseDelta;
-    }
-    if (c2 >= 'A' && c2 <= 'Z') {
-        return c1 == c2 || c1 == c2 + caseDelta;
-    }
-    return c1 == c2;
-}
-
-static inline bool compareIgnoringCaseForASCIIOnly(QChar c1, char c2)
-{
-    if (c2 >= 'a' && c2 <= 'z') {
-        return c1 == c2 || c1.unicode() == c2 - caseDelta;
-    }
-    if (c2 >= 'A' && c2 <= 'Z') {
-        return c1 == c2 || c1.unicode() == c2 + caseDelta;
-    }
-    return c1 == c2;
-}
-
-
 QString QString::number(int n)
 {
     QString qs;
@@ -718,6 +739,30 @@ NSString *QString::getNSString() const
     return nil;
 }
 
+inline void QString::detachInternal()
+{
+    KWQStringData *oldData = *dataHandle;
+    KWQStringData *newData;
+    if (oldData->_isAsciiValid)
+        newData = new KWQStringData(oldData->ascii(), oldData->_length);
+    else {
+        ASSERT(oldData->_isUnicodeValid);
+        // No need to copy the allocated unicode bytes.
+        if (oldData->isUnicodeInternal())
+            newData = new KWQStringData(oldData->unicode(), oldData->_length);
+        else {
+            newData = new KWQStringData(oldData->unicode(), oldData->_length, oldData->_maxUnicode);
+            oldData->_unicode = 0;
+            oldData->_isUnicodeValid = 0;
+        }
+    }
+    newData->_isHeapAllocated = 1;
+    newData->refCount = oldData->refCount - 1;
+    *dataHandle = newData;
+    
+    oldData->refCount = 1;
+}
+
 inline void QString::detachIfInternal()
 {
     KWQStringData *oldData = *dataHandle;
@@ -737,7 +782,7 @@ QString::~QString()
     // Only free the handle if no other string has a reference to the
     // data.  The handle will be freed by the string that has the
     // last reference to data.
-    bool needToFreeHandle = oldHandle != shared_null_handle && oldData->refCount == 1;
+    bool needToFreeHandle = oldData->refCount == 1 && oldData != shared_null;
 
     // Copy our internal data if necessary, other strings still need it.
     detachIfInternal();
@@ -770,7 +815,7 @@ QString::QString()
 QString::QString(KWQStringData *constData, bool /*dummy*/) 
 {
     internalData.deref();
-    dataHandle = (KWQStringData **)allocateHandle();
+    dataHandle = allocateHandle();
     *dataHandle = constData;
     
     // The QConstString constructor allocated the KWQStringData.
@@ -783,7 +828,7 @@ QString::QString(QChar qc)
 #ifdef QSTRING_DEBUG_ALLOCATIONS
     countInstance (&dataHandle);
 #endif
-    dataHandle = (KWQStringData **)allocateHandle();
+    dataHandle = allocateHandle();
 
     // Copy the QChar.
     if (IS_ASCII_QCHAR(qc)) {
@@ -802,7 +847,7 @@ QString::QString(const QByteArray &qba)
 #ifdef QSTRING_DEBUG_ALLOCATIONS
     countInstance (&dataHandle);
 #endif
-    dataHandle = (KWQStringData **)allocateHandle();
+    dataHandle = allocateHandle();
 
     // Copy data
     *dataHandle = &internalData;
@@ -819,7 +864,7 @@ QString::QString(const QChar *unicode, uint length)
         dataHandle = makeSharedNullHandle();
        dataHandle[0]->ref();
     } else {
-        dataHandle = (KWQStringData **)allocateHandle();
+        dataHandle = allocateHandle();
 
         // Copy the QChar *
         *dataHandle = &internalData;
@@ -835,7 +880,7 @@ QString::QString(const char *chs)
 
     if (chs) {
         internalData.initialize(chs,strlen(chs));
-       dataHandle = (KWQStringData **)allocateHandle();
+       dataHandle = allocateHandle();
        *dataHandle = &internalData;
     } else {
        internalData.deref();
@@ -849,7 +894,7 @@ QString::QString(const char *chs, int len)
 #ifdef QSTRING_DEBUG_ALLOCATIONS
     countInstance (&dataHandle);
 #endif
-    dataHandle = (KWQStringData **)allocateHandle();
+    dataHandle = allocateHandle();
     *dataHandle = &internalData;
     internalData.initialize(chs,len);
 }
@@ -917,10 +962,10 @@ QChar QString::at(uint i) const
     return thisData->_unicode[i];
 }
 
-int QString::compare( const QString& s ) const
+int QString::compare(const QString& s) const
 {
     if (dataHandle[0]->_isAsciiValid && s.dataHandle[0]->_isAsciiValid)
-        return strcmp (ascii(), s.ascii());
+        return strcmp(ascii(), s.ascii());
     return ucstrcmp(*this,s);
 }
 
@@ -972,24 +1017,24 @@ bool QString::startsWith( const QString& s ) const
 
 bool QString::startsWith(const char *prefix) const
 {
-    int prefixLength = strlen(prefix);
-    if (dataHandle[0]->_isAsciiValid) {
-        return strncmp(prefix, ascii(), prefixLength) == 0;
-    } else if (dataHandle[0]->_isUnicodeValid) {
-        int l = dataHandle[0]->_length;
-        if (prefixLength > l) {
+    KWQStringData *data = *dataHandle;
+
+    uint prefixLength = strlen(prefix);
+    if (data->_isAsciiValid) {
+        return strncmp(prefix, data->_ascii, prefixLength) == 0;
+    } else {
+        ASSERT(data->_isUnicodeValid);
+        if (prefixLength > data->_length) {
             return false;
         }
-        const QChar *uni = unicode();        
-        for (int i = 0; i < prefixLength; ++i) {
+        const QChar *uni = data->_unicode;        
+        for (uint i = 0; i < prefixLength; ++i) {
             if (uni[i] != prefix[i]) {
                 return false;
             }
         }
-    } else {
-        FATAL("invalid character cache");
+        return true;
     }
-    return true;
 }
 
 bool QString::startsWith(const char *prefix, bool caseSensitive) const
@@ -997,24 +1042,25 @@ bool QString::startsWith(const char *prefix, bool caseSensitive) const
     if (caseSensitive) {
         return startsWith(prefix);
     }
-    int prefixLength = strlen(prefix);
-    if (dataHandle[0]->_isAsciiValid) {
-        return strncasecmp(prefix, ascii(), prefixLength) == 0;
-    } else if (dataHandle[0]->_isUnicodeValid) {
-        int l = dataHandle[0]->_length;
-        if (prefixLength > l) {
+
+    KWQStringData *data = *dataHandle;
+
+    uint prefixLength = strlen(prefix);
+    if (data->_isAsciiValid) {
+        return strncasecmp(prefix, data->_ascii, prefixLength) == 0;
+    } else {
+        ASSERT(data->_isUnicodeValid);
+        if (prefixLength > data->_length) {
             return false;
         }
-        const QChar *uni = unicode();        
-        for (int i = 0; i < prefixLength; ++i) {
-            if (!compareIgnoringCaseForASCIIOnly(uni[i], prefix[i])) {
+        const QChar *uni = data->_unicode;        
+        for (uint i = 0; i < prefixLength; ++i) {
+            if (!equalCaseInsensitive(uni[i], prefix[i])) {
                 return false;
             }
         }
-    } else {
-        FATAL("invalid character cache");
+        return true;
     }
-    return true;
 }
 
 bool QString::endsWith( const QString& s ) const
@@ -1031,7 +1077,7 @@ bool QString::endsWith( const QString& s ) const
     return TRUE;
 }
 
-QCString QString::utf8() const
+QCString QString::utf8(int &length) const
 {
     uint len = dataHandle[0]->_length;
     if (len == 0) {
@@ -1040,6 +1086,7 @@ QCString QString::utf8() const
     CFStringRef s = getCFString();
     CFIndex utf8Size;
     CFStringGetBytes(s, CFRangeMake(0, len), kCFStringEncodingUTF8, '?', false, 0, 0, &utf8Size);
+    length = utf8Size;
     QCString qcs(utf8Size + 1);
     CFStringGetCString(s, qcs.data(), utf8Size + 1, kCFStringEncodingUTF8);
     return qcs;
@@ -1094,8 +1141,8 @@ int QString::find(const QString &str, int index, bool caseSensitive) const
     // FIXME, use the first character algorithm
     /*
       We use some weird hashing for efficiency's sake.  Instead of
-      comparing strings, we compare the hash value of str with that of
-      a part of this QString.  Only if that matches, we call ucstrncmp
+      comparing strings, we compare the sum of str with that of
+      a part of this QString.  Only if that matches, we call memcmp
       or ucstrnicmp.
 
       The hash value of a string is the sum of the cells of its
@@ -1118,139 +1165,97 @@ int QString::find(const QString &str, int index, bool caseSensitive) const
     int i;
     if ( caseSensitive ) {
        for ( i = 0; i < lstr; i++ ) {
-           hthis += uthis[i].cell();
-           hstr += ustr[i].cell();
+           hthis += uthis[i].unicode();
+           hstr += ustr[i].unicode();
        }
        i = 0;
        while ( TRUE ) {
-           if ( hthis == hstr && ucstrncmp(uthis + i, ustr, lstr) == 0 )
+           if ( hthis == hstr && memcmp(uthis + i, ustr, lstr * sizeof(QChar)) == 0 )
                return index + i;
            if ( i == delta )
                return -1;
-           hthis += uthis[i + lstr].cell();
-           hthis -= uthis[i].cell();
+           hthis += uthis[i + lstr].unicode();
+           hthis -= uthis[i].unicode();
            i++;
        }
     } else {
        for ( i = 0; i < lstr; i++ ) {
-           hthis += uthis[i].lower().cell();
-           hstr += ustr[i].lower().cell();
+           hthis += tolower(uthis[i].unicode());
+           hstr += tolower(ustr[i].unicode());
        }
        i = 0;
        while ( TRUE ) {
-           if ( hthis == hstr && ucstrnicmp(uthis + i, ustr, lstr) == 0 )
+           if ( hthis == hstr && equalCaseInsensitive(uthis + i, ustr, lstr) )
                return index + i;
            if ( i == delta )
                return -1;
-           hthis += uthis[i + lstr].lower().cell();
-           hthis -= uthis[i].lower().cell();
+           hthis += tolower(uthis[i + lstr].unicode());
+           hthis -= tolower(uthis[i].unicode());
            i++;
        }
     }
-    
-    // Should never get here.
-    return -1;
 }
 
-
 // This function should be as fast as possible, every little bit helps.
 // Our usage patterns are typically small strings.  In time trials
 // this simplistic algorithm is much faster than Boyer-Moore or hash
 // based algorithms.
 int QString::find(const char *chs, int index, bool caseSensitive) const
 {
-    if (dataHandle[0]->_isAsciiValid){
-        char *ptr = dataHandle[0]->ascii();
-        
-        if (chs) {
-            int len = dataHandle[0]->_length;
-            
-            ptr += index;
-            
-            if (len && (index >= 0) && (index < len)) {
-                int remaining = len - index;
-                int compareToLength = strlen(chs);
-                            
-                char firstC = *chs;
-                
-                if (caseSensitive) {
-                    while (remaining >= compareToLength) {
-                        if (*ptr++ == firstC) {
-                            const char *_chs = chs + 1;
-                            char *compareTo = ptr;
-                            char c2;
-                            while ((c2 = *_chs++))
-                                if (*compareTo++ != c2)
-                                    break;
-                            if (c2 == 0)
-                                return len - remaining;
-                        }
-                        remaining--;
-                    }
-                } else {
-                    while (remaining >= compareToLength) {
-                        if (compareIgnoringCaseForASCIIOnly(*ptr++, firstC)) {
-                            const char *_chs = chs + 1;
-                            char *compareTo = ptr;
-                            char c2;
-                            while ((c2 = *_chs++))
-                                if (!compareIgnoringCaseForASCIIOnly(*compareTo++, c2))
-                                    break;
-                            if (c2 == 0)
-                                return len - remaining;
-                            _chs = chs + 1;
-                        }
-                        remaining--;
-                    }
+    if (!chs || index < 0)
+        return -1;
+
+    KWQStringData *data = *dataHandle;
+
+    int chsLength = strlen(chs);
+    int n = data->_length - index;
+    if (n < 0)
+        return -1;
+    n -= chsLength - 1;
+    if (n <= 0)
+        return -1;
+
+    const char *chsPlusOne = chs + 1;
+    int chsLengthMinusOne = chsLength - 1;
+
+    if (data->_isAsciiValid) {
+        char *ptr = data->_ascii + index - 1;
+        if (caseSensitive) {
+            char c = *chs;
+            do {
+                if (*++ptr == c && memcmp(ptr + 1, chsPlusOne, chsLengthMinusOne) == 0) {
+                    return data->_length - chsLength - n + 1;
                 }
-            }
+            } while (--n);
+        } else {
+            int lc = tolower(*chs);
+            do {
+                if (tolower(*++ptr) == lc && equalCaseInsensitive(ptr + 1, chsPlusOne, chsLengthMinusOne)) {
+                    return data->_length - chsLength - n + 1;
+                }
+            } while (--n);
         }
-    }
-    else if (dataHandle[0]->_isUnicodeValid){
-        QChar *ptr = (QChar *)dataHandle[0]->unicode();
-
-        if (chs) {
-            int len = dataHandle[0]->_length;
-
-            ptr += index;
-            if (len && (index >= 0) && (index < len)) {
-                int remaining = len - index;
-                int compareToLength = strlen(chs);
-                
-                if (caseSensitive) {
-                    QChar firstC = *chs;
-                    while (remaining >= compareToLength) {
-                        if (*ptr++ == firstC) {
-                            QChar *compareTo = ptr;
-                            const char *_chs = chs + 1;
-                            char c2;
-                            while ((c2 = *_chs++))
-                                if (*compareTo++ != c2)
-                                    break;
-                            if (c2 == 0)
-                                return len - remaining;
-                        }
-                        remaining--;
-                    }
-                } else {
-                    char firstC = *chs;
-                    while (remaining >= compareToLength) {
-                        if (compareIgnoringCaseForASCIIOnly(*ptr++, firstC)) {
-                            QChar *compareTo = ptr;
-                            const char *_chs = chs + 1;
-                            char c2;
-                            while ((c2 = *_chs++))
-                                if (!compareIgnoringCaseForASCIIOnly(*compareTo++, c2))
-                                    break;
-                            if (c2 == 0)
-                                return len - remaining;
-                        }
-                        remaining--;
-                    }
+    } else {
+        ASSERT(data->_isUnicodeValid);
+
+        const QChar *ptr = data->_unicode + index - 1;
+        if (caseSensitive) {
+            QChar c = *chs;
+            do {
+                if (*++ptr == c && equal(ptr + 1, chsPlusOne, chsLengthMinusOne)) {
+                    return data->_length - chsLength - n + 1;
                 }
-            }
+            } while (--n);
+        } else {
+            int lc = tolower((unsigned char)*chs);
+            do {
+                if (tolower((++ptr)->unicode()) == lc && equalCaseInsensitive(ptr + 1, chsPlusOne, chsLengthMinusOne)) {
+                    return data->_length - chsLength - n + 1;
+                }
+            } while (--n);
         }
     }
+
     return -1;
 }
 
@@ -1318,7 +1323,7 @@ int QString::findRev( const QString& str, int index, bool cs ) const
        }
        i = index;
        while ( TRUE ) {
-           if ( hthis == hstr && ucstrncmp(uthis + i, ustr, lstr) == 0 )
+           if ( hthis == hstr && memcmp(uthis + i, ustr, lstr * sizeof(QChar)) == 0 )
                return i;
            if ( i == 0 )
                return -1;
@@ -1333,7 +1338,7 @@ int QString::findRev( const QString& str, int index, bool cs ) const
        }
        i = index;
        while ( TRUE ) {
-           if ( hthis == hstr && ucstrnicmp(uthis + i, ustr, lstr) == 0 )
+           if ( hthis == hstr && equalCaseInsensitive(uthis + i, ustr, lstr) )
                return i;
            if ( i == 0 )
                return -1;
@@ -1352,138 +1357,201 @@ int QString::findRev( const QString& str, int index, bool cs ) const
 static int containsCount = 0;
 #endif
 
-int QString::contains( QChar c, bool cs ) const
+int QString::contains(QChar c, bool cs) const
 {
     int count = 0;
     
-    if (dataHandle[0]->_isAsciiValid){
+    KWQStringData *data = *dataHandle;
+    
+    if (data->_isAsciiValid) {
         if (!IS_ASCII_QCHAR(c))
             return 0;
-            
-        char tc, ac = (char)c;
-        const char *cPtr = ascii();
-        if ( !cPtr )
-            return 0;
-        int n = dataHandle[0]->_length;
-        if ( cs ) {                                    // case sensitive
-            while ( n-- )
-                if ( *cPtr++ == ac )
-                    count++;
+        const char *cPtr = data->_ascii;
+        int n = data->_length;
+        char ac = c.unicode();
+        if (cs) {                                      // case sensitive
+            while (n--)
+                count += *cPtr++ == ac;
         } else {                                       // case insensitive
-            ac = (ac >= 'A' && ac <= 'Z') ? ac + caseDelta : ac;
-            while ( n-- ) {
-                tc = *cPtr++;
-                tc =  (tc >= 'A' && tc <= 'Z') ? tc + caseDelta : tc;
-                if ( tc == ac )
-                    count++;
+            int lc = tolower(ac);
+            while (n--) {
+                count += tolower(*cPtr++) == lc;
             }
         }
-    }
-    else if (dataHandle[0]->_isUnicodeValid){
-        const QChar *uc = unicode();
-        if ( !uc )
-            return 0;
-        int n = dataHandle[0]->_length;
-        if ( cs ) {                                    // case sensitive
+    } else {
+        ASSERT(data->_isUnicodeValid);
+        const QChar *uc = data->_unicode;
+        int n = data->_length;
+        if (cs) {                                      // case sensitive
             while ( n-- )
-                if ( *uc++ == c )
-                    count++;
+                count += *uc++ == c;
         } else {                                       // case insensitive
-            c = c.lower();
-            while ( n-- ) {
-                if ( uc->lower() == c )
-                    count++;
+            int lc = tolower(c.unicode());
+            while (n--) {
+                count += tolower(uc->unicode()) == lc;
                 uc++;
             }
         }
     } 
-    else
-        FATAL("invalid character cache");
+
     return count;
 }
 
 int QString::contains(char ch) const
 {
-    return contains (QChar(ch),true);
+    return contains(QChar(ch), true);
 }
 
 int QString::contains(const char *str, bool caseSensitive) const
 {
-    if ( !str )
+    if (!str)
         return 0;
 
-    if (dataHandle[0]->_isAsciiValid){
-        int count = 0;
-        const char *uc = ascii();
-        int n = dataHandle[0]->_length;
-        int toLen = strlen(str);
-        
-        while ( n-- ) {
-            if ( caseSensitive ) {
-                if ( strncmp( uc, str, toLen ) == 0 )
-                    count++;
-            } else {
-                if ( strncasecmp(uc, str, toLen) == 0 )
-                    count++;
-            }
-            uc++;
+    int len = strlen(str);
+    char c = *str;
+
+    KWQStringData *data = *dataHandle;
+    int n = data->_length;
+
+    n -= len - 1;
+    if (n <= 0)
+        return 0;
+
+    int count = 0;
+
+    if (data->_isAsciiValid) {
+        const char *p = data->_ascii;
+        if (caseSensitive) {
+            do {
+                count += *p == c && memcmp(p + 1, str + 1, len - 1) == 0;
+                p++;
+            } while (--n);
+        } else {
+            int lc = tolower(c);
+            do {
+                count += tolower(*p) == lc && equalCaseInsensitive(p + 1, str + 1, len - 1);
+                p++;
+            } while (--n);
+        }
+    } else {
+        ASSERT(data->_isUnicodeValid);
+        const QChar *p = data->_unicode;
+        if (caseSensitive) {
+            do {
+                count += *p == c && equal(p + 1, str + 1, len - 1);
+                p++;
+            } while (--n);
+        } else {
+            int lc = tolower(c);
+            do {
+                count += tolower(p->unicode()) == lc && equalCaseInsensitive(p + 1, str + 1, len - 1);
+                p++;
+            } while (--n);
         }
-        return count;
     }
-    else if (dataHandle[0]->_isUnicodeValid)
-        return contains(QString(str),caseSensitive);
-    else
-        FATAL("invalid character cache");
 
-    return 0;
+    return count;
 }
 
 int QString::contains(const QString &str, bool caseSensitive) const
 {
-    int count = 0;
-    const QChar *uc = unicode();
-    if ( !str )
-       return 0;
+    if (str.isEmpty())
+        return 0;
+
+    const QChar *strP = str.unicode();
     int len = str.dataHandle[0]->_length;
+    QChar c = *strP;
+
+    const QChar *p = unicode();
     int n = dataHandle[0]->_length;
-    while ( n-- ) {                            // counts overlapping strings
-       // ### Doesn't account for length of this - searches over "end"
-       if ( caseSensitive ) {
-           if ( ucstrncmp( uc, str.unicode(), len ) == 0 )
-               count++;
-       } else {
-           if ( ucstrnicmp(uc, str.unicode(), len) == 0 )
-               count++;
-       }
-       uc++;
+
+    n -= len - 1;
+    if (n <= 0)
+        return 0;
+
+    int count = 0;
+
+    if (caseSensitive) {
+        int byteCount = len * sizeof(QChar);
+        do {
+            count += *p == c && memcmp(p, strP, byteCount) == 0;
+            ++p;
+        } while (--n);
+    } else {
+        do {
+            count += p->lower() == c && equalCaseInsensitive(p, strP, len) == 0;
+            ++p;
+        } while (--n);
     }
+
     return count;
 }
 
 bool QString::isAllASCII() const
 {
-    if (dataHandle[0]->_isAsciiValid) {
-        const char *p = ascii();
-        int n = dataHandle[0]->_length;
+    KWQStringData *data = *dataHandle;
+
+    int n = data->_length;
+    if (data->_isAsciiValid) {
+        const char *p = data->_ascii;
         while (n--) {
             unsigned char c = *p++;
             if (c > 0x7F) {
                 return false;
             }
         }
-    }
-    else if (dataHandle[0]->_isUnicodeValid) {
-        const QChar *p = unicode();
-        int n = dataHandle[0]->_length;
+    } else {
+        ASSERT(data->_isUnicodeValid);
+        const QChar *p = data->_unicode;
         while (n--) {
             if ((*p++).unicode() > 0x7F) {
                 return false;
             }
         }
     }
+
+    return true;
+}
+
+bool QString::isAllLatin1() const
+{
+    KWQStringData *data = *dataHandle;
+
+    if (data->_isAsciiValid) {
+        return true;
+    }
+
+    ASSERT(data->_isUnicodeValid);
+    int n = data->_length;
+    const QChar *p = data->_unicode;
+    while (n--) {
+        if ((*p++).unicode() > 0xFF) {
+            return false;
+        }
+    }
+
     return true;
 }
 
+void QString::copyLatin1(char *buffer) const
+{
+    KWQStringData *data = *dataHandle;
+
+    int length = data->_length;
+
+    if (data->_isAsciiValid) {
+        memcpy(buffer, data->_ascii, length + 1);
+        return;
+    }
+
+    ASSERT(data->_isUnicodeValid);
+    const QChar *uc = data->_unicode;
+    while (length--)
+        *buffer++ = *uc++;
+    *buffer = 0;
+}
+
+
 short QString::toShort(bool *ok, int base) const
 {
     long v = toLong( ok, base );
@@ -1541,13 +1609,14 @@ long QString::toLong(bool *ok, int base) const
     while ( l && ok_in_base(*p,base) ) {
        l--;
        int dv;
-       if ( p->isDigit() ) {
-           dv = p->digitValue();
+        int c = p->unicode();
+       if ( isdigit(c) ) {
+           dv = c - '0';
        } else {
-           if ( *p >= 'a' && *p <= 'z' )
-               dv = *p - 'a' + 10;
+           if ( c >= 'a' )
+               dv = c - 'a' + 10;
            else
-               dv = *p - 'A' + 10;
+               dv = c - 'A' + 10;
        }
        if ( val > max_mult || (val == max_mult && dv > (LONG_MAX % base)+neg) )
            goto bye;
@@ -1586,13 +1655,14 @@ ulong QString::toULong(bool *ok, int base) const
     while ( l && ok_in_base(*p,base) ) {
        l--;
        uint dv;
-       if ( p->isDigit() ) {
-           dv = p->digitValue();
+        int c = p->unicode();
+       if ( isdigit(c) ) {
+           dv = c - '0';
        } else {
-           if ( *p >= 'a' && *p <= 'z' )
-               dv = *p - 'a' + 10;
+           if ( c >= 'a' )
+               dv = c - 'a' + 10;
            else
-               dv = *p - 'A' + 10;
+               dv = c - 'A' + 10;
        }
        if ( val > max_mult || (val == max_mult && dv > (ULONG_MAX % base)) )
            goto bye;
@@ -1915,7 +1985,7 @@ void QString::deref()
 
 QString &QString::setUnicode(const QChar *uni, uint len)
 {
-    detach();
+    detachAndDiscardCharacters();
     
     // Free our handle if it isn't the shared null handle, and if no-one else is using it.
     bool needToFreeHandle = dataHandle != shared_null_handle && dataHandle[0]->refCount == 1;
@@ -1930,7 +2000,7 @@ QString &QString::setUnicode(const QChar *uni, uint len)
         deref();
         if (needToFreeHandle)
             freeHandle(dataHandle);
-        dataHandle = (KWQStringData **)allocateHandle();
+        dataHandle = allocateHandle();
        *dataHandle = new KWQStringData(uni, len);
         dataHandle[0]->_isHeapAllocated = 1;
     } else {
@@ -1951,7 +2021,7 @@ QString &QString::setLatin1(const char *str, int len)
     if ( len < 0 )
        len = strlen(str);
 
-    detach();
+    detachAndDiscardCharacters();
     
     // Free our handle if it isn't the shared null handle, and if no-one else is using it.
     bool needToFreeHandle = dataHandle != shared_null_handle && dataHandle[0]->refCount == 1;
@@ -1960,7 +2030,7 @@ QString &QString::setLatin1(const char *str, int len)
         deref();
         if (needToFreeHandle)
             freeHandle(dataHandle);
-        dataHandle = (KWQStringData **)allocateHandle();
+        dataHandle = allocateHandle();
         *dataHandle = new KWQStringData(str,len);
         dataHandle[0]->_isHeapAllocated = 1;
     } else {
@@ -2022,14 +2092,14 @@ QString &QString::sprintf(const char *format, ...)
     }
     
     // Arrange for storage for the resulting string.
-    detach();
+    detachAndDiscardCharacters();
     if (len >= dataHandle[0]->_maxAscii || dataHandle[0]->refCount != 1 || !dataHandle[0]->_isAsciiValid) {
         // Free our handle if it isn't the shared null handle, and if no-one else is using it.
         bool needToFreeHandle = dataHandle != shared_null_handle && dataHandle[0]->refCount == 1;
         deref();
         if (needToFreeHandle)
             freeHandle(dataHandle);
-        dataHandle = (KWQStringData **)allocateHandle();
+        dataHandle = allocateHandle();
         *dataHandle = new KWQStringData((char *)0, len);
         dataHandle[0]->_isHeapAllocated = 1;
     } else {
@@ -2124,8 +2194,8 @@ QString &QString::insert(uint index, const QString &qs)
 #ifdef QSTRING_DEBUG_UNICODE
     forceUnicode();
 #endif
-    if (dataHandle[0]->_isAsciiValid && qs.dataHandle[0]->_isAsciiValid){
-        insert (index, qs.ascii(), qs.length());
+    if (dataHandle[0]->_isAsciiValid && qs.isAllLatin1()) {
+        insert(index, qs.latin1(), qs.length());
     }
     else {
         uint insertLength = qs.dataHandle[0]->_length;
@@ -2171,7 +2241,9 @@ QString &QString::insert(uint index, const QChar *insertChars, uint insertLength
     setLength(originalLength + insertLength);
 
     QChar *targetChars = const_cast<QChar *>(unicode());
-    memmove(targetChars + index + insertLength, targetChars + index, (originalLength - index) * sizeof(QChar));
+    if (originalLength > index) {
+        memmove(targetChars + index + insertLength, targetChars + index, (originalLength - index) * sizeof(QChar));
+    }
     memcpy(targetChars + index, insertChars, insertLength * sizeof(QChar));
     
     return *this;
@@ -2222,7 +2294,7 @@ QString &QString::insert(uint index, char ch)
 {
     detach();
     
-    if (dataHandle[0]->_isAsciiValid){
+    if (dataHandle[0]->_isAsciiValid) {
         uint originalLength = dataHandle[0]->_length;
         char *targetChars;
         
@@ -2258,58 +2330,48 @@ QString &QString::insert(uint index, char ch)
     return *this;
 }
 
-inline void QString::detachInternal()
-{
-    KWQStringData *oldData = *dataHandle;
-    KWQStringData *newData;
-    if (oldData->_isAsciiValid)
-        newData = new KWQStringData(oldData->ascii(), oldData->_length);
-    else {
-        ASSERT(oldData->_isUnicodeValid);
-        // No need to copy the allocated unicode bytes.
-        if (oldData->isUnicodeInternal())
-            newData = new KWQStringData(oldData->unicode(), oldData->_length);
-        else {
-            newData = new KWQStringData(oldData->unicode(), oldData->_length, oldData->_maxUnicode);
-            oldData->_unicode = 0;
-            oldData->_isUnicodeValid = 0;
-        }
-    }
-    newData->_isHeapAllocated = 1;
-    newData->refCount = oldData->refCount - 1;
-    *dataHandle = newData;
-    
-    oldData->refCount = 1;
-}
-
 // Copy KWQStringData if necessary. Must be called before the string data is mutated.
 void QString::detach()
 {
-    if (dataHandle != shared_null_handle && dataHandle[0]->refCount == 1)
+    KWQStringData *oldData = *dataHandle;
+
+    if (oldData->refCount == 1 && oldData != shared_null)
         return;
 
 #ifdef QSTRING_DEBUG_ALLOCATIONS
     stringDataDetachments++;
 #endif
-    KWQStringData *oldData = *dataHandle;
-    
-    // Copy data for this string so we can safely mutate it,
-    // and put it in a new handle.
+
+    // Copy data for this string so we can safely mutate it.
     KWQStringData *newData;
     if (oldData->_isAsciiValid)
         newData = new KWQStringData(oldData->ascii(), oldData->_length);
     else
         newData = new KWQStringData(oldData->unicode(), oldData->_length);
-
-    // Copy our internal data so other strings can still safely reference it.
-    detachIfInternal();
-    
     newData->_isHeapAllocated = 1;
-    dataHandle = (KWQStringData **)allocateHandle();
-    *dataHandle = newData;
-    
-    // Release the old data.
+
+    // There is now one less client for the old data.
     oldData->deref();
+
+    // If the old data is our internal data, then we'll keep that.
+    // This decreases the chance we'll have to do a detachInternal later
+    // when this object is destroyed.
+    if (oldData == &internalData) {
+        newData->refCount = oldData->refCount;
+        oldData->refCount = 1;
+        *dataHandle = newData;
+        newData = oldData;
+    }
+
+    // Create a new handle.
+    dataHandle = allocateHandle();
+    *dataHandle = newData;
+}
+
+void QString::detachAndDiscardCharacters()
+{
+    // Missing optimization: Don't bother copying the old data if we detach.
+    detach();
 }
 
 QString &QString::remove(uint index, uint len)
@@ -2320,6 +2382,9 @@ QString &QString::remove(uint index, uint len)
     } else if ( index + len >= olen ) {  // index ok
         setLength( index );
     } else if ( len != 0 ) {
+        // Missing optimization: Could avoid copying characters we are going to remove
+        // by making a special version of detach().
+
        detach();
         
 #ifdef QSTRING_DEBUG_UNICODE
@@ -2414,15 +2479,16 @@ QChar *QString::forceUnicode()
 // bytes will contain garbage.
 void QString::setLength(uint newLen)
 {
-    detach();
-    
-    // If we going to change the length, we'll need our own data.
-    if (dataHandle == shared_null_handle) {
-        deref();
-        dataHandle = (KWQStringData **)allocateHandle();
-        *dataHandle = new KWQStringData();
-        dataHandle[0]->_isHeapAllocated = 1;
+    if (newLen == 0) {
+        setUnicode(0, 0);
+        return;
     }
+
+    // Missing optimization: Could avoid copying characters we are going to remove
+    // by making a special version of detach().
+    detach();
+
+    ASSERT(dataHandle != shared_null_handle);
     
 #ifdef QSTRING_DEBUG_UNICODE
     forceUnicode();
@@ -2431,7 +2497,6 @@ void QString::setLength(uint newLen)
         if (newLen+1 > dataHandle[0]->_maxAscii) {
             dataHandle[0]->increaseAsciiSize(newLen+1);
         }
-        
         // Ensure null termination, although newly allocated
         // bytes contain garbage.
         dataHandle[0]->_ascii[newLen] = 0;
@@ -2456,7 +2521,7 @@ void QString::truncate(uint newLen)
 
 void QString::fill(QChar qc, int len)
 {
-    detach();
+    detachAndDiscardCharacters();
     
 #ifdef QSTRING_DEBUG_UNICODE
     forceUnicode();
@@ -2491,57 +2556,7 @@ void QString::fill(QChar qc, int len)
     }
 }
 
-void QString::compose()
-{
-    // FIXME: unimplemented because we don't do ligatures yet
-    ERROR("not yet implemented");
-}
-
-QString QString::visual()
-{
-    // FIXME: unimplemented because we don't do BIDI yet
-    ERROR("not yet implemented");
-    return QString(*this);
-}
-
-QString &QString::operator+=(const QString &qs)
-{
-    detach();
-
-    if (dataHandle[0]->_isUnicodeValid && dataHandle[0]->_length + qs.dataHandle[0]->_length < dataHandle[0]->_maxUnicode){
-        uint i = qs.dataHandle[0]->_length;
-        QChar *tp = &dataHandle[0]->_unicode[dataHandle[0]->_length];
-        if (qs.dataHandle[0]->_isAsciiValid){
-            char *fp = (char *)qs.ascii();
-            while (i--)
-                *tp++ = *fp++;
-        }
-        else if(qs.dataHandle[0]->_isUnicodeValid){
-            QChar *fp = (QChar *)qs.unicode();
-            while (i--)
-                *tp++ = *fp++;
-        }
-        else 
-            FATAL("invalid character cache");
-        dataHandle[0]->_length += qs.dataHandle[0]->_length;
-        dataHandle[0]->_isAsciiValid = 0;
-        return *this;
-    }
-    else if (dataHandle[0]->_isAsciiValid && qs.dataHandle[0]->_isAsciiValid && dataHandle[0]->_length + qs.dataHandle[0]->_length < dataHandle[0]->_maxAscii){
-        uint i = qs.dataHandle[0]->_length;
-        char *tp = &dataHandle[0]->_ascii[dataHandle[0]->_length];
-        char *fp = (char *)qs.ascii();
-        while (i--)
-            *tp++ = *fp++;
-        *tp = 0;
-        dataHandle[0]->_length += qs.dataHandle[0]->_length;
-        dataHandle[0]->_isUnicodeValid = 0;
-        return *this;
-    }
-    return insert(dataHandle[0]->_length, qs);
-}
-
-QString &QString::operator+=(QChar qc)
+QString &QString::append(QChar qc)
 {
     detach();
     
@@ -2562,7 +2577,7 @@ QString &QString::operator+=(QChar qc)
     return insert(thisData->_length, qc);
 }
 
-QString &QString::operator+=(char ch)
+QString &QString::append(char ch)
 {
     detach();
     
@@ -2583,6 +2598,14 @@ QString &QString::operator+=(char ch)
     return insert(thisData->_length, ch);
 }
 
+void QString::reserve(uint length)
+{
+    if (length > dataHandle[0]->_maxUnicode) {
+        detach();
+        dataHandle[0]->increaseUnicodeSize(length);
+    }
+}
+
 bool operator==(const QString &s1, const QString &s2)
 {
     if (s1.dataHandle[0]->_isAsciiValid && s2.dataHandle[0]->_isAsciiValid) {
@@ -2825,7 +2848,7 @@ static void CHECK_PAGE_LISTS()
 
 #endif
 
-static HandleNode *_initializeHandleNodeBlock(HandlePageNode *pageNode)
+static HandleNode *initializeHandleNodeBlock(HandlePageNode *pageNode)
 {
     uint i;
     HandleNode *block, *aNode;
@@ -2852,21 +2875,21 @@ static HandleNode *_initializeHandleNodeBlock(HandlePageNode *pageNode)
     return block;
 }
 
-HandlePageNode *_allocatePageNode()
+static HandlePageNode *allocatePageNode()
 {
     HandlePageNode *node = (HandlePageNode *)malloc(sizeof(HandlePageNode));
     node->next = node->previous = 0;
-    node->nodes = _initializeHandleNodeBlock(node);
+    node->nodes = initializeHandleNodeBlock(node);
     return node;
 }
 
-void _initializeHandleNodes()
+static inline void initializeHandleNodes()
 {
     if (freeNodeAllocationPages == 0)
-        freeNodeAllocationPages = _allocatePageNode();
+        freeNodeAllocationPages = allocatePageNode();
 }
 
-HandleNode *_allocateNode(HandlePageNode *pageNode)
+static HandleNode *allocateNode(HandlePageNode *pageNode)
 {
     CHECK_PAGE_LISTS();
 
@@ -2908,24 +2931,22 @@ HandleNode *_allocateNode(HandlePageNode *pageNode)
     return allocated;
 }
 
-
-void *allocateHandle()
+KWQStringData **allocateHandle()
 {
 #if CHECK_FOR_HANDLE_LEAKS
-    return malloc(sizeof(void *));
+    return static_cast<KWQStringData **>(malloc(sizeof(KWQStringData *)));
 #endif
 
-    _initializeHandleNodes();
+    initializeHandleNodes();
     
 #ifdef QSTRING_DEBUG_ALLOCATIONS
     handleInstances++;
 #endif
 
-    return _allocateNode (freeNodeAllocationPages);
+    return reinterpret_cast<KWQStringData **>(allocateNode(freeNodeAllocationPages));
 }
 
-
-void freeHandle(void *_free)
+void freeHandle(KWQStringData **_free)
 {
 #if CHECK_FOR_HANDLE_LEAKS
     free(_free);
index 1b32330..8d5f11f 100644 (file)
@@ -41,6 +41,7 @@ private:
     QString convert(const char *chs, int len, bool flush)
         { return convert(reinterpret_cast<const unsigned char *>(chs), len, flush); }
     QString convert(const unsigned char *chs, int len, bool flush);
+    QString convertLatin1(const unsigned char *chs, int len);
     QString convertUTF16(const unsigned char *chs, int len);
     QString convertUsingTEC(const unsigned char *chs, int len, bool flush);
     
@@ -236,6 +237,41 @@ KWQTextDecoder::~KWQTextDecoder()
     }
 }
 
+QString KWQTextDecoder::convertLatin1(const unsigned char *s, int length)
+{
+    ASSERT(_numBufferedBytes == 0);
+
+    int i;
+    for (i = 0; i != length; ++i) {
+        if (s[i] == 0) {
+            break;
+        }
+    }
+    if (i == length) {
+        return QString(reinterpret_cast<const char *>(s), length);
+    }
+
+    QString result;
+    
+    result.reserve(length);
+    
+    result.append(reinterpret_cast<const char *>(s), i);
+    int start = i + 1;
+    for (; i != length; ++i) {
+        if (s[i] == 0) {
+            if (start != i) {
+                result.append(reinterpret_cast<const char *>(&s[start]), i - start);
+            }
+            start = i + 1;
+        }
+    }
+    if (start != length) {
+        result.append(reinterpret_cast<const char *>(&s[start]), length - start);
+    }
+
+    return result;
+}
+
 QString KWQTextDecoder::convertUTF16(const unsigned char *s, int length)
 {
     ASSERT(_numBufferedBytes == 0 || _numBufferedBytes == 1);
@@ -245,6 +281,8 @@ QString KWQTextDecoder::convertUTF16(const unsigned char *s, int length)
     
     QString result;
     
+    result.reserve(length / 2);
+
     if (_numBufferedBytes != 0 && len != 0) {
         ASSERT(_numBufferedBytes == 1);
         UniChar c;
@@ -262,7 +300,7 @@ QString KWQTextDecoder::convertUTF16(const unsigned char *s, int length)
     }
     
     while (len > 1) {
-        UniChar buffer[4096];
+        UniChar buffer[16384];
         int runLength = MIN(len / 2, sizeof(buffer) / sizeof(buffer[0]));
         int bufferLength = 0;
         if (_littleEndian) {
@@ -411,10 +449,12 @@ QString KWQTextDecoder::convertUsingTEC(const unsigned char *chs, int len, bool
     
     QString result;
 
+    result.reserve(len);
+
     const unsigned char *sourcePointer = chs;
     int sourceLength = len;
     bool bufferWasFull = false;
-    UniChar buffer[4096];
+    UniChar buffer[16384];
 
     while (sourceLength || bufferWasFull) {
         int bytesRead = 0;
@@ -430,7 +470,7 @@ QString KWQTextDecoder::convertUsingTEC(const unsigned char *chs, int len, bool
                 break;
             case kTextMalformedInputErr:
             case kTextUndefinedElementErr:
-                // FIXME: Put in FFFD character into the output string?
+                // FIXME: Put FFFD character into the output string in this case?
                 TECClearConverterContextInfo(_converter);
                 if (sourceLength) {
                     sourcePointer += 1;
@@ -480,25 +520,32 @@ QString KWQTextDecoder::convertUsingTEC(const unsigned char *chs, int len, bool
 
 QString KWQTextDecoder::convert(const unsigned char *chs, int len, bool flush)
 {
-    if (_encoding == kCFStringEncodingUnicode) {
+    //#define PARTIAL_CHARACTER_HANDLING_TEST_CHUNK_SIZE 1000
+
+    switch (_encoding) {
+    case kCFStringEncodingISOLatin1:
+    case kCFStringEncodingWindowsLatin1:
+        return convertLatin1(chs, len);
+
+    case kCFStringEncodingUnicode:
         return convertUTF16(chs, len);
-    }
 
-//#define PARTIAL_CHARACTER_HANDLING_TEST_CHUNK_SIZE 1000
+    default:
 #if PARTIAL_CHARACTER_HANDLING_TEST_CHUNK_SIZE
-    QString result;
-    int chunkSize;
-    for (int i = 0; i != len; i += chunkSize) {
-        chunkSize = len - i;
-        if (chunkSize > PARTIAL_CHARACTER_HANDLING_TEST_CHUNK_SIZE) {
-            chunkSize = PARTIAL_CHARACTER_HANDLING_TEST_CHUNK_SIZE;
+        QString result;
+        int chunkSize;
+        for (int i = 0; i != len; i += chunkSize) {
+            chunkSize = len - i;
+            if (chunkSize > PARTIAL_CHARACTER_HANDLING_TEST_CHUNK_SIZE) {
+                chunkSize = PARTIAL_CHARACTER_HANDLING_TEST_CHUNK_SIZE;
+            }
+            result += convertUsingTEC(chs + i, chunkSize, flush && (i + chunkSize == len));
         }
-        result += convertUsingTEC(chs + i, chunkSize, flush && (i + chunkSize == len));
-    }
-    return result;
+        return result;
 #else
-    return convertUsingTEC(chs, len, flush);
+        return convertUsingTEC(chs, len, flush);
 #endif
+    }
 }
 
 QString KWQTextDecoder::toUnicode(const char *chs, int len, bool flush)
index 2a21cdc..bac6d18 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2003 Apple Computer, Inc.  All rights reserved.
+ * Copyright (C) 2004 Apple Computer, Inc.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -31,12 +31,3 @@ class QWidget;
 @protocol KWQWidgetHolder
 - (QWidget *)widget;
 @end
-
-@interface KWQView : NSView <KWQWidgetHolder>
-{
-    QWidget *widget;
-    bool isFlipped;
-}
-- initWithWidget:(QWidget *)w; 
-- (void)setIsFlipped:(bool)flag;
-@end
diff --git a/WebCore/kwq/KWQView.mm b/WebCore/kwq/KWQView.mm
deleted file mode 100644 (file)
index 15e9d78..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2003 Apple Computer, Inc.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
- */
-
-#import "KWQView.h"
-
-@implementation KWQView
-
-- initWithFrame:(NSRect)frame
-{
-    [super initWithFrame:frame];
-    isFlipped = YES;
-    return self;
-}
-
-- initWithWidget:(QWidget *)w 
-{
-    [super init];
-    widget = w;
-    return self;
-}
-
-- (void)setIsFlipped:(bool)flag
-{
-    isFlipped = flag;
-}
-
-- (BOOL)isFlipped 
-{
-    return isFlipped;
-}
-
-- (QWidget *)widget
-{
-    return widget;
-}
-
-@end
index 7eff52a..0038f52 100644 (file)
@@ -43,7 +43,7 @@
 class NSView;
 #endif
 
-class QWidgetPrivate;
+class KWQWidgetPrivate;
 
 class QWidget : public QObject, public QPaintDevice {
 public:
@@ -156,7 +156,7 @@ public:
     void sendConsumedMouseUp();
 
 private:
-    QWidgetPrivate *data;
+    KWQWidgetPrivate *data;
 };
 
 #endif
index 38955a3..7fbe2ff 100644 (file)
@@ -28,7 +28,6 @@
 #import "KWQExceptions.h"
 #import "KWQKHTMLPart.h"
 #import "KWQLogging.h"
-#import "KWQView.h"
 #import "KWQWindowWidget.h"
 #import "WebCoreBridge.h"
 #import "WebCoreFrameView.h"
@@ -45,8 +44,7 @@ using khtml::RenderWidget;
     emulate most QWidgets using NSViews.
 */
 
-
-class QWidgetPrivate
+class KWQWidgetPrivate
 {
 public:
     QStyle *style;
@@ -56,28 +54,19 @@ public:
     bool visible;
 };
 
-QWidget::QWidget() 
-    : data(new QWidgetPrivate)
+QWidget::QWidget() : data(new KWQWidgetPrivate)
 {
-    data->view = nil;
-
-    KWQ_BLOCK_EXCEPTIONS;
-    data->view = [[KWQView alloc] initWithWidget:this];
-    KWQ_UNBLOCK_EXCEPTIONS;
-
     static QStyle defaultStyle;
     data->style = &defaultStyle;
-
+    data->view = nil;
     data->visible = true;
 }
 
-QWidget::QWidget(NSView *view)
-    : data(new QWidgetPrivate)
+QWidget::QWidget(NSView *view) : data(new KWQWidgetPrivate)
 {
-    data->view = [view retain];
-
     static QStyle defaultStyle;
     data->style = &defaultStyle;
+    data->view = [view retain];
     data->visible = true;
 }
 
@@ -432,9 +421,13 @@ void QWidget::hide()
 void QWidget::setFrameGeometry(const QRect &rect)
 {
     KWQ_BLOCK_EXCEPTIONS;
-    [getOuterView() setNeedsDisplay: YES];
-    [getOuterView() setFrame:rect];
-    [getOuterView() setNeedsDisplay: YES];
+    NSView *v = getOuterView();
+    NSRect f = rect;
+    if (!NSEqualRects(f, [v frame])) {
+        [v setNeedsDisplay:YES];
+        [v setFrame:f];
+        [v setNeedsDisplay:YES];
+    }
     KWQ_UNBLOCK_EXCEPTIONS;
 }
 
index ca23132..9b187c4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2003 Apple Computer, Inc.  All rights reserved.
+ * Copyright (C) 2004 Apple Computer, Inc.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -37,11 +37,12 @@ struct WebCoreTextStyle
     int wordSpacing;
     int padding;
     NSString **families;
-    unsigned smallCaps:1;
-    unsigned rtl:1;
-    unsigned visuallyOrdered:1;
-    unsigned applyRounding:1;
-    unsigned attemptFontSubstitution:1;
+    unsigned smallCaps : 1;
+    unsigned rtl : 1;
+    unsigned visuallyOrdered : 1;
+    unsigned applyRunRounding : 1;
+    unsigned applyWordRounding : 1;
+    unsigned attemptFontSubstitution : 1;
 };
 
 struct WebCoreTextRun
index 8153e06..8d758c3 100644 (file)
@@ -46,7 +46,8 @@ void WebCoreInitializeEmptyTextStyle(WebCoreTextStyle *style)
     style->letterSpacing = 0;
     style->wordSpacing = 0;
     style->smallCaps = false;
-    style->applyRounding = true;
+    style->applyRunRounding = true;
+    style->applyWordRounding = true;
     style->attemptFontSubstitution = true;
     style->families = nil;
 }
index 8153e06..8d758c3 100644 (file)
@@ -46,7 +46,8 @@ void WebCoreInitializeEmptyTextStyle(WebCoreTextStyle *style)
     style->letterSpacing = 0;
     style->wordSpacing = 0;
     style->smallCaps = false;
-    style->applyRounding = true;
+    style->applyRunRounding = true;
+    style->applyWordRounding = true;
     style->attemptFontSubstitution = true;
     style->families = nil;
 }
index 3afb345..f95727a 100644 (file)
@@ -1,3 +1,37 @@
+2004-02-08  Darin Adler  <darin@apple.com>
+
+        Reviewed by Dave.
+
+        - fixed things seen in the profile, for a total speedup of 4% on cvs-base
+        - fixed some layout regressions from my last speedup due to text measurement inconsistencies by adding
+          a flag to control whether word rounding is done or not
+        - fixed text measurement to be used with AppKit to match AppKit again, as it did at some point in the past
+
+        * WebCoreSupport.subproj/WebTextRenderer.h: Remove some unused fields, and added a field to say whether we
+        treat this font as fixed pitch.
+        * WebCoreSupport.subproj/WebTextRenderer.m:
+        (getUncachedWidth): Remove space width hack from this level. There was already a width hack up at the higher
+        level for space itself, so there's not a significant speed benefit, and the higher level can make a more
+        intelligent choice based on the current rounding setting since it's not cached.
+        (-[WebTextRenderer _computeWidthForSpace]): Don't store so many widths; just the adjusted width we will
+        actually use.
+        (widthForNextCharacter): Use two different rules for when to adjust space widths, based on whether this is
+        a fixed pitch font or not. Also, don't do any adjusting of space widths if applyWordRounding is false.
+
+        * Misc.subproj/WebKitNSStringExtras.m:
+        (-[NSString _web_drawAtPoint:font:textColor:]): Turn off rounding, so we get the kind of spacing AppKit would normally give.
+        (-[NSString _web_widthWithFont:]): Ditto.
+        * Misc.subproj/WebStringTruncator.m: (stringWidth): Ditto.
+
+2004-02-08  Darin Adler  <darin@apple.com>
+
+        Reviewed by NOBODY (OOPS!).
+
+        - fixed things seen in the profile, for a total speedup of 3.7% on cvs-base
+
+        * Misc.subproj/WebNSURLExtras.m: (-[NSURL _web_userVisibleString]): Check for "xn--" as we
+        walk the string instead of in a separate call to strcasestr. Faster this way.
+
 2004-02-07  Darin Adler  <darin@apple.com>
 
         * WebKit.pbproj/project.pbxproj: Get rid of the DEPLOYMENT_LOCATION and DEPLOYMENT_POSTPROCESSING
index 9d79769..7daacdf 100644 (file)
@@ -40,6 +40,8 @@ static BOOL canUseFastRenderer (const UniChar *buffer, unsigned length)
         WebCoreInitializeTextRun (&run, buffer, length, 0, length);
         WebCoreTextStyle style;
         WebCoreInitializeEmptyTextStyle(&style);
+        style.applyRunRounding = NO;
+        style.applyWordRounding = NO;
         style.textColor = textColor;
         [renderer drawRun:&run style:&style atPoint:point];
     }
@@ -90,6 +92,8 @@ static BOOL canUseFastRenderer (const UniChar *buffer, unsigned length)
         WebCoreInitializeTextRun (&run, buffer, length, 0, length);
         WebCoreTextStyle style;
         WebCoreInitializeEmptyTextStyle(&style);
+        style.applyRunRounding = NO;
+        style.applyWordRounding = NO;
         width = [renderer floatWidthForRun:&run style:&style widths: 0];
     }
     else {
index 3989d68..fd5d6c2 100644 (file)
@@ -383,6 +383,8 @@ static NSString *mapHostNames(NSString *string, BOOL encode)
     const unsigned char *before = [data bytes];
     int length = [data length];
 
+    bool needsHostNameDecoding = false;
+
     const unsigned char *p = before;
     int bufferLength = (length * 3) + 1;
     char *after = malloc(bufferLength); // large enough to %-escape every character
@@ -413,6 +415,10 @@ static NSString *mapHostNames(NSString *string, BOOL encode)
         } 
         else {
             *q++ = c;
+
+            // Check for "xn--" in an efficient, non-case-sensitive, way.
+            if (c == '-' && i >= 3 && !needsHostNameDecoding && (q[-4] | 0x20) == 'x' && (q[-3] | 0x20) == 'n' && q[-2] == '-')
+                needsHostNameDecoding = true;
         }
     }
     *q = '\0';
@@ -445,11 +451,9 @@ static NSString *mapHostNames(NSString *string, BOOL encode)
         result = [NSString stringWithUTF8String:after];
     }
 
-    // As an optimization, only do host name decoding if we have xn-- somewhere.
-    bool needsHostNameDecoding = strcasestr(after, "xn--") != NULL;
-  
     free(after);
     
+    // As an optimization, only do host name decoding if we have "xn--" somewhere.
     return needsHostNameDecoding ? mapHostNames(result, NO) : result;
 }
 
index 60b032c..9cc0163 100644 (file)
@@ -7,6 +7,7 @@
 //  Complete rewrite with API similar to slow truncator by Al Dul
 
 #import <WebKit/WebStringTruncator.h>
+
 #import <Cocoa/Cocoa.h>
 
 #import <WebKit/WebAssertions.h>
@@ -63,6 +64,8 @@ static float stringWidth(WebTextRenderer *renderer, const unichar *characters, u
     WebCoreInitializeTextRun (&run, characters, length, 0, length);
     WebCoreTextStyle style;
     WebCoreInitializeEmptyTextStyle(&style);
+    style.applyRunRounding = NO;
+    style.applyWordRounding = NO;
     return [renderer floatWidthForRun:&run style:&style widths:0];
 }
 
index fc0d348..66a58e1 100644 (file)
@@ -26,14 +26,14 @@ typedef struct CharacterWidthIterator CharacterWidthIterator;
     ATSStyleGroupPtr styleGroup;
     
 @public
-    ATSGlyphRef spaceGlyph;
     NSFont *font;
     GlyphMap *characterToGlyphMap;                     // Used for 16bit clean unicode characters.
     UnicodeGlyphMap *unicodeCharacterToGlyphMap;       // Used for surrogates.
     WidthMap *glyphToWidthMap;
+
+    BOOL treatAsFixedPitch;
+    ATSGlyphRef spaceGlyph;
     float spaceWidth;
-    float ceiledSpaceWidth;
-    float roundedSpaceWidth;
     float adjustedSpaceWidth;
 
     int numSubstituteFontWidthMaps;
index eb924b9..2855bbe 100644 (file)
@@ -1,6 +1,6 @@
 /*     
     WebTextRenderer.m      
-    Copyright 2002, Apple, Inc. All rights reserved.
+    Copyright 2004, Apple, Inc. All rights reserved.
 */
 
 #import "WebTextRenderer.h"
@@ -8,11 +8,10 @@
 #import <ApplicationServices/ApplicationServices.h>
 #import <Cocoa/Cocoa.h>
 
+#import <AppKit/NSFont_Private.h>
 #import <CoreGraphics/CoreGraphicsPrivate.h>
 #import <QD/ATSUnicodePriv.h>
 
-#import <AppKit/NSFont_Private.h>
-
 #import <WebCore/WebCoreUnicode.h>
 
 #import <WebKit/WebGlyphBuffer.h>
@@ -27,7 +26,7 @@
 // Macros
 #define SPACE 0x0020
 
-#define ROUND_TO_INT(x) (unsigned)((x)+.5)
+#define ROUND_TO_INT(x) (int)((x)+.5)
 
 // Lose precision beyond 1000ths place. This is to work around an apparent
 // bug in CoreGraphics where there seem to be small errors to some metrics.
@@ -209,17 +208,6 @@ static WebGlyphWidth getUncachedWidth(WebTextRenderer *renderer, WidthMap *map,
     if (errorResult == 0)
         FATAL_ALWAYS ("Unable to cache glyph widths for %@ %f",  [renderer->font displayName], [renderer->font pointSize]);
 
-    // Hack to ensure that characters that match the width of the space character
-    // have the same integer width as the space character.  This is necessary so
-    // glyphs in fixed pitch fonts all have the same integer width.  We can't depend
-    // on the fixed pitch property of NSFont because that isn't set for all
-    // monospaced fonts, in particular Courier!  This has the downside of inappropriately
-    // adjusting the widths of characters in non-monospaced fonts that are coincidentally
-    // the same width as a space in that font.  In practice this is not an issue as the
-    // adjustment is always at the sub-pixel level.
-    if (width == renderer->spaceWidth)
-        return renderer->ceiledSpaceWidth;
-
     return width;
 }
 
@@ -375,15 +363,15 @@ static BOOL alwaysUseATSU = NO;
 
 #ifdef COMPARE_APPKIT_CG_METRICS
     printf ("\nCG/Appkit metrics for font %s, %f, lineGap %f, adjustment %f, _canDrawOutsideLineHeight %d, _isSystemFont %d\n", [[font displayName] cString], [font pointSize], lineGap, adjustment, (int)[font _canDrawOutsideLineHeight], (int)[font _isSystemFont]);
-    if ((int)ROUND_TO_INT([font ascender]) != ascent ||
-        (int)ROUND_TO_INT(-[font descender]) != descent ||
-        (int)ROUND_TO_INT([font defaultLineHeightForFont]) != lineSpacing){
+    if (ROUND_TO_INT([font ascender]) != ascent ||
+        ROUND_TO_INT(-[font descender]) != descent ||
+        ROUND_TO_INT([font defaultLineHeightForFont]) != lineSpacing){
         printf ("\nCG/Appkit mismatched metrics for font %s, %f (%s)\n", [[font displayName] cString], [font pointSize],
                 ([font screenFont] ? [[[font screenFont] displayName] cString] : "none"));
         printf ("ascent(%s), descent(%s), lineSpacing(%s)\n",
-                ((int)ROUND_TO_INT([font ascender]) != ascent) ? "different" : "same",
-                ((int)ROUND_TO_INT(-[font descender]) != descent) ? "different" : "same",
-                ((int)ROUND_TO_INT([font defaultLineHeightForFont]) != lineSpacing) ? "different" : "same");
+                (ROUND_TO_INT([font ascender]) != ascent) ? "different" : "same",
+                (ROUND_TO_INT(-[font descender]) != descent) ? "different" : "same",
+                (ROUND_TO_INT([font defaultLineHeightForFont]) != lineSpacing) ? "different" : "same");
         printf ("CG:  ascent %f, ", asc);
         printf ("descent %f, ", dsc);
         printf ("lineGap %f, ", lineGap);
@@ -419,40 +407,6 @@ static BOOL alwaysUseATSU = NO;
     [super dealloc];
 }
 
-- (int)widthForCharacters:(const UniChar *)characters length:(unsigned)stringLength
-{
-    WebCoreTextRun run;
-    WebCoreInitializeTextRun (&run, characters, stringLength, 0, stringLength);
-    WebCoreTextStyle style;
-    WebCoreInitializeEmptyTextStyle(&style);
-    return ROUND_TO_INT([self floatWidthForRun:&run style:&style widths: 0]);
-}
-
-- (int)widthForString:(NSString *)string
-{
-    UniChar localCharacterBuffer[LOCAL_BUFFER_SIZE];
-    UniChar *characterBuffer = localCharacterBuffer;
-    const UniChar *usedCharacterBuffer = CFStringGetCharactersPtr((CFStringRef)string);
-    unsigned length;
-    int width;
-
-    // Get the characters from the string into a buffer.
-    length = [string length];
-    if (!usedCharacterBuffer) {
-        if (length > LOCAL_BUFFER_SIZE)
-            characterBuffer = (UniChar *)malloc(length * sizeof(UniChar));
-        [string getCharacters:characterBuffer];
-        usedCharacterBuffer = characterBuffer;
-    }
-
-    width = [self widthForCharacters:usedCharacterBuffer length:length];
-    
-    if (characterBuffer != localCharacterBuffer)
-        free(characterBuffer);
-
-    return width;
-}
-
 - (int)ascent
 {
     // This simple return obviously can't throw an exception.
@@ -751,27 +705,20 @@ static inline BOOL fontContainsString(NSFont *font, NSString *string)
 }
 
 // Nasty hack to determine if we should round or ceil space widths.
-// If the font is monospace, or fake monospace we ceil to ensure that 
+// If the font is monospace or fake monospace we ceil to ensure that 
 // every character and the space are the same width.  Otherwise we round.
 - (BOOL)_computeWidthForSpace
 {
-    UniChar c = ' ';
-    float _spaceWidth;
-
-    spaceGlyph = [self _extendCharacterToGlyphMapToInclude: c];
-    if (spaceGlyph == 0){
+    spaceGlyph = [self _extendCharacterToGlyphMapToInclude:SPACE];
+    if (spaceGlyph == 0) {
         return NO;
     }
-    _spaceWidth = widthForGlyph(self, spaceGlyph, 0);
-    ceiledSpaceWidth = (float)CEIL_TO_INT(_spaceWidth);
-    roundedSpaceWidth = (float)ROUND_TO_INT(_spaceWidth);
-    if ([font isFixedPitch] || [font _isFakeFixedPitch]){
-        adjustedSpaceWidth = ceiledSpaceWidth;
-    }
-    else {
-        adjustedSpaceWidth = roundedSpaceWidth;
-    }
-    spaceWidth = _spaceWidth;
+
+    float width = widthForGlyph(self, spaceGlyph, 0);
+    spaceWidth = width;
+
+    treatAsFixedPitch = [font isFixedPitch] || [font _isFakeFixedPitch];
+    adjustedSpaceWidth = treatAsFixedPitch ? CEIL_TO_INT(width) : ROUND_TO_INT(width);
     
     return YES;
 }
@@ -1887,13 +1834,15 @@ static float widthForNextCharacter(CharacterWidthIterator *iterator, ATSGlyphRef
         }
     }
 
-    // Now that we have glyph and font, get its width.  We special case spaces.
-    // They are always an even integer width.
-    WebGlyphWidth width;
-    if (*glyphUsed == renderer->spaceGlyph)
+    // Now that we have glyph and font, get its width.
+    WebGlyphWidth width = widthForGlyph(renderer, *glyphUsed, *fontUsed);
+
+    // We special case spaces in two ways when applying word rounding.
+    // First, we round spaces to an adjusted width in all fonts.
+    // Second, in fixed-pitch fonts we ensure that all characters that
+    // match the width of the space character have the same width as the space character.
+    if ((renderer->treatAsFixedPitch ? width == renderer->spaceWidth : *glyphUsed == renderer->spaceGlyph) && iterator->style->applyWordRounding)
         width = renderer->adjustedSpaceWidth;
-    else
-        width = widthForGlyph(renderer, *glyphUsed, *fontUsed);
 
     // Try to find a substitute font if this font didn't have a glyph for a character in the
     // string.  If one isn't found we end up drawing and measuring the 0 glyph, usually a box.
@@ -1920,7 +1869,7 @@ static float widthForNextCharacter(CharacterWidthIterator *iterator, ATSGlyphRef
             WebCoreInitializeTextRun(&clusterRun, characterArray, characterArrayLength, 0, characterArrayLength);
             WebCoreTextStyle clusterStyle = *iterator->style;
             clusterStyle.padding = 0;
-            clusterStyle.applyRounding = false;
+            clusterStyle.applyRunRounding = false;
             clusterStyle.attemptFontSubstitution = false;
             
             WebTextRenderer *substituteRenderer;
@@ -1948,7 +1897,7 @@ static float widthForNextCharacter(CharacterWidthIterator *iterator, ATSGlyphRef
 
     // Force characters that are used to determine word boundaries for the rounding hack
     // to be integer width, so following words will start on an integer boundary.
-    if (isRoundingHackCharacter(c)) {
+    if (isRoundingHackCharacter(c) && iterator->style->applyWordRounding) {
         width = CEIL_TO_INT(width);
     }
     
@@ -1992,10 +1941,10 @@ static float widthForNextCharacter(CharacterWidthIterator *iterator, ATSGlyphRef
     // floats we can remove this (and related) hacks.
     //
     // Check to see if the next character is a "RoundingHackCharacter", if so, adjust.
-    if (currentCharacter < run->length && isRoundingHackCharacter(cp[clusterLength])) {
+    if (currentCharacter < run->length && isRoundingHackCharacter(cp[clusterLength]) && iterator->style->applyWordRounding) {
         width += ceilCurrentWidth(iterator);
     }
-    else if (currentCharacter >= (unsigned)run->to && (len > 1 || run->length == 1) && iterator->style->applyRounding) {
+    else if (currentCharacter >= (unsigned)run->to && (len > 1 || run->length == 1) && iterator->style->applyRunRounding) {
         width += ceilCurrentWidth(iterator);
     }