summaryrefslogtreecommitdiffstats
path: root/WebCore/platform
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/platform')
-rw-r--r--WebCore/platform/ArrayImpl.cpp145
-rw-r--r--WebCore/platform/ArrayImpl.h76
-rw-r--r--WebCore/platform/ContextMenuItem.h2
-rw-r--r--WebCore/platform/Cursor.h2
-rw-r--r--WebCore/platform/DeprecatedArray.h72
-rw-r--r--WebCore/platform/DeprecatedCString.cpp306
-rw-r--r--WebCore/platform/DeprecatedCString.h74
-rw-r--r--WebCore/platform/DeprecatedString.cpp2679
-rw-r--r--WebCore/platform/DeprecatedString.h644
-rw-r--r--WebCore/platform/DeprecatedStringList.cpp (renamed from WebCore/platform/wx/wxcode/gtk/non-kerned-drawing.cpp)73
-rw-r--r--WebCore/platform/DeprecatedStringList.h (renamed from WebCore/platform/network/qt/AuthenticationChallenge.h)34
-rw-r--r--WebCore/platform/DeprecatedValueListImpl.cpp15
-rw-r--r--WebCore/platform/DragData.h2
-rw-r--r--WebCore/platform/DragImage.h2
-rw-r--r--WebCore/platform/FileSystem.h38
-rw-r--r--WebCore/platform/KURL.cpp1127
-rw-r--r--WebCore/platform/KURL.h231
-rw-r--r--WebCore/platform/LocalizedStrings.h5
-rw-r--r--WebCore/platform/Locker.h (renamed from WebCore/platform/MainThread.h)38
-rw-r--r--WebCore/platform/MIMETypeRegistry.cpp3
-rw-r--r--WebCore/platform/MessageQueue.h115
-rw-r--r--WebCore/platform/NotImplemented.h5
-rw-r--r--WebCore/platform/PlatformKeyboardEvent.h9
-rw-r--r--WebCore/platform/PlatformMenuDescription.h3
-rw-r--r--WebCore/platform/PlatformMouseEvent.h1
-rw-r--r--WebCore/platform/ScrollBar.cpp3
-rw-r--r--WebCore/platform/ScrollView.h10
-rw-r--r--WebCore/platform/SecurityOrigin.h2
-rw-r--r--WebCore/platform/SecurityOriginHash.h4
-rw-r--r--WebCore/platform/SharedBuffer.cpp12
-rw-r--r--WebCore/platform/SystemTime.h5
-rw-r--r--WebCore/platform/Threading.h255
-rw-r--r--WebCore/platform/ThreadingNone.cpp51
-rw-r--r--WebCore/platform/Timer.cpp5
-rw-r--r--WebCore/platform/Widget.h9
-rw-r--r--WebCore/platform/android/AndroidLog.cpp62
-rw-r--r--WebCore/platform/android/AndroidLog.h29
-rw-r--r--WebCore/platform/android/ChromeClientAndroid.cpp213
-rw-r--r--WebCore/platform/android/ChromeClientAndroid.h101
-rw-r--r--WebCore/platform/android/ClipboardAndroid.cpp222
-rw-r--r--WebCore/platform/android/ClipboardAndroid.h (renamed from WebCore/platform/network/mac/ResourceError.h)71
-rw-r--r--WebCore/platform/android/ContextMenuClientAndroid.cpp38
-rw-r--r--WebCore/platform/android/ContextMenuClientAndroid.h42
-rw-r--r--WebCore/platform/android/Cookie.cpp51
-rw-r--r--WebCore/platform/android/CookieClient.h37
-rw-r--r--WebCore/platform/android/CursorAndroid.cpp261
-rw-r--r--WebCore/platform/android/DragClientAndroid.cpp43
-rw-r--r--WebCore/platform/android/DragClientAndroid.h41
-rw-r--r--WebCore/platform/android/DragDataAndroid.cpp89
-rw-r--r--WebCore/platform/android/EditorAndroid.cpp45
-rw-r--r--WebCore/platform/android/EditorClientAndroid.cpp241
-rw-r--r--WebCore/platform/android/EditorClientAndroid.h103
-rw-r--r--WebCore/platform/android/FileChooserAndroid.cpp67
-rw-r--r--WebCore/platform/android/FileSystemAndroid.cpp39
-rw-r--r--WebCore/platform/android/FrameLoaderClientAndroid.cpp1173
-rw-r--r--WebCore/platform/android/FrameLoaderClientAndroid.h216
-rw-r--r--WebCore/platform/android/InspectorClientAndroid.h49
-rw-r--r--WebCore/platform/android/IteratorAndroid.h41
-rw-r--r--WebCore/platform/android/JavaVM/jni.h24
-rw-r--r--WebCore/platform/android/KeyEventAndroid.cpp256
-rw-r--r--WebCore/platform/android/KeyboardCodes.h544
-rw-r--r--WebCore/platform/android/LocalizedStringsAndroid.cpp (renamed from WebCore/platform/network/curl/AuthenticationChallenge.h)32
-rw-r--r--WebCore/platform/android/PlatformScrollBar.h58
-rw-r--r--WebCore/platform/android/PlatformScrollBarAndroid.cpp80
-rw-r--r--WebCore/platform/android/PopupMenuAndroid.cpp55
-rw-r--r--WebCore/platform/android/QLineEditAndroid.cpp120
-rw-r--r--WebCore/platform/android/RenderSkinAndroid.cpp65
-rw-r--r--WebCore/platform/android/RenderSkinAndroid.h83
-rw-r--r--WebCore/platform/android/RenderSkinButton.cpp94
-rw-r--r--WebCore/platform/android/RenderSkinButton.h44
-rw-r--r--WebCore/platform/android/RenderSkinCombo.cpp84
-rw-r--r--WebCore/platform/android/RenderSkinCombo.h61
-rw-r--r--WebCore/platform/android/RenderSkinRadio.cpp83
-rw-r--r--WebCore/platform/android/RenderSkinRadio.h59
-rw-r--r--WebCore/platform/android/RenderThemeAndroid.cpp313
-rw-r--r--WebCore/platform/android/RenderThemeAndroid.h102
-rw-r--r--WebCore/platform/android/ScreenAndroid.cpp114
-rw-r--r--WebCore/platform/android/ScrollViewAndroid.cpp334
-rw-r--r--WebCore/platform/android/SearchPopupMenuAndroid.cpp57
-rw-r--r--WebCore/platform/android/SharedTimerAndroid.cpp57
-rw-r--r--WebCore/platform/android/SystemTimeAndroid.cpp52
-rw-r--r--WebCore/platform/android/TemporaryLinkStubs.cpp290
-rw-r--r--WebCore/platform/android/TextBoundaries.cpp77
-rw-r--r--WebCore/platform/android/TextBreakIteratorInternalICU.cpp28
-rw-r--r--WebCore/platform/android/TextEditAndroid.cpp377
-rw-r--r--WebCore/platform/android/ThreadingAndroid.cpp (renamed from WebCore/platform/gtk/MainThreadGtk.cpp)42
-rw-r--r--WebCore/platform/android/TimerClient.h34
-rw-r--r--WebCore/platform/android/WidgetAndroid.cpp161
-rw-r--r--WebCore/platform/android/android-encodings.txt44
-rw-r--r--WebCore/platform/android/jni/JavaBridge.cpp332
-rw-r--r--WebCore/platform/android/jni/JavaSharedClient.cpp106
-rw-r--r--WebCore/platform/android/jni/JavaSharedClient.h45
-rw-r--r--WebCore/platform/android/jni/WebCoreFrameBridge.cpp1249
-rw-r--r--WebCore/platform/android/jni/WebCoreFrameBridge.h106
-rw-r--r--WebCore/platform/android/jni/WebCoreJni.cpp83
-rw-r--r--WebCore/platform/android/jni/WebCoreJni.h32
-rw-r--r--WebCore/platform/android/jni/WebCoreRefObject.h38
-rw-r--r--WebCore/platform/android/jni/WebCoreResourceLoader.cpp395
-rw-r--r--WebCore/platform/android/jni/WebCoreResourceLoader.h67
-rw-r--r--WebCore/platform/android/jni/WebCoreViewBridge.h191
-rw-r--r--WebCore/platform/android/jni/WebHistory.cpp969
-rw-r--r--WebCore/platform/android/jni/WebHistory.h72
-rw-r--r--WebCore/platform/android/jni/WebIconDatabase.cpp232
-rw-r--r--WebCore/platform/android/jni/WebIconDatabase.h69
-rw-r--r--WebCore/platform/android/jni/WebSettings.cpp309
-rw-r--r--WebCore/platform/android/jni/WebViewCore.cpp2211
-rw-r--r--WebCore/platform/android/jni/WebViewCore.h400
-rw-r--r--WebCore/platform/android/nav/CacheBuilder.cpp2974
-rw-r--r--WebCore/platform/android/nav/CacheBuilder.h251
-rw-r--r--WebCore/platform/android/nav/CachedDebug.h75
-rw-r--r--WebCore/platform/android/nav/CachedFrame.cpp1303
-rw-r--r--WebCore/platform/android/nav/CachedFrame.h220
-rw-r--r--WebCore/platform/android/nav/CachedHistory.cpp196
-rw-r--r--WebCore/platform/android/nav/CachedHistory.h83
-rw-r--r--WebCore/platform/android/nav/CachedNode.cpp332
-rw-r--r--WebCore/platform/android/nav/CachedNode.h217
-rw-r--r--WebCore/platform/android/nav/CachedNodeType.h32
-rw-r--r--WebCore/platform/android/nav/CachedPrefix.h35
-rw-r--r--WebCore/platform/android/nav/CachedRoot.cpp1054
-rw-r--r--WebCore/platform/android/nav/CachedRoot.h101
-rw-r--r--WebCore/platform/android/nav/SelectText.cpp246
-rw-r--r--WebCore/platform/android/nav/SelectText.h34
-rw-r--r--WebCore/platform/android/nav/WebView.cpp1922
-rw-r--r--WebCore/platform/android/sort.cpp48
-rw-r--r--WebCore/platform/android/stl/algorithm237
-rw-r--r--WebCore/platform/android/stl/concept_checks.h811
-rw-r--r--WebCore/platform/android/stl/cstring128
-rw-r--r--WebCore/platform/android/stl/heap.h47
-rw-r--r--WebCore/platform/android/stl/iostream.h1
-rw-r--r--WebCore/platform/android/stl/limits23
-rw-r--r--WebCore/platform/android/stl/memory132
-rw-r--r--WebCore/platform/android/stl/new.h17
-rw-r--r--WebCore/platform/android/stl/stl_config.h576
-rw-r--r--WebCore/platform/android/stl/stl_heap.h297
-rw-r--r--WebCore/platform/android/stl/stl_iterator_base.h273
-rw-r--r--WebCore/platform/android/stl/strings.h17
-rw-r--r--WebCore/platform/cf/KURLCFNet.cpp58
-rw-r--r--WebCore/platform/graphics/AffineTransform.h6
-rw-r--r--WebCore/platform/graphics/BitmapImage.cpp4
-rw-r--r--WebCore/platform/graphics/BitmapImage.h13
-rw-r--r--WebCore/platform/graphics/Color.cpp59
-rw-r--r--WebCore/platform/graphics/Color.h4
-rw-r--r--WebCore/platform/graphics/Font.cpp57
-rw-r--r--WebCore/platform/graphics/Font.h3
-rw-r--r--WebCore/platform/graphics/FontFallbackList.cpp9
-rw-r--r--WebCore/platform/graphics/FontFamily.cpp2
-rw-r--r--WebCore/platform/graphics/FontFamily.h2
-rw-r--r--WebCore/platform/graphics/FontSelector.h5
-rw-r--r--WebCore/platform/graphics/GlyphBuffer.h31
-rw-r--r--WebCore/platform/graphics/GlyphPageTreeNode.h6
-rw-r--r--WebCore/platform/graphics/GraphicsContext.h90
-rw-r--r--WebCore/platform/graphics/Image.h9
-rw-r--r--WebCore/platform/graphics/ImageBuffer.h14
-rw-r--r--WebCore/platform/graphics/ImageSource.h16
-rw-r--r--WebCore/platform/graphics/Path.h3
-rw-r--r--WebCore/platform/graphics/SimpleFontData.h14
-rw-r--r--WebCore/platform/graphics/android/AffineTransformAndroid.cpp168
-rw-r--r--WebCore/platform/graphics/android/FontAndroid.cpp150
-rw-r--r--WebCore/platform/graphics/android/FontCacheAndroid.cpp156
-rw-r--r--WebCore/platform/graphics/android/FontCustomPlatformData.cpp68
-rw-r--r--WebCore/platform/graphics/android/FontCustomPlatformData.h47
-rw-r--r--WebCore/platform/graphics/android/FontDataAndroid.cpp121
-rw-r--r--WebCore/platform/graphics/android/FontPlatformData.h104
-rw-r--r--WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp151
-rw-r--r--WebCore/platform/graphics/android/GlyphMapAndroid.cpp (renamed from WebCore/platform/graphics/win/GlyphPageTreeNodeCairoWin.cpp)59
-rw-r--r--WebCore/platform/graphics/android/GraphicsContextAndroid.cpp1114
-rw-r--r--WebCore/platform/graphics/android/ImageAndroid.cpp254
-rw-r--r--WebCore/platform/graphics/android/ImageBufferAndroid.cpp53
-rw-r--r--WebCore/platform/graphics/android/ImageSourceAndroid.cpp336
-rw-r--r--WebCore/platform/graphics/android/PathAndroid.cpp231
-rw-r--r--WebCore/platform/graphics/android/PlatformGraphics.h25
-rw-r--r--WebCore/platform/graphics/android/PlatformGraphicsContext.cpp73
-rw-r--r--WebCore/platform/graphics/android/PlatformGraphicsContext.h108
-rw-r--r--WebCore/platform/graphics/android/SkBitmapRef.h54
-rw-r--r--WebCore/platform/graphics/android/android_graphics.cpp223
-rw-r--r--WebCore/platform/graphics/android/android_graphics.h80
-rw-r--r--WebCore/platform/graphics/cairo/FontCairo.cpp65
-rw-r--r--WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp50
-rw-r--r--WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h20
-rw-r--r--WebCore/platform/graphics/cairo/ImageBufferCairo.cpp14
-rw-r--r--WebCore/platform/graphics/cairo/ImageSourceCairo.cpp19
-rw-r--r--WebCore/platform/graphics/cairo/PathCairo.cpp8
-rw-r--r--WebCore/platform/graphics/cg/GraphicsContextCG.cpp49
-rw-r--r--WebCore/platform/graphics/cg/ImageBufferCG.cpp112
-rw-r--r--WebCore/platform/graphics/cg/ImageSourceCG.cpp27
-rw-r--r--WebCore/platform/graphics/gtk/FontGtk.cpp28
-rw-r--r--WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp2
-rw-r--r--WebCore/platform/graphics/gtk/IconGtk.cpp3
-rw-r--r--WebCore/platform/graphics/mac/IconMac.mm4
-rw-r--r--WebCore/platform/graphics/mac/ImageMac.mm1
-rw-r--r--WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm13
-rw-r--r--WebCore/platform/graphics/mac/SimpleFontDataMac.mm53
-rw-r--r--WebCore/platform/graphics/qt/GraphicsContextQt.cpp33
-rw-r--r--WebCore/platform/graphics/qt/IconQt.cpp2
-rw-r--r--WebCore/platform/graphics/qt/ImageBufferQt.cpp13
-rw-r--r--WebCore/platform/graphics/win/FontCacheWin.cpp15
-rw-r--r--WebCore/platform/graphics/win/FontCairoWin.cpp (renamed from WebCore/platform/wx/wxcode/non-kerned-drawing.h)36
-rw-r--r--WebCore/platform/graphics/win/FontCustomPlatformData.h7
-rw-r--r--WebCore/platform/graphics/win/FontCustomPlatformDataCairo.cpp61
-rw-r--r--WebCore/platform/graphics/win/FontCustomPlatformDataCairo.h49
-rw-r--r--WebCore/platform/graphics/win/FontPlatformData.h75
-rw-r--r--WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp134
-rw-r--r--WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp89
-rw-r--r--WebCore/platform/graphics/win/FontPlatformDataWin.cpp108
-rw-r--r--WebCore/platform/graphics/win/GlyphPageTreeNodeWin.cpp (renamed from WebCore/platform/graphics/win/GlyphPageTreeNodeCGWin.cpp)6
-rw-r--r--WebCore/platform/graphics/win/GraphicsContextCGWin.cpp71
-rw-r--r--WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp20
-rw-r--r--WebCore/platform/graphics/win/GraphicsContextWin.cpp77
-rw-r--r--WebCore/platform/graphics/win/IconWin.cpp6
-rw-r--r--WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp1
-rw-r--r--WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp46
-rw-r--r--WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp96
-rw-r--r--WebCore/platform/graphics/win/SimpleFontDataWin.cpp47
-rw-r--r--WebCore/platform/graphics/wx/FontPlatformData.h7
-rwxr-xr-xWebCore/platform/graphics/wx/FontPlatformDataWx.cpp4
-rw-r--r--WebCore/platform/graphics/wx/FontWx.cpp36
-rw-r--r--WebCore/platform/graphics/wx/GraphicsContextWx.cpp22
-rw-r--r--WebCore/platform/graphics/wx/ImageBufferWx.cpp14
-rw-r--r--WebCore/platform/graphics/wx/PathWx.cpp6
-rw-r--r--WebCore/platform/gtk/CookieJarGtk.cpp1
-rw-r--r--WebCore/platform/gtk/CursorGtk.cpp1
-rw-r--r--WebCore/platform/gtk/FileChooserGtk.cpp3
-rw-r--r--WebCore/platform/gtk/FileSystemGtk.cpp21
-rw-r--r--WebCore/platform/gtk/KeyEventGtk.cpp25
-rw-r--r--WebCore/platform/gtk/LocalizedStringsGtk.cpp5
-rw-r--r--WebCore/platform/gtk/MouseEventGtk.cpp9
-rw-r--r--WebCore/platform/gtk/PasteboardGtk.cpp6
-rw-r--r--WebCore/platform/gtk/PopupMenuGtk.cpp3
-rw-r--r--WebCore/platform/gtk/TemporaryLinkStubs.cpp17
-rw-r--r--WebCore/platform/gtk/ThreadingGtk.cpp209
-rw-r--r--WebCore/platform/gtk/WheelEventGtk.cpp9
-rw-r--r--WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp1
-rw-r--r--WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp1
-rw-r--r--WebCore/platform/image-decoders/png/PNGImageDecoder.cpp1
-rw-r--r--WebCore/platform/mac/ClipboardMac.mm14
-rw-r--r--WebCore/platform/mac/CookieJar.mm14
-rw-r--r--WebCore/platform/mac/DeprecatedStringListMac.mm (renamed from WebCore/platform/network/curl/ResourceError.h)27
-rw-r--r--WebCore/platform/mac/DeprecatedStringMac.mm85
-rw-r--r--WebCore/platform/mac/FileChooserMac.mm3
-rw-r--r--WebCore/platform/mac/KURLMac.mm49
-rw-r--r--WebCore/platform/mac/LocalizedStringsMac.mm9
-rw-r--r--WebCore/platform/mac/PasteboardMac.mm5
-rw-r--r--WebCore/platform/mac/PopupMenuMac.mm3
-rw-r--r--WebCore/platform/mac/SSLKeyGeneratorMac.mm4
-rw-r--r--WebCore/platform/mac/SharedBufferMac.mm3
-rw-r--r--WebCore/platform/mac/SystemTimeMac.cpp5
-rw-r--r--WebCore/platform/mac/Threading.mm (renamed from WebCore/platform/mac/MainThreadMac.mm)2
-rw-r--r--WebCore/platform/mac/WebCoreSystemInterface.h9
-rw-r--r--WebCore/platform/mac/WebCoreSystemInterface.mm8
-rw-r--r--WebCore/platform/network/AuthenticationChallenge.cpp (renamed from WebCore/platform/network/AuthenticationChallengeBase.cpp)53
-rw-r--r--WebCore/platform/network/AuthenticationChallenge.h (renamed from WebCore/platform/network/mac/AuthenticationChallenge.h)59
-rw-r--r--WebCore/platform/network/AuthenticationChallengeBase.h70
-rw-r--r--WebCore/platform/network/FormData.cpp34
-rw-r--r--WebCore/platform/network/FormData.h14
-rw-r--r--WebCore/platform/network/HTTPParsers.cpp5
-rw-r--r--WebCore/platform/network/ResourceError.cpp (renamed from WebCore/platform/network/qt/ResourceError.h)24
-rw-r--r--WebCore/platform/network/ResourceError.h168
-rw-r--r--WebCore/platform/network/ResourceErrorBase.h83
-rw-r--r--WebCore/platform/network/ResourceHandle.cpp8
-rw-r--r--WebCore/platform/network/ResourceHandle.h2
-rw-r--r--WebCore/platform/network/ResourceHandleInternal.h12
-rw-r--r--WebCore/platform/network/ResourceResponseBase.cpp70
-rw-r--r--WebCore/platform/network/ResourceResponseBase.h28
-rw-r--r--WebCore/platform/network/android/ResourceHandleAndroid.cpp144
-rw-r--r--WebCore/platform/network/android/ResourceRequest.h93
-rw-r--r--WebCore/platform/network/android/ResourceResponse.h (renamed from WebCore/platform/network/ResourceErrorBase.cpp)48
-rw-r--r--WebCore/platform/network/cf/AuthenticationCF.cpp38
-rw-r--r--WebCore/platform/network/cf/AuthenticationChallenge.h57
-rw-r--r--WebCore/platform/network/cf/FormDataStreamCFNet.cpp7
-rw-r--r--WebCore/platform/network/cf/ResourceError.h74
-rw-r--r--WebCore/platform/network/cf/ResourceErrorCF.cpp21
-rw-r--r--WebCore/platform/network/cf/ResourceRequest.h2
-rw-r--r--WebCore/platform/network/cf/ResourceResponse.h15
-rw-r--r--WebCore/platform/network/cf/ResourceResponseCFNet.cpp16
-rw-r--r--WebCore/platform/network/curl/ResourceHandleManager.cpp83
-rw-r--r--WebCore/platform/network/curl/ResourceRequest.h2
-rw-r--r--WebCore/platform/network/curl/ResourceResponse.h10
-rw-r--r--WebCore/platform/network/mac/AuthenticationMac.mm34
-rw-r--r--WebCore/platform/network/mac/ResourceErrorMac.mm19
-rw-r--r--WebCore/platform/network/mac/ResourceRequest.h4
-rw-r--r--WebCore/platform/network/mac/ResourceRequestMac.mm12
-rw-r--r--WebCore/platform/network/mac/ResourceResponse.h15
-rw-r--r--WebCore/platform/network/mac/ResourceResponseMac.mm13
-rw-r--r--WebCore/platform/network/qt/ResourceHandleQt.cpp1
-rw-r--r--WebCore/platform/network/qt/ResourceRequest.h2
-rw-r--r--WebCore/platform/network/qt/ResourceResponse.h12
-rw-r--r--WebCore/platform/network/win/CookieJarWin.cpp34
-rw-r--r--WebCore/platform/network/win/ResourceHandleWin.cpp22
-rw-r--r--WebCore/platform/pthreads/ThreadingPthreads.cpp200
-rw-r--r--WebCore/platform/qt/ClipboardQt.cpp7
-rw-r--r--WebCore/platform/qt/CookieJarQt.cpp1
-rw-r--r--WebCore/platform/qt/CursorQt.cpp1
-rw-r--r--WebCore/platform/qt/FileChooserQt.cpp3
-rw-r--r--WebCore/platform/qt/FileSystemQt.cpp17
-rw-r--r--WebCore/platform/qt/KURLQt.cpp8
-rw-r--r--WebCore/platform/qt/Localizations.cpp5
-rw-r--r--WebCore/platform/qt/PlugInInfoStoreQt.cpp89
-rw-r--r--WebCore/platform/qt/PopupMenuQt.cpp3
-rw-r--r--WebCore/platform/qt/RenderThemeQt.cpp5
-rw-r--r--WebCore/platform/qt/RenderThemeQt.h2
-rw-r--r--WebCore/platform/qt/TemporaryLinkStubs.cpp13
-rw-r--r--WebCore/platform/qt/ThreadingQt.cpp (renamed from WebCore/platform/qt/MainThreadQt.cpp)4
-rw-r--r--WebCore/platform/sql/SQLValue.h2
-rw-r--r--WebCore/platform/sql/SQLiteAuthorizer.h2
-rw-r--r--WebCore/platform/sql/SQLiteDatabase.h2
-rw-r--r--WebCore/platform/sql/SQLiteTransaction.cpp1
-rw-r--r--WebCore/platform/symbian/DeprecatedStringSymbian.cpp82
-rw-r--r--WebCore/platform/text/AtomicString.cpp40
-rw-r--r--WebCore/platform/text/AtomicString.h25
-rw-r--r--WebCore/platform/text/BidiResolver.h52
-rw-r--r--WebCore/platform/text/CString.cpp21
-rw-r--r--WebCore/platform/text/CString.h18
-rw-r--r--WebCore/platform/text/CharacterNames.h2
-rw-r--r--WebCore/platform/text/PlatformString.h89
-rw-r--r--WebCore/platform/text/RegularExpression.cpp127
-rw-r--r--WebCore/platform/text/RegularExpression.h30
-rw-r--r--WebCore/platform/text/SegmentedString.cpp44
-rw-r--r--WebCore/platform/text/SegmentedString.h32
-rw-r--r--WebCore/platform/text/String.cpp299
-rw-r--r--WebCore/platform/text/StringImpl.cpp140
-rw-r--r--WebCore/platform/text/StringImpl.h20
-rw-r--r--WebCore/platform/text/TextBreakIteratorICU.cpp2
-rw-r--r--WebCore/platform/text/TextCodecICU.cpp33
-rw-r--r--WebCore/platform/text/TextCodecLatin1.cpp1
-rw-r--r--WebCore/platform/text/TextCodecUserDefined.cpp1
-rw-r--r--WebCore/platform/text/TextStream.cpp119
-rw-r--r--WebCore/platform/text/TextStream.h30
-rw-r--r--WebCore/platform/text/mac/ShapeArabic.c24
-rw-r--r--WebCore/platform/text/qt/StringQt.cpp10
-rw-r--r--WebCore/platform/text/wx/StringWx.cpp7
-rw-r--r--WebCore/platform/win/BString.cpp10
-rw-r--r--WebCore/platform/win/BString.h6
-rw-r--r--WebCore/platform/win/ClipboardUtilitiesWin.cpp146
-rw-r--r--WebCore/platform/win/ClipboardUtilitiesWin.h22
-rw-r--r--WebCore/platform/win/ClipboardWin.cpp37
-rw-r--r--WebCore/platform/win/DragImageCairoWin.cpp3
-rw-r--r--WebCore/platform/win/FileChooserWin.cpp3
-rw-r--r--WebCore/platform/win/FileSystemWin.cpp11
-rw-r--r--WebCore/platform/win/MutexWin.cpp83
-rw-r--r--WebCore/platform/win/PasteboardWin.cpp14
-rw-r--r--WebCore/platform/win/PlatformScrollBarWin.cpp772
-rw-r--r--WebCore/platform/win/PopupMenuWin.cpp3
-rw-r--r--WebCore/platform/win/SharedTimerWin.cpp10
-rw-r--r--WebCore/platform/win/ThreadConditionWin.cpp240
-rw-r--r--WebCore/platform/win/ThreadingWin.cpp (renamed from WebCore/platform/win/MainThreadWin.cpp)93
-rw-r--r--WebCore/platform/wx/FileSystemWx.cpp40
-rw-r--r--WebCore/platform/wx/LocalizedStringsWx.cpp7
-rw-r--r--WebCore/platform/wx/MouseWheelEventWx.cpp4
-rw-r--r--WebCore/platform/wx/ScrollViewWx.cpp17
-rwxr-xr-xWebCore/platform/wx/TemporaryLinkStubs.cpp23
-rw-r--r--WebCore/platform/wx/ThreadingWx.cpp (renamed from WebCore/platform/wx/MainThreadWx.cpp)2
-rw-r--r--WebCore/platform/wx/wxcode/mac/carbon/non-kerned-drawing.cpp67
-rw-r--r--WebCore/platform/wx/wxcode/win/non-kerned-drawing.cpp125
353 files changed, 37602 insertions, 4981 deletions
diff --git a/WebCore/platform/ArrayImpl.cpp b/WebCore/platform/ArrayImpl.cpp
new file mode 100644
index 0000000..330120f
--- /dev/null
+++ b/WebCore/platform/ArrayImpl.cpp
@@ -0,0 +1,145 @@
+/*
+ * 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
+ * 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.
+ */
+
+#include "config.h"
+#include "ArrayImpl.h"
+
+#include <limits>
+#include <new>
+#include <stddef.h>
+#include <string.h>
+
+namespace WebCore {
+
+ArrayImpl::ArrayPrivate::ArrayPrivate(size_t pItemSize, size_t pNumItems) :
+ numItems(pNumItems),
+ itemSize(pItemSize),
+ data(pNumItems > 0 ? static_cast<char *>(fastMalloc(itemSize * numItems)) : NULL)
+{
+}
+
+ArrayImpl::ArrayPrivate::~ArrayPrivate()
+{
+ fastFree(data);
+}
+
+
+ArrayImpl::ArrayImpl(size_t itemSize, size_t numItems) :
+ d(new ArrayPrivate(itemSize, numItems))
+{
+}
+
+ArrayImpl::ArrayImpl(const ArrayImpl &a) :
+ d(a.d)
+{
+}
+
+ArrayImpl::~ArrayImpl()
+{
+}
+
+ArrayImpl &ArrayImpl::operator=(const ArrayImpl &a)
+{
+ d = a.d;
+ return *this;
+}
+
+void *ArrayImpl::data() const
+{
+ return d->data;
+}
+
+bool ArrayImpl::resize(size_t newSize)
+{
+ if (newSize != d->numItems) {
+ char *newData;
+
+ if (newSize != 0) {
+ size_t maxSize = std::numeric_limits<size_t>::max() / d->itemSize;
+ if (newSize > maxSize)
+ return false;
+ newData = static_cast<char *>(fastRealloc(d->data, newSize * d->itemSize));
+ if (!newData)
+ return false;
+ } else {
+ newData = 0;
+ fastFree(d->data);
+ }
+
+ d->data = newData;
+ d->numItems = newSize;
+ }
+
+ return true;
+}
+
+void ArrayImpl::duplicate(const void *data, size_t newSize)
+{
+ if (data == NULL) {
+ newSize = 0;
+ }
+
+ if (!d->hasOneRef())
+ d = new ArrayPrivate(d->itemSize, newSize);
+
+ if (d->numItems != newSize) {
+ resize(newSize);
+ }
+
+ memcpy(d->data, data, newSize * d->itemSize);
+}
+
+void ArrayImpl::detach()
+{
+ if (!d->hasOneRef())
+ duplicate(d->data, d->numItems);
+}
+
+bool ArrayImpl::fill(const void *item, int numItems)
+{
+ if (numItems == -1) {
+ numItems = d->numItems;
+ }
+
+ if ((unsigned)numItems != d->numItems) {
+ if (!resize(numItems)) {
+ return false;
+ }
+ }
+
+ for (int i = 0; i < numItems; i++) {
+ memcpy(&d->data[i * d->itemSize], item, d->itemSize);
+ }
+
+ return true;
+}
+
+bool ArrayImpl::operator==(const ArrayImpl &a) const
+{
+ return d->numItems == a.d->numItems && d->itemSize == a.d->itemSize
+ && (d->data == a.d->data || memcmp(d->data, a.d->data, d->itemSize*d->numItems) == 0);
+}
+
+}
diff --git a/WebCore/platform/ArrayImpl.h b/WebCore/platform/ArrayImpl.h
new file mode 100644
index 0000000..a4cfc1c
--- /dev/null
+++ b/WebCore/platform/ArrayImpl.h
@@ -0,0 +1,76 @@
+/*
+ * 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
+ * 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.
+ */
+
+#ifndef ArrayImpl_h
+#define ArrayImpl_h
+
+#include <wtf/RefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace WebCore {
+
+class ArrayImpl
+{
+ public:
+ ArrayImpl(size_t itemSize, size_t numItems = 0);
+ ~ArrayImpl();
+
+ ArrayImpl(const ArrayImpl &);
+ ArrayImpl &operator=(const ArrayImpl &);
+
+ void *at(size_t pos) const { return &d->data[pos * d->itemSize]; }
+
+ void *data() const;
+ unsigned size() const;
+ bool resize(size_t size);
+ void duplicate(const void *data, size_t size);
+ bool fill(const void *item, int size = -1);
+ void detach();
+
+ bool operator==(const ArrayImpl &) const;
+
+ private:
+ class ArrayPrivate : public RefCounted<ArrayPrivate>
+ {
+ public:
+ ArrayPrivate(size_t pNumItems, size_t pItemSize);
+ ~ArrayPrivate();
+
+ size_t numItems;
+ size_t itemSize;
+ char *data;
+ };
+
+ RefPtr<ArrayPrivate> d;
+};
+
+inline unsigned ArrayImpl::size() const
+{
+ return d->numItems;
+}
+
+}
+
+#endif
diff --git a/WebCore/platform/ContextMenuItem.h b/WebCore/platform/ContextMenuItem.h
index 22e042f..01a012d 100644
--- a/WebCore/platform/ContextMenuItem.h
+++ b/WebCore/platform/ContextMenuItem.h
@@ -167,6 +167,8 @@ namespace WebCore {
bool checked;
bool enabled;
};
+#elif defined ANDROID
+ typedef void* PlatformMenuItemDescription;
#elif PLATFORM(WX)
typedef wxMenuItem* PlatformMenuItemDescription;
#endif
diff --git a/WebCore/platform/Cursor.h b/WebCore/platform/Cursor.h
index c021ebc..98b0db6 100644
--- a/WebCore/platform/Cursor.h
+++ b/WebCore/platform/Cursor.h
@@ -59,7 +59,7 @@ namespace WebCore {
#if PLATFORM(WIN)
class SharedCursor : public RefCounted<SharedCursor> {
public:
- SharedCursor(HCURSOR nativeCursor) : RefCounted<SharedCursor>(0), m_nativeCursor(nativeCursor) {}
+ SharedCursor(HCURSOR nativeCursor) : m_nativeCursor(nativeCursor) {}
~SharedCursor() {
DestroyIcon(m_nativeCursor);
}
diff --git a/WebCore/platform/DeprecatedArray.h b/WebCore/platform/DeprecatedArray.h
new file mode 100644
index 0000000..6c358f3
--- /dev/null
+++ b/WebCore/platform/DeprecatedArray.h
@@ -0,0 +1,72 @@
+/*
+ * 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
+ * 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.
+ */
+
+#ifndef DeprecatedArray_h
+#define DeprecatedArray_h
+
+#include "ArrayImpl.h"
+#include <wtf/Platform.h>
+
+namespace WebCore {
+
+template <class T> class DeprecatedArray {
+public:
+ DeprecatedArray() : impl(sizeof(T)) { }
+ DeprecatedArray(int i) : impl(sizeof(T), i) { }
+
+ bool isEmpty() { return impl.size() == 0; }
+ T &at(unsigned u) { return *(T *)impl.at(u); }
+ const T &at(unsigned u) const { return *(T *)impl.at(u); }
+ T *data() { return (T *)impl.data(); }
+ const T *data() const { return (T *)impl.data(); }
+ unsigned size() const { return impl.size(); }
+ unsigned count() const { return impl.size(); }
+ bool resize(unsigned size) { return impl.resize(size); }
+ DeprecatedArray<T>& duplicate(const DeprecatedArray<T> &a) { impl.duplicate(a.data(), a.size()); return *this; }
+ DeprecatedArray<T>& duplicate(const T *data, int size) { impl.duplicate(data, size); return *this; }
+ void detach() { impl.detach(); }
+ bool fill(const T &item, int size=-1) { return impl.fill(&item, size); }
+ DeprecatedArray<T>& assign(const DeprecatedArray<T> &a) { return *this = a; }
+
+ T &operator[](int i) { return *(T *)impl.at(i); }
+ const T &operator[](int i) const { return *(T *)impl.at(i); }
+#if PLATFORM(WIN_OS)
+ // FIXME: Look into this strange compile error on Win32.
+ T &operator[](unsigned i) { return *(T *)impl.at(i); }
+ const T &operator[](unsigned i) const { return *(T *)impl.at(i); }
+#endif
+ bool operator==(const DeprecatedArray<T> &a) const { return impl == a.impl; }
+ bool operator!=(const DeprecatedArray<T> &a) const { return !(*this == a); }
+ operator const T*() const { return data(); }
+
+ private:
+ ArrayImpl impl;
+};
+
+typedef DeprecatedArray<char> DeprecatedByteArray;
+
+} // namespace WebCore
+
+#endif // DeprecatedArray_h
diff --git a/WebCore/platform/DeprecatedCString.cpp b/WebCore/platform/DeprecatedCString.cpp
new file mode 100644
index 0000000..2702d70
--- /dev/null
+++ b/WebCore/platform/DeprecatedCString.cpp
@@ -0,0 +1,306 @@
+/*
+ * Copyright (C) 2003, 2007 Apple 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.
+ */
+
+#include "config.h"
+#include "DeprecatedCString.h"
+
+#include <wtf/ASCIICType.h>
+#include <wtf/Assertions.h>
+
+using namespace WTF;
+
+namespace WebCore {
+
+DeprecatedCString::DeprecatedCString()
+{
+}
+
+DeprecatedCString::DeprecatedCString(int size) : DeprecatedByteArray(size)
+{
+ if( size>0 && data() )
+ {
+ data()[0] = 0; // first null
+ data()[size-1] = 0; // last byte
+ }
+ // else null
+}
+
+
+DeprecatedCString::DeprecatedCString(const char *str)
+{
+ size_t len;
+ if( str && (len=strlen(str)+1) && resize(len) ) // include null
+ strcpy( data(), str );
+ // else null
+}
+
+
+DeprecatedCString::DeprecatedCString(const char *str, unsigned max)
+{
+ if( str && max )
+ {
+ // perform a truncated strlen on str
+ const char* p = str;
+ unsigned len = 1; // for the null
+ while( *p++ && len<max )
+ len ++;
+
+ if( resize(len) )
+ {
+ char *dest = data();
+ strncpy( dest, str, len );
+ dest[len-1] = 0; // re-terminate
+ }
+ }
+ // else null
+}
+
+bool DeprecatedCString::isEmpty() const
+{ return length()==0; }
+
+
+unsigned DeprecatedCString::length() const
+{
+ const char *d = data();
+ return d ? strlen(d) : 0;
+}
+
+
+bool DeprecatedCString::resize(unsigned len)
+{
+ bool success = DeprecatedByteArray::resize(len);
+ if( success && len>0 )
+ data()[len-1] = 0; // always terminate last byte
+
+ return success;
+}
+
+
+bool DeprecatedCString::truncate(unsigned pos)
+{
+ return resize(pos+1);
+}
+
+
+DeprecatedCString DeprecatedCString::lower() const
+{
+ // convert
+ DeprecatedCString tmp = *this; // copy
+ char* str = tmp.data();
+ if( str )
+ {
+ while( *str != 0 )
+ {
+ *str = toASCIILower(*str);
+ str++;
+ }
+ }
+
+ return tmp;
+}
+
+
+DeprecatedCString DeprecatedCString::upper() const
+{
+ DeprecatedCString tmp = *this; // copy
+ char* str = tmp.data();
+ if( str )
+ {
+ while( *str != 0 )
+ {
+ *str = toASCIIUpper(*str);
+ str++;
+ }
+ }
+
+ return tmp;
+}
+
+
+inline DeprecatedCString DeprecatedCString::left(unsigned len) const
+{ return mid(0, len); }
+
+
+inline DeprecatedCString DeprecatedCString::right(unsigned len) const
+{ return mid(length() - len, len); }
+
+
+DeprecatedCString DeprecatedCString::mid(unsigned index, unsigned len) const
+{
+ unsigned size = length();
+ if( data() && index<size ) // return null if index out-of-range
+ {
+ // clip length
+ if( len > size - index )
+ len = size - index;
+
+ // copy and return
+ return DeprecatedCString( &(data()[index]), len+1); // include nul
+ }
+
+ // degenerate case
+ return DeprecatedCString();
+}
+
+int DeprecatedCString::find(const char *sub, int index, bool cs) const
+{
+ const char* str = data();
+ if( str && str[0] && sub && index>=0 ) // don't search empty strings
+ {
+ // advance until we get to index
+ int pos = 0;
+ while( pos < index )
+ if( str[pos++] == 0 )
+ return -1; // index is beyond end of str
+
+ // now search from index onward
+ while( str[index] != 0 )
+ {
+ char a, b;
+
+ // compare until we reach the end or a mismatch
+ pos = 0;
+ if( cs )
+ while( (a=sub[pos]) && (b=str[index]) && a==b )
+ pos++, index++;
+ else
+ while( (a=sub[pos]) && (b=str[index]) && toASCIILower(a)==toASCIILower(b) )
+ pos++, index++;
+
+ // reached the end of our compare string without a mismatch?
+ if( sub[pos] == 0 )
+ return index - pos;
+
+ index ++;
+ }
+ }
+
+ return -1;
+}
+
+int DeprecatedCString::contains(char c, bool cs) const
+{
+ unsigned found = 0;
+ unsigned len = length();
+
+ if (len) {
+ const char *str = data();
+
+ if (cs) {
+ for (unsigned i = 0; i != len; ++i) {
+ found += str[i] == c;
+ }
+ } else {
+ c = toASCIILower(c);
+
+ for (unsigned i = 0; i != len; ++i) {
+ char chr = str[i];
+ chr = toASCIILower(chr);
+ found += chr == c;
+ }
+ }
+ }
+
+ return found;
+}
+
+DeprecatedCString &DeprecatedCString::operator=(const char *assignFrom)
+{
+ duplicate(assignFrom, (assignFrom ? strlen(assignFrom) : 0) + 1);
+ return *this;
+}
+
+DeprecatedCString& DeprecatedCString::append(const char *s)
+{
+ if (s) {
+ unsigned len2 = strlen(s);
+ if (len2) {
+ detach();
+ unsigned len1 = length();
+ if (DeprecatedByteArray::resize(len1 + len2 + 1))
+ memcpy(data() + len1, s, len2 + 1);
+ }
+ }
+
+ return *this;
+}
+
+DeprecatedCString &DeprecatedCString::append(char c)
+{
+ detach();
+ unsigned len = length();
+
+ if (DeprecatedByteArray::resize(len + 2)) {
+ *(data() + len) = c;
+ *(data() + len + 1) = '\0';
+ }
+
+ return *this;
+}
+
+DeprecatedCString &DeprecatedCString::replace(char c1, char c2)
+{
+ unsigned len = length();
+
+ if (len) {
+ // Search for the first instance of c1 before detaching,
+ // just in case there is nothing to replace. In that case
+ // we don't want to detach this from other shared instances
+ // since we have no need to modify it.
+ unsigned i;
+ {
+ const char *s = data();
+ for (i = 0; i != len; ++i) {
+ if (s[i] == c1) {
+ break;
+ }
+ }
+ }
+
+ if (i != len) {
+ detach();
+ char *s = data();
+ // Start at the first instance of c1; no need to rescan earlier chars.
+ for (; i != len; ++i) {
+ if (s[i] == c1) {
+ s[i] = c2;
+ }
+ }
+ }
+ }
+
+ return *this;
+}
+
+bool operator==(const DeprecatedCString &s1, const char *s2)
+{
+ if (s1.size() == 0 && !s2)
+ return true;
+ if (s1.size() == 0 && s2)
+ return false;
+ return strcmp(s1, s2) == 0;
+}
+
+}
diff --git a/WebCore/platform/DeprecatedCString.h b/WebCore/platform/DeprecatedCString.h
new file mode 100644
index 0000000..a10eb82
--- /dev/null
+++ b/WebCore/platform/DeprecatedCString.h
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+#ifndef DeprecatedCString_h
+#define DeprecatedCString_h
+
+#include "DeprecatedArray.h"
+#include <string.h>
+
+namespace WebCore {
+
+class DeprecatedCString : public DeprecatedByteArray {
+public:
+ DeprecatedCString();
+ DeprecatedCString(int);
+ DeprecatedCString(const char *);
+ DeprecatedCString(const char *, unsigned);
+
+ DeprecatedCString &operator=(const char *);
+
+ bool isEmpty() const;
+ bool isNull() const { return data() == 0; }
+ int find(const char *, int index=0, bool cs=true) const;
+ int contains(char, bool cs=true) const;
+ unsigned length() const;
+ bool truncate(unsigned);
+ DeprecatedCString lower() const;
+ DeprecatedCString upper() const;
+ DeprecatedCString left(unsigned) const;
+ DeprecatedCString right(unsigned) const;
+ DeprecatedCString mid(unsigned, unsigned len=0xffffffff) const;
+
+ DeprecatedCString &append(char);
+ DeprecatedCString &append(const char *);
+ DeprecatedCString &replace(char, char);
+
+ operator const char *() const { return data(); }
+ DeprecatedCString &operator+=(const char *s) { return append(s); }
+ DeprecatedCString &operator+=(char c) { return append(c); }
+
+private:
+ bool resize(unsigned);
+};
+
+bool operator==(const DeprecatedCString &s1, const char *s2);
+inline bool operator==(const char *s1, const DeprecatedCString &s2) { return s2 == s1; }
+inline bool operator!=(const DeprecatedCString &s1, const char *s2) { return !(s1 == s2); }
+inline bool operator!=(const char *s1, const DeprecatedCString &s2) { return !(s1 == s2); }
+
+}
+
+#endif
diff --git a/WebCore/platform/DeprecatedString.cpp b/WebCore/platform/DeprecatedString.cpp
new file mode 100644
index 0000000..3656224
--- /dev/null
+++ b/WebCore/platform/DeprecatedString.cpp
@@ -0,0 +1,2679 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007 Apple 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.
+ */
+
+#include "config.h"
+#include "DeprecatedString.h"
+
+#include "CString.h"
+#include "FloatConversion.h"
+#include "Logging.h"
+#include "PlatformString.h"
+#include "RegularExpression.h"
+#include "TextEncoding.h"
+#include <kjs/dtoa.h>
+#include <kjs/identifier.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <wtf/Platform.h>
+#include <wtf/StringExtras.h>
+
+#if PLATFORM(WIN_OS)
+#include <windows.h>
+#endif
+
+#if PLATFORM(QT)
+#include <QString>
+#endif
+
+using namespace std;
+using namespace KJS;
+using namespace WTF;
+
+namespace WebCore {
+
+COMPILE_ASSERT(sizeof(DeprecatedChar) == 2, deprecated_char_is_2_bytes)
+
+#define CHECK_FOR_HANDLE_LEAKS 0
+
+#if PLATFORM(SYMBIAN)
+#undef CHECK_FOR_HANDLE_LEAKS
+// symbian:fixme need page aligned allocations as Symbian platform does not have support for valloc
+#define CHECK_FOR_HANDLE_LEAKS 1
+#endif
+
+#define ALLOC_QCHAR_GOOD_SIZE(X) (X)
+#define ALLOC_CHAR_GOOD_SIZE(X) (X)
+
+#define ALLOC_CHAR(N) (char*)fastMalloc(N)
+#define REALLOC_CHAR(P, N) (char *)fastRealloc(P, N)
+#define DELETE_CHAR(P) fastFree(P)
+
+#define WEBCORE_ALLOCATE_CHARACTERS(N) (DeprecatedChar*)fastMalloc(sizeof(DeprecatedChar)*(N))
+#define WEBCORE_REALLOCATE_CHARACTERS(P, N) (DeprecatedChar *)fastRealloc(P, sizeof(DeprecatedChar)*(N))
+#define DELETE_QCHAR(P) fastFree(P)
+
+#ifndef CHECK_FOR_HANDLE_LEAKS
+struct HandleNode;
+struct HandlePageNode;
+
+static HandleNode *allocateNode(HandlePageNode *pageNode);
+static HandlePageNode *allocatePageNode();
+
+static HandlePageNode *usedNodeAllocationPages = 0;
+static HandlePageNode *freeNodeAllocationPages = 0;
+
+static inline void initializeHandleNodes()
+{
+ if (freeNodeAllocationPages == 0)
+ freeNodeAllocationPages = allocatePageNode();
+}
+#endif
+
+static inline DeprecatedStringData **allocateHandle()
+{
+#ifdef CHECK_FOR_HANDLE_LEAKS
+ return static_cast<DeprecatedStringData **>(fastMalloc(sizeof(DeprecatedStringData *)));
+#else
+
+ initializeHandleNodes();
+
+ return reinterpret_cast<DeprecatedStringData **>(allocateNode(freeNodeAllocationPages));
+#endif
+}
+
+static void freeHandle(DeprecatedStringData **);
+
+#define IS_ASCII_QCHAR(c) ((c).unicode() > 0 && (c).unicode() <= 0xff)
+
+static const int caseDelta = ('a' - 'A');
+
+const char * const DeprecatedString::null = 0;
+
+DeprecatedStringData *DeprecatedString::shared_null = 0;
+DeprecatedStringData **DeprecatedString::shared_null_handle = 0;
+
+// -------------------------------------------------------------------------
+// Utility functions
+// -------------------------------------------------------------------------
+
+static inline int ucstrcmp( const DeprecatedString &as, const DeprecatedString &bs )
+{
+ const DeprecatedChar *a = as.unicode();
+ const DeprecatedChar *b = bs.unicode();
+ if ( a == b )
+ return 0;
+ if ( a == 0 )
+ return 1;
+ if ( b == 0 )
+ return -1;
+ int l = min(as.length(), bs.length());
+ while ( l-- && *a == *b )
+ a++,b++;
+ if ( l == -1 )
+ return ( as.length() - bs.length() );
+ return a->unicode() - b->unicode();
+}
+
+static bool equal(const DeprecatedChar *a, const char *b, int l)
+{
+ 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 bool equalCaseInsensitive(const char *a, const char *b, int l)
+{
+ ASSERT(l >= 0);
+ while (l--) {
+ if (toASCIILower(*a) != toASCIILower(*b))
+ return false;
+ a++; b++;
+ }
+ return true;
+}
+
+static bool equalCaseInsensitive(const DeprecatedChar *a, const char *b, int l)
+{
+ ASSERT(l >= 0);
+ while (l--) {
+ if (toASCIILower(a->unicode()) != static_cast<unsigned char>(toASCIILower(*b)))
+ return false;
+ a++; b++;
+ }
+ return true;
+}
+
+static bool equalCaseInsensitive(const DeprecatedChar *a, const DeprecatedChar *b, int l)
+{
+ ASSERT(l >= 0);
+ while (l--) {
+ if (toASCIILower(a->unicode()) != toASCIILower(b->unicode()))
+ return false;
+ a++; b++;
+ }
+ return true;
+}
+
+static inline bool equalCaseInsensitive(char c1, char c2)
+{
+ return toASCIILower(c1) == toASCIILower(c2);
+}
+
+static inline bool equalCaseInsensitive(DeprecatedChar c1, char c2)
+{
+ return toASCIILower(c1.unicode()) == static_cast<unsigned char>(toASCIILower(c2));
+}
+
+static bool isCharacterAllowedInBase(DeprecatedChar c, int base)
+{
+ ::UChar uc = c.unicode();
+ if (uc > 0x7F)
+ return false;
+ if (isASCIIDigit(uc))
+ return uc - '0' < base;
+ if (isASCIIAlpha(uc)) {
+ if (base > 36)
+ base = 36;
+ return (uc >= 'a' && uc < 'a' + base - 10)
+ || (uc >= 'A' && uc < 'A' + base - 10);
+ }
+ return false;
+}
+
+// -------------------------------------------------------------------------
+// DeprecatedStringData
+// -------------------------------------------------------------------------
+
+// FIXME, make constructor explicity take a 'copy' flag.
+// This can be used to hand off ownership of allocated data when detaching and
+// deleting QStrings.
+
+DeprecatedStringData::DeprecatedStringData() :
+ refCount(1), _length(0), _unicode(0), _ascii(0), _maxUnicode(WEBCORE_DS_INTERNAL_BUFFER_UCHARS), _isUnicodeValid(0), _isHeapAllocated(0), _maxAscii(WEBCORE_DS_INTERNAL_BUFFER_CHARS), _isAsciiValid(1)
+{
+ _ascii = _internalBuffer;
+ _internalBuffer[0] = 0;
+}
+
+void DeprecatedStringData::initialize()
+{
+ refCount = 1;
+ _length = 0;
+ _unicode = 0;
+ _ascii = _internalBuffer;
+ _maxUnicode = WEBCORE_DS_INTERNAL_BUFFER_UCHARS;
+ _isUnicodeValid = 0;
+ _maxAscii = WEBCORE_DS_INTERNAL_BUFFER_CHARS;
+ _isAsciiValid = 1;
+ _internalBuffer[0] = 0;
+ _isHeapAllocated = 0;
+}
+
+// Don't copy data.
+DeprecatedStringData::DeprecatedStringData(DeprecatedChar *u, unsigned l, unsigned m) :
+ refCount(1), _length(l), _unicode(u), _ascii(0), _maxUnicode(m), _isUnicodeValid(1), _isHeapAllocated(0), _maxAscii(WEBCORE_DS_INTERNAL_BUFFER_CHARS), _isAsciiValid(0)
+{
+ ASSERT(m >= l);
+}
+
+// Don't copy data.
+void DeprecatedStringData::initialize(DeprecatedChar *u, unsigned l, unsigned m)
+{
+ ASSERT(m >= l);
+ refCount = 1;
+ _length = l;
+ _unicode = u;
+ _ascii = 0;
+ _maxUnicode = m;
+ _isUnicodeValid = 1;
+ _maxAscii = 0;
+ _isAsciiValid = 0;
+ _isHeapAllocated = 0;
+}
+
+// Copy data
+DeprecatedStringData::DeprecatedStringData(const DeprecatedChar *u, unsigned l)
+{
+ initialize (u, l);
+}
+
+// Copy data
+void DeprecatedStringData::initialize(const DeprecatedChar *u, unsigned l)
+{
+ refCount = 1;
+ _length = l;
+ _ascii = 0;
+ _isUnicodeValid = 1;
+ _maxAscii = 0;
+ _isAsciiValid = 0;
+ _isHeapAllocated = 0;
+
+ if (l > WEBCORE_DS_INTERNAL_BUFFER_UCHARS) {
+ _maxUnicode = ALLOC_QCHAR_GOOD_SIZE(l);
+ _unicode = WEBCORE_ALLOCATE_CHARACTERS(_maxUnicode);
+ memcpy(_unicode, u, l*sizeof(DeprecatedChar));
+ } else {
+ _maxUnicode = WEBCORE_DS_INTERNAL_BUFFER_UCHARS;
+ _unicode = (DeprecatedChar *)_internalBuffer;
+ if (l)
+ memcpy(_internalBuffer, u, l*sizeof(DeprecatedChar));
+ }
+}
+
+
+// Copy data
+DeprecatedStringData::DeprecatedStringData(const char *a, unsigned l)
+{
+ initialize(a, l);
+}
+
+
+// Copy data
+void DeprecatedStringData::initialize(const char *a, unsigned l)
+{
+ refCount = 1;
+ _length = l;
+ _unicode = 0;
+ _isUnicodeValid = 0;
+ _maxUnicode = 0;
+ _isAsciiValid = 1;
+ _isHeapAllocated = 0;
+
+ if (l > WEBCORE_DS_INTERNAL_BUFFER_CHARS) {
+ _maxAscii = ALLOC_CHAR_GOOD_SIZE(l+1);
+ _ascii = ALLOC_CHAR(_maxAscii);
+ if (a)
+ memcpy(_ascii, a, l);
+ _ascii[l] = 0;
+ } else {
+ _maxAscii = WEBCORE_DS_INTERNAL_BUFFER_CHARS;
+ _ascii = _internalBuffer;
+ if (a)
+ memcpy(_internalBuffer, a, l);
+ _internalBuffer[l] = 0;
+ }
+}
+
+DeprecatedStringData* DeprecatedStringData::createAndAdopt(DeprecatedStringData &o)
+{
+ DeprecatedStringData* data = new DeprecatedStringData();
+ data->adopt(o);
+ return data;
+}
+
+void DeprecatedStringData::adopt(DeprecatedStringData& o)
+{
+ ASSERT(refCount == 1);
+ _length = o._length;
+ _unicode = o._unicode;
+ _ascii = o._ascii;
+ _maxUnicode = o._maxUnicode;
+ _isUnicodeValid = o._isUnicodeValid;
+ _isHeapAllocated = 0;
+ _maxAscii = o._maxAscii;
+ _isAsciiValid = o._isAsciiValid;
+
+ // Handle the case where either the Unicode or 8-bit pointer was
+ // pointing to the internal buffer. We need to point at the
+ // internal buffer in the new object, and copy the characters.
+ if (_unicode == reinterpret_cast<DeprecatedChar *>(o._internalBuffer)) {
+ if (_isUnicodeValid) {
+ ASSERT(!_isAsciiValid || _ascii != o._internalBuffer);
+ ASSERT(_length <= WEBCORE_DS_INTERNAL_BUFFER_UCHARS);
+ memcpy(_internalBuffer, o._internalBuffer, _length * sizeof(DeprecatedChar));
+ _unicode = reinterpret_cast<DeprecatedChar *>(_internalBuffer);
+ } else {
+ _unicode = 0;
+ }
+ }
+ if (_ascii == o._internalBuffer) {
+ if (_isAsciiValid) {
+ ASSERT(_length <= WEBCORE_DS_INTERNAL_BUFFER_CHARS);
+ memcpy(_internalBuffer, o._internalBuffer, _length);
+ _internalBuffer[_length] = 0;
+ _ascii = _internalBuffer;
+ } else {
+ _ascii = 0;
+ }
+ }
+
+ // Clean up the other DeprecatedStringData just enough so that it can be destroyed
+ // cleanly. It's not in a good enough state to use, but that's OK. It just
+ // needs to be in a state where ~DeprecatedStringData won't do anything harmful,
+ // and setting these to 0 will do that (preventing any double-free problems).
+ o._unicode = 0;
+ o._ascii = 0;
+}
+
+DeprecatedStringData *DeprecatedString::makeSharedNull()
+{
+ if (!shared_null) {
+ shared_null = new DeprecatedStringData;
+ shared_null->ref();
+ shared_null->_maxAscii = 0;
+ shared_null->_maxUnicode = 0;
+ shared_null->_unicode = (DeprecatedChar *)&shared_null->_internalBuffer[0];
+ shared_null->_isUnicodeValid = 1;
+ }
+ return shared_null;
+}
+
+DeprecatedStringData **DeprecatedString::makeSharedNullHandle()
+{
+ if (!shared_null_handle) {
+ shared_null_handle = allocateHandle();
+ *shared_null_handle = makeSharedNull();
+ }
+ return shared_null_handle;
+}
+
+DeprecatedStringData::~DeprecatedStringData()
+{
+ ASSERT(refCount == 0);
+ if (_unicode && !isUnicodeInternal())
+ DELETE_QCHAR(_unicode);
+ if (_ascii && !isAsciiInternal())
+ DELETE_CHAR(_ascii);
+}
+
+void DeprecatedStringData::increaseAsciiSize(unsigned size)
+{
+ ASSERT(this != DeprecatedString::shared_null);
+
+ unsigned newSize = (unsigned)ALLOC_CHAR_GOOD_SIZE((size * 3 + 1) / 2);
+
+ if (!_isAsciiValid)
+ makeAscii();
+ ASSERT(_isAsciiValid);
+
+ if (isAsciiInternal()) {
+ char *newAscii = ALLOC_CHAR(newSize);
+ if (_length)
+ memcpy(newAscii, _ascii, _length);
+ _ascii = newAscii;
+ } else {
+ _ascii = REALLOC_CHAR(_ascii, newSize);
+ }
+
+ _maxAscii = newSize;
+ _isAsciiValid = 1;
+ _isUnicodeValid = 0;
+}
+
+
+void DeprecatedStringData::increaseUnicodeSize(unsigned size)
+{
+ ASSERT(size > _length);
+ ASSERT(this != DeprecatedString::shared_null);
+
+ unsigned newSize = (unsigned)ALLOC_QCHAR_GOOD_SIZE((size * 3 + 1) / 2);
+
+ if (!_isUnicodeValid)
+ makeUnicode();
+ ASSERT(_isUnicodeValid);
+
+ if (isUnicodeInternal()) {
+ DeprecatedChar *newUni = WEBCORE_ALLOCATE_CHARACTERS(newSize);
+ if (_length)
+ memcpy(newUni, _unicode, _length*sizeof(DeprecatedChar));
+ _unicode = newUni;
+ } else {
+ _unicode = WEBCORE_REALLOCATE_CHARACTERS(_unicode, newSize);
+ }
+
+ _maxUnicode = newSize;
+ _isUnicodeValid = 1;
+ _isAsciiValid = 0;
+}
+
+
+char *DeprecatedStringData::makeAscii()
+{
+ ASSERT(this != DeprecatedString::shared_null);
+
+ if (_isUnicodeValid){
+ DeprecatedChar copyBuf[WEBCORE_DS_INTERNAL_BUFFER_CHARS];
+ DeprecatedChar *str;
+
+ if (_ascii && !isAsciiInternal())
+ DELETE_QCHAR(_ascii);
+
+ if (_length < WEBCORE_DS_INTERNAL_BUFFER_CHARS){
+ if (isUnicodeInternal()) {
+ unsigned i = _length;
+ DeprecatedChar *tp = &copyBuf[0], *fp = _unicode;
+ while (i--)
+ *tp++ = *fp++;
+ str = &copyBuf[0];
+ _isUnicodeValid = 0;
+ }
+ else
+ str = _unicode;
+ _ascii = _internalBuffer;
+ _maxAscii = WEBCORE_DS_INTERNAL_BUFFER_CHARS;
+ }
+ else {
+ unsigned newSize = ALLOC_CHAR_GOOD_SIZE(_length+1);
+ _ascii = ALLOC_CHAR(newSize);
+ _maxAscii = newSize;
+ str = _unicode;
+ }
+
+ unsigned i = _length;
+ char* cp = _ascii;
+ while (i--)
+ // FIXME: this converts non-Latin1 characters to '\0', which may be not what we want in some cases.
+ // In particular, toDouble() may fail to report errors, believing that the string ends earlier
+ // than it actually does.
+ *cp++ = (*str++).latin1();
+ *cp = 0;
+
+ _isAsciiValid = 1;
+ }
+ else if (!_isAsciiValid)
+ FATAL("ASCII character cache not valid");
+
+ return _ascii;
+}
+
+
+DeprecatedChar *DeprecatedStringData::makeUnicode()
+{
+ ASSERT(this != DeprecatedString::shared_null);
+
+ if (_isAsciiValid){
+ char copyBuf[WEBCORE_DS_INTERNAL_BUFFER_CHARS];
+ char *str;
+
+ if (_unicode && !isUnicodeInternal())
+ DELETE_QCHAR(_unicode);
+
+ if (_length <= WEBCORE_DS_INTERNAL_BUFFER_UCHARS){
+ if (isAsciiInternal()) {
+ unsigned i = _length;
+ char *tp = &copyBuf[0], *fp = _ascii;
+ while (i--)
+ *tp++ = *fp++;
+ str = &copyBuf[0];
+ _isAsciiValid = 0;
+ }
+ else
+ str = _ascii;
+ _unicode = (DeprecatedChar *)_internalBuffer;
+ _maxUnicode = WEBCORE_DS_INTERNAL_BUFFER_UCHARS;
+ }
+ else {
+ unsigned newSize = ALLOC_QCHAR_GOOD_SIZE(_length);
+ _unicode = WEBCORE_ALLOCATE_CHARACTERS(newSize);
+ _maxUnicode = newSize;
+ str = _ascii;
+ }
+ unsigned i = _length;
+ DeprecatedChar *cp = _unicode;
+ while ( i-- )
+ *cp++ = *str++;
+
+ _isUnicodeValid = 1;
+ }
+ else if (!_isUnicodeValid)
+ FATAL("invalid character cache");
+
+ return _unicode;
+}
+
+
+// -------------------------------------------------------------------------
+// DeprecatedString
+// -------------------------------------------------------------------------
+
+
+DeprecatedString DeprecatedString::number(int n)
+{
+ DeprecatedString qs;
+ qs.setNum(n);
+ return qs;
+}
+
+DeprecatedString DeprecatedString::number(unsigned n)
+{
+ DeprecatedString qs;
+ qs.setNum(n);
+ return qs;
+}
+
+DeprecatedString DeprecatedString::number(long n)
+{
+ DeprecatedString qs;
+ qs.setNum(n);
+ return qs;
+}
+
+DeprecatedString DeprecatedString::number(unsigned long n)
+{
+ DeprecatedString qs;
+ qs.setNum(n);
+ return qs;
+}
+
+DeprecatedString DeprecatedString::number(double n)
+{
+ DeprecatedString qs;
+ qs.setNum(n);
+ return qs;
+}
+
+inline void DeprecatedString::detachIfInternal()
+{
+ DeprecatedStringData *oldData = *dataHandle;
+ if (oldData->refCount > 1 && oldData == &internalData) {
+ DeprecatedStringData *newData = DeprecatedStringData::createAndAdopt(*oldData);
+ newData->_isHeapAllocated = 1;
+ newData->refCount = oldData->refCount;
+ oldData->refCount = 1;
+ oldData->deref();
+ *dataHandle = newData;
+ }
+}
+
+const DeprecatedChar *DeprecatedString::stableUnicode()
+{
+ // if we're using the internal data of another string, detach now
+ if (!dataHandle[0]->_isHeapAllocated && *dataHandle != &internalData) {
+ detach();
+ }
+ return unicode();
+}
+
+
+DeprecatedString::~DeprecatedString()
+{
+ ASSERT(dataHandle);
+ ASSERT(dataHandle[0]->refCount != 0);
+
+ // 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 = dataHandle[0]->refCount == 1 && *dataHandle != shared_null;
+
+ // Copy our internal data if necessary, other strings still need it.
+ detachIfInternal();
+
+ // Remove our reference. This should always be the last reference
+ // if *dataHandle points to our internal DeprecatedStringData. If we just detached,
+ // this will remove the extra ref from the new handle.
+ dataHandle[0]->deref();
+
+ ASSERT(*dataHandle != &internalData || dataHandle[0]->refCount == 0);
+
+ if (needToFreeHandle)
+ freeHandle(dataHandle);
+
+#ifndef NDEBUG
+ dataHandle = 0;
+#endif
+}
+
+
+DeprecatedString::DeprecatedString()
+{
+ internalData.deref();
+ dataHandle = makeSharedNullHandle();
+ dataHandle[0]->ref();
+}
+
+
+// Careful, just used by DeprecatedConstString
+DeprecatedString::DeprecatedString(DeprecatedStringData *constData, bool /*dummy*/)
+{
+ internalData.deref();
+ dataHandle = allocateHandle();
+ *dataHandle = constData;
+
+ // The DeprecatedConstString constructor allocated the DeprecatedStringData.
+ constData->_isHeapAllocated = 1;
+}
+
+
+DeprecatedString::DeprecatedString(DeprecatedChar qc)
+{
+ dataHandle = allocateHandle();
+
+ // Copy the DeprecatedChar.
+ if (IS_ASCII_QCHAR(qc)) {
+ char c = qc.unicode();
+ *dataHandle = &internalData;
+ internalData.initialize( &c, 1 );
+ }
+ else {
+ *dataHandle = &internalData;
+ internalData.initialize( &qc, 1 );
+ }
+}
+
+DeprecatedString::DeprecatedString(const DeprecatedChar *unicode, unsigned length)
+{
+ if (!unicode || !length) {
+ internalData.deref();
+ dataHandle = makeSharedNullHandle();
+ dataHandle[0]->ref();
+ } else {
+ dataHandle = allocateHandle();
+
+ // Copy the DeprecatedChar *
+ *dataHandle = &internalData;
+ internalData.initialize(unicode, length);
+ }
+}
+
+DeprecatedString::DeprecatedString(const char *chs)
+{
+ if (chs) {
+ internalData.initialize(chs,strlen(chs));
+ dataHandle = allocateHandle();
+ *dataHandle = &internalData;
+ } else {
+ internalData.deref();
+ dataHandle = makeSharedNullHandle();
+ dataHandle[0]->ref();
+ }
+}
+
+DeprecatedString::DeprecatedString(const char *chs, int len)
+{
+ dataHandle = allocateHandle();
+ *dataHandle = &internalData;
+ internalData.initialize(chs,len);
+}
+
+DeprecatedString::DeprecatedString(const DeprecatedString &qs) : dataHandle(qs.dataHandle)
+{
+ internalData.deref();
+ dataHandle[0]->ref();
+}
+
+DeprecatedString &DeprecatedString::operator=(const DeprecatedString &qs)
+{
+ if (this == &qs)
+ return *this;
+
+ // 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;
+
+ qs.dataHandle[0]->ref();
+ deref();
+
+ if (needToFreeHandle)
+ freeHandle(dataHandle);
+
+ dataHandle = qs.dataHandle;
+
+ return *this;
+}
+
+DeprecatedString &DeprecatedString::operator=(const DeprecatedCString &qcs)
+{
+ return setLatin1(qcs);
+}
+
+DeprecatedString &DeprecatedString::operator=(const char *chs)
+{
+ return setLatin1(chs);
+}
+
+DeprecatedString &DeprecatedString::operator=(DeprecatedChar qc)
+{
+ return *this = DeprecatedString(qc);
+}
+
+DeprecatedString &DeprecatedString::operator=(char ch)
+{
+ return *this = DeprecatedString(DeprecatedChar(ch));
+}
+
+DeprecatedChar DeprecatedString::at(unsigned i) const
+{
+ DeprecatedStringData *thisData = *dataHandle;
+
+ if (i >= thisData->_length)
+ return 0;
+
+ if (thisData->_isAsciiValid) {
+ return thisData->_ascii[i];
+ }
+
+ ASSERT(thisData->_isUnicodeValid);
+ return thisData->_unicode[i];
+}
+
+int DeprecatedString::compare(const DeprecatedString& s) const
+{
+ if (dataHandle[0]->_isAsciiValid && s.dataHandle[0]->_isAsciiValid)
+ return strcmp(ascii(), s.ascii());
+ return ucstrcmp(*this,s);
+}
+
+int DeprecatedString::compare(const char *chs) const
+{
+ if (!chs)
+ return isEmpty() ? 0 : 1;
+ DeprecatedStringData *d = dataHandle[0];
+ if (d->_isAsciiValid)
+ return strcmp(ascii(), chs);
+ const DeprecatedChar *s = unicode();
+ unsigned len = d->_length;
+ for (unsigned i = 0; i != len; ++i) {
+ char c2 = chs[i];
+ if (!c2)
+ return 1;
+ DeprecatedChar c1 = s[i];
+ if (c1.unicode() < c2)
+ return -1;
+ if (c1.unicode() > c2)
+ return 1;
+ }
+ return chs[len] ? -1 : 0;
+}
+
+bool DeprecatedString::startsWith( const DeprecatedString& s ) const
+{
+ if (dataHandle[0]->_isAsciiValid){
+ const char *asc = ascii();
+
+ for ( int i =0; i < (int) s.dataHandle[0]->_length; i++ ) {
+ if ( i >= (int) dataHandle[0]->_length || asc[i] != s[i] )
+ return false;
+ }
+ }
+ else if (dataHandle[0]->_isUnicodeValid){
+ const DeprecatedChar *uni = unicode();
+
+ for ( int i =0; i < (int) s.dataHandle[0]->_length; i++ ) {
+ if ( i >= (int) dataHandle[0]->_length || uni[i] != s[i] )
+ return false;
+ }
+ }
+ else
+ FATAL("invalid character cache");
+
+ return true;
+}
+
+bool DeprecatedString::startsWith(const char *prefix) const
+{
+ DeprecatedStringData *data = *dataHandle;
+
+ unsigned prefixLength = strlen(prefix);
+ if (data->_isAsciiValid) {
+ return strncmp(prefix, data->_ascii, prefixLength) == 0;
+ } else {
+ ASSERT(data->_isUnicodeValid);
+ if (prefixLength > data->_length) {
+ return false;
+ }
+ const DeprecatedChar *uni = data->_unicode;
+ for (unsigned i = 0; i < prefixLength; ++i) {
+ if (uni[i] != prefix[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
+
+bool DeprecatedString::startsWith(const char *prefix, bool caseSensitive) const
+{
+ if (caseSensitive) {
+ return startsWith(prefix);
+ }
+
+ DeprecatedStringData *data = *dataHandle;
+
+ unsigned prefixLength = strlen(prefix);
+ if (data->_isAsciiValid) {
+ return strncasecmp(prefix, data->_ascii, prefixLength) == 0;
+ } else {
+ ASSERT(data->_isUnicodeValid);
+ if (prefixLength > data->_length) {
+ return false;
+ }
+ const DeprecatedChar *uni = data->_unicode;
+ for (unsigned i = 0; i < prefixLength; ++i) {
+ if (!equalCaseInsensitive(uni[i], prefix[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
+
+bool DeprecatedString::endsWith(const DeprecatedString& s) const
+{
+ const DeprecatedChar *uni = unicode();
+
+ int length = dataHandle[0]->_length;
+ int slength = s.dataHandle[0]->_length;
+ if (length < slength)
+ return false;
+
+ for (int i = length - slength, j = 0; i < length; i++, j++) {
+ if (uni[i] != s[j])
+ return false;
+ }
+
+ return true;
+}
+
+bool DeprecatedString::isNull() const
+{
+ return dataHandle == shared_null_handle;
+}
+
+int DeprecatedString::find(DeprecatedChar qc, int index) const
+{
+ if (dataHandle[0]->_isAsciiValid) {
+ if (!IS_ASCII_QCHAR(qc))
+ return -1;
+ return find(qc.unicode(), index);
+ }
+ return find(DeprecatedString(qc), index, true);
+}
+
+int DeprecatedString::find(char ch, int index) const
+{
+ if (dataHandle[0]->_isAsciiValid){
+ const char *cp = ascii();
+
+ if ( index < 0 )
+ index += dataHandle[0]->_length;
+
+ if (index >= (int)dataHandle[0]->_length)
+ return -1;
+
+ for (int i = index; i < (int)dataHandle[0]->_length; i++)
+ if (cp[i] == ch)
+ return i;
+ }
+ else if (dataHandle[0]->_isUnicodeValid)
+ return find(DeprecatedChar(ch), index, true);
+ else
+ FATAL("invalid character cache");
+
+ return -1;
+}
+
+int DeprecatedString::find(const DeprecatedString &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 sum of str with that of
+ a part of this DeprecatedString. Only if that matches, we call memcmp
+ or ucstrnicmp.
+
+ The hash value of a string is the sum of the cells of its
+ QChars.
+ */
+ if ( index < 0 )
+ index += dataHandle[0]->_length;
+ int lstr = str.dataHandle[0]->_length;
+ int lthis = dataHandle[0]->_length - index;
+ if ( (unsigned)lthis > dataHandle[0]->_length )
+ return -1;
+ int delta = lthis - lstr;
+ if ( delta < 0 )
+ return -1;
+
+ const DeprecatedChar *uthis = unicode() + index;
+ const DeprecatedChar *ustr = str.unicode();
+ unsigned hthis = 0;
+ unsigned hstr = 0;
+ int i;
+ if ( caseSensitive ) {
+ for ( i = 0; i < lstr; i++ ) {
+ hthis += uthis[i].unicode();
+ hstr += ustr[i].unicode();
+ }
+ i = 0;
+ while ( true ) {
+ if ( hthis == hstr && memcmp(uthis + i, ustr, lstr * sizeof(DeprecatedChar)) == 0 )
+ return index + i;
+ if ( i == delta )
+ return -1;
+ hthis += uthis[i + lstr].unicode();
+ hthis -= uthis[i].unicode();
+ i++;
+ }
+ } else {
+ for ( i = 0; i < lstr; i++ ) {
+ hthis += toASCIILower(uthis[i].unicode());
+ hstr += toASCIILower(ustr[i].unicode());
+ }
+ i = 0;
+ while ( true ) {
+ if ( hthis == hstr && equalCaseInsensitive(uthis + i, ustr, lstr) )
+ return index + i;
+ if ( i == delta )
+ return -1;
+ hthis += toASCIILower(uthis[i + lstr].unicode());
+ hthis -= toASCIILower(uthis[i].unicode());
+ i++;
+ }
+ }
+}
+
+// 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 DeprecatedString::find(const char *chs, int index, bool caseSensitive) const
+{
+ if (!chs || index < 0)
+ return -1;
+
+ DeprecatedStringData *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 {
+ unsigned char lc = toASCIILower(*chs);
+ do {
+ if (toASCIILower(*++ptr) == lc && equalCaseInsensitive(ptr + 1, chsPlusOne, chsLengthMinusOne)) {
+ return data->_length - chsLength - n + 1;
+ }
+ } while (--n);
+ }
+ } else {
+ ASSERT(data->_isUnicodeValid);
+
+ const DeprecatedChar *ptr = data->_unicode + index - 1;
+ if (caseSensitive) {
+ DeprecatedChar c = *chs;
+ do {
+ if (*++ptr == c && equal(ptr + 1, chsPlusOne, chsLengthMinusOne)) {
+ return data->_length - chsLength - n + 1;
+ }
+ } while (--n);
+ } else {
+ unsigned char lc = toASCIILower(*chs);
+ do {
+ if (toASCIILower((++ptr)->unicode()) == lc && equalCaseInsensitive(ptr + 1, chsPlusOne, chsLengthMinusOne)) {
+ return data->_length - chsLength - n + 1;
+ }
+ } while (--n);
+ }
+ }
+
+ return -1;
+}
+
+int DeprecatedString::find(const RegularExpression &qre, int index) const
+{
+ if ( index < 0 )
+ index += dataHandle[0]->_length;
+ return qre.match( *this, index );
+}
+
+int DeprecatedString::findRev(char ch, int index) const
+{
+ if (dataHandle[0]->_isAsciiValid){
+ const char *cp = ascii();
+
+ if (index < 0)
+ index += dataHandle[0]->_length;
+ if (index > (int)dataHandle[0]->_length)
+ return -1;
+
+ for (int i = index; i >= 0; i--) {
+ if (cp[i] == ch)
+ return i;
+ }
+ }
+ else if (dataHandle[0]->_isUnicodeValid)
+ return findRev(DeprecatedString(DeprecatedChar(ch)), index);
+ else
+ FATAL("invalid character cache");
+
+ return -1;
+}
+
+int DeprecatedString::findRev(const char *chs, int index) const
+{
+ return findRev(DeprecatedString(chs), index);
+}
+
+int DeprecatedString::findRev( const DeprecatedString& str, int index, bool cs ) const
+{
+ // FIXME, use the first character algorithm
+ /*
+ See DeprecatedString::find() for explanations.
+ */
+ int lthis = dataHandle[0]->_length;
+ if ( index < 0 )
+ index += lthis;
+
+ int lstr = str.dataHandle[0]->_length;
+ int delta = lthis - lstr;
+ if ( index < 0 || index > lthis || delta < 0 )
+ return -1;
+ if ( index > delta )
+ index = delta;
+
+ const DeprecatedChar *uthis = unicode();
+ const DeprecatedChar *ustr = str.unicode();
+ unsigned hthis = 0;
+ unsigned hstr = 0;
+ int i;
+ if ( cs ) {
+ for ( i = 0; i < lstr; i++ ) {
+ hthis += uthis[index + i].unicode();
+ hstr += ustr[i].unicode();
+ }
+ i = index;
+ while ( true ) {
+ if ( hthis == hstr && memcmp(uthis + i, ustr, lstr * sizeof(DeprecatedChar)) == 0 )
+ return i;
+ if ( i == 0 )
+ return -1;
+ i--;
+ hthis -= uthis[i + lstr].unicode();
+ hthis += uthis[i].unicode();
+ }
+ } else {
+ for ( i = 0; i < lstr; i++ ) {
+ hthis += uthis[index + i].lower().unicode();
+ hstr += ustr[i].lower().unicode();
+ }
+ i = index;
+ while ( true ) {
+ if ( hthis == hstr && equalCaseInsensitive(uthis + i, ustr, lstr) )
+ return i;
+ if ( i == 0 )
+ return -1;
+ i--;
+ hthis -= uthis[i + lstr].lower().unicode();
+ hthis += uthis[i].lower().unicode();
+ }
+ }
+
+ // Should never get here.
+ return -1;
+}
+
+
+int DeprecatedString::contains(DeprecatedChar c, bool cs) const
+{
+ int count = 0;
+
+ DeprecatedStringData *data = *dataHandle;
+
+ if (data->_isAsciiValid) {
+ if (!IS_ASCII_QCHAR(c))
+ return 0;
+ 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
+ unsigned char lc = toASCIILower(ac);
+ while (n--) {
+ count += toASCIILower(*cPtr++) == lc;
+ }
+ }
+ } else {
+ ASSERT(data->_isUnicodeValid);
+ const DeprecatedChar *uc = data->_unicode;
+ int n = data->_length;
+ if (cs) { // case sensitive
+ while ( n-- )
+ count += *uc++ == c;
+ } else { // case insensitive
+ ::UChar lc = toASCIILower(c.unicode());
+ while (n--) {
+ count += toASCIILower(uc->unicode()) == lc;
+ uc++;
+ }
+ }
+ }
+
+ return count;
+}
+
+int DeprecatedString::contains(char ch) const
+{
+ return contains(DeprecatedChar(ch), true);
+}
+
+int DeprecatedString::contains(const char *str, bool caseSensitive) const
+{
+ if (!str)
+ return 0;
+
+ int len = strlen(str);
+ char c = *str;
+
+ DeprecatedStringData *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 {
+ char lc = toASCIILower(c);
+ do {
+ count += toASCIILower(*p) == lc && equalCaseInsensitive(p + 1, str + 1, len - 1);
+ p++;
+ } while (--n);
+ }
+ } else {
+ ASSERT(data->_isUnicodeValid);
+ const DeprecatedChar *p = data->_unicode;
+ if (caseSensitive) {
+ do {
+ count += *p == c && equal(p + 1, str + 1, len - 1);
+ p++;
+ } while (--n);
+ } else {
+ unsigned char lc = toASCIILower(c);
+ do {
+ count += toASCIILower(p->unicode()) == lc && equalCaseInsensitive(p + 1, str + 1, len - 1);
+ p++;
+ } while (--n);
+ }
+ }
+
+ return count;
+}
+
+int DeprecatedString::contains(const DeprecatedString &str, bool caseSensitive) const
+{
+ if (str.isEmpty())
+ return 0;
+
+ const DeprecatedChar *strP = str.unicode();
+ int len = str.dataHandle[0]->_length;
+ DeprecatedChar c = *strP;
+
+ const DeprecatedChar *p = unicode();
+ int n = dataHandle[0]->_length;
+
+ n -= len - 1;
+ if (n <= 0)
+ return 0;
+
+ int count = 0;
+
+ if (caseSensitive) {
+ int byteCount = len * sizeof(DeprecatedChar);
+ 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 DeprecatedString::isAllASCII() const
+{
+ DeprecatedStringData *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 {
+ ASSERT(data->_isUnicodeValid);
+ const DeprecatedChar *p = data->_unicode;
+ while (n--) {
+ if ((*p++).unicode() > 0x7F) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+bool DeprecatedString::isAllLatin1() const
+{
+ DeprecatedStringData *data = *dataHandle;
+
+ if (data->_isAsciiValid) {
+ return true;
+ }
+
+ ASSERT(data->_isUnicodeValid);
+ int n = data->_length;
+ const DeprecatedChar *p = data->_unicode;
+ while (n--) {
+ if ((*p++).unicode() > 0xFF) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool DeprecatedString::hasFastLatin1() const
+{
+ DeprecatedStringData *data = *dataHandle;
+ return data->_isAsciiValid;
+}
+
+void DeprecatedString::copyLatin1(char *buffer, unsigned position, unsigned maxLength) const
+{
+ DeprecatedStringData *data = *dataHandle;
+
+ int length = data->_length;
+ if (position > static_cast<unsigned>(length))
+ length = 0;
+ else
+ length -= position;
+ if (static_cast<unsigned>(length) > maxLength)
+ length = static_cast<int>(maxLength);
+
+ buffer[length] = 0;
+
+ if (data->_isAsciiValid) {
+ memcpy(buffer, data->_ascii + position, length);
+ return;
+ }
+
+ ASSERT(data->_isUnicodeValid);
+ const DeprecatedChar* uc = data->_unicode + position;
+ while (length--)
+ *buffer++ = (*uc++).latin1();
+}
+
+short DeprecatedString::toShort(bool *ok, int base) const
+{
+ int v = toInt(ok, base);
+ short sv = v;
+ if (sv != v) {
+ if (ok)
+ *ok = false;
+ return 0;
+ }
+ return sv;
+}
+
+unsigned short DeprecatedString::toUShort(bool *ok, int base) const
+{
+ unsigned v = toUInt(ok, base);
+ unsigned short sv = v;
+ if (sv != v) {
+ if (ok)
+ *ok = false;
+ return 0;
+ }
+ return sv;
+}
+
+template <typename IntegralType> static inline
+IntegralType toIntegralType(const DeprecatedString& string, bool *ok, int base)
+{
+ static const IntegralType integralMax = std::numeric_limits<IntegralType>::max();
+ static const bool isSigned = std::numeric_limits<IntegralType>::is_signed;
+ const DeprecatedChar* p = string.unicode();
+ const IntegralType maxMultiplier = integralMax / base;
+
+ int length = string.length();
+ IntegralType value = 0;
+ bool isOk = false;
+ bool isNegative = false;
+
+ if (!p)
+ goto bye;
+
+ // skip leading whitespace
+ while (length && p->isSpace()) {
+ length--;
+ p++;
+ }
+
+ if (isSigned && length && *p == '-') {
+ length--;
+ p++;
+ isNegative = true;
+ } else if (length && *p == '+') {
+ length--;
+ p++;
+ }
+
+ if (!length || !isCharacterAllowedInBase(*p, base))
+ goto bye;
+
+ while (length && isCharacterAllowedInBase(*p, base)) {
+ length--;
+ IntegralType digitValue;
+ ::UChar c = p->unicode();
+ if (isASCIIDigit(c))
+ digitValue = c - '0';
+ else if (c >= 'a')
+ digitValue = c - 'a' + 10;
+ else
+ digitValue = c - 'A' + 10;
+
+ if (value > maxMultiplier || (value == maxMultiplier && digitValue > (integralMax % base) + isNegative))
+ goto bye;
+
+ value = base * value + digitValue;
+ p++;
+ }
+
+ if (isNegative)
+ value = -value;
+
+ // skip trailing space
+ while (length && p->isSpace()) {
+ length--;
+ p++;
+ }
+
+ if (!length)
+ isOk = true;
+bye:
+ if (ok)
+ *ok = isOk;
+ return isOk ? value : 0;
+}
+
+int DeprecatedString::toInt(bool *ok, int base) const
+{
+ return toIntegralType<int>(*this, ok, base);
+}
+
+int64_t DeprecatedString::toInt64(bool *ok, int base) const
+{
+ return toIntegralType<int64_t>(*this, ok, base);
+}
+
+unsigned DeprecatedString::toUInt(bool *ok, int base) const
+{
+ return toIntegralType<unsigned>(*this, ok, base);
+}
+
+uint64_t DeprecatedString::toUInt64(bool *ok, int base) const
+{
+ return toIntegralType<uint64_t>(*this, ok, base);
+}
+
+double DeprecatedString::toDouble(bool *ok) const
+{
+ if (isEmpty()) {
+ if (ok)
+ *ok = false;
+ return 0;
+ }
+ const char *s = latin1();
+ char *end;
+ double val = kjs_strtod(s, &end);
+ if (ok)
+ *ok = end == 0 || *end == '\0';
+ return val;
+}
+
+float DeprecatedString::toFloat(bool* ok) const
+{
+ // FIXME: this will return ok even when the string does not fit into a float
+ return narrowPrecisionToFloat(toDouble(ok));
+}
+
+DeprecatedString DeprecatedString::left(unsigned len) const
+{
+ return mid(0, len);
+}
+
+DeprecatedString DeprecatedString::right(unsigned len) const
+{
+ return mid(length() - len, len);
+}
+
+DeprecatedString DeprecatedString::mid(unsigned start, unsigned len) const
+{
+ if (dataHandle && *dataHandle) {
+ DeprecatedStringData &data = **dataHandle;
+
+ // clip length
+ if (start >= data._length)
+ return DeprecatedString();
+
+ if (len > data._length - start)
+ len = data._length - start;
+
+ if (len == 0)
+ return DeprecatedString();
+
+ if (start == 0 && len == data._length)
+ return *this;
+
+ ASSERT(start + len >= start && // unsigned overflow
+ start + len <= data._length); // past the end
+
+ // ascii case
+ if (data._isAsciiValid && data._ascii)
+ return DeprecatedString(&data._ascii[start] , len);
+
+ // unicode case
+ if (data._isUnicodeValid && data._unicode)
+ return DeprecatedString(&data._unicode[start], len);
+ }
+
+ // degenerate case
+ return DeprecatedString();
+}
+
+DeprecatedString DeprecatedString::copy() const
+{
+ // does not need to be a deep copy
+ return DeprecatedString(*this);
+}
+
+DeprecatedString DeprecatedString::lower() const
+{
+ DeprecatedString s(*this);
+ DeprecatedStringData *d = *s.dataHandle;
+ int l = d->_length;
+ if (l) {
+ bool detached = false;
+ if (d->_isAsciiValid) {
+ char *p = d->_ascii;
+ while (l--) {
+ char c = *p;
+ // FIXME: Doesn't work for 0x80-0xFF.
+ if (c >= 'A' && c <= 'Z') {
+ if (!detached) {
+ s.detach();
+ d = *s.dataHandle;
+ p = d->_ascii + d->_length - l - 1;
+ detached = true;
+ }
+ *p = c + ('a' - 'A');
+ }
+ p++;
+ }
+ }
+ else {
+ ASSERT(d->_isUnicodeValid);
+ DeprecatedChar *p = d->_unicode;
+ while (l--) {
+ DeprecatedChar c = *p;
+ // FIXME: Doesn't work for 0x80-0xFF.
+ if (IS_ASCII_QCHAR(c)) {
+ if (c.unicode() >= 'A' && c.unicode() <= 'Z') {
+ if (!detached) {
+ s.detach();
+ d = *s.dataHandle;
+ p = d->_unicode + d->_length - l - 1;
+ detached = true;
+ }
+ *p = c.unicode() + ('a' - 'A');
+ }
+ } else {
+ DeprecatedChar clower = c.lower();
+ if (clower != c) {
+ if (!detached) {
+ s.detach();
+ d = *s.dataHandle;
+ p = d->_unicode + d->_length - l - 1;
+ detached = true;
+ }
+ *p = clower;
+ }
+ }
+ p++;
+ }
+ }
+ }
+ return s;
+}
+
+DeprecatedString DeprecatedString::stripWhiteSpace() const
+{
+ if ( isEmpty() ) // nothing to do
+ return *this;
+ if ( !at(0).isSpace() && !at(dataHandle[0]->_length-1).isSpace() )
+ return *this;
+
+ int start = 0;
+ int end = dataHandle[0]->_length - 1;
+
+ DeprecatedString result = fromLatin1("");
+ while ( start<=end && at(start).isSpace() ) // skip white space from start
+ start++;
+ if ( start > end ) { // only white space
+ return result;
+ }
+ while ( end && at(end).isSpace() ) // skip white space from end
+ end--;
+ int l = end - start + 1;
+
+ if (dataHandle[0]->_isAsciiValid){
+ result.setLength( l );
+ if ( l )
+ memcpy(const_cast<char*>(result.dataHandle[0]->ascii()), &ascii()[start], l );
+ }
+ else if (dataHandle[0]->_isUnicodeValid){
+ result.setLength( l );
+ if ( l )
+ memcpy(result.forceUnicode(), &unicode()[start], sizeof(DeprecatedChar)*l );
+ }
+ else
+ FATAL("invalid character cache");
+ return result;
+}
+
+DeprecatedString DeprecatedString::simplifyWhiteSpace() const
+{
+ if ( isEmpty() ) // nothing to do
+ return *this;
+
+ DeprecatedString result;
+
+ if (dataHandle[0]->_isAsciiValid){
+ result.setLength( dataHandle[0]->_length );
+ const char *from = ascii();
+ const char *fromend = from + dataHandle[0]->_length;
+ int outc=0;
+
+ char *to = const_cast<char*>(result.ascii());
+ while ( true ) {
+ while ( from!=fromend && DeprecatedChar(*from).isSpace() )
+ from++;
+ while ( from!=fromend && !DeprecatedChar(*from).isSpace() )
+ to[outc++] = *from++;
+ if ( from!=fromend )
+ to[outc++] = ' ';
+ else
+ break;
+ }
+ if ( outc > 0 && to[outc-1] == ' ' )
+ outc--;
+ result.truncate( outc );
+ }
+ else if (dataHandle[0]->_isUnicodeValid){
+ result.setLength( dataHandle[0]->_length );
+ const DeprecatedChar *from = unicode();
+ const DeprecatedChar *fromend = from + dataHandle[0]->_length;
+ int outc=0;
+
+ DeprecatedChar *to = result.forceUnicode();
+ while ( true ) {
+ while ( from!=fromend && from->isSpace() )
+ from++;
+ while ( from!=fromend && !from->isSpace() )
+ to[outc++] = *from++;
+ if ( from!=fromend )
+ to[outc++] = ' ';
+ else
+ break;
+ }
+ if ( outc > 0 && to[outc-1] == ' ' )
+ outc--;
+ result.truncate( outc );
+ }
+ else
+ FATAL("invalid character cache");
+
+ return result;
+}
+
+void DeprecatedString::deref()
+{
+ dataHandle[0]->deref();
+}
+
+
+DeprecatedString &DeprecatedString::setUnicode(const DeprecatedChar *uni, unsigned len)
+{
+ 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;
+
+ if (len == 0) {
+ deref();
+ if (needToFreeHandle)
+ freeHandle(dataHandle);
+ dataHandle = makeSharedNullHandle();
+ dataHandle[0]->ref();
+ } else if (len > dataHandle[0]->_maxUnicode || dataHandle[0]->refCount != 1 || !dataHandle[0]->_isUnicodeValid) {
+ deref();
+ if (needToFreeHandle)
+ freeHandle(dataHandle);
+ dataHandle = allocateHandle();
+ *dataHandle = new DeprecatedStringData(uni, len);
+ dataHandle[0]->_isHeapAllocated = 1;
+ } else {
+ if ( uni )
+ memcpy( (void *)unicode(), uni, sizeof(DeprecatedChar)*len );
+ dataHandle[0]->_length = len;
+ dataHandle[0]->_isAsciiValid = 0;
+ }
+
+ return *this;
+}
+
+
+DeprecatedString &DeprecatedString::setLatin1(const char *str, int len)
+{
+ if ( str == 0 )
+ return setUnicode(0,0);
+ if ( len < 0 )
+ len = strlen(str);
+
+ 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;
+
+ if (len+1 > (int)dataHandle[0]->_maxAscii || dataHandle[0]->refCount != 1 || !dataHandle[0]->_isAsciiValid) {
+ deref();
+ if (needToFreeHandle)
+ freeHandle(dataHandle);
+ dataHandle = allocateHandle();
+ *dataHandle = new DeprecatedStringData(str,len);
+ dataHandle[0]->_isHeapAllocated = 1;
+ } else {
+ strcpy(const_cast<char*>(ascii()), str );
+ dataHandle[0]->_length = len;
+ dataHandle[0]->_isUnicodeValid = 0;
+ }
+ return *this;
+}
+
+DeprecatedString &DeprecatedString::setNum(short n)
+{
+ return format("%d", n);
+}
+
+DeprecatedString &DeprecatedString::setNum(unsigned short n)
+{
+ return format("%u", n);
+}
+
+DeprecatedString &DeprecatedString::setNum(int n)
+{
+ return format("%d", n);
+}
+
+DeprecatedString &DeprecatedString::setNum(unsigned n)
+{
+ return format("%u", n);
+}
+
+DeprecatedString &DeprecatedString::setNum(long n)
+{
+ return format("%ld", n);
+}
+
+DeprecatedString &DeprecatedString::setNum(unsigned long n)
+{
+ return format("%lu", n);
+}
+
+DeprecatedString &DeprecatedString::setNum(double n)
+{
+ return format("%.6lg", n);
+}
+
+DeprecatedString &DeprecatedString::format(const char *format, ...)
+{
+ // FIXME: this needs the same windows compat fixes as String::format
+
+ va_list args;
+ va_start(args, format);
+
+ // Do the format once to get the length.
+#if COMPILER(MSVC)
+ int result = _vscprintf(format, args);
+#else
+ char ch;
+ int result = vsnprintf(&ch, 1, format, args);
+#endif
+
+ // Handle the empty string case to simplify the code below.
+ if (result <= 0) { // POSIX returns 0 in error; Windows returns a negative number.
+ setUnicode(0, 0);
+ return *this;
+ }
+ unsigned len = result;
+
+ // Arrange for storage for the resulting string.
+ 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 = allocateHandle();
+ *dataHandle = new DeprecatedStringData((char *)0, len);
+ dataHandle[0]->_isHeapAllocated = 1;
+ } else {
+ dataHandle[0]->_length = len;
+ dataHandle[0]->_isUnicodeValid = 0;
+ }
+
+ // Now do the formatting again, guaranteed to fit.
+ vsprintf(const_cast<char*>(ascii()), format, args);
+
+ va_end(args);
+ return *this;
+}
+
+DeprecatedString &DeprecatedString::prepend(const DeprecatedString &qs)
+{
+ return insert(0, qs);
+}
+
+DeprecatedString &DeprecatedString::prepend(const DeprecatedChar *characters, unsigned length)
+{
+ return insert(0, characters, length);
+}
+
+DeprecatedString &DeprecatedString::append(const DeprecatedString &qs)
+{
+ return insert(dataHandle[0]->_length, qs);
+}
+
+DeprecatedString &DeprecatedString::append(const char *characters, unsigned length)
+{
+ return insert(dataHandle[0]->_length, characters, length);
+}
+
+DeprecatedString &DeprecatedString::append(const DeprecatedChar *characters, unsigned length)
+{
+ return insert(dataHandle[0]->_length, characters, length);
+}
+
+DeprecatedString &DeprecatedString::insert(unsigned index, const char *insertChars, unsigned insertLength)
+{
+ if (insertLength == 0)
+ return *this;
+
+ detach();
+
+ if (dataHandle[0]->_isAsciiValid){
+ unsigned originalLength = dataHandle[0]->_length;
+ char *targetChars;
+
+ // Ensure that we have enough space.
+ setLength (originalLength + insertLength);
+ targetChars = const_cast<char*>(ascii());
+
+ // Move tail to make space for inserted characters.
+ memmove (targetChars+index+insertLength, targetChars+index, originalLength-index);
+
+ // Insert characters.
+ memcpy (targetChars+index, insertChars, insertLength);
+
+ dataHandle[0]->_isUnicodeValid = 0;
+ }
+ else if (dataHandle[0]->_isUnicodeValid){
+ unsigned originalLength = dataHandle[0]->_length;
+ DeprecatedChar *targetChars;
+
+ // Ensure that we have enough space.
+ setLength (originalLength + insertLength);
+ targetChars = (DeprecatedChar *)unicode();
+
+ // Move tail to make space for inserted characters.
+ memmove (targetChars+(index+insertLength), targetChars+index, (originalLength-index)*sizeof(DeprecatedChar));
+
+ // Insert characters.
+ unsigned i = insertLength;
+ DeprecatedChar *target = targetChars+index;
+
+ while (i--)
+ *target++ = *insertChars++;
+ }
+ else
+ FATAL("invalid character cache");
+
+ return *this;
+}
+
+
+DeprecatedString &DeprecatedString::insert(unsigned index, const DeprecatedString &qs)
+{
+ if (qs.dataHandle[0]->_length == 0)
+ return *this;
+
+ if (dataHandle[0]->_isAsciiValid && qs.isAllLatin1()) {
+ insert(index, qs.latin1(), qs.length());
+ }
+ else {
+ unsigned insertLength = qs.dataHandle[0]->_length;
+ unsigned originalLength = dataHandle[0]->_length;
+
+ forceUnicode();
+
+ // Ensure that we have enough space.
+ setLength (originalLength + insertLength);
+ DeprecatedChar *targetChars = const_cast<DeprecatedChar *>(unicode());
+
+ // Move tail to make space for inserted characters.
+ memmove (targetChars+(index+insertLength), targetChars+index, (originalLength-index)*sizeof(DeprecatedChar));
+
+ // Insert characters.
+ if (qs.dataHandle[0]->_isAsciiValid){
+ unsigned i = insertLength;
+ DeprecatedChar *target = targetChars+index;
+ char *a = const_cast<char*>(qs.ascii());
+
+ while (i--)
+ *target++ = *a++;
+ }
+ else {
+ DeprecatedChar *insertChars = (DeprecatedChar *)qs.unicode();
+ memcpy (targetChars+index, insertChars, insertLength*sizeof(DeprecatedChar));
+ }
+
+ dataHandle[0]->_isAsciiValid = 0;
+ }
+
+ return *this;
+}
+
+
+DeprecatedString &DeprecatedString::insert(unsigned index, const DeprecatedChar *insertChars, unsigned insertLength)
+{
+ if (insertLength == 0)
+ return *this;
+
+ forceUnicode();
+
+ unsigned originalLength = dataHandle[0]->_length;
+ setLength(originalLength + insertLength);
+
+ DeprecatedChar *targetChars = const_cast<DeprecatedChar *>(unicode());
+ if (originalLength > index) {
+ memmove(targetChars + index + insertLength, targetChars + index, (originalLength - index) * sizeof(DeprecatedChar));
+ }
+ memcpy(targetChars + index, insertChars, insertLength * sizeof(DeprecatedChar));
+
+ return *this;
+}
+
+
+DeprecatedString &DeprecatedString::insert(unsigned index, DeprecatedChar qc)
+{
+ detach();
+
+ if (dataHandle[0]->_isAsciiValid && IS_ASCII_QCHAR(qc)){
+ unsigned originalLength = dataHandle[0]->_length;
+ char insertChar = qc.unicode();
+ char *targetChars;
+
+ // Ensure that we have enough space.
+ setLength (originalLength + 1);
+ targetChars = const_cast<char*>(ascii());
+
+ // Move tail to make space for inserted character.
+ memmove (targetChars+index+1, targetChars+index, originalLength-index);
+
+ // Insert character.
+ targetChars[index] = insertChar;
+ targetChars[dataHandle[0]->_length] = 0;
+
+ dataHandle[0]->_isUnicodeValid = 0;
+ }
+ else {
+ unsigned originalLength = dataHandle[0]->_length;
+
+ forceUnicode();
+
+ // Ensure that we have enough space.
+ setLength (originalLength + 1);
+ DeprecatedChar *targetChars = const_cast<DeprecatedChar *>(unicode());
+
+ // Move tail to make space for inserted character.
+ memmove (targetChars+(index+1), targetChars+index, (originalLength-index)*sizeof(DeprecatedChar));
+
+ targetChars[index] = qc;
+ }
+
+ return *this;
+}
+
+
+DeprecatedString &DeprecatedString::insert(unsigned index, char ch)
+{
+ detach();
+
+ if (dataHandle[0]->_isAsciiValid) {
+ unsigned originalLength = dataHandle[0]->_length;
+ char *targetChars;
+
+ // Ensure that we have enough space.
+ setLength (originalLength + 1);
+ targetChars = const_cast<char*>(ascii());
+
+ // Move tail to make space for inserted character.
+ memmove (targetChars+index+1, targetChars+index, originalLength-index);
+
+ // Insert character.
+ targetChars[index] = ch;
+ targetChars[dataHandle[0]->_length] = 0;
+
+ dataHandle[0]->_isUnicodeValid = 0;
+ }
+ else if (dataHandle[0]->_isUnicodeValid){
+ unsigned originalLength = dataHandle[0]->_length;
+ DeprecatedChar *targetChars;
+
+ // Ensure that we have enough space.
+ setLength (originalLength + 1);
+ targetChars = (DeprecatedChar *)unicode();
+
+ // Move tail to make space for inserted character.
+ memmove (targetChars+(index+1), targetChars+index, (originalLength-index)*sizeof(DeprecatedChar));
+
+ targetChars[index] = (DeprecatedChar)ch;
+ }
+ else
+ FATAL("invalid character cache");
+
+ return *this;
+}
+
+// Copy DeprecatedStringData if necessary. Must be called before the string data is mutated.
+void DeprecatedString::detach()
+{
+ DeprecatedStringData *oldData = *dataHandle;
+
+ if (oldData->refCount == 1 && oldData != shared_null)
+ return;
+
+ // Copy data for this string so we can safely mutate it.
+ DeprecatedStringData *newData;
+ if (oldData->_isAsciiValid)
+ newData = new DeprecatedStringData(oldData->ascii(), oldData->_length);
+ else
+ newData = new DeprecatedStringData(oldData->unicode(), oldData->_length);
+ newData->_isHeapAllocated = 1;
+
+ // 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 DeprecatedString::detachAndDiscardCharacters()
+{
+ // Missing optimization: Don't bother copying the old data if we detach.
+ detach();
+}
+
+DeprecatedString &DeprecatedString::remove(unsigned index, unsigned len)
+{
+ unsigned olen = dataHandle[0]->_length;
+ if ( index >= olen ) {
+ // range problems
+ } 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();
+
+ if (dataHandle[0]->_isAsciiValid){
+ memmove( dataHandle[0]->ascii()+index, dataHandle[0]->ascii()+index+len,
+ sizeof(char)*(olen-index-len) );
+ setLength( olen-len );
+ dataHandle[0]->_isUnicodeValid = 0;
+ }
+ else if (dataHandle[0]->_isUnicodeValid){
+ memmove( dataHandle[0]->unicode()+index, dataHandle[0]->unicode()+index+len,
+ sizeof(DeprecatedChar)*(olen-index-len) );
+ setLength( olen-len );
+ }
+ else
+ FATAL("invalid character cache");
+ }
+ return *this;
+}
+
+DeprecatedString &DeprecatedString::replace(unsigned index, unsigned len, const DeprecatedString& str)
+{
+ return remove(index, len).insert(index, str);
+}
+
+DeprecatedString &DeprecatedString::replace(char pattern, const DeprecatedString &str)
+{
+ int slen = str.dataHandle[0]->_length;
+ int index = 0;
+ while ((index = find(pattern, index)) >= 0) {
+ replace(index, 1, str);
+ index += slen;
+ }
+ return *this;
+}
+
+DeprecatedString &DeprecatedString::replace(DeprecatedChar pattern, const DeprecatedString &str)
+{
+ int slen = str.dataHandle[0]->_length;
+ int index = 0;
+ while ((index = find(pattern, index)) >= 0) {
+ replace(index, 1, str);
+ index += slen;
+ }
+ return *this;
+}
+
+DeprecatedString &DeprecatedString::replace(const DeprecatedString &pattern, const DeprecatedString &str)
+{
+ if (pattern.isEmpty())
+ return *this;
+ int plen = pattern.dataHandle[0]->_length;
+ int slen = str.dataHandle[0]->_length;
+ int index = 0;
+ while ((index = find(pattern, index)) >= 0) {
+ replace(index, plen, str);
+ index += slen;
+ }
+ return *this;
+}
+
+
+DeprecatedString &DeprecatedString::replace(const RegularExpression &qre, const DeprecatedString &str)
+{
+ if ( isEmpty() )
+ return *this;
+ int index = 0;
+ int slen = str.dataHandle[0]->_length;
+ int len;
+ while ( index < (int)dataHandle[0]->_length ) {
+ index = qre.match( *this, index, &len);
+ if ( index >= 0 ) {
+ replace( index, len, str );
+ index += slen;
+ if ( !len )
+ break; // Avoid infinite loop on 0-length matches, e.g. [a-z]*
+ }
+ else
+ break;
+ }
+ return *this;
+}
+
+
+DeprecatedString &DeprecatedString::replace(DeprecatedChar oldChar, DeprecatedChar newChar)
+{
+ if (oldChar != newChar && find(oldChar) != -1) {
+ unsigned length = dataHandle[0]->_length;
+
+ detach();
+ if (dataHandle[0]->_isAsciiValid && IS_ASCII_QCHAR(newChar)) {
+ char *p = const_cast<char *>(ascii());
+ dataHandle[0]->_isUnicodeValid = 0;
+ char oldC = oldChar.unicode();
+ char newC = newChar.unicode();
+ for (unsigned i = 0; i != length; ++i) {
+ if (p[i] == oldC) {
+ p[i] = newC;
+ }
+ }
+ } else {
+ DeprecatedChar *p = const_cast<DeprecatedChar *>(unicode());
+ dataHandle[0]->_isAsciiValid = 0;
+ for (unsigned i = 0; i != length; ++i) {
+ if (p[i] == oldChar) {
+ p[i] = newChar;
+ }
+ }
+ }
+ }
+
+ return *this;
+}
+
+
+DeprecatedChar *DeprecatedString::forceUnicode()
+{
+ detach();
+ DeprecatedChar *result = const_cast<DeprecatedChar *>(unicode());
+ dataHandle[0]->_isAsciiValid = 0;
+ return result;
+}
+
+
+// Increase buffer size if necessary. Newly allocated
+// bytes will contain garbage.
+void DeprecatedString::setLength(unsigned newLen)
+{
+ 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);
+
+ if (dataHandle[0]->_isAsciiValid){
+ 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;
+ }
+
+ if (dataHandle[0]->_isUnicodeValid){
+ if (newLen > dataHandle[0]->_maxUnicode) {
+ dataHandle[0]->increaseUnicodeSize(newLen);
+ }
+ }
+
+ dataHandle[0]->_length = newLen;
+}
+
+
+void DeprecatedString::truncate(unsigned newLen)
+{
+ if ( newLen < dataHandle[0]->_length )
+ setLength( newLen );
+}
+
+void DeprecatedString::fill(DeprecatedChar qc, int len)
+{
+ detachAndDiscardCharacters();
+
+ // len == -1 means fill to string length.
+ if (len < 0) {
+ len = dataHandle[0]->_length;
+ }
+
+ if (len == 0) {
+ if (dataHandle != shared_null_handle) {
+ ASSERT(dataHandle[0]->refCount == 1);
+ deref();
+ freeHandle(dataHandle);
+ dataHandle = makeSharedNullHandle();
+ shared_null->ref();
+ }
+ } else {
+ if (dataHandle[0]->_isAsciiValid && IS_ASCII_QCHAR(qc)) {
+ setLength(len);
+ char *nd = const_cast<char*>(ascii());
+ while (len--)
+ *nd++ = qc.unicode();
+ dataHandle[0]->_isUnicodeValid = 0;
+ } else {
+ setLength(len);
+ DeprecatedChar *nd = forceUnicode();
+ while (len--)
+ *nd++ = qc;
+ }
+ }
+}
+
+DeprecatedString &DeprecatedString::append(DeprecatedChar qc)
+{
+ detach();
+
+ DeprecatedStringData *thisData = *dataHandle;
+ if (thisData->_isUnicodeValid && thisData->_length + 1 < thisData->_maxUnicode){
+ thisData->_unicode[thisData->_length] = qc;
+ thisData->_length++;
+ thisData->_isAsciiValid = 0;
+ return *this;
+ }
+ else if (thisData->_isAsciiValid && IS_ASCII_QCHAR(qc) && thisData->_length + 2 < thisData->_maxAscii){
+ thisData->_ascii[thisData->_length] = qc.unicode();
+ thisData->_length++;
+ thisData->_ascii[thisData->_length] = 0;
+ thisData->_isUnicodeValid = 0;
+ return *this;
+ }
+ return insert(thisData->_length, qc);
+}
+
+DeprecatedString &DeprecatedString::append(char ch)
+{
+ detach();
+
+ DeprecatedStringData *thisData = *dataHandle;
+ if (thisData->_isUnicodeValid && thisData->_length + 1 < thisData->_maxUnicode){
+ thisData->_unicode[thisData->_length] = (DeprecatedChar)ch;
+ thisData->_length++;
+ thisData->_isAsciiValid = 0;
+ return *this;
+ }
+ else if (thisData->_isAsciiValid && thisData->_length + 2 < thisData->_maxAscii){
+ thisData->_ascii[thisData->_length] = ch;
+ thisData->_length++;
+ thisData->_ascii[thisData->_length] = 0;
+ thisData->_isUnicodeValid = 0;
+ return *this;
+ }
+ return insert(thisData->_length, ch);
+}
+
+void DeprecatedString::reserve(unsigned length)
+{
+ if (length > dataHandle[0]->_maxUnicode) {
+ detach();
+ dataHandle[0]->increaseUnicodeSize(length);
+ }
+}
+
+bool operator==(const DeprecatedString &s1, const DeprecatedString &s2)
+{
+ if (s1.dataHandle[0]->_isAsciiValid && s2.dataHandle[0]->_isAsciiValid) {
+ return strcmp(s1.ascii(), s2.ascii()) == 0;
+ }
+ return s1.dataHandle[0]->_length == s2.dataHandle[0]->_length
+ && memcmp(s1.unicode(), s2.unicode(), s1.dataHandle[0]->_length * sizeof(DeprecatedChar)) == 0;
+}
+
+bool operator==(const DeprecatedString &s1, const char *chs)
+{
+ if (!chs)
+ return s1.isNull();
+ DeprecatedStringData *d = s1.dataHandle[0];
+ unsigned len = d->_length;
+ if (d->_isAsciiValid) {
+ const char *s = s1.ascii();
+ for (unsigned i = 0; i != len; ++i) {
+ char c = chs[i];
+ if (!c || s[i] != c)
+ return false;
+ }
+ } else {
+ const DeprecatedChar *s = s1.unicode();
+ for (unsigned i = 0; i != len; ++i) {
+ char c = chs[i];
+ if (!c || s[i] != c)
+ return false;
+ }
+ }
+ return chs[len] == '\0';
+}
+
+DeprecatedString operator+(const DeprecatedString &qs1, const DeprecatedString &qs2)
+{
+ return DeprecatedString(qs1) += qs2;
+}
+
+DeprecatedString operator+(const DeprecatedString &qs, const char *chs)
+{
+ return DeprecatedString(qs) += chs;
+}
+
+DeprecatedString operator+(const DeprecatedString &qs, DeprecatedChar qc)
+{
+ return DeprecatedString(qs) += qc;
+}
+
+DeprecatedString operator+(const DeprecatedString &qs, char ch)
+{
+ return DeprecatedString(qs) += ch;
+}
+
+DeprecatedString operator+(const char *chs, const DeprecatedString &qs)
+{
+ return DeprecatedString(chs) += qs;
+}
+
+DeprecatedString operator+(DeprecatedChar qc, const DeprecatedString &qs)
+{
+ return DeprecatedString(qc) += qs;
+}
+
+DeprecatedString operator+(char ch, const DeprecatedString &qs)
+{
+ return DeprecatedString(DeprecatedChar(ch)) += qs;
+}
+
+DeprecatedConstString::DeprecatedConstString(const DeprecatedChar* unicode, unsigned length) :
+ DeprecatedString(new DeprecatedStringData((DeprecatedChar *)unicode, length, length), true)
+{
+}
+
+DeprecatedConstString::~DeprecatedConstString()
+{
+ DeprecatedStringData *data = *dataHandle;
+ if (data->refCount > 1) {
+ DeprecatedChar *tp;
+ if (data->_length <= WEBCORE_DS_INTERNAL_BUFFER_UCHARS) {
+ data->_maxUnicode = WEBCORE_DS_INTERNAL_BUFFER_UCHARS;
+ tp = (DeprecatedChar *)&data->_internalBuffer[0];
+ } else {
+ data->_maxUnicode = ALLOC_QCHAR_GOOD_SIZE(data->_length);
+ tp = WEBCORE_ALLOCATE_CHARACTERS(data->_maxUnicode);
+ }
+ memcpy(tp, data->_unicode, data->_length * sizeof(DeprecatedChar));
+ data->_unicode = tp;
+ data->_isUnicodeValid = 1;
+ data->_isAsciiValid = 0;
+ } else {
+ data->_unicode = 0;
+ }
+}
+
+struct HandlePageNode
+{
+ HandlePageNode *next;
+ HandlePageNode *previous;
+ void *nodes;
+};
+
+struct HandleNode {
+ union {
+ struct {
+ unsigned short next;
+ unsigned short previous;
+ } internalNode;
+
+ HandleNode *freeNodes; // Always at block[0] in page.
+
+ HandlePageNode *pageNode; // Always at block[1] in page
+
+ void *handle;
+ } type;
+};
+
+#ifndef CHECK_FOR_HANDLE_LEAKS
+
+static const size_t pageSize = 4096;
+static const uintptr_t pageMask = ~(pageSize - 1);
+static const size_t nodeBlockSize = pageSize / sizeof(HandleNode);
+
+static HandleNode *initializeHandleNodeBlock(HandlePageNode *pageNode)
+{
+ unsigned i;
+ HandleNode* block;
+ HandleNode* aNode;
+
+#if PLATFORM(WIN_OS)
+ block = (HandleNode*)VirtualAlloc(0, pageSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
+#elif PLATFORM(SYMBIAN)
+ // symbian::fixme needs to do page aligned allocation as valloc is not supported.
+ block = NULL;
+#else
+ block = (HandleNode*)valloc(pageSize);
+#endif
+
+ for (i = 2; i < nodeBlockSize; i++) {
+ aNode = &block[i];
+ if (i > 2)
+ aNode->type.internalNode.previous = i-1;
+ else
+ aNode->type.internalNode.previous = 0;
+ if (i != nodeBlockSize - 1)
+ aNode->type.internalNode.next = i+1;
+ else
+ aNode->type.internalNode.next = 0;
+ }
+ block[0].type.freeNodes = &block[nodeBlockSize - 1];
+ block[1].type.pageNode = pageNode;
+
+ return block;
+}
+
+static HandlePageNode *allocatePageNode()
+{
+ HandlePageNode *node = (HandlePageNode *)fastMalloc(sizeof(HandlePageNode));
+ node->next = node->previous = 0;
+ node->nodes = initializeHandleNodeBlock(node);
+ return node;
+}
+
+static HandleNode *allocateNode(HandlePageNode *pageNode)
+{
+ HandleNode *block = (HandleNode *)pageNode->nodes;
+ HandleNode *freeNodes = block[0].type.freeNodes;
+ HandleNode *allocated;
+
+ // Check to see if we're out of nodes.
+ if (freeNodes == 0) {
+ FATAL("out of nodes");
+ return 0;
+ }
+
+ // Remove node from end of free list
+ allocated = freeNodes;
+ if (allocated->type.internalNode.previous >= 2) {
+ block[0].type.freeNodes = block + allocated->type.internalNode.previous;
+ block[0].type.freeNodes->type.internalNode.next = 0;
+ }
+ else {
+ // Used last node on this page.
+ block[0].type.freeNodes = 0;
+
+ freeNodeAllocationPages = freeNodeAllocationPages->previous;
+ if (freeNodeAllocationPages)
+ freeNodeAllocationPages->next = 0;
+
+ pageNode->previous = usedNodeAllocationPages;
+ pageNode->next = 0;
+ if (usedNodeAllocationPages)
+ usedNodeAllocationPages->next = pageNode;
+ usedNodeAllocationPages = pageNode;
+ }
+
+ return allocated;
+}
+
+#endif
+
+void freeHandle(DeprecatedStringData **_free)
+{
+#ifdef CHECK_FOR_HANDLE_LEAKS
+ fastFree(_free);
+ return;
+#else
+
+ HandleNode *free = (HandleNode *)_free;
+ HandleNode *base = (HandleNode *)((uintptr_t)free & pageMask);
+ HandleNode *freeNodes = base[0].type.freeNodes;
+ HandlePageNode *pageNode = base[1].type.pageNode;
+
+ if (freeNodes == 0){
+ free->type.internalNode.previous = 0;
+ }
+ else {
+ // Insert at head of free list.
+ free->type.internalNode.previous = freeNodes - base;
+ freeNodes->type.internalNode.next = free - base;
+ }
+ free->type.internalNode.next = 0;
+ base[0].type.freeNodes = free;
+
+ // Remove page from used/free list and place on free list
+ if (freeNodeAllocationPages != pageNode) {
+ if (pageNode->previous)
+ pageNode->previous->next = pageNode->next;
+ if (pageNode->next)
+ pageNode->next->previous = pageNode->previous;
+ if (usedNodeAllocationPages == pageNode)
+ usedNodeAllocationPages = pageNode->previous;
+
+ pageNode->previous = freeNodeAllocationPages;
+ pageNode->next = 0;
+ if (freeNodeAllocationPages)
+ freeNodeAllocationPages->next = pageNode;
+ freeNodeAllocationPages = pageNode;
+ }
+#endif
+}
+
+DeprecatedString DeprecatedString::fromUtf8(const char *chs)
+{
+ return UTF8Encoding().decode(chs, strlen(chs)).deprecatedString();
+}
+
+DeprecatedString DeprecatedString::fromUtf8(const char *chs, int len)
+{
+ return UTF8Encoding().decode(chs, len).deprecatedString();
+}
+
+DeprecatedCString DeprecatedString::utf8(int& length) const
+{
+ DeprecatedCString result = UTF8Encoding().encode((::UChar*)unicode(), this->length()).deprecatedCString();
+ length = result.length();
+ return result;
+}
+
+DeprecatedString::DeprecatedString(const Identifier& str)
+{
+ if (str.isNull()) {
+ internalData.deref();
+ dataHandle = makeSharedNullHandle();
+ dataHandle[0]->ref();
+ } else {
+ dataHandle = allocateHandle();
+ *dataHandle = &internalData;
+ internalData.initialize(reinterpret_cast<const DeprecatedChar*>(str.data()), str.size());
+ }
+}
+
+DeprecatedString::DeprecatedString(const UString& str)
+{
+ if (str.isNull()) {
+ internalData.deref();
+ dataHandle = makeSharedNullHandle();
+ dataHandle[0]->ref();
+ } else {
+ dataHandle = allocateHandle();
+ *dataHandle = &internalData;
+ internalData.initialize(reinterpret_cast<const DeprecatedChar*>(str.data()), str.size());
+ }
+}
+
+#if PLATFORM(QT)
+DeprecatedString::DeprecatedString(const QString& str)
+{
+ if (str.isNull()) {
+ internalData.deref();
+ dataHandle = makeSharedNullHandle();
+ dataHandle[0]->ref();
+ } else {
+ dataHandle = allocateHandle();
+ *dataHandle = &internalData;
+ internalData.initialize(reinterpret_cast<const DeprecatedChar*>(str.data()), str.length());
+ }
+}
+#endif
+
+DeprecatedString::operator Identifier() const
+{
+ if (isNull())
+ return Identifier();
+ return Identifier(reinterpret_cast<const KJS::UChar*>(unicode()), length());
+}
+
+DeprecatedString::operator UString() const
+{
+ if (isNull())
+ return UString();
+ return UString(reinterpret_cast<const KJS::UChar*>(unicode()), length());
+}
+
+bool equalIgnoringCase(const DeprecatedString& a, const DeprecatedString& b)
+{
+ unsigned len = a.length();
+ if (len != b.length())
+ return false;
+
+ DeprecatedStringData* dataA = a.dataHandle[0];
+ DeprecatedStringData* dataB = b.dataHandle[0];
+
+ if (dataA->_isAsciiValid != dataB->_isAsciiValid)
+ return false;
+
+ if (dataA->_isAsciiValid && dataB->_isAsciiValid)
+ return strncasecmp(dataA->_ascii, dataB->_ascii, len) == 0;
+
+ ASSERT(dataA->_isUnicodeValid);
+ ASSERT(dataB->_isUnicodeValid);
+ return equalCaseInsensitive(dataA->_unicode, dataB->_unicode, len);
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/DeprecatedString.h b/WebCore/platform/DeprecatedString.h
new file mode 100644
index 0000000..c413134
--- /dev/null
+++ b/WebCore/platform/DeprecatedString.h
@@ -0,0 +1,644 @@
+/*
+ * Copyright (C) 2005, 2006, 2007 Apple 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.
+ */
+
+#ifndef DeprecatedString_h
+#define DeprecatedString_h
+
+#include "DeprecatedCString.h"
+#include <wtf/ASCIICType.h>
+#include <wtf/unicode/Unicode.h>
+
+/* On some ARM platforms GCC won't pack structures by default so sizeof(DeprecatedChar)
+ will end up being != 2 which causes crashes since the code depends on that. */
+#if COMPILER(GCC) && PLATFORM(FORCE_PACK)
+#define PACK_STRUCT __attribute__((packed))
+#else
+#define PACK_STRUCT
+#endif
+
+#if PLATFORM(CF)
+typedef const struct __CFString * CFStringRef;
+#endif
+
+#if PLATFORM(MAC)
+#ifdef __OBJC__
+@class NSString;
+#else
+class NSString;
+#endif
+#endif
+
+#if PLATFORM(QT)
+class QString;
+#endif
+
+#if PLATFORM(WX)
+class wxString;
+#endif
+
+namespace KJS {
+ class Identifier;
+ class UString;
+}
+
+namespace WebCore {
+
+class RegularExpression;
+
+class DeprecatedChar {
+public:
+ DeprecatedChar();
+ DeprecatedChar(char);
+ DeprecatedChar(unsigned char);
+ DeprecatedChar(short);
+ DeprecatedChar(unsigned short);
+ DeprecatedChar(int);
+ DeprecatedChar(unsigned);
+
+ unsigned short unicode() const;
+ char latin1() const;
+ bool isSpace() const;
+ DeprecatedChar lower() const;
+ DeprecatedChar upper() const;
+
+private:
+ unsigned short c;
+} PACK_STRUCT;
+
+inline DeprecatedChar::DeprecatedChar() : c(0)
+{
+}
+
+inline DeprecatedChar::DeprecatedChar(char ch) : c((unsigned char) ch)
+{
+}
+
+inline DeprecatedChar::DeprecatedChar(unsigned char uch) : c(uch)
+{
+}
+
+inline DeprecatedChar::DeprecatedChar(short n) : c(n)
+{
+}
+
+inline DeprecatedChar::DeprecatedChar(unsigned short n) : c(n)
+{
+}
+
+inline DeprecatedChar::DeprecatedChar(unsigned n) : c(n)
+{
+}
+
+inline DeprecatedChar::DeprecatedChar(int n) : c(n)
+{
+}
+
+inline unsigned short DeprecatedChar::unicode() const
+{
+ return c;
+}
+
+inline bool DeprecatedChar::isSpace() const
+{
+#if USE(ICU_UNICODE)
+ // Use isspace() for basic Latin-1.
+ // This will include newlines, which aren't included in unicode DirWS.
+ return c <= 0x7F ? WTF::isASCIISpace(c) : (u_charDirection(c) == U_WHITE_SPACE_NEUTRAL);
+#elif USE(QT4_UNICODE)
+ return QChar(c).isSpace();
+#endif
+}
+
+inline DeprecatedChar DeprecatedChar::lower() const
+{
+#if USE(ICU_UNICODE)
+ // FIXME: If fast enough, we should just call u_tolower directly.
+ return c <= 0x7F ? WTF::toASCIILower(c) : u_tolower(c);
+#elif USE(QT4_UNICODE)
+ return QChar(c).toLower().unicode();
+#endif
+}
+
+inline DeprecatedChar DeprecatedChar::upper() const
+{
+#if USE(ICU_UNICODE)
+ // FIXME: If fast enough, we should just call u_toupper directly.
+ return c <= 0x7F ? WTF::toASCIIUpper(c) : u_toupper(c);
+#elif USE(QT4_UNICODE)
+ return QChar(c).toUpper().unicode();
+#endif
+}
+
+inline char DeprecatedChar::latin1() const
+{
+ return c > 0xff ? 0 : c;
+}
+
+inline bool operator==(DeprecatedChar qc1, DeprecatedChar qc2)
+{
+ return qc1.unicode() == qc2.unicode();
+}
+
+inline bool operator==(DeprecatedChar qc, char ch)
+{
+ return qc.unicode() == (unsigned char) ch;
+}
+
+inline bool operator==(char ch, DeprecatedChar qc)
+{
+ return (unsigned char) ch == qc.unicode();
+}
+
+inline bool operator!=(DeprecatedChar qc1, DeprecatedChar qc2)
+{
+ return qc1.unicode() != qc2.unicode();
+}
+
+inline bool operator!=(DeprecatedChar qc, char ch)
+{
+ return qc.unicode() != (unsigned char) ch;
+}
+
+inline bool operator!=(char ch, DeprecatedChar qc)
+{
+ return (unsigned char) ch != qc.unicode();
+}
+
+// Keep this struct to <= 46 bytes, that's what the system will allocate.
+// Will be rounded up to a multiple of 4, so we're stuck at 44.
+
+#define WEBCORE_DS_INTERNAL_BUFFER_SIZE 20
+#define WEBCORE_DS_INTERNAL_BUFFER_CHARS WEBCORE_DS_INTERNAL_BUFFER_SIZE-1
+#define WEBCORE_DS_INTERNAL_BUFFER_UCHARS WEBCORE_DS_INTERNAL_BUFFER_SIZE/2
+
+struct DeprecatedStringData
+{
+ // Uses shared null data.
+ DeprecatedStringData();
+ void initialize();
+
+ // No copy.
+ DeprecatedStringData(DeprecatedChar *u, unsigned l, unsigned m);
+ void initialize(DeprecatedChar *u, unsigned l, unsigned m);
+
+ // Copy bytes.
+ DeprecatedStringData(const DeprecatedChar *u, unsigned l);
+ void initialize(const DeprecatedChar *u, unsigned l);
+
+ // Copy bytes.
+ DeprecatedStringData(const char *u, unsigned l);
+ void initialize(const char *u, unsigned l);
+
+ // Move from destination to source.
+ static DeprecatedStringData* createAndAdopt(DeprecatedStringData &);
+
+ ~DeprecatedStringData();
+
+#ifdef WEBCORE_DS_DEBUG_ALLOCATIONS
+ void* operator new(size_t s);
+ void operator delete(void*p);
+#endif
+
+ inline void ref() { refCount++; }
+ inline void deref() { if (--refCount == 0 && _isHeapAllocated) delete this; }
+
+ char *ascii();
+ char *makeAscii();
+ void increaseAsciiSize(unsigned size);
+
+ DeprecatedChar *unicode();
+ DeprecatedChar *makeUnicode();
+ void increaseUnicodeSize(unsigned size);
+
+ bool isUnicodeInternal() const { return (char *)_unicode == _internalBuffer; }
+ bool isAsciiInternal() const { return _ascii == _internalBuffer; }
+
+ unsigned refCount;
+ unsigned _length;
+ mutable DeprecatedChar *_unicode;
+ mutable char *_ascii;
+
+ unsigned _maxUnicode : 30;
+ bool _isUnicodeValid : 1;
+ bool _isHeapAllocated : 1; // Fragile, but the only way we can be sure the instance was created with 'new'.
+ unsigned _maxAscii : 31;
+ bool _isAsciiValid : 1;
+
+ // _internalBuffer must be at the end - otherwise it breaks on archs that
+ // don't pack structs on byte boundary, like some versions of gcc on ARM
+ char _internalBuffer[WEBCORE_DS_INTERNAL_BUFFER_SIZE]; // Pad out to a (((size + 1) & ~15) + 14) size
+
+private:
+ void adopt(DeprecatedStringData&);
+
+ DeprecatedStringData(const DeprecatedStringData &);
+ DeprecatedStringData &operator=(const DeprecatedStringData &);
+};
+
+class DeprecatedString;
+
+bool operator==(const DeprecatedString&, const DeprecatedString&);
+bool operator==(const DeprecatedString&, const char*);
+
+class DeprecatedString {
+public:
+ static const char * const null;
+
+ DeprecatedString();
+ DeprecatedString(DeprecatedChar);
+ DeprecatedString(const DeprecatedChar *, unsigned);
+ DeprecatedString(const char *);
+ DeprecatedString(const char *, int len);
+ DeprecatedString(const KJS::Identifier&);
+ DeprecatedString(const KJS::UString&);
+
+ DeprecatedString(const DeprecatedString &);
+ DeprecatedString &operator=(const DeprecatedString &);
+
+ ~DeprecatedString();
+
+ operator KJS::Identifier() const;
+ operator KJS::UString() const;
+
+#if PLATFORM(QT)
+ DeprecatedString(const QString&);
+ operator QString() const;
+#endif
+
+ static DeprecatedString fromLatin1(const char *);
+ static DeprecatedString fromLatin1(const char *, int len);
+ static DeprecatedString fromUtf8(const char *);
+ static DeprecatedString fromUtf8(const char *, int len);
+#if PLATFORM(CF)
+ static DeprecatedString fromCFString(CFStringRef);
+#endif
+#if PLATFORM(MAC)
+ static DeprecatedString fromNSString(NSString*);
+#endif
+#if PLATFORM(SYMBIAN)
+ static DeprecatedString fromDes(const TDesC&);
+ static DeprecatedString fromDes(const TDesC8&);
+#endif
+ DeprecatedString &operator=(char);
+ DeprecatedString &operator=(DeprecatedChar);
+ DeprecatedString &operator=(const char *);
+ DeprecatedString &operator=(const DeprecatedCString &);
+
+ unsigned length() const;
+
+ const DeprecatedChar *unicode() const;
+ const DeprecatedChar *stableUnicode();
+ const char *latin1() const;
+ const char *ascii() const;
+ bool isAllASCII() const;
+ bool isAllLatin1() const;
+ bool hasFastLatin1() const;
+ void copyLatin1(char *buffer, unsigned position = 0, unsigned length = 0xffffffff) const;
+ DeprecatedCString utf8() const { int length; return utf8(length); }
+ DeprecatedCString utf8(int &length) const;
+
+ bool isNull() const;
+ bool isEmpty() const;
+
+ DeprecatedChar at(unsigned) const;
+
+ int compare(const DeprecatedString &) const;
+ int compare(const char *) const;
+
+ bool startsWith(const DeprecatedString &) const;
+ bool startsWith(const char *) const;
+ bool startsWith(const char *, bool caseSensitive) const;
+
+ int find(char, int index = 0) const;
+ int find(DeprecatedChar, int index = 0) const;
+ int find(const char *, int index = 0, bool cs = true) const;
+ int find(const DeprecatedString &, int index = 0, bool cs = true) const;
+ int find(const RegularExpression &, int index = 0) const;
+
+ int findRev(char, int index = -1) const;
+ int findRev(const DeprecatedString& str, int index, bool cs = true) const;
+ int findRev(const char *, int index = -1) const;
+
+ int contains(char) const;
+ int contains(const char *, bool cs = true) const;
+ int contains(const DeprecatedString &, bool cs = true) const;
+ int contains(DeprecatedChar c, bool cs = true) const;
+
+ bool endsWith(const DeprecatedString &) const;
+
+ short toShort(bool *ok = 0, int base = 10) const;
+ unsigned short toUShort(bool *ok = 0, int base = 10) const;
+ int toInt(bool *ok = 0, int base = 10) const;
+ int64_t toInt64(bool *ok = 0, int base = 10) const;
+ unsigned toUInt(bool *ok = 0, int base = 10) const;
+ uint64_t toUInt64(bool *ok = 0, int base = 10) const;
+
+ double toDouble(bool *ok = 0) const;
+ float toFloat(bool* ok = 0) const;
+
+ static DeprecatedString number(int);
+ static DeprecatedString number(unsigned);
+ static DeprecatedString number(long);
+ static DeprecatedString number(unsigned long);
+ static DeprecatedString number(double);
+
+ DeprecatedString left(unsigned) const;
+ DeprecatedString right(unsigned) const;
+ DeprecatedString mid(unsigned, unsigned len=0xffffffff) const;
+
+ DeprecatedString copy() const;
+
+ DeprecatedString lower() const;
+ DeprecatedString stripWhiteSpace() const;
+ DeprecatedString simplifyWhiteSpace() const;
+
+ DeprecatedString &setUnicode(const DeprecatedChar *, unsigned);
+ DeprecatedString &setLatin1(const char *, int len=-1);
+
+ DeprecatedString &setNum(short);
+ DeprecatedString &setNum(unsigned short);
+ DeprecatedString &setNum(int);
+ DeprecatedString &setNum(unsigned);
+ DeprecatedString &setNum(long);
+ DeprecatedString &setNum(unsigned long);
+ DeprecatedString &setNum(double);
+
+ DeprecatedString& format(const char *, ...) WTF_ATTRIBUTE_PRINTF(2, 3);
+
+ DeprecatedString &append(const DeprecatedString &);
+ DeprecatedString &append(DeprecatedChar);
+ DeprecatedString &append(char);
+ DeprecatedString &insert(unsigned, const DeprecatedString &);
+ DeprecatedString &insert(unsigned, DeprecatedChar);
+ DeprecatedString &insert(unsigned, char);
+ DeprecatedString &insert(unsigned index, const char *insertChars, unsigned insertLength);
+ DeprecatedString &prepend(const DeprecatedString &);
+ DeprecatedString &remove(unsigned, unsigned);
+ DeprecatedString &remove(const DeprecatedChar &c) { return replace(DeprecatedString(c), ""); }
+ DeprecatedString &remove(const DeprecatedString &s) { return replace(s, ""); }
+ DeprecatedString &replace(unsigned index, unsigned len, const DeprecatedString &s);
+ DeprecatedString &replace(char, const DeprecatedString &);
+ DeprecatedString &replace(DeprecatedChar, const DeprecatedString &);
+ DeprecatedString &replace(const DeprecatedString &, const DeprecatedString &);
+ DeprecatedString &replace(const RegularExpression &, const DeprecatedString &);
+ DeprecatedString &replace(DeprecatedChar, DeprecatedChar);
+
+ DeprecatedString &append(const DeprecatedChar *, unsigned length);
+ DeprecatedString &append(const char *, unsigned length);
+ DeprecatedString &insert(unsigned position, const DeprecatedChar *, unsigned length);
+ DeprecatedString &prepend(const DeprecatedChar *, unsigned length);
+
+ void fill(DeprecatedChar, int len=-1);
+ void truncate(unsigned);
+
+ void reserve(unsigned);
+
+ bool operator!() const;
+
+ const DeprecatedChar operator[](int) const;
+
+ DeprecatedString &operator+=(const DeprecatedString &s) { return append(s); }
+ DeprecatedString &operator+=(DeprecatedChar c) { return append(c); }
+ DeprecatedString &operator+=(char c) { return append(c); }
+
+#if PLATFORM(CF)
+ CFStringRef getCFString() const;
+ void setBufferFromCFString(CFStringRef);
+#endif
+
+#if PLATFORM(MAC)
+ NSString *getNSString() const;
+
+#ifdef __OBJC__
+ operator NSString*() const { return getNSString(); }
+#endif
+
+#endif
+
+#if PLATFORM(WX)
+ operator wxString() const;
+#endif
+
+#if PLATFORM(SYMBIAN)
+ TPtrC des() const;
+ TPtrC8 des8() const;
+ void setBufferFromDes(const TDesC&);
+ void setBufferFromDes(const TDesC8&);
+#endif
+
+private:
+ // Used by DeprecatedConstString.
+ DeprecatedString(DeprecatedStringData *constData, bool /*dummy*/);
+ void detach();
+ void detachAndDiscardCharacters();
+ void detachIfInternal();
+ void detachInternal();
+ void deref();
+ DeprecatedChar *forceUnicode();
+ void setLength(unsigned);
+
+ DeprecatedStringData **dataHandle;
+ DeprecatedStringData internalData;
+
+ static DeprecatedStringData *shared_null;
+ static DeprecatedStringData *makeSharedNull();
+ static DeprecatedStringData **shared_null_handle;
+ static DeprecatedStringData **makeSharedNullHandle();
+
+ friend bool operator==(const DeprecatedString &, const DeprecatedString &);
+ friend bool operator==(const DeprecatedString &, const char *);
+ friend bool equalIgnoringCase(const DeprecatedString&, const DeprecatedString&);
+
+ friend class DeprecatedConstString;
+ friend class QGDict;
+ friend struct DeprecatedStringData;
+};
+
+DeprecatedString operator+(const DeprecatedString &, const DeprecatedString &);
+DeprecatedString operator+(const DeprecatedString &, const char *);
+DeprecatedString operator+(const DeprecatedString &, DeprecatedChar);
+DeprecatedString operator+(const DeprecatedString &, char);
+DeprecatedString operator+(const char *, const DeprecatedString &);
+DeprecatedString operator+(DeprecatedChar, const DeprecatedString &);
+DeprecatedString operator+(char, const DeprecatedString &);
+
+bool equalIgnoringCase(const DeprecatedString&, const DeprecatedString&);
+inline bool equalIgnoringCase(const DeprecatedString& a, const char* b) { return equalIgnoringCase(a, DeprecatedString(b)); }
+inline bool equalIgnoringCase(const char* a, const DeprecatedString& b) { return equalIgnoringCase(DeprecatedString(a), b); }
+
+inline char *DeprecatedStringData::ascii()
+{
+ return _isAsciiValid ? _ascii : makeAscii();
+}
+
+inline DeprecatedChar *DeprecatedStringData::unicode()
+{
+ return _isUnicodeValid ? _unicode : makeUnicode();
+}
+
+inline unsigned DeprecatedString::length() const
+{
+ return dataHandle[0]->_length;
+}
+
+inline bool DeprecatedString::isEmpty() const
+{
+ return dataHandle[0]->_length == 0;
+}
+
+inline const char *DeprecatedString::latin1() const
+{
+ return dataHandle[0]->ascii();
+}
+
+inline const DeprecatedChar *DeprecatedString::unicode() const
+{
+ return dataHandle[0]->unicode();
+}
+
+#if PLATFORM(MAC)
+#if PLATFORM(CF)
+inline CFStringRef DeprecatedString::getCFString() const
+{
+ return (CFStringRef)getNSString();
+}
+#endif
+#endif
+
+inline DeprecatedString DeprecatedString::fromLatin1(const char *chs)
+{
+ return chs;
+}
+
+inline DeprecatedString DeprecatedString::fromLatin1(const char *chs, int length)
+{
+ return DeprecatedString(chs, length);
+}
+
+inline const char *DeprecatedString::ascii() const
+{
+ return latin1();
+}
+
+inline bool DeprecatedString::operator!() const
+{
+ return isNull();
+}
+
+inline const DeprecatedChar DeprecatedString::operator[](int index) const
+{
+ return at(index);
+}
+
+inline bool operator==(const char *chs, const DeprecatedString &qs)
+{
+ return qs == chs;
+}
+
+inline bool operator!=(const DeprecatedString &qs1, const DeprecatedString &qs2)
+{
+ return !(qs1 == qs2);
+}
+
+inline bool operator!=(const DeprecatedString &qs, const char *chs)
+{
+ return !(qs == chs);
+}
+
+inline bool operator!=(const char *chs, const DeprecatedString &qs)
+{
+ return !(qs == chs);
+}
+
+inline bool operator<(const DeprecatedString &qs1, const DeprecatedString &qs2)
+{
+ return qs1.compare(qs2) < 0;
+}
+
+inline bool operator<(const DeprecatedString &qs, const char *chs)
+{
+ return qs.compare(chs) < 0;
+}
+
+inline bool operator<(const char *chs, const DeprecatedString &qs)
+{
+ return qs.compare(chs) > 0;
+}
+
+inline bool operator<=(const DeprecatedString &qs1, const DeprecatedString &qs2)
+{
+ return qs1.compare(qs2) <= 0;
+}
+
+inline bool operator<=(const DeprecatedString &qs, const char *chs)
+{
+ return qs.compare(chs) <= 0;
+}
+
+inline bool operator<=(const char *chs, const DeprecatedString &qs)
+{
+ return qs.compare(chs) >= 0;
+}
+
+inline bool operator>(const DeprecatedString &qs1, const DeprecatedString &qs2)
+{
+ return qs1.compare(qs2) > 0;
+}
+
+inline bool operator>(const DeprecatedString &qs, const char *chs)
+{
+ return qs.compare(chs) > 0;
+}
+
+inline bool operator>(const char *chs, const DeprecatedString &qs)
+{
+ return qs.compare(chs) < 0;
+}
+
+inline bool operator>=(const DeprecatedString &qs1, const DeprecatedString &qs2)
+{
+ return qs1.compare(qs2) >= 0;
+}
+
+inline bool operator>=(const DeprecatedString &qs, const char *chs)
+{
+ return qs.compare(chs) >= 0;
+}
+
+inline bool operator>=(const char *chs, const DeprecatedString &qs)
+{
+ return qs.compare(chs) <= 0;
+}
+
+class DeprecatedConstString : private DeprecatedString {
+public:
+ DeprecatedConstString(const DeprecatedChar *, unsigned);
+ ~DeprecatedConstString();
+ const DeprecatedString &string() const { return *this; }
+};
+
+}
+
+#endif
diff --git a/WebCore/platform/wx/wxcode/gtk/non-kerned-drawing.cpp b/WebCore/platform/DeprecatedStringList.cpp
index b86a9bc..ee82221 100644
--- a/WebCore/platform/wx/wxcode/gtk/non-kerned-drawing.cpp
+++ b/WebCore/platform/DeprecatedStringList.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Kevin Watters, Kevin Ollivier. All rights reserved.
+ * 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
@@ -20,48 +20,55 @@
* 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.
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
-#include "GlyphBuffer.h"
-#include "GraphicsContext.h"
-#include "SimpleFontData.h"
-
-#include <wx/defs.h>
-#include <wx/dcclient.h>
-#include <wx/gdicmn.h>
-#include <vector>
+#include "DeprecatedStringList.h"
namespace WebCore {
-void drawTextWithSpacing(GraphicsContext* graphicsContext, const SimpleFontData* font, const wxColour& color, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point)
+DeprecatedStringList DeprecatedStringList::split(const DeprecatedString &separator, const DeprecatedString &s, bool allowEmptyEntries)
{
-#if USE(WXGC)
- wxGCDC* dc = static_cast<wxGCDC*>(graphicsContext->platformContext());
-#else
- wxDC* dc = graphicsContext->platformContext();
-#endif
-
- wxFont wxfont = font->getWxFont();
- if (wxfont.IsOk())
- dc->SetFont(wxfont);
- dc->SetTextForeground(color);
+ DeprecatedStringList result;
- // convert glyphs to wxString
- GlyphBufferGlyph* glyphs = const_cast<GlyphBufferGlyph*>(glyphBuffer.glyphs(from));
- int offset = point.x();
- wxString text = wxEmptyString;
- for (unsigned i = 0; i < numGlyphs; i++) {
- text = text.Append((wxChar)glyphs[i]);
- offset += glyphBuffer.advanceAt(from + i);
+ int startPos = 0;
+ int endPos;
+ while ((endPos = s.find(separator, startPos)) != -1) {
+ if (allowEmptyEntries || startPos != endPos)
+ result.append(s.mid(startPos, endPos - startPos));
+ startPos = endPos + separator.length();
}
+ if (allowEmptyEntries || startPos != (int)s.length())
+ result.append(s.mid(startPos));
+
+ return result;
+}
+
+DeprecatedStringList DeprecatedStringList::split(const DeprecatedChar &separator, const DeprecatedString &s, bool allowEmptyEntries)
+{
+ return DeprecatedStringList::split(DeprecatedString(separator), s, allowEmptyEntries);
+}
+
+DeprecatedString DeprecatedStringList::join(const DeprecatedString &separator) const
+{
+ DeprecatedString result;
- // the y point is actually the bottom point of the text, turn it into the top
- float height = font->ascent() - font->descent();
- wxCoord ypoint = (wxCoord) (point.y() - height);
-
- dc->DrawText(text, (wxCoord)point.x(), ypoint);
+ for (ConstIterator i = begin(), j = ++begin(); i != end(); ++i, ++j) {
+ result += *i;
+ if (j != end()) {
+ result += separator;
+ }
+ }
+
+ return result;
+}
+
+DeprecatedString DeprecatedStringList::pop_front()
+{
+ DeprecatedString front = first();
+ remove(begin());
+ return front;
}
}
diff --git a/WebCore/platform/network/qt/AuthenticationChallenge.h b/WebCore/platform/DeprecatedStringList.h
index 753ac6f..aa735bf 100644
--- a/WebCore/platform/network/qt/AuthenticationChallenge.h
+++ b/WebCore/platform/DeprecatedStringList.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * 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
@@ -22,23 +22,31 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef AuthenticationChallenge_h
-#define AuthenticationChallenge_h
-#include "AuthenticationChallengeBase.h"
+#ifndef DeprecatedStringList_h
+#define DeprecatedStringList_h
+
+#include "DeprecatedString.h"
+#include "DeprecatedValueList.h"
+
+#ifdef __OBJC__
+@class NSArray;
+#endif
namespace WebCore {
-class AuthenticationChallenge : public AuthenticationChallengeBase {
+class DeprecatedStringList : public DeprecatedValueList<DeprecatedString> {
public:
- AuthenticationChallenge()
- {
- }
-
- AuthenticationChallenge(const ProtectionSpace& protectionSpace, const Credential& proposedCredential, unsigned previousFailureCount, const ResourceResponse& response, const ResourceError& error)
- : AuthenticationChallengeBase(protectionSpace, proposedCredential, previousFailureCount, response, error)
- {
- }
+ static DeprecatedStringList split(const DeprecatedString &, const DeprecatedString &, bool allowEmptyEntries = false);
+ static DeprecatedStringList split(const DeprecatedChar &, const DeprecatedString &, bool allowEmptyEntries = false);
+
+ DeprecatedString join(const DeprecatedString &) const;
+
+ DeprecatedString pop_front();
+
+#ifdef __OBJC__
+ NSArray *getNSArray() const;
+#endif
};
}
diff --git a/WebCore/platform/DeprecatedValueListImpl.cpp b/WebCore/platform/DeprecatedValueListImpl.cpp
index 5bbb697..10a4200 100644
--- a/WebCore/platform/DeprecatedValueListImpl.cpp
+++ b/WebCore/platform/DeprecatedValueListImpl.cpp
@@ -51,18 +51,17 @@ public:
};
inline DeprecatedValueListImpl::Private::Private(void (*deleteFunc)(DeprecatedValueListImplNode*),
- DeprecatedValueListImplNode* (*copyFunc)(DeprecatedValueListImplNode*))
- : RefCounted<Private>(0)
- , head(NULL)
- , tail(NULL)
- , deleteNode(deleteFunc)
- , copyNode(copyFunc)
- , count(0)
+ DeprecatedValueListImplNode* (*copyFunc)(DeprecatedValueListImplNode*)) :
+ head(NULL),
+ tail(NULL),
+ deleteNode(deleteFunc),
+ copyNode(copyFunc),
+ count(0)
{
}
inline DeprecatedValueListImpl::Private::Private(const Private &other)
- : RefCounted<Private>(0)
+ : RefCounted<DeprecatedValueListImpl::Private>()
, deleteNode(other.deleteNode)
, copyNode(other.copyNode)
, count(other.count)
diff --git a/WebCore/platform/DragData.h b/WebCore/platform/DragData.h
index c4b9337..d139352 100644
--- a/WebCore/platform/DragData.h
+++ b/WebCore/platform/DragData.h
@@ -52,6 +52,8 @@ typedef class wxDataObject* DragDataRef;
#elif PLATFORM(GTK)
// FIXME: this should probably be something gdk-specific
typedef void* DragDataRef;
+#elif defined ANDROID
+typedef void* DragDataRef;
#endif
diff --git a/WebCore/platform/DragImage.h b/WebCore/platform/DragImage.h
index 4c0d257..f3b06c6 100644
--- a/WebCore/platform/DragImage.h
+++ b/WebCore/platform/DragImage.h
@@ -66,6 +66,8 @@ namespace WebCore {
typedef wxDragImage* DragImageRef;
#elif PLATFORM(GTK)
typedef void* DragImageRef;
+#elif defined ANDROID
+ typedef void* DragImageRef;
#endif
IntSize dragImageSize(DragImageRef);
diff --git a/WebCore/platform/FileSystem.h b/WebCore/platform/FileSystem.h
index d2a3011..da31281 100644
--- a/WebCore/platform/FileSystem.h
+++ b/WebCore/platform/FileSystem.h
@@ -30,12 +30,6 @@
#ifndef FileSystem_h
#define FileSystem_h
-#if PLATFORM(GTK)
-#include <gmodule.h>
-#endif
-
-#include <time.h>
-
#include <wtf/Platform.h>
typedef const struct __CFData* CFDataRef;
@@ -47,38 +41,10 @@ class String;
#if PLATFORM(WIN)
typedef HANDLE PlatformFileHandle;
-typedef FILETIME PlatformFileTime;
-typedef HMODULE PlatformModule;
const PlatformFileHandle invalidPlatformFileHandle = INVALID_HANDLE_VALUE;
-
-struct PlatformModuleVersion {
- unsigned leastSig;
- unsigned mostSig;
-
- PlatformModuleVersion(unsigned)
- : leastSig(0)
- , mostSig(0)
- {
- }
-
- PlatformModuleVersion(unsigned lsb, unsigned msb)
- : leastSig(lsb)
- , mostSig(msb)
- {
- }
-
-};
#else
typedef int PlatformFileHandle;
-typedef time_t PlatformFileTime;
-#if PLATFORM(GTK)
-typedef GModule* PlatformModule;
-#else
-typedef void* PlatformModule;
-#endif
const PlatformFileHandle invalidPlatformFileHandle = -1;
-
-typedef unsigned PlatformModuleVersion;
#endif
bool fileExists(const String&);
@@ -89,7 +55,6 @@ bool getFileModificationTime(const String&, time_t& result);
String pathByAppendingComponent(const String& path, const String& component);
bool makeAllDirectories(const String& path);
String homeDirectoryPath();
-String pathGetFileName(const String&);
CString fileSystemRepresentation(const String&);
@@ -100,9 +65,6 @@ CString openTemporaryFile(const char* prefix, PlatformFileHandle&);
void closeFile(PlatformFileHandle&);
int writeToFile(PlatformFileHandle, const char* data, int length);
-// Methods for dealing with loadable modules
-bool unloadModule(PlatformModule);
-
#if PLATFORM(WIN)
String localUserSpecificStorageDirectory();
String roamingUserSpecificStorageDirectory();
diff --git a/WebCore/platform/KURL.cpp b/WebCore/platform/KURL.cpp
index b858108..45922e7 100644
--- a/WebCore/platform/KURL.cpp
+++ b/WebCore/platform/KURL.cpp
@@ -28,28 +28,20 @@
#include "CString.h"
#include "PlatformString.h"
+#include "RegularExpression.h"
#include "TextEncoding.h"
-
+#include <wtf/Vector.h>
#if USE(ICU_UNICODE)
#include <unicode/uidna.h>
#elif USE(QT4_UNICODE)
#include <QUrl>
#endif
-#include <stdio.h>
-
using namespace std;
using namespace WTF;
namespace WebCore {
-typedef Vector<char, 512> CharBuffer;
-typedef Vector<UChar, 512> UCharBuffer;
-
-// FIXME: This file makes too much use of the + operator on String.
-// We either have to optimize that operator so it doesn't involve
-// so many allocations, or change this to use Vector<UChar> instead.
-
enum URLCharacterClasses {
// alpha
SchemeFirstChar = 1 << 0,
@@ -74,52 +66,56 @@ enum URLCharacterClasses {
// "#" | "?" | "/" | nul
PathSegmentEndChar = 1 << 5,
+ // digit | "A" | "B" | "C" | "D" | "E" | "F" | "a" | "b" | "c" | "d" | "e" | "f"
+ HexDigitChar = 1 << 6,
+
// not allowed in path
- BadChar = 1 << 6
+ BadChar = 1 << 7
+
};
static const char hexDigits[17] = "0123456789ABCDEF";
static const unsigned char characterClassTable[256] = {
/* 0 nul */ PathSegmentEndChar, /* 1 soh */ BadChar,
- /* 2 stx */ BadChar, /* 3 etx */ BadChar,
+ /* 2 stx */ BadChar, /* 3 etx */ BadChar,
/* 4 eot */ BadChar, /* 5 enq */ BadChar, /* 6 ack */ BadChar, /* 7 bel */ BadChar,
- /* 8 bs */ BadChar, /* 9 ht */ BadChar, /* 10 nl */ BadChar, /* 11 vt */ BadChar,
+ /* 8 bs */ BadChar, /* 9 ht */ BadChar, /* 10 nl */ BadChar, /* 11 vt */ BadChar,
/* 12 np */ BadChar, /* 13 cr */ BadChar, /* 14 so */ BadChar, /* 15 si */ BadChar,
/* 16 dle */ BadChar, /* 17 dc1 */ BadChar, /* 18 dc2 */ BadChar, /* 19 dc3 */ BadChar,
/* 20 dc4 */ BadChar, /* 21 nak */ BadChar, /* 22 syn */ BadChar, /* 23 etb */ BadChar,
/* 24 can */ BadChar, /* 25 em */ BadChar, /* 26 sub */ BadChar, /* 27 esc */ BadChar,
/* 28 fs */ BadChar, /* 29 gs */ BadChar, /* 30 rs */ BadChar, /* 31 us */ BadChar,
/* 32 sp */ BadChar, /* 33 ! */ UserInfoChar,
- /* 34 " */ BadChar, /* 35 # */ PathSegmentEndChar | BadChar,
+ /* 34 " */ BadChar, /* 35 # */ PathSegmentEndChar | BadChar,
/* 36 $ */ UserInfoChar, /* 37 % */ UserInfoChar | HostnameChar | IPv6Char | BadChar,
/* 38 & */ UserInfoChar, /* 39 ' */ UserInfoChar,
- /* 40 ( */ UserInfoChar, /* 41 ) */ UserInfoChar,
+ /* 40 ( */ UserInfoChar, /* 41 ) */ UserInfoChar,
/* 42 * */ UserInfoChar, /* 43 + */ SchemeChar | UserInfoChar,
- /* 44 , */ UserInfoChar,
- /* 45 - */ SchemeChar | UserInfoChar | HostnameChar,
- /* 46 . */ SchemeChar | UserInfoChar | HostnameChar,
+ /* 44 , */ UserInfoChar,
+ /* 45 - */ SchemeChar | UserInfoChar | HostnameChar,
+ /* 46 . */ SchemeChar | UserInfoChar | HostnameChar,
/* 47 / */ PathSegmentEndChar,
- /* 48 0 */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
- /* 49 1 */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
- /* 50 2 */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
- /* 51 3 */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
- /* 52 4 */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
- /* 53 5 */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
- /* 54 6 */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
- /* 55 7 */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
- /* 56 8 */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
- /* 57 9 */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
+ /* 48 0 */ SchemeChar | UserInfoChar | HostnameChar | HexDigitChar | IPv6Char,
+ /* 49 1 */ SchemeChar | UserInfoChar | HostnameChar | HexDigitChar | IPv6Char,
+ /* 50 2 */ SchemeChar | UserInfoChar | HostnameChar | HexDigitChar | IPv6Char,
+ /* 51 3 */ SchemeChar | UserInfoChar | HostnameChar | HexDigitChar | IPv6Char,
+ /* 52 4 */ SchemeChar | UserInfoChar | HostnameChar | HexDigitChar | IPv6Char,
+ /* 53 5 */ SchemeChar | UserInfoChar | HostnameChar | HexDigitChar | IPv6Char,
+ /* 54 6 */ SchemeChar | UserInfoChar | HostnameChar | HexDigitChar | IPv6Char,
+ /* 55 7 */ SchemeChar | UserInfoChar | HostnameChar | HexDigitChar | IPv6Char,
+ /* 56 8 */ SchemeChar | UserInfoChar | HostnameChar | HexDigitChar | IPv6Char,
+ /* 57 9 */ SchemeChar | UserInfoChar | HostnameChar | HexDigitChar | IPv6Char,
/* 58 : */ UserInfoChar | IPv6Char, /* 59 ; */ UserInfoChar,
/* 60 < */ BadChar, /* 61 = */ UserInfoChar,
/* 62 > */ BadChar, /* 63 ? */ PathSegmentEndChar | BadChar,
/* 64 @ */ 0,
- /* 65 A */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
- /* 66 B */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
- /* 67 C */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
- /* 68 D */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
- /* 69 E */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
- /* 70 F */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
+ /* 65 A */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | HexDigitChar | IPv6Char,
+ /* 66 B */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | HexDigitChar | IPv6Char,
+ /* 67 C */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | HexDigitChar | IPv6Char,
+ /* 68 D */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | HexDigitChar | IPv6Char,
+ /* 69 E */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | HexDigitChar | IPv6Char,
+ /* 70 F */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | HexDigitChar | IPv6Char,
/* 71 G */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
/* 72 H */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
/* 73 I */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
@@ -145,12 +141,12 @@ static const unsigned char characterClassTable[256] = {
/* 94 ^ */ 0,
/* 95 _ */ UserInfoChar | HostnameChar,
/* 96 ` */ 0,
- /* 97 a */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
- /* 98 b */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
- /* 99 c */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
- /* 100 d */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
- /* 101 e */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
- /* 102 f */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
+ /* 97 a */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | HexDigitChar | IPv6Char,
+ /* 98 b */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | HexDigitChar | IPv6Char,
+ /* 99 c */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | HexDigitChar | IPv6Char,
+ /* 100 d */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | HexDigitChar | IPv6Char,
+ /* 101 e */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | HexDigitChar | IPv6Char,
+ /* 102 f */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | HexDigitChar | IPv6Char,
/* 103 g */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
/* 104 h */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
/* 105 i */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
@@ -208,157 +204,137 @@ static const unsigned char characterClassTable[256] = {
};
static int copyPathRemovingDots(char* dst, const char* src, int srcStart, int srcEnd);
-static void encodeRelativeString(const String& rel, const TextEncoding&, CharBuffer& ouput);
-static String substituteBackslashes(const String&);
+static char* encodeRelativeString(const KURL &base, const DeprecatedString& rel, const TextEncoding&);
+static DeprecatedString substituteBackslashes(const DeprecatedString &string);
-static inline bool isSchemeFirstChar(char c) { return characterClassTable[static_cast<unsigned char>(c)] & SchemeFirstChar; }
-static inline bool isSchemeFirstChar(UChar c) { return c <= 0xff && (characterClassTable[c] & SchemeFirstChar); }
-static inline bool isSchemeChar(char c) { return characterClassTable[static_cast<unsigned char>(c)] & SchemeChar; }
-static inline bool isSchemeChar(UChar c) { return c <= 0xff && (characterClassTable[c] & SchemeChar); }
+static inline bool isSchemeFirstChar(unsigned char c) { return characterClassTable[c] & SchemeFirstChar; }
+static inline bool isSchemeChar(unsigned char c) { return characterClassTable[c] & SchemeChar; }
static inline bool isUserInfoChar(unsigned char c) { return characterClassTable[c] & UserInfoChar; }
static inline bool isHostnameChar(unsigned char c) { return characterClassTable[c] & HostnameChar; }
static inline bool isIPv6Char(unsigned char c) { return characterClassTable[c] & IPv6Char; }
-static inline bool isPathSegmentEndChar(char c) { return characterClassTable[static_cast<unsigned char>(c)] & PathSegmentEndChar; }
-static inline bool isPathSegmentEndChar(UChar c) { return c <= 0xff && (characterClassTable[c] & PathSegmentEndChar); }
+static inline bool isPathSegmentEndChar(unsigned char c) { return characterClassTable[c] & PathSegmentEndChar; }
static inline bool isBadChar(unsigned char c) { return characterClassTable[c] & BadChar; }
+static inline bool isHexDigit(unsigned char c) { return characterClassTable[c] & HexDigitChar; }
-static inline int hexDigitValue(UChar c)
+static inline int hexDigitValue(unsigned char c)
{
- ASSERT(isASCIIHexDigit(c));
+ ASSERT(isHexDigit(c));
if (c < 'A')
return c - '0';
return (c - 'A' + 10) & 0xF; // handle both upper and lower case without a branch
}
-// Copies the source to the destination, assuming all the source characters are
-// ASCII. The destination buffer must be large enough. Null characters are allowed
-// in the source string, and no attempt is made to null-terminate the result.
-static void copyASCII(const UChar* src, int length, char* dest)
-{
- for (int i = 0; i < length; i++)
- dest[i] = static_cast<char>(src[i]);
-}
-
-// FIXME: Move to PlatformString.h eventually.
-// Returns the index of the first index in string |s| of any of the characters
-// in |toFind|. |toFind| should be a null-terminated string, all characters up
-// to the null will be searched. Returns int if not found.
-static int findFirstOf(const UChar* s, int sLen, int startPos, const char* toFind)
-{
- for (int i = startPos; i < sLen; i++) {
- const char* cur = toFind;
- while (*cur) {
- if (s[i] == *(cur++))
- return i;
- }
- }
- return -1;
-}
-
-// KURL
-
+#ifdef ANDROID_JAVASCRIPT_SECURITY
inline bool KURL::protocolIs(const String& string, const char* protocol)
{
return WebCore::protocolIs(string, protocol);
}
+#endif
+
+// KURL
-KURL::KURL()
- : m_isValid(false)
+KURL::KURL() : m_isValid(false)
{
}
-KURL::KURL(const char* url)
+KURL::KURL(const char *url)
{
- if (!url || url[0] != '/') {
+ if (url && url[0] == '/') {
+ // 5 for "file:", 1 for terminator
+ size_t urlLength = strlen(url) + 1;
+ Vector<char, 2048> buffer(urlLength + 5);
+ buffer[0] = 'f';
+ buffer[1] = 'i';
+ buffer[2] = 'l';
+ buffer[3] = 'e';
+ buffer[4] = ':';
+ memcpy(&buffer[5], url, urlLength);
+ parse(buffer.data(), 0);
+ } else
parse(url, 0);
- return;
- }
-
- size_t urlLength = strlen(url) + 1;
- CharBuffer buffer(urlLength + 5); // 5 for "file:".
- buffer[0] = 'f';
- buffer[1] = 'i';
- buffer[2] = 'l';
- buffer[3] = 'e';
- buffer[4] = ':';
- memcpy(&buffer[5], url, urlLength);
- parse(buffer.data(), 0);
}
-KURL::KURL(const String& url)
+KURL::KURL(const DeprecatedString &url)
{
- if (url[0] != '/') {
- parse(url);
- return;
- }
-
- CharBuffer buffer(url.length() + 6); // 5 for "file:", 1 for terminator.
- buffer[0] = 'f';
- buffer[1] = 'i';
- buffer[2] = 'l';
- buffer[3] = 'e';
- buffer[4] = ':';
- copyASCII(url.characters(), url.length(), &buffer[5]);
- buffer[url.length() + 5] = '\0'; // Need null terminator.
-
- parse(buffer.data(), 0);
+ if (!url.isEmpty() && url[0] == '/') {
+ // 5 for "file:", 1 for terminator
+ Vector<char, 2048> buffer(url.length() + 6);
+ buffer[0] = 'f';
+ buffer[1] = 'i';
+ buffer[2] = 'l';
+ buffer[3] = 'e';
+ buffer[4] = ':';
+ url.copyLatin1(&buffer[5]);
+ parse(buffer.data(), 0);
+ } else
+ parse(url.ascii(), &url);
}
-KURL::KURL(const KURL& base, const String& relative)
+KURL::KURL(const KURL& base, const DeprecatedString& relative)
{
init(base, relative, UTF8Encoding());
}
-KURL::KURL(const KURL& base, const String& relative, const TextEncoding& encoding)
+KURL::KURL(const KURL& base, const DeprecatedString& relative, const TextEncoding& encoding)
{
init(base, relative, encoding);
}
-void KURL::init(const KURL& base, const String& relative, const TextEncoding& encoding)
+void KURL::init(const KURL &base, const DeprecatedString &relative, const TextEncoding& encoding)
{
// Allow at least absolute URLs to resolve against an empty URL.
if (!base.m_isValid && !base.isEmpty()) {
- m_string = relative;
m_isValid = false;
return;
}
+
+ bool absolute = false;
- // For compatibility with Win IE, treat backslashes as if they were slashes,
- // as long as we're not dealing with javascript: or data: URLs.
- String rel = relative;
- if (rel.contains('\\') && !(protocolIs(rel, "javascript") || protocolIs(rel, "data")))
- rel = substituteBackslashes(rel);
-
- String* originalString = &rel;
-
- bool allASCII = charactersAreAllASCII(rel.characters(), rel.length());
- CharBuffer strBuffer;
- char* str;
- size_t len;
+ // for compatibility with Win IE, we must treat backslashes as if they were slashes, as long as we're not dealing with the javascript: schema
+ DeprecatedString substitutedRelative;
+#ifdef ANDROID_JAVASCRIPT_SECURITY
+ bool shouldSubstituteBackslashes = relative.contains('\\') && !(protocolIs(relative, "javascript") || protocolIs(relative, "data"));
+#else
+ bool shouldSubstituteBackslashes = relative.contains('\\') && !(relative.startsWith("javascript:", false) || relative.startsWith("data:", false));
+#endif
+ if (shouldSubstituteBackslashes)
+ substitutedRelative = substituteBackslashes(relative);
+
+ const DeprecatedString &rel = shouldSubstituteBackslashes ? substitutedRelative : relative;
+
+ bool allASCII = rel.isAllASCII();
+ char *strBuffer;
+ const char *str;
if (allASCII) {
- len = rel.length();
- strBuffer.resize(len + 1);
- copyASCII(rel.characters(), len, strBuffer.data());
- strBuffer[len] = 0;
- str = strBuffer.data();
+ strBuffer = 0;
+ str = rel.ascii();
} else {
- originalString = 0;
- encodeRelativeString(rel, encoding, strBuffer);
- str = strBuffer.data();
- len = strlen(str);
+ strBuffer = encodeRelativeString(base, rel, encoding);
+ str = strBuffer;
}
-
- // Get rid of leading whitespace.
+
+ // workaround for sites that put leading whitespace whitespace on
+ // URL references
+ bool strippedStart = false;
while (*str == ' ') {
- originalString = 0;
str++;
- --len;
+ strippedStart = true;
}
- // Get rid of trailing whitespace.
- while (len && str[len - 1] == ' ') {
- originalString = 0;
- str[--len] = '\0';
+ // workaround for trailing whitespace - a bit more complicated cause we have to copy
+ // it would be even better to replace null-termination with a length parameter
+ int len = strlen(str);
+ int charsToChopOffEnd = 0;
+ for (int pos = len - 1; pos >= 0 && str[pos] == ' '; pos--) {
+ charsToChopOffEnd++;
+ }
+ if (charsToChopOffEnd > 0) {
+ char *newStrBuffer = (char *)fastMalloc((len + 1) - charsToChopOffEnd);
+ strncpy(newStrBuffer, str, len - charsToChopOffEnd);
+ newStrBuffer[len - charsToChopOffEnd] = '\0';
+ fastFree(strBuffer);
+ strBuffer = newStrBuffer;
+ str = strBuffer;
}
// According to the RFC, the reference should be interpreted as an
@@ -366,108 +342,119 @@ void KURL::init(const KURL& base, const String& relative, const TextEncoding& en
// algorithm. If the URI reference is absolute it will have a
// scheme, meaning that it will have a colon before the first
// non-scheme element.
- bool absolute = false;
- char* p = str;
+ const char *p = str;
if (isSchemeFirstChar(*p)) {
++p;
while (isSchemeChar(*p)) {
++p;
}
if (*p == ':') {
- if (p[1] != '/' && equalIgnoringCase(base.protocol(), String(str, p - str)) && base.isHierarchical()) {
+ if (p[1] != '/' && base.protocol().lower() == DeprecatedString(str, p - str).lower() && base.isHierarchical())
str = p + 1;
- originalString = 0;
- } else
+ else
absolute = true;
}
}
if (absolute) {
- parse(str, originalString);
+ parse(str, (allASCII && !strippedStart && (charsToChopOffEnd == 0)) ? &rel : 0);
} else {
// If the base is empty or opaque (e.g. data: or javascript:), then the URL is invalid
// unless the relative URL is a single fragment.
if (!base.isHierarchical()) {
- if (str[0] == '#')
- parse(base.m_string.left(base.queryEndPos) + str);
- else {
- m_string = relative;
+ if (str[0] == '#') {
+ DeprecatedString newURL = base.urlString.left(base.queryEndPos) + str;
+ parse(newURL.ascii(), &newURL);
+ } else
m_isValid = false;
- }
+
+ if (strBuffer)
+ fastFree(strBuffer);
return;
}
- switch (str[0]) {
+ switch(str[0]) {
case '\0':
// the reference must be empty - the RFC says this is a
// reference to the same document
- *this = base;
- break;
+ {
+ *this = base;
+ break;
+ }
case '#':
// must be fragment-only reference
- parse(base.m_string.left(base.queryEndPos) + str);
- break;
+ {
+ DeprecatedString newURL = base.urlString.left(base.queryEndPos) + str;
+ parse(newURL.ascii(), &newURL);
+ break;
+ }
case '?':
// query-only reference, special case needed for non-URL results
- parse(base.m_string.left(base.pathEndPos) + str);
- break;
+ {
+ DeprecatedString newURL = base.urlString.left(base.pathEndPos) + str;
+ parse(newURL.ascii(), &newURL);
+ break;
+ }
case '/':
// must be net-path or absolute-path reference
- if (str[1] == '/') {
- // net-path
- parse(base.m_string.left(base.schemeEndPos + 1) + str);
- } else {
- // abs-path
- parse(base.m_string.left(base.portEndPos) + str);
+ {
+ if (str[1] == '/') {
+ // net-path
+ DeprecatedString newURL = base.urlString.left(base.schemeEndPos + 1) + str;
+ parse(newURL.ascii(), &newURL);
+ } else {
+ // abs-path
+ DeprecatedString newURL = base.urlString.left(base.portEndPos) + str;
+ parse(newURL.ascii(), &newURL);
+ }
+ break;
}
- break;
default:
{
// must be relative-path reference
// Base part plus relative part plus one possible slash added in between plus terminating \0 byte.
- CharBuffer buffer(base.pathEndPos + 1 + len + 1);
-
- char* bufferPos = buffer.data();
+ Vector<char, 2048> buffer(base.pathEndPos + 1 + strlen(str) + 1);
+ char *bufferPos = buffer.data();
+
// first copy everything before the path from the base
- unsigned baseLength = base.m_string.length();
- const UChar* baseCharacters = base.m_string.characters();
- CharBuffer baseStringBuffer(baseLength);
- for (unsigned i = 0; i < baseLength; ++i)
- baseStringBuffer[i] = static_cast<char>(baseCharacters[i]);
- const char* baseString = baseStringBuffer.data();
- const char* baseStringStart = baseString;
- const char* pathStart = baseStringStart + base.portEndPos;
- while (baseStringStart < pathStart)
+ const char *baseString = base.urlString.ascii();
+ const char *baseStringStart = baseString;
+ const char *pathStart = baseStringStart + base.portEndPos;
+ while (baseStringStart < pathStart) {
*bufferPos++ = *baseStringStart++;
- char* bufferPathStart = bufferPos;
-
- // now copy the base path
- const char* baseStringEnd = baseString + base.pathEndPos;
+ }
+ char *bufferPathStart = bufferPos;
+ // now copy the base path
+ const char *baseStringEnd = baseString + base.pathEndPos;
+
// go back to the last slash
- while (baseStringEnd > baseStringStart && baseStringEnd[-1] != '/')
+ while (baseStringEnd > baseStringStart && baseStringEnd[-1] != '/') {
baseStringEnd--;
-
+ }
+
if (baseStringEnd == baseStringStart) {
// no path in base, add a path separator if necessary
- if (base.schemeEndPos + 1 != base.pathEndPos && *str != '\0' && *str != '?' && *str != '#')
+ if (base.schemeEndPos + 1 != base.pathEndPos && *str != '\0' && *str != '?' && *str != '#') {
*bufferPos++ = '/';
+ }
} else {
bufferPos += copyPathRemovingDots(bufferPos, baseStringStart, 0, baseStringEnd - baseStringStart);
}
- const char* relStringStart = str;
- const char* relStringPos = relStringStart;
-
+ const char *relStringStart = str;
+ const char *relStringPos = relStringStart;
+
while (*relStringPos != '\0' && *relStringPos != '?' && *relStringPos != '#') {
if (relStringPos[0] == '.' && bufferPos[-1] == '/') {
if (isPathSegmentEndChar(relStringPos[1])) {
// skip over "." segment
relStringPos += 1;
- if (relStringPos[0] == '/')
+ if (relStringPos[0] == '/') {
relStringPos++;
+ }
continue;
} else if (relStringPos[1] == '.' && isPathSegmentEndChar(relStringPos[2])) {
// skip over ".." segment and rewind the last segment
@@ -475,16 +462,19 @@ void KURL::init(const KURL& base, const String& relative, const TextEncoding& en
// ".." segments - we choose to drop them since some web content
// relies on this.
relStringPos += 2;
- if (relStringPos[0] == '/')
+ if (relStringPos[0] == '/') {
relStringPos++;
- if (bufferPos > bufferPathStart + 1)
+ }
+ if (bufferPos > bufferPathStart + 1) {
bufferPos--;
- while (bufferPos > bufferPathStart + 1 && bufferPos[-1] != '/')
+ }
+ while (bufferPos > bufferPathStart + 1 && bufferPos[-1] != '/') {
bufferPos--;
+ }
continue;
}
}
-
+
*bufferPos = *relStringPos;
relStringPos++;
bufferPos++;
@@ -495,12 +485,16 @@ void KURL::init(const KURL& base, const String& relative, const TextEncoding& en
strcpy(bufferPos, relStringPos);
parse(buffer.data(), 0);
-
+
ASSERT(strlen(buffer.data()) + 1 <= buffer.size());
break;
}
}
}
+
+ if (strBuffer) {
+ fastFree(strBuffer);
+ }
}
bool KURL::hasPath() const
@@ -508,79 +502,89 @@ bool KURL::hasPath() const
return m_isValid && pathEndPos != portEndPos;
}
-String KURL::lastPathComponent() const
+DeprecatedString KURL::lastPathComponent() const
{
if (!hasPath())
- return String();
+ return DeprecatedString();
int end = pathEndPos - 1;
- if (m_string[end] == '/')
+ if (urlString[end] == '/')
--end;
- int start = m_string.reverseFind('/', end);
+ int start = urlString.findRev('/', end);
if (start < portEndPos)
- return String();
+ return DeprecatedString();
++start;
- return m_string.substring(start, end - start + 1);
+ return urlString.mid(start, end - start + 1);
}
-String KURL::protocol() const
+DeprecatedString KURL::protocol() const
{
- if (!m_isValid)
- return String();
+ if (!m_isValid) {
+ return DeprecatedString();
+ }
- return m_string.left(schemeEndPos);
+ return urlString.left(schemeEndPos);
}
-String KURL::host() const
+DeprecatedString KURL::host() const
{
- if (!m_isValid)
- return String();
+ if (!m_isValid) {
+ return DeprecatedString();
+ }
int start = (passwordEndPos == userStartPos) ? passwordEndPos : passwordEndPos + 1;
- return decodeURLEscapeSequences(m_string.substring(start, hostEndPos - start));
+ return decode_string(urlString.mid(start, hostEndPos - start));
}
-unsigned short KURL::port() const
+unsigned short int KURL::port() const
{
- if (!m_isValid)
+ if (!m_isValid) {
return 0;
+ }
- if (hostEndPos == portEndPos)
- return 0;
+ if (hostEndPos != portEndPos) {
+ bool ok;
+ unsigned short result = urlString.mid(hostEndPos + 1, portEndPos - hostEndPos - 1).toUShort(&ok);
+ if (!ok) {
+ result = 0;
+ }
+ return result;
+ }
- int number = m_string.substring(hostEndPos + 1, portEndPos - hostEndPos - 1).toInt();
- if (number < 0 || number > 0xFFFF)
- return 0;
- return number;
+ return 0;
}
-String KURL::pass() const
+DeprecatedString KURL::pass() const
{
- if (!m_isValid)
- return String();
+ if (!m_isValid) {
+ return DeprecatedString();
+ }
- if (passwordEndPos == userEndPos)
- return String();
+ if (passwordEndPos == userEndPos) {
+ return DeprecatedString();
+ }
- return decodeURLEscapeSequences(m_string.substring(userEndPos + 1, passwordEndPos - userEndPos - 1));
+ return decode_string(urlString.mid(userEndPos + 1, passwordEndPos - userEndPos - 1));
}
-String KURL::user() const
+DeprecatedString KURL::user() const
{
- if (!m_isValid)
- return String();
+ if (!m_isValid) {
+ return DeprecatedString();
+ }
- return decodeURLEscapeSequences(m_string.substring(userStartPos, userEndPos - userStartPos));
+ return decode_string(urlString.mid(userStartPos, userEndPos - userStartPos));
}
-String KURL::ref() const
+DeprecatedString KURL::ref() const
{
- if (!m_isValid || fragmentEndPos == queryEndPos)
- return String();
+ if (!m_isValid || fragmentEndPos == queryEndPos) {
+ return DeprecatedString();
+ }
- return m_string.substring(queryEndPos + 1, fragmentEndPos - (queryEndPos + 1));
+ return urlString.mid(queryEndPos + 1, fragmentEndPos - (queryEndPos + 1));
}
bool KURL::hasRef() const
@@ -588,6 +592,7 @@ bool KURL::hasRef() const
return m_isValid && fragmentEndPos != queryEndPos;
}
+#ifdef ANDROID_JAVASCRIPT_SECURITY
static inline void assertProtocolIsGood(const char* protocol)
{
#ifndef NDEBUG
@@ -606,208 +611,209 @@ bool KURL::protocolIs(const char* protocol) const
if (!m_isValid)
return false;
for (int i = 0; i < schemeEndPos; ++i) {
- if (!protocol[i] || toASCIILower(m_string[i]) != protocol[i])
+ if (!protocol[i] || toASCIILower(urlString[i].unicode()) != protocol[i])
return false;
}
return !protocol[schemeEndPos]; // We should have consumed all characters in the argument.
}
+#endif
-String KURL::query() const
+DeprecatedString KURL::query() const
{
- if (!m_isValid)
- return String();
+ if (!m_isValid) {
+ return DeprecatedString();
+ }
- return m_string.substring(pathEndPos, queryEndPos - pathEndPos);
+ return urlString.mid(pathEndPos, queryEndPos - pathEndPos);
}
-String KURL::path() const
+DeprecatedString KURL::path() const
{
- if (!m_isValid)
- return String();
+ if (!m_isValid) {
+ return DeprecatedString();
+ }
- return decodeURLEscapeSequences(m_string.substring(portEndPos, pathEndPos - portEndPos));
+ return decode_string(urlString.mid(portEndPos, pathEndPos - portEndPos));
}
-void KURL::setProtocol(const String& s)
+void KURL::setProtocol(const DeprecatedString &s)
{
if (!m_isValid) {
- parse(s + ":" + m_string);
+ DeprecatedString newURL = s + ":" + urlString;
+ parse(newURL.ascii(), &newURL);
return;
}
- parse(s + m_string.substring(schemeEndPos));
+ DeprecatedString newURL = s + urlString.mid(schemeEndPos);
+ parse(newURL.ascii(), &newURL);
}
-void KURL::setHost(const String& s)
+void KURL::setHost(const DeprecatedString &s)
{
- if (!m_isValid)
- return;
-
- bool slashSlashNeeded = userStartPos == schemeEndPos + 1;
- int hostStart = (passwordEndPos == userStartPos) ? passwordEndPos : passwordEndPos + 1;
-
- parse(m_string.left(hostStart) + (slashSlashNeeded ? "//" : "") + s + m_string.substring(hostEndPos));
+ if (m_isValid) {
+ bool slashSlashNeeded = userStartPos == schemeEndPos + 1;
+ int hostStart = (passwordEndPos == userStartPos) ? passwordEndPos : passwordEndPos + 1;
+
+ DeprecatedString newURL = urlString.left(hostStart) + (slashSlashNeeded ? "//" : DeprecatedString()) + s + urlString.mid(hostEndPos);
+ parse(newURL.ascii(), &newURL);
+ }
}
void KURL::setPort(unsigned short i)
{
- if (!m_isValid)
- return;
-
- bool colonNeeded = portEndPos == hostEndPos;
- int portStart = (colonNeeded ? hostEndPos : hostEndPos + 1);
-
- parse(m_string.left(portStart) + (colonNeeded ? ":" : "") + String::number(i) + m_string.substring(portEndPos));
+ if (m_isValid) {
+ bool colonNeeded = portEndPos == hostEndPos;
+ int portStart = (colonNeeded ? hostEndPos : hostEndPos + 1);
+ DeprecatedString newURL = urlString.left(portStart) + (colonNeeded ? ":" : DeprecatedString()) + DeprecatedString::number(i) + urlString.mid(portEndPos);
+ parse(newURL.ascii(), &newURL);
+ }
}
-void KURL::setHostAndPort(const String& hostAndPort)
+void KURL::setHostAndPort(const DeprecatedString& hostAndPort)
{
- if (!m_isValid)
- return;
-
- bool slashSlashNeeded = userStartPos == schemeEndPos + 1;
- int hostStart = (passwordEndPos == userStartPos) ? passwordEndPos : passwordEndPos + 1;
-
- parse(m_string.left(hostStart) + (slashSlashNeeded ? "//" : "") + hostAndPort + m_string.substring(portEndPos));
+ if (m_isValid) {
+ bool slashSlashNeeded = userStartPos == schemeEndPos + 1;
+ int hostStart = (passwordEndPos == userStartPos) ? passwordEndPos : passwordEndPos + 1;
+
+ DeprecatedString newURL = urlString.left(hostStart) + (slashSlashNeeded ? "//" : DeprecatedString()) + hostAndPort + urlString.mid(portEndPos);
+ parse(newURL.ascii(), &newURL);
+ }
}
-void KURL::setUser(const String& user)
+void KURL::setUser(const DeprecatedString &user)
{
- if (!m_isValid)
- return;
-
- String u;
- int end = userEndPos;
- if (!user.isEmpty()) {
- u = user;
- if (userStartPos == schemeEndPos + 1)
- u = "//" + u;
- // Add '@' if we didn't have one before.
- if (end == hostEndPos || (end == passwordEndPos && m_string[end] != '@'))
- u.append('@');
- } else {
- // Remove '@' if we now have neither user nor password.
- if (userEndPos == passwordEndPos && end != hostEndPos && m_string[end] == '@')
- end += 1;
+ if (m_isValid) {
+ DeprecatedString u;
+ int end = userEndPos;
+ if (!user.isEmpty()) {
+ u = user;
+ if (userStartPos == schemeEndPos + 1)
+ u = "//" + u;
+ // Add '@' if we didn't have one before.
+ if (end == hostEndPos || (end == passwordEndPos && urlString[end] != '@'))
+ u += '@';
+ } else {
+ // Remove '@' if we now have neither user nor password.
+ if (userEndPos == passwordEndPos && end != hostEndPos && urlString[end] == '@')
+ end += 1;
+ }
+ const DeprecatedString newURL = urlString.left(userStartPos) + u + urlString.mid(end);
+ parse(newURL.ascii(), &newURL);
}
- parse(m_string.left(userStartPos) + u + m_string.substring(end));
}
-void KURL::setPass(const String& password)
+void KURL::setPass(const DeprecatedString &password)
{
- if (!m_isValid)
- return;
-
- String p;
- int end = passwordEndPos;
- if (!password.isEmpty()) {
- p = ":" + password + "@";
- if (userEndPos == schemeEndPos + 1)
- p = "//" + p;
- // Eat the existing '@' since we are going to add our own.
- if (end != hostEndPos && m_string[end] == '@')
- end += 1;
- } else {
- // Remove '@' if we now have neither user nor password.
- if (userStartPos == userEndPos && end != hostEndPos && m_string[end] == '@')
- end += 1;
+ if (m_isValid) {
+ DeprecatedString p;
+ int end = passwordEndPos;
+ if (!password.isEmpty()) {
+ p = ':' + password + '@';
+ if (userEndPos == schemeEndPos + 1)
+ p = "//" + p;
+ // Eat the existing '@' since we are going to add our own.
+ if (end != hostEndPos && urlString[end] == '@')
+ end += 1;
+ } else {
+ // Remove '@' if we now have neither user nor password.
+ if (userStartPos == userEndPos && end != hostEndPos && urlString[end] == '@')
+ end += 1;
+ }
+ const DeprecatedString newURL = urlString.left(userEndPos) + p + urlString.mid(end);
+ parse(newURL.ascii(), &newURL);
}
- parse(m_string.left(userEndPos) + p + m_string.substring(end));
}
-void KURL::setRef(const String& s)
+void KURL::setRef(const DeprecatedString &s)
{
- if (!m_isValid)
- return;
- parse(m_string.left(queryEndPos) + (s.isEmpty() ? "" : "#" + s));
+ if (m_isValid) {
+ DeprecatedString newURL = urlString.left(queryEndPos) + (s.isEmpty() ? DeprecatedString() : "#" + s);
+ parse(newURL.ascii(), &newURL);
+ }
}
-void KURL::setQuery(const String& query)
+void KURL::setQuery(const DeprecatedString &query)
{
- if (!m_isValid)
- return;
-
- if ((query.isEmpty() || query[0] != '?') && !query.isNull())
- parse(m_string.left(pathEndPos) + "?" + query + m_string.substring(queryEndPos));
- else
- parse(m_string.left(pathEndPos) + query + m_string.substring(queryEndPos));
+ if (m_isValid) {
+ DeprecatedString q;
+ if (!query.isNull() && (query.isEmpty() || query[0] != '?')) {
+ q = "?" + query;
+ } else {
+ q = query;
+ }
+ DeprecatedString newURL = urlString.left(pathEndPos) + q + urlString.mid(queryEndPos);
+ parse(newURL.ascii(), &newURL);
+ }
}
-void KURL::setPath(const String& s)
+void KURL::setPath(const DeprecatedString &s)
{
- if (!m_isValid)
- return;
-
- parse(m_string.left(portEndPos) + encodeWithURLEscapeSequences(s) + m_string.substring(pathEndPos));
+ if (m_isValid) {
+ DeprecatedString newURL = urlString.left(portEndPos) + encode_string(s) + urlString.mid(pathEndPos);
+ parse(newURL.ascii(), &newURL);
+ }
}
-String KURL::prettyURL() const
+DeprecatedString KURL::prettyURL() const
{
- if (!m_isValid)
- return m_string;
-
- Vector<UChar> result;
+ if (!m_isValid) {
+ return urlString;
+ }
- append(result, protocol());
- result.append(':');
+ DeprecatedString result = protocol() + ":";
- Vector<UChar> authority;
+ DeprecatedString authority;
if (hostEndPos != passwordEndPos) {
if (userEndPos != userStartPos) {
- append(authority, user());
- authority.append('@');
+ authority += user();
+ authority += "@";
}
- append(authority, host());
+ authority += host();
if (port() != 0) {
- authority.append(':');
- append(authority, String::number(port()));
+ authority += ":";
+ authority += DeprecatedString::number(port());
}
}
- if (!authority.isEmpty()) {
- result.append('/');
- result.append('/');
- result.append(authority);
- } else if (protocolIs("file")) {
- result.append('/');
- result.append('/');
- }
+ if (!authority.isEmpty())
+ result += "//" + authority;
+ else if (protocol() == "file")
+ result += "//";
- append(result, path());
- append(result, query());
+ result += path();
+ result += query();
if (fragmentEndPos != queryEndPos) {
- result.append('#');
- append(result, ref());
+ result += "#" + ref();
}
- return String::adopt(result);
+ return result;
}
-String decodeURLEscapeSequences(const String& str)
+DeprecatedString KURL::decode_string(const DeprecatedString& urlString)
{
- return decodeURLEscapeSequences(str, UTF8Encoding());
+ return decode_string(urlString, UTF8Encoding());
}
-String decodeURLEscapeSequences(const String& str, const TextEncoding& encoding)
+DeprecatedString KURL::decode_string(const DeprecatedString& urlString, const TextEncoding& encoding)
{
- Vector<UChar> result;
+ DeprecatedString result("");
- CharBuffer buffer;
+ Vector<char, 2048> buffer(0);
- int length = str.length();
+ int length = urlString.length();
int decodedPosition = 0;
int searchPosition = 0;
int encodedRunPosition;
- while ((encodedRunPosition = str.find('%', searchPosition)) >= 0) {
+ while ((encodedRunPosition = urlString.find('%', searchPosition)) >= 0) {
// Find the sequence of %-escape codes.
int encodedRunEnd = encodedRunPosition;
while (length - encodedRunEnd >= 3
- && str[encodedRunEnd] == '%'
- && isASCIIHexDigit(str[encodedRunEnd + 1])
- && isASCIIHexDigit(str[encodedRunEnd + 2]))
+ && urlString[encodedRunEnd] == '%'
+ && isHexDigit(urlString[encodedRunEnd + 1].latin1())
+ && isHexDigit(urlString[encodedRunEnd + 2].latin1()))
encodedRunEnd += 3;
if (encodedRunEnd == encodedRunPosition) {
++searchPosition;
@@ -815,12 +821,16 @@ String decodeURLEscapeSequences(const String& str, const TextEncoding& encoding)
}
searchPosition = encodedRunEnd;
+ // Copy the entire %-escape sequence into an 8-bit buffer.
+ int encodedRunLength = encodedRunEnd - encodedRunPosition;
+ buffer.clear();
+ buffer.grow(encodedRunLength + 1);
+ urlString.copyLatin1(buffer.data(), encodedRunPosition, encodedRunLength);
+
// Decode the %-escapes into bytes.
- unsigned runLength = (encodedRunEnd - encodedRunPosition) / 3;
- buffer.resize(runLength);
- char* p = buffer.data();
- const UChar* q = str.characters() + encodedRunPosition;
- for (unsigned i = 0; i < runLength; ++i) {
+ char *p = buffer.data();
+ const char *q = buffer.data();
+ while (*q) {
*p++ = (hexDigitValue(q[1]) << 4) | hexDigitValue(q[2]);
q += 3;
}
@@ -831,14 +841,13 @@ String decodeURLEscapeSequences(const String& str, const TextEncoding& encoding)
continue;
// Build up the string with what we just skipped and what we just decoded.
- result.append(str.characters() + decodedPosition, encodedRunPosition - decodedPosition);
- result.append(decoded.characters(), decoded.length());
+ result.append(urlString.mid(decodedPosition, encodedRunPosition - decodedPosition));
+ result.append(reinterpret_cast<const DeprecatedChar*>(decoded.characters()), decoded.length());
decodedPosition = encodedRunEnd;
}
- result.append(str.characters() + decodedPosition, length - decodedPosition);
-
- return String::adopt(result);
+ result.append(urlString.mid(decodedPosition, length - decodedPosition));
+ return result;
}
bool KURL::isLocalFile() const
@@ -847,15 +856,15 @@ bool KURL::isLocalFile() const
// and including feed would allow feeds to potentially let someone's blog
// read the contents of the clipboard on a drag, even without a drop.
// Likewise with using the FrameLoader::shouldTreatURLAsLocal() function.
- return protocolIs("file");
+ return equalIgnoringCase(protocol(), "file");
}
-static void appendEscapingBadChars(char*& buffer, const char* strStart, size_t length)
+static void appendEscapingBadChars(char*& buffer, const char *strStart, size_t length)
{
- char* p = buffer;
+ char *p = buffer;
- const char* str = strStart;
- const char* strEnd = strStart + length;
+ const char *str = strStart;
+ const char *strEnd = strStart + length;
while (str < strEnd) {
unsigned char c = *str++;
if (isBadChar(c)) {
@@ -870,20 +879,20 @@ static void appendEscapingBadChars(char*& buffer, const char* strStart, size_t l
*p++ = c;
}
}
-
+
buffer = p;
}
// copy a path, accounting for "." and ".." segments
-static int copyPathRemovingDots(char* dst, const char* src, int srcStart, int srcEnd)
+static int copyPathRemovingDots(char *dst, const char *src, int srcStart, int srcEnd)
{
- char* bufferPathStart = dst;
+ char *bufferPathStart = dst;
// empty path is a special case, and need not have a leading slash
if (srcStart != srcEnd) {
- const char* baseStringStart = src + srcStart;
- const char* baseStringEnd = src + srcEnd;
- const char* baseStringPos = baseStringStart;
+ const char *baseStringStart = src + srcStart;
+ const char *baseStringEnd = src + srcEnd;
+ const char *baseStringPos = baseStringStart;
// this code is unprepared for paths that do not begin with a
// slash and we should always have one in the source string
@@ -932,9 +941,9 @@ static int copyPathRemovingDots(char* dst, const char* src, int srcStart, int sr
return dst - bufferPathStart;
}
-static inline bool hasSlashDotOrDotDot(const char* str)
+static inline bool hasSlashDotOrDotDot(const char *str)
{
- const unsigned char* p = reinterpret_cast<const unsigned char*>(str);
+ const unsigned char *p = reinterpret_cast<const unsigned char *>(str);
if (!*p)
return false;
unsigned char pc = *p;
@@ -951,30 +960,21 @@ static inline bool matchLetter(char c, char lowercaseLetter)
return (c | 0x20) == lowercaseLetter;
}
-void KURL::parse(const String& string)
-{
- // FIXME: This throws away the high bytes of all the characters in the string!
- CharBuffer buffer(string.length() + 1);
- copyASCII(string.characters(), string.length(), buffer.data());
- buffer[string.length()] = '\0';
- parse(buffer.data(), &string);
-}
-
-void KURL::parse(const char* url, const String* originalString)
+void KURL::parse(const char *url, const DeprecatedString *originalString)
{
m_isValid = true;
if (!url || url[0] == '\0') {
// valid URL must be non-empty
- m_string = originalString ? *originalString : url;
m_isValid = false;
+ urlString = url;
return;
}
if (!isSchemeFirstChar(url[0])) {
// scheme must start with an alphabetic character
- m_string = originalString ? *originalString : url;
m_isValid = false;
+ urlString = url;
return;
}
@@ -985,8 +985,8 @@ void KURL::parse(const char* url, const String* originalString)
}
if (url[schemeEnd] != ':') {
- m_string = originalString ? *originalString : url;
m_isValid = false;
+ urlString = url;
return;
}
@@ -1004,7 +1004,7 @@ void KURL::parse(const char* url, const String* originalString)
if (hierarchical && url[schemeEnd + 2] == '/') {
// part after the scheme must be a net_path, parse the authority section
- // FIXME: Authority characters may be scanned twice.
+ // FIXME: authority characters may be scanned twice
userStart += 2;
userEnd = userStart;
@@ -1015,7 +1015,7 @@ void KURL::parse(const char* url, const String* originalString)
}
userEnd++;
}
-
+
if (url[userEnd] == '@') {
// actual end of the userinfo, start on the host
if (colonPos != 0) {
@@ -1035,8 +1035,8 @@ void KURL::parse(const char* url, const String* originalString)
hostStart = userStart;
} else {
// invalid character
- m_string = originalString ? *originalString : url;
m_isValid = false;
+ urlString = url;
return;
}
@@ -1052,8 +1052,8 @@ void KURL::parse(const char* url, const String* originalString)
hostEnd++;
} else {
// invalid character
- m_string = originalString ? *originalString : url;
m_isValid = false;
+ urlString = url;
return;
}
} else {
@@ -1076,8 +1076,8 @@ void KURL::parse(const char* url, const String* originalString)
if (!isPathSegmentEndChar(url[portEnd])) {
// invalid character
- m_string = originalString ? *originalString : url;
m_isValid = false;
+ urlString = url;
return;
}
} else {
@@ -1087,7 +1087,7 @@ void KURL::parse(const char* url, const String* originalString)
hostStart = hostEnd = passwordEnd;
portStart = portEnd = hostEnd;
}
-
+
int pathStart = portEnd;
int pathEnd = pathStart;
int queryStart;
@@ -1098,14 +1098,14 @@ void KURL::parse(const char* url, const String* originalString)
if (!hierarchical) {
while (url[pathEnd] != '\0' && url[pathEnd] != '?' && url[pathEnd] != '#')
pathEnd++;
-
+
queryStart = pathEnd;
queryEnd = queryStart;
if (url[queryStart] == '?') {
while (url[queryEnd] != '\0' && url[queryEnd] != '#')
queryEnd++;
}
-
+
fragmentStart = queryEnd;
fragmentEnd = fragmentStart;
if (url[fragmentStart] == '#') {
@@ -1113,13 +1113,13 @@ void KURL::parse(const char* url, const String* originalString)
fragmentEnd = fragmentStart;
while (url[fragmentEnd] != '\0')
fragmentEnd++;
- }
+ }
}
else {
while (url[pathEnd] != '\0' && url[pathEnd] != '?' && url[pathEnd] != '#') {
pathEnd++;
}
-
+
queryStart = pathEnd;
queryEnd = queryStart;
if (url[queryStart] == '?') {
@@ -1127,7 +1127,7 @@ void KURL::parse(const char* url, const String* originalString)
queryEnd++;
}
}
-
+
fragmentStart = queryEnd;
fragmentEnd = fragmentStart;
if (url[fragmentStart] == '#') {
@@ -1148,8 +1148,9 @@ void KURL::parse(const char* url, const String* originalString)
// copy in the scheme
const char *schemeEndPtr = url + schemeEnd;
- while (strPtr < schemeEndPtr)
+ while (strPtr < schemeEndPtr) {
*p++ = *strPtr++;
+ }
schemeEndPos = p - buffer.data();
// Check if we're http or https.
@@ -1176,12 +1177,12 @@ void KURL::parse(const char* url, const String* originalString)
&& matchLetter(url[2], 'l')
&& matchLetter(url[3], 'e')
&& url[4] == ':';
-
+
// File URLs need a host part unless it is just file:// or file://localhost
bool degenFilePath = pathStart == pathEnd
&& (hostStart == hostEnd
|| hostIsLocalHost);
-
+
bool haveNonHostAuthorityPart = userStart != userEnd || passwordStart != passwordEnd || portStart != portEnd;
// add ":" after scheme
@@ -1204,41 +1205,46 @@ void KURL::parse(const char* url, const String* originalString)
// copy in the user
strPtr = url + userStart;
- const char* userEndPtr = url + userEnd;
- while (strPtr < userEndPtr)
+ const char *userEndPtr = url + userEnd;
+ while (strPtr < userEndPtr) {
*p++ = *strPtr++;
+ }
userEndPos = p - buffer.data();
-
+
// copy in the password
if (passwordEnd != passwordStart) {
*p++ = ':';
strPtr = url + passwordStart;
- const char* passwordEndPtr = url + passwordEnd;
- while (strPtr < passwordEndPtr)
+ const char *passwordEndPtr = url + passwordEnd;
+ while (strPtr < passwordEndPtr) {
*p++ = *strPtr++;
+ }
}
passwordEndPos = p - buffer.data();
-
+
// If we had any user info, add "@"
- if (p - buffer.data() != userStartPos)
+ if (p - buffer.data() != userStartPos) {
*p++ = '@';
-
+ }
+
// copy in the host, except in the case of a file URL with authority="localhost"
if (!(isFile && hostIsLocalHost && !haveNonHostAuthorityPart)) {
strPtr = url + hostStart;
- const char* hostEndPtr = url + hostEnd;
- while (strPtr < hostEndPtr)
+ const char *hostEndPtr = url + hostEnd;
+ while (strPtr < hostEndPtr) {
*p++ = *strPtr++;
+ }
}
hostEndPos = p - buffer.data();
-
+
// copy in the port
if (hostEnd != portStart) {
*p++ = ':';
strPtr = url + portStart;
const char *portEndPtr = url + portEnd;
- while (strPtr < portEndPtr)
+ while (strPtr < portEndPtr) {
*p++ = *strPtr++;
+ }
}
portEndPos = p - buffer.data();
} else {
@@ -1247,23 +1253,26 @@ void KURL::parse(const char* url, const String* originalString)
// For canonicalization, ensure we have a '/' for no path.
// Only do this for http and https.
- if (isHTTPorHTTPS && pathEnd - pathStart == 0)
+ if (isHTTPorHTTPS && pathEnd - pathStart == 0) {
*p++ = '/';
-
+ }
+
// add path, escaping bad characters
+
if (hierarchical && hasSlashDotOrDotDot(url)) {
- CharBuffer path_buffer(pathEnd - pathStart + 1);
+ Vector<char, 4096> path_buffer(pathEnd - pathStart + 1);
copyPathRemovingDots(path_buffer.data(), url, pathStart, pathEnd);
appendEscapingBadChars(p, path_buffer.data(), strlen(path_buffer.data()));
} else
appendEscapingBadChars(p, url + pathStart, pathEnd - pathStart);
pathEndPos = p - buffer.data();
-
+
+
// add query, escaping bad characters
appendEscapingBadChars(p, url + queryStart, queryEnd - queryStart);
queryEndPos = p - buffer.data();
-
+
// add fragment, escaping bad characters
if (fragmentEnd != queryEnd) {
*p++ = '#';
@@ -1271,36 +1280,36 @@ void KURL::parse(const char* url, const String* originalString)
}
fragmentEndPos = p - buffer.data();
+ // If we didn't end up actually changing the original string and
+ // it started as a DeprecatedString, just reuse it, to avoid extra
+ // allocation.
+ if (originalString && strncmp(buffer.data(), url, fragmentEndPos) == 0) {
+ urlString = *originalString;
+ } else
+ urlString = DeprecatedString(buffer.data(), fragmentEndPos);
+
ASSERT(p - buffer.data() <= (int)buffer.size());
+}
- // If we didn't end up actually changing the original string and
- // it was already in a String, reuse it to avoid extra allocation.
- if (originalString && strncmp(buffer.data(), url, fragmentEndPos) == 0)
- m_string = *originalString;
- else
- m_string = String(buffer.data(), fragmentEndPos);
+bool operator==(const KURL &a, const KURL &b)
+{
+ return a.urlString == b.urlString;
}
bool equalIgnoringRef(const KURL& a, const KURL& b)
{
- if (a.queryEndPos != b.queryEndPos)
- return false;
- unsigned queryLength = a.queryEndPos;
- for (unsigned i = 0; i < queryLength; ++i)
- if (a.string()[i] != b.string()[i])
- return false;
- return true;
+ return a.urlString.left(a.queryEndPos) == b.urlString.left(b.queryEndPos);
}
-String encodeWithURLEscapeSequences(const String& notEncodedString)
+DeprecatedString KURL::encode_string(const DeprecatedString& notEncodedString)
{
- CString asUTF8 = notEncodedString.utf8();
-
- CharBuffer buffer(asUTF8.length() * 3 + 1);
- char* p = buffer.data();
+ DeprecatedCString asUTF8 = notEncodedString.utf8();
+
+ Vector<char, 4096> buffer(asUTF8.length() * 3 + 1);
+ char *p = buffer.data();
- const char* str = asUTF8.data();
- const char* strEnd = str + asUTF8.length();
+ const char *str = asUTF8;
+ const char *strEnd = str + asUTF8.length();
while (str < strEnd) {
unsigned char c = *str++;
if (isBadChar(c)) {
@@ -1310,92 +1319,96 @@ String encodeWithURLEscapeSequences(const String& notEncodedString)
} else
*p++ = c;
}
+
+ DeprecatedString result(buffer.data(), p - buffer.data());
+
+ ASSERT(p - buffer.data() <= (int)buffer.size());
- ASSERT(p - buffer.data() <= static_cast<int>(buffer.size()));
-
- return String(buffer.data(), p - buffer.data());
+ return result;
}
-// Appends the punycoded hostname identified by the given string and length to
-// the output buffer. The result will not be null terminated.
-static void appendEncodedHostname(UCharBuffer& buffer, const UChar* str, unsigned strLen)
+static DeprecatedString encodeHostname(const DeprecatedString &s)
{
// Needs to be big enough to hold an IDN-encoded name.
// For host names bigger than this, we won't do IDN encoding, which is almost certainly OK.
const unsigned hostnameBufferLength = 2048;
- if (strLen > hostnameBufferLength || charactersAreAllASCII(str, strLen))
- buffer.append(str, strLen);
+ if (s.isAllASCII() || s.length() > hostnameBufferLength)
+ return s;
#if USE(ICU_UNICODE)
- UChar hostnameBuffer[hostnameBufferLength];
+ UChar buffer[hostnameBufferLength];
UErrorCode error = U_ZERO_ERROR;
- int32_t numCharactersConverted = uidna_IDNToASCII(str, strLen, hostnameBuffer,
- hostnameBufferLength, UIDNA_ALLOW_UNASSIGNED, 0, &error);
- if (error != U_ZERO_ERROR)
- buffer.append(hostnameBuffer, numCharactersConverted);
+ int32_t numCharactersConverted = uidna_IDNToASCII
+ (reinterpret_cast<const UChar *>(s.unicode()), s.length(), buffer, hostnameBufferLength, UIDNA_ALLOW_UNASSIGNED, 0, &error);
+ if (error != U_ZERO_ERROR) {
+ return s;
+ }
+ return DeprecatedString(reinterpret_cast<DeprecatedChar *>(buffer), numCharactersConverted);
#elif USE(QT4_UNICODE)
- QByteArray result = QUrl::toAce(String(str, strLen));
- buffer.append(result.constData(), result.length());
+ QByteArray result = QUrl::toAce(s);
+ return DeprecatedString(result.constData(), result.length());
#endif
}
-static void findHostnamesInMailToURL(const UChar* str, int strLen, Vector<pair<int, int> >& nameRanges)
+static Vector<pair<int, int> > findHostnamesInMailToURL(const DeprecatedString &s)
{
// In a mailto: URL, host names come after a '@' character and end with a '>' or ',' or '?' or end of string character.
// Skip quoted strings so that characters in them don't confuse us.
// When we find a '?' character, we are past the part of the URL that contains host names.
- nameRanges.clear();
+ Vector<pair<int, int> > a;
int p = 0;
while (1) {
// Find start of host name or of quoted string.
- int hostnameOrStringStart = findFirstOf(str, strLen, p, "\"@?");
- if (hostnameOrStringStart == -1)
- return;
- UChar c = str[hostnameOrStringStart];
+ int hostnameOrStringStart = s.find(RegularExpression("[\"@?]"), p);
+ if (hostnameOrStringStart == -1) {
+ return a;
+ }
+ DeprecatedChar c = s[hostnameOrStringStart];
p = hostnameOrStringStart + 1;
- if (c == '?')
- return;
-
+ if (c == '?') {
+ return a;
+ }
+
if (c == '@') {
// Find end of host name.
int hostnameStart = p;
- int hostnameEnd = findFirstOf(str, strLen, p, ">,?");
+ int hostnameEnd = s.find(RegularExpression("[>,?]"), p);
bool done;
if (hostnameEnd == -1) {
- hostnameEnd = strLen;
+ hostnameEnd = s.length();
done = true;
} else {
p = hostnameEnd;
done = false;
}
- nameRanges.append(make_pair(hostnameStart, hostnameEnd));
+ a.append(make_pair(hostnameStart, hostnameEnd));
if (done)
- return;
+ return a;
} else {
// Skip quoted string.
ASSERT(c == '"');
while (1) {
- int escapedCharacterOrStringEnd = findFirstOf(str, strLen, p, "\"\\");
+ int escapedCharacterOrStringEnd = s.find(RegularExpression("[\"\\]"), p);
if (escapedCharacterOrStringEnd == -1)
- return;
+ return a;
- c = str[escapedCharacterOrStringEnd];
+ c = s[escapedCharacterOrStringEnd];
p = escapedCharacterOrStringEnd + 1;
-
+
// If we are the end of the string, then break from the string loop back to the host name loop.
if (c == '"')
break;
-
+
// Skip escaped character.
ASSERT(c == '\\');
- if (p == strLen)
- return;
+ if (p == static_cast<int>(s.length()))
+ return a;
++p;
}
@@ -1403,168 +1416,158 @@ static void findHostnamesInMailToURL(const UChar* str, int strLen, Vector<pair<i
}
}
-static bool findHostnameInHierarchicalURL(const UChar* str, int strLen, int& startOffset, int& endOffset)
+static bool findHostnameInHierarchicalURL(const DeprecatedString &s, int &startOffset, int &endOffset)
{
// Find the host name in a hierarchical URL.
- // It comes after a "://" sequence, with scheme characters preceding, and
- // this should be the first colon in the string.
- // It ends with the end of the string or a ":" or a path segment ending character.
+ // It comes after a "://" sequence, with scheme characters preceding.
+ // If ends with the end of the string or a ":" or a path segment ending character.
// If there is a "@" character, the host part is just the part after the "@".
- int separator = findFirstOf(str, strLen, 0, ":");
- if (separator == -1 || separator + 2 >= strLen ||
- str[separator + 1] != '/' || str[separator + 2] != '/')
+ int separator = s.find("://");
+ if (separator <= 0) {
return false;
+ }
// Check that all characters before the :// are valid scheme characters.
- if (!isSchemeFirstChar(str[0]))
+ if (!isSchemeFirstChar(s[0].latin1())) {
return false;
+ }
for (int i = 1; i < separator; ++i) {
- if (!isSchemeChar(str[i]))
+ if (!isSchemeChar(s[i].latin1())) {
return false;
+ }
}
// Start after the separator.
int authorityStart = separator + 3;
// Find terminating character.
- int hostnameEnd = strLen;
- for (int i = authorityStart; i < strLen; ++i) {
- UChar c = str[i];
- if (c == ':' || (isPathSegmentEndChar(c) && c != 0)) {
+ int length = s.length();
+ int hostnameEnd = length;
+ for (int i = authorityStart; i < length; ++i) {
+ char c = s[i].latin1();
+ if (c == ':' || (isPathSegmentEndChar(c) && c != '\0')) {
hostnameEnd = i;
break;
}
}
// Find "@" for the start of the host name.
- int userInfoTerminator = findFirstOf(str, strLen, authorityStart, "@");
+ int userInfoTerminator = s.find('@', authorityStart);
int hostnameStart;
- if (userInfoTerminator == -1 || userInfoTerminator > hostnameEnd)
+ if (userInfoTerminator == -1 || userInfoTerminator > hostnameEnd) {
hostnameStart = authorityStart;
- else
+ } else {
hostnameStart = userInfoTerminator + 1;
+ }
startOffset = hostnameStart;
endOffset = hostnameEnd;
return true;
}
-// Converts all hostnames found in the given input to punycode, preserving the
-// rest of the URL unchanged. The output will NOT be null-terminated.
-static void encodeHostnames(const String& str, UCharBuffer& output)
+static DeprecatedString encodeHostnames(const DeprecatedString &s)
{
- output.clear();
-
- if (protocolIs(str, "mailto")) {
- Vector<pair<int, int> > hostnameRanges;
- findHostnamesInMailToURL(str.characters(), str.length(), hostnameRanges);
+ if (s.startsWith("mailto:", false)) {
+ const Vector<pair<int, int> > hostnameRanges = findHostnamesInMailToURL(s);
int n = hostnameRanges.size();
- int p = 0;
- for (int i = 0; i < n; ++i) {
- const pair<int, int>& r = hostnameRanges[i];
- output.append(&str.characters()[p], r.first - p);
- appendEncodedHostname(output, &str.characters()[r.first], r.second - r.first);
- p = r.second;
+ if (n != 0) {
+ DeprecatedString result;
+ unsigned p = 0;
+ for (int i = 0; i < n; ++i) {
+ const pair<int, int> &r = hostnameRanges[i];
+ result += s.mid(p, r.first);
+ result += encodeHostname(s.mid(r.first, r.second - r.first));
+ p = r.second;
+ }
+ result += s.mid(p);
+ return result;
}
- // This will copy either everything after the last hostname, or the
- // whole thing if there is no hostname.
- output.append(&str.characters()[p], str.length() - p);
} else {
int hostStart, hostEnd;
- if (findHostnameInHierarchicalURL(str.characters(), str.length(), hostStart, hostEnd)) {
- output.append(str.characters(), hostStart); // Before hostname.
- appendEncodedHostname(output, &str.characters()[hostStart], hostEnd - hostStart);
- output.append(&str.characters()[hostEnd], str.length() - hostEnd); // After hostname.
- } else {
- // No hostname to encode, return the input.
- output.append(str.characters(), str.length());
+ if (findHostnameInHierarchicalURL(s, hostStart, hostEnd)) {
+ return s.left(hostStart) + encodeHostname(s.mid(hostStart, hostEnd - hostStart)) + s.mid(hostEnd);
}
}
+ return s;
}
-static void encodeRelativeString(const String& rel, const TextEncoding& encoding, CharBuffer& output)
+static char *encodeRelativeString(const KURL &base, const DeprecatedString &rel, const TextEncoding& encoding)
{
- UCharBuffer s;
- encodeHostnames(rel, s);
+ DeprecatedString s = encodeHostnames(rel);
- TextEncoding pathEncoding(UTF8Encoding());
- TextEncoding otherEncoding = (encoding.isValid() && !protocolIs(rel, "mailto")) ? encoding : UTF8Encoding();
+ char *strBuffer;
+ TextEncoding pathEncoding(UTF8Encoding());
+ TextEncoding otherEncoding = (encoding.isValid() && !rel.startsWith("mailto:", false)) ? encoding : UTF8Encoding();
+
int pathEnd = -1;
if (pathEncoding != otherEncoding) {
- // Find the first instance of either # or ?, keep pathEnd at -1 otherwise.
- pathEnd = findFirstOf(s.data(), s.size(), 0, "#?");
+ pathEnd = s.find(RegularExpression("[?#]"));
}
-
if (pathEnd == -1) {
- CString decoded = pathEncoding.encode(s.data(), s.size());
- output.resize(decoded.length());
- memcpy(output.data(), decoded.data(), decoded.length());
+ CString decoded = pathEncoding.encode(reinterpret_cast<const UChar*>(s.unicode()), s.length());
+ int decodedLength = decoded.length();
+ strBuffer = static_cast<char *>(fastMalloc(decodedLength + 1));
+ memcpy(strBuffer, decoded.data(), decodedLength);
+ strBuffer[decodedLength] = 0;
} else {
- CString pathDecoded = pathEncoding.encode(s.data(), pathEnd);
- CString otherDecoded = otherEncoding.encode(s.data() + pathEnd, s.size() - pathEnd);
-
- output.resize(pathDecoded.length() + otherDecoded.length());
- memcpy(output.data(), pathDecoded.data(), pathDecoded.length());
- memcpy(output.data() + pathDecoded.length(), otherDecoded.data(), otherDecoded.length());
+ int length = s.length();
+ CString pathDecoded = pathEncoding.encode(reinterpret_cast<const UChar*>(s.unicode()), pathEnd);
+ CString otherDecoded = otherEncoding.encode(reinterpret_cast<const UChar*>(s.unicode()) + pathEnd, length - pathEnd);
+ int pathDecodedLength = pathDecoded.length();
+ int otherDecodedLength = otherDecoded.length();
+ strBuffer = static_cast<char *>(fastMalloc(pathDecodedLength + otherDecodedLength + 1));
+ memcpy(strBuffer, pathDecoded.data(), pathDecodedLength);
+ memcpy(strBuffer + pathDecodedLength, otherDecoded.data(), otherDecodedLength);
+ strBuffer[pathDecodedLength + otherDecodedLength] = 0;
}
- output.append('\0'); // null-terminate the output.
+
+ return strBuffer;
}
-static String substituteBackslashes(const String& string)
+static DeprecatedString substituteBackslashes(const DeprecatedString &string)
{
int questionPos = string.find('?');
int hashPos = string.find('#');
- int pathEnd;
-
- if (hashPos >= 0 && (questionPos < 0 || questionPos > hashPos))
+ unsigned pathEnd;
+
+ if (hashPos >= 0 && (questionPos < 0 || questionPos > hashPos)) {
pathEnd = hashPos;
- else if (questionPos >= 0)
+ } else if (questionPos >= 0) {
pathEnd = questionPos;
- else
+ } else {
pathEnd = string.length();
+ }
- return string.left(pathEnd).replace('\\','/') + string.substring(pathEnd);
+ return string.left(pathEnd).replace('\\','/') + string.mid(pathEnd);
}
bool KURL::isHierarchical() const
{
if (!m_isValid)
return false;
- ASSERT(m_string[schemeEndPos] == ':');
- return m_string[schemeEndPos + 1] == '/';
-}
-
-void KURL::copyToBuffer(CharBuffer& buffer) const
-{
- // FIXME: This throws away the high bytes of all the characters in the string!
- // That's fine for a valid URL, which is all ASCII, but not for invalid URLs.
- buffer.resize(m_string.length());
- copyASCII(m_string.characters(), m_string.length(), buffer.data());
+ ASSERT(urlString[schemeEndPos] == ':');
+ return urlString[schemeEndPos + 1] == '/';
}
+#ifdef ANDROID_JAVASCRIPT_SECURITY
bool protocolIs(const String& url, const char* protocol)
{
- // Do the comparison without making a new string object.
assertProtocolIsGood(protocol);
+ String stripped = url.stripWhiteSpace();
for (int i = 0; ; ++i) {
if (!protocol[i])
- return url[i] == ':';
- if (toASCIILower(url[i]) != protocol[i])
+ return stripped[i] == ':';
+ if (toASCIILower(stripped[i]) != protocol[i])
return false;
}
}
-
-const KURL& blankURL()
-{
- static KURL staticBlankURL("about:blank");
- return staticBlankURL;
-}
+#endif
#ifndef NDEBUG
void KURL::print() const
{
- printf("%s\n", m_string.utf8().data());
+ printf("%s\n", urlString.ascii());
}
#endif
diff --git a/WebCore/platform/KURL.h b/WebCore/platform/KURL.h
index 8728e4f..5c340d4 100644
--- a/WebCore/platform/KURL.h
+++ b/WebCore/platform/KURL.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -26,10 +26,12 @@
#ifndef KURL_h
#define KURL_h
+#include "DeprecatedString.h"
#include "PlatformString.h"
+#include <wtf/Platform.h>
#if PLATFORM(CF)
-typedef const struct __CFURL* CFURLRef;
+typedef const struct __CFURL * CFURLRef;
#endif
#if PLATFORM(MAC)
@@ -39,142 +41,107 @@ typedef const struct __CFURL* CFURLRef;
class NSURL;
#endif
#endif
-
#if PLATFORM(QT)
class QUrl;
#endif
namespace WebCore {
-class TextEncoding;
+ class KURL;
+ class TextEncoding;
+
+ bool operator==(const KURL&, const KURL&);
+ inline bool operator!=(const KURL &a, const KURL &b) { return !(a == b); }
+
+ bool equalIgnoringRef(const KURL&, const KURL&);
class KURL {
public:
- // Generates a URL which contains a null string.
KURL();
+ KURL(const char*);
+ KURL(const KURL&, const DeprecatedString&);
+ KURL(const KURL&, const DeprecatedString&, const TextEncoding&);
+ KURL(const DeprecatedString&);
+#if PLATFORM(MAC)
+ KURL(NSURL*);
+#endif
+#if PLATFORM(CF)
+ KURL(CFURLRef);
+#endif
+#if PLATFORM(QT)
+ KURL(const QUrl&);
+#endif
+
+ bool isNull() const { return urlString.isNull(); }
+ bool isEmpty() const { return urlString.isEmpty(); }
- // The argument is an absolute URL string. The string is assumed to be
- // already encoded.
- // FIXME: This constructor has a special case for strings that start with
- // "/", prepending "file://" to such strings; it would be good to get
- // rid of that special case.
- explicit KURL(const char*);
-
- // The argument is an absolute URL string. The string is assumed to be
- // already encoded.
- // FIXME: For characters with codes other than 0000-00FF will be chopped
- // off, so this call is currently not safe to use with arbitrary strings.
- // FIXME: This constructor has a special case for strings that start with
- // "/", prepending "file://" to such strings; it would be good to get
- // rid of that special case.
- explicit KURL(const String&);
-
- // Resolves the relative URL with the given base URL. If provided, the
- // TextEncoding is used to encode non-ASCII characers. The base URL can be
- // null or empty, in which case the relative URL will be interpreted as
- // absolute.
- // FIXME: If the base URL is invalid, this always creates an invalid
- // URL. Instead I think it would be better to treat all invalid base URLs
- // the same way we treate null and empty base URLs.
- KURL(const KURL& base, const String& relative);
- KURL(const KURL& base, const String& relative, const TextEncoding&);
-
- // FIXME: The above functions should be harmonized so that passing a
- // base of null or the empty string gives the same result as the
- // standard String constructor.
-
- bool isNull() const { return m_string.isNull(); }
- bool isEmpty() const { return m_string.isEmpty(); }
-
- // Returns true if this URL has a path. Note that "http://foo.com/" has a
- // path of "/", so this function will return true. Only invalid or
- // non-hierarchical (like "javascript:") URLs will have no path.
bool hasPath() const;
- const String& string() const { return m_string; }
-
- String protocol() const;
- String host() const;
- unsigned short port() const;
- String user() const;
- String pass() const;
- String path() const;
- String lastPathComponent() const;
- String query() const; // Includes the "?".
- String ref() const; // Does *not* include the "#".
+ String string() const { return urlString; }
+ const DeprecatedString& deprecatedString() const { return urlString; }
+
+ DeprecatedString protocol() const;
+ DeprecatedString host() const;
+ unsigned short int port() const;
+ DeprecatedString user() const;
+ DeprecatedString pass() const;
+ DeprecatedString path() const;
+ DeprecatedString lastPathComponent() const;
+ DeprecatedString query() const;
+ DeprecatedString ref() const;
bool hasRef() const;
- String prettyURL() const;
- String fileSystemPath() const;
-
- // Returns true if the current URL's protocol is the same as the null-
- // terminated ASCII argument. The argument must be lower-case.
- bool protocolIs(const char*) const;
- bool isLocalFile() const;
-
- void setProtocol(const String&);
- void setHost(const String&);
-
- // Setting the port to 0 will clear any port from the URL.
- void setPort(unsigned short);
-
- // Input is like "foo.com" or "foo.com:8000".
- void setHostAndPort(const String&);
-
- void setUser(const String&);
- void setPass(const String&);
-
- // If you pass an empty path for HTTP or HTTPS URLs, the resulting path
- // will be "/".
- void setPath(const String&);
+ DeprecatedString encodedHtmlRef() const { return ref(); }
- // The query may begin with a question mark, or, if not, one will be added
- // for you. Setting the query to the empty string will leave a "?" in the
- // URL (with nothing after it). To clear the query, pass a null string.
- void setQuery(const String&);
+ void setProtocol(const DeprecatedString &);
+ void setHost(const DeprecatedString &);
+ void setPort(unsigned short int);
+ void setHostAndPort(const DeprecatedString&);
+ void setUser(const DeprecatedString &);
+ void setPass(const DeprecatedString &);
+ void setPath(const DeprecatedString &);
+ void setQuery(const DeprecatedString &);
+ void setRef(const DeprecatedString &);
- void setRef(const String&);
-
- friend bool equalIgnoringRef(const KURL&, const KURL&);
-
- operator const String&() const { return m_string; }
- operator KJS::UString() const { return m_string; }
+ DeprecatedString prettyURL() const;
#if PLATFORM(CF)
- KURL(CFURLRef);
CFURLRef createCFURL() const;
#endif
-
#if PLATFORM(MAC)
- KURL(NSURL*);
- operator NSURL*() const;
-#endif
-#ifdef __OBJC__
- operator NSString*() const { return m_string; }
+ NSURL *getNSURL() const;
#endif
-
#if PLATFORM(QT)
- KURL(const QUrl&);
operator QUrl() const;
#endif
+#ifdef ANDROID_JAVASCRIPT_SECURITY
+ // Returns true if the current URL's protocol is the same as the null-
+ // terminated ASCII argument. The argument must be lower-case.
+ bool protocolIs(const char*) const;
+#endif
+ bool isLocalFile() const;
+ String fileSystemPath() const;
+
+ static DeprecatedString decode_string(const DeprecatedString&);
+ static DeprecatedString decode_string(const DeprecatedString&, const TextEncoding&);
+ static DeprecatedString encode_string(const DeprecatedString&);
+
+ friend bool operator==(const KURL &, const KURL &);
+
#ifndef NDEBUG
void print() const;
#endif
private:
bool isHierarchical() const;
- void init(const KURL&, const String&, const TextEncoding&);
+ void init(const KURL&, const DeprecatedString&, const TextEncoding&);
+#ifdef ANDROID_JAVASCRIPT_SECURITY
static bool protocolIs(const String&, const char*);
- void copyToBuffer(Vector<char, 512>& buffer) const;
-
- // Parses the given URL. The originalString parameter allows for an
- // optimization: When the source is the same as the fixed-up string,
- // it will use the passed-in string instead of allocating a new one.
- void parse(const String&);
- void parse(const char* url, const String* originalString);
+#endif
+ void parse(const char *url, const DeprecatedString *originalString);
- String m_string;
+ DeprecatedString urlString;
bool m_isValid;
int schemeEndPos;
int userStartPos;
@@ -185,63 +152,13 @@ private:
int pathEndPos;
int queryEndPos;
int fragmentEndPos;
+
+ friend bool equalIgnoringRef(const KURL& a, const KURL& b);
};
-bool operator==(const KURL&, const KURL&);
-bool operator==(const KURL&, const String&);
-bool operator==(const String&, const KURL&);
-bool operator!=(const KURL&, const KURL&);
-bool operator!=(const KURL&, const String&);
-bool operator!=(const String&, const KURL&);
-
-bool equalIgnoringRef(const KURL&, const KURL&);
-
-const KURL& blankURL();
-
-// Functions to do URL operations on strings.
-// These are operations that aren't faster on a parsed URL.
-
+#ifdef ANDROID_JAVASCRIPT_SECURITY
bool protocolIs(const String& url, const char* protocol);
-
-// Unescapes the given string using URL escaping rules, given an optional
-// encoding (defaulting to UTF-8 otherwise). DANGER: If the URL has "%00"
-// in it, the resulting string will have embedded null characters!
-String decodeURLEscapeSequences(const String&);
-String decodeURLEscapeSequences(const String&, const TextEncoding&);
-
-String encodeWithURLEscapeSequences(const String&);
-
-// Inlines.
-
-inline bool operator==(const KURL& a, const KURL& b)
-{
- return a.string() == b.string();
-}
-
-inline bool operator==(const KURL& a, const String& b)
-{
- return a.string() == b;
-}
-
-inline bool operator==(const String& a, const KURL& b)
-{
- return a == b.string();
-}
-
-inline bool operator!=(const KURL& a, const KURL& b)
-{
- return a.string() != b.string();
-}
-
-inline bool operator!=(const KURL& a, const String& b)
-{
- return a.string() != b;
-}
-
-inline bool operator!=(const String& a, const KURL& b)
-{
- return a != b.string();
-}
+#endif
}
diff --git a/WebCore/platform/LocalizedStrings.h b/WebCore/platform/LocalizedStrings.h
index f640c78..a61f3ce 100644
--- a/WebCore/platform/LocalizedStrings.h
+++ b/WebCore/platform/LocalizedStrings.h
@@ -29,8 +29,7 @@
namespace WebCore {
class String;
- class IntSize;
-
+
String inputElementAltText();
String resetButtonDefaultLabel();
String searchableIndexIntroduction();
@@ -106,8 +105,6 @@ namespace WebCore {
String uploadFileText();
String allFilesText();
#endif
-
- String imageTitle(const String& filename, const IntSize& size);
}
#endif
diff --git a/WebCore/platform/MainThread.h b/WebCore/platform/Locker.h
index 55758ea..7217bf1 100644
--- a/WebCore/platform/MainThread.h
+++ b/WebCore/platform/Locker.h
@@ -1,19 +1,18 @@
/*
- * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
- * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)
+ * Copyright (C) 2008 Apple 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.
+ * 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.
+ * documentation and/or other materials provided with the distribution.
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
+ * from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -26,28 +25,21 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#ifndef Locker_h
+#define Locker_h
-#ifndef MainThread_h
-#define MainThread_h
-
-#include <wtf/Threading.h>
+#include <wtf/Noncopyable.h>
namespace WebCore {
-typedef void MainThreadFunction(void*);
-
-void callOnMainThread(MainThreadFunction*, void* context);
+template <typename T> class Locker : Noncopyable {
+public:
+ Locker(T& lockable) : m_lockable(lockable) { m_lockable.lock(); }
+ ~Locker() { m_lockable.unlock(); }
+private:
+ T& m_lockable;
+};
-void initializeThreadingAndMainThread();
-
-#if !PLATFORM(WIN)
-inline void initializeThreadingAndMainThread()
-{
- WTF::initializeThreading();
}
-#endif
-
-} // namespace WebCore
-
-#endif // MainThread_h
+#endif
diff --git a/WebCore/platform/MIMETypeRegistry.cpp b/WebCore/platform/MIMETypeRegistry.cpp
index 2bca60d..ecd8f54 100644
--- a/WebCore/platform/MIMETypeRegistry.cpp
+++ b/WebCore/platform/MIMETypeRegistry.cpp
@@ -33,6 +33,9 @@
#if PLATFORM(CG)
#include <ApplicationServices/ApplicationServices.h>
#endif
+#if PLATFORM(MAC)
+#include "WebCoreSystemInterface.h"
+#endif
#if PLATFORM(QT)
#include <qimagereader.h>
#endif
diff --git a/WebCore/platform/MessageQueue.h b/WebCore/platform/MessageQueue.h
new file mode 100644
index 0000000..dd35449
--- /dev/null
+++ b/WebCore/platform/MessageQueue.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2008 Apple 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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.
+ */
+
+#ifndef MessageQueue_h
+#define MessageQueue_h
+
+#include "Threading.h"
+#include <wtf/Assertions.h>
+#include <wtf/Deque.h>
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+ template<typename DataType>
+ class MessageQueue : Noncopyable {
+ public:
+ MessageQueue() : m_killed(false) {}
+
+ void append(const DataType&);
+ void prepend(const DataType&);
+ bool waitForMessage(DataType&);
+ bool tryGetMessage(DataType&);
+ void kill();
+ bool killed() const { return m_killed; }
+
+ private:
+ Mutex m_mutex;
+ ThreadCondition m_condition;
+ Deque<DataType> m_queue;
+ bool m_killed;
+ };
+
+ template<typename DataType>
+ inline void MessageQueue<DataType>::append(const DataType& message)
+ {
+ MutexLocker lock(m_mutex);
+ m_queue.append(message);
+ m_condition.signal();
+ }
+
+ template<typename DataType>
+ inline void MessageQueue<DataType>::prepend(const DataType& message)
+ {
+ MutexLocker lock(m_mutex);
+ m_queue.prepend(message);
+ m_condition.signal();
+ }
+
+ template<typename DataType>
+ inline bool MessageQueue<DataType>::waitForMessage(DataType& result)
+ {
+ MutexLocker lock(m_mutex);
+ if (m_killed)
+ return false;
+
+ if (m_queue.isEmpty())
+ m_condition.wait(m_mutex);
+ if (m_killed)
+ return false;
+
+ ASSERT(!m_queue.isEmpty());
+ result = m_queue.first();
+ m_queue.removeFirst();
+ return true;
+ }
+
+ template<typename DataType>
+ inline bool MessageQueue<DataType>::tryGetMessage(DataType& result)
+ {
+ MutexLocker lock(m_mutex);
+ if (m_killed)
+ return false;
+ if (m_queue.isEmpty())
+ return false;
+
+ result = m_queue.first();
+ m_queue.removeFirst();
+ return true;
+ }
+
+ template<typename DataType>
+ inline void MessageQueue<DataType>::kill()
+ {
+ MutexLocker lock(m_mutex);
+ m_killed = true;
+ m_condition.broadcast();
+ }
+}
+
+#endif // MessageQueue_h
diff --git a/WebCore/platform/NotImplemented.h b/WebCore/platform/NotImplemented.h
index 00e29c8..31dd589 100644
--- a/WebCore/platform/NotImplemented.h
+++ b/WebCore/platform/NotImplemented.h
@@ -43,6 +43,11 @@
if (qgetenv("DISABLE_NI_WARNING").isEmpty()) \
qDebug("FIXME: UNIMPLEMENTED: %s:%d (%s)", __FILE__, __LINE__, WTF_PRETTY_FUNCTION)
+#elif defined ANDROID
+
+ #define notImplemented() fprintf(stderr, "%s\n", __PRETTY_FUNCTION__)
+// #define notImplemented() LOGV("%s\n", __PRETTY_FUNCTION__)
+
#elif defined(NDEBUG)
#define notImplemented() ((void)0)
diff --git a/WebCore/platform/PlatformKeyboardEvent.h b/WebCore/platform/PlatformKeyboardEvent.h
index 4346295..c85edc4 100644
--- a/WebCore/platform/PlatformKeyboardEvent.h
+++ b/WebCore/platform/PlatformKeyboardEvent.h
@@ -1,6 +1,5 @@
/*
* Copyright (C) 2004, 2005, 2006 Apple Computer, Inc. All rights reserved.
- * Copyright (C) 2008 Collabora, Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -119,7 +118,10 @@ namespace WebCore {
#if PLATFORM(GTK)
PlatformKeyboardEvent(GdkEventKey*);
- GdkEventKey* gdkEventKey() const;
+#endif
+
+#ifdef ANDROID_BRIDGE
+ PlatformKeyboardEvent(int keyCode, int keyValue, bool down, bool forceAutoRepeat, bool cap, bool fn, bool sym);
#endif
#if PLATFORM(QT)
@@ -149,9 +151,6 @@ namespace WebCore {
#if PLATFORM(WIN)
bool m_isSystemKey;
#endif
-#if PLATFORM(GTK)
- GdkEventKey* m_gdkEventKey;
-#endif
};
} // namespace WebCore
diff --git a/WebCore/platform/PlatformMenuDescription.h b/WebCore/platform/PlatformMenuDescription.h
index 7ecc4ce..8d428fc 100644
--- a/WebCore/platform/PlatformMenuDescription.h
+++ b/WebCore/platform/PlatformMenuDescription.h
@@ -53,6 +53,9 @@ namespace WebCore {
typedef const QList<ContextMenuItem>* PlatformMenuDescription;
#elif PLATFORM(GTK)
typedef GtkMenu* PlatformMenuDescription;
+#elif defined ANDROID
+// Currently Android is not using this. Until its use is deemed necessary/desirable, typedef to void*.
+ typedef void* PlatformMenuDescription;
#elif PLATFORM(WX)
typedef wxMenu* PlatformMenuDescription;
#endif
diff --git a/WebCore/platform/PlatformMouseEvent.h b/WebCore/platform/PlatformMouseEvent.h
index 983a5d1..e2d65a5 100644
--- a/WebCore/platform/PlatformMouseEvent.h
+++ b/WebCore/platform/PlatformMouseEvent.h
@@ -129,7 +129,6 @@ namespace WebCore {
#if PLATFORM(QT)
PlatformMouseEvent(QInputEvent*, int clickCount);
#endif
-
#if PLATFORM(WX)
PlatformMouseEvent(const wxMouseEvent&, const wxPoint& globalPoint);
#endif
diff --git a/WebCore/platform/ScrollBar.cpp b/WebCore/platform/ScrollBar.cpp
index 0b8e9ab..5618047 100644
--- a/WebCore/platform/ScrollBar.cpp
+++ b/WebCore/platform/ScrollBar.cpp
@@ -34,8 +34,7 @@ using std::min;
namespace WebCore {
Scrollbar::Scrollbar(ScrollbarClient* client, ScrollbarOrientation orientation, ScrollbarControlSize controlSize)
- : RefCounted<Scrollbar>(0)
- , m_client(client)
+ : m_client(client)
, m_orientation(orientation)
, m_controlSize(controlSize)
, m_visibleSize(0)
diff --git a/WebCore/platform/ScrollView.h b/WebCore/platform/ScrollView.h
index b78d5bc..761e594 100644
--- a/WebCore/platform/ScrollView.h
+++ b/WebCore/platform/ScrollView.h
@@ -235,6 +235,16 @@ namespace WebCore {
class ScrollViewPrivate;
ScrollViewPrivate* m_data;
#endif
+#ifdef ANDROID
+ ScrollView();
+ ~ScrollView();
+ // we call layout() just before creating the picture
+ // this allows ignoring invals generated by layout() during this phase
+ void ignoreUpdateContents(bool );
+ private:
+ struct ScrollViewPrivate;
+ ScrollViewPrivate* m_data;
+#endif
};
} // namespace WebCore
diff --git a/WebCore/platform/SecurityOrigin.h b/WebCore/platform/SecurityOrigin.h
index 6f7e6f5..bb9ae12 100644
--- a/WebCore/platform/SecurityOrigin.h
+++ b/WebCore/platform/SecurityOrigin.h
@@ -31,9 +31,9 @@
#include <wtf/RefCounted.h>
#include <wtf/PassRefPtr.h>
-#include <wtf/Threading.h>
#include "PlatformString.h"
+#include "Threading.h"
namespace WebCore {
diff --git a/WebCore/platform/SecurityOriginHash.h b/WebCore/platform/SecurityOriginHash.h
index a5f25e5..7881474 100644
--- a/WebCore/platform/SecurityOriginHash.h
+++ b/WebCore/platform/SecurityOriginHash.h
@@ -35,7 +35,7 @@
namespace WebCore {
struct SecurityOriginHash {
- static unsigned hash(const RefPtr<SecurityOrigin>& origin)
+ static unsigned hash(RefPtr<SecurityOrigin> origin)
{
unsigned hashCodes[3] = {
origin->protocol().impl() ? origin->protocol().impl()->hash() : 0,
@@ -45,7 +45,7 @@ struct SecurityOriginHash {
return StringImpl::computeHash(reinterpret_cast<UChar*>(hashCodes), 3 * sizeof(unsigned) / sizeof(UChar));
}
- static bool equal(const RefPtr<SecurityOrigin>& a, const RefPtr<SecurityOrigin>& b)
+ static bool equal(RefPtr<SecurityOrigin> a, RefPtr<SecurityOrigin> b)
{
if (a == 0 || b == 0)
return a == b;
diff --git a/WebCore/platform/SharedBuffer.cpp b/WebCore/platform/SharedBuffer.cpp
index db3183d..449c5a0 100644
--- a/WebCore/platform/SharedBuffer.cpp
+++ b/WebCore/platform/SharedBuffer.cpp
@@ -29,18 +29,15 @@
namespace WebCore {
SharedBuffer::SharedBuffer()
- : RefCounted<SharedBuffer>(0)
{
}
SharedBuffer::SharedBuffer(const char* data, int size)
- : RefCounted<SharedBuffer>(0)
{
m_buffer.append(data, size);
}
SharedBuffer::SharedBuffer(const unsigned char* data, int size)
- : RefCounted<SharedBuffer>(0)
{
m_buffer.append(data, size);
}
@@ -112,4 +109,13 @@ inline unsigned SharedBuffer::platformDataSize() const
#endif
+#if !PLATFORM(MAC) && !PLATFORM(WIN)
+
+PassRefPtr<SharedBuffer> SharedBuffer::createWithContentsOfFile(const String& filePath)
+{
+ return 0;
+}
+
+#endif
+
}
diff --git a/WebCore/platform/SystemTime.h b/WebCore/platform/SystemTime.h
index 2b1eed0..367580a 100644
--- a/WebCore/platform/SystemTime.h
+++ b/WebCore/platform/SystemTime.h
@@ -34,7 +34,10 @@ namespace WebCore {
// Return the number of seconds since a user event has been generated
float userIdleTime();
-
+
+#ifdef ANDROID_INSTRUMENT
+ uint32_t get_thread_msec();
+#endif
}
#endif
diff --git a/WebCore/platform/Threading.h b/WebCore/platform/Threading.h
new file mode 100644
index 0000000..f84fd3b
--- /dev/null
+++ b/WebCore/platform/Threading.h
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)
+ *
+ * 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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.
+ *
+ *
+ * Note: The implementations of InterlockedIncrement and InterlockedDecrement are based
+ * on atomic_increment and atomic_exchange_and_add from the Boost C++ Library. The license
+ * is virtually identical to the Apple license above but is included here for completeness.
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef Threading_h
+#define Threading_h
+
+#include "Locker.h"
+
+#include <wtf/Assertions.h>
+#include <wtf/Noncopyable.h>
+
+#if PLATFORM(WIN_OS)
+#include <windows.h>
+#elif PLATFORM(DARWIN)
+#include <libkern/OSAtomic.h>
+#elif defined ANDROID
+#include "cutils/atomic.h"
+#elif COMPILER(GCC)
+#if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 2))
+#include <ext/atomicity.h>
+#else
+#include <bits/atomicity.h>
+#endif
+#endif
+
+#if USE(PTHREADS)
+#include <pthread.h>
+#endif
+
+#if PLATFORM(GTK)
+typedef struct _GMutex GMutex;
+typedef struct _GCond GCond;
+#endif
+
+#if PLATFORM(QT)
+class QMutex;
+class QWaitCondition;
+#endif
+
+#include <stdint.h>
+
+namespace WebCore {
+
+typedef uint32_t ThreadIdentifier;
+typedef void* (*ThreadFunction)(void* argument);
+
+// Returns 0 if thread creation failed
+ThreadIdentifier createThread(ThreadFunction, void*);
+ThreadIdentifier currentThread();
+int waitForThreadCompletion(ThreadIdentifier, void**);
+void detachThread(ThreadIdentifier);
+
+#if USE(PTHREADS)
+typedef pthread_mutex_t PlatformMutex;
+typedef pthread_cond_t PlatformCondition;
+#elif PLATFORM(GTK)
+typedef GMutex* PlatformMutex;
+typedef GCond* PlatformCondition;
+#elif PLATFORM(QT)
+typedef QMutex* PlatformMutex;
+typedef QWaitCondition* PlatformCondition;
+#elif PLATFORM(WIN_OS)
+struct PlatformMutex {
+ CRITICAL_SECTION m_internalMutex;
+ size_t m_recursionCount;
+};
+struct PlatformCondition {
+ size_t m_timedOut;
+ size_t m_blocked;
+ size_t m_waitingForRemoval;
+ HANDLE m_gate;
+ HANDLE m_queue;
+ HANDLE m_mutex;
+};
+#else
+typedef void* PlatformMutex;
+typedef void* PlatformCondition;
+#endif
+
+class Mutex : Noncopyable {
+public:
+ Mutex();
+ ~Mutex();
+
+ void lock();
+ bool tryLock();
+ void unlock();
+
+public:
+ PlatformMutex& impl() { return m_mutex; }
+private:
+ PlatformMutex m_mutex;
+};
+
+typedef Locker<Mutex> MutexLocker;
+
+class ThreadCondition : Noncopyable {
+public:
+ ThreadCondition();
+ ~ThreadCondition();
+
+ void wait(Mutex& mutex);
+ void signal();
+ void broadcast();
+
+private:
+ PlatformCondition m_condition;
+};
+
+#if PLATFORM(WIN_OS)
+#define WTF_USE_LOCKFREE_THREADSAFESHARED 1
+
+inline void atomicIncrement(int volatile* addend) { InterlockedIncrement(reinterpret_cast<long volatile*>(addend)); }
+inline int atomicDecrement(int volatile* addend) { return InterlockedDecrement(reinterpret_cast<long volatile*>(addend)); }
+
+#elif PLATFORM(DARWIN)
+#define WTF_USE_LOCKFREE_THREADSAFESHARED 1
+
+inline void atomicIncrement(int volatile* addend) { OSAtomicIncrement32Barrier(const_cast<int*>(addend)); }
+inline int atomicDecrement(int volatile* addend) { return OSAtomicDecrement32Barrier(const_cast<int*>(addend)); }
+
+#elif defined ANDROID
+
+inline void atomicIncrement(int volatile* addend) { android_atomic_inc(addend); }
+inline int atomicDecrement(int volatile* addend) { return android_atomic_dec(addend); }
+
+#elif COMPILER(GCC)
+#define WTF_USE_LOCKFREE_THREADSAFESHARED 1
+
+inline void atomicIncrement(int volatile* addend) { __gnu_cxx::__atomic_add(addend, 1); }
+inline int atomicDecrement(int volatile* addend) { return __gnu_cxx::__exchange_and_add(addend, -1) - 1; }
+
+#endif
+
+template<class T> class ThreadSafeShared : Noncopyable {
+public:
+ ThreadSafeShared()
+ : m_refCount(0)
+ {
+ }
+
+ void ref()
+ {
+#if USE(LOCKFREE_THREADSAFESHARED)
+ atomicIncrement(&m_refCount);
+#else
+ MutexLocker locker(m_mutex);
+ ++m_refCount;
+#endif
+ }
+
+ void deref()
+ {
+#if USE(LOCKFREE_THREADSAFESHARED)
+ if (atomicDecrement(&m_refCount) <= 0)
+#else
+ {
+ MutexLocker locker(m_mutex);
+ --m_refCount;
+ }
+ if (m_refCount <= 0)
+#endif
+ delete static_cast<T*>(this);
+ }
+
+ bool hasOneRef()
+ {
+ return refCount() == 1;
+ }
+
+ int refCount() const
+ {
+#if !USE(LOCKFREE_THREADSAFESHARED)
+ MutexLocker locker(m_mutex);
+#endif
+ return static_cast<int const volatile &>(m_refCount);
+ }
+
+private:
+ int m_refCount;
+#if !USE(LOCKFREE_THREADSAFESHARED)
+ mutable Mutex m_mutex;
+#endif
+};
+
+typedef void MainThreadFunction(void*);
+
+void callOnMainThread(MainThreadFunction*, void* context);
+
+void initializeThreading();
+
+#if !PLATFORM(WIN) && !PLATFORM(GTK)
+inline void initializeThreading()
+{
+}
+#endif
+
+} // namespace WebCore
+
+#endif // Threading_h
diff --git a/WebCore/platform/ThreadingNone.cpp b/WebCore/platform/ThreadingNone.cpp
new file mode 100644
index 0000000..10ba8d7
--- /dev/null
+++ b/WebCore/platform/ThreadingNone.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)
+ *
+ * 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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.
+ */
+#include "config.h"
+#include "Threading.h"
+
+namespace WebCore {
+
+ThreadIdentifier createThread(ThreadFunction, void*) { return 0; }
+int waitForThreadCompletion(ThreadIdentifier, void**) { return 0; }
+void detachThread(ThreadIdentifier) { }
+ThreadIdentifier currentThread() { return 0; }
+
+Mutex::Mutex() {}
+Mutex::~Mutex() {}
+void Mutex::lock() {}
+bool Mutex::tryLock() { return false; }
+void Mutex::unlock() {};
+
+ThreadCondition::ThreadCondition() {}
+ThreadCondition::~ThreadCondition() {}
+void ThreadCondition::wait(Mutex& mutex) {}
+void ThreadCondition::signal() {}
+void ThreadCondition::broadcast() {}
+
+} // namespace WebCore
diff --git a/WebCore/platform/Timer.cpp b/WebCore/platform/Timer.cpp
index 94e2af8..bf2eeef 100644
--- a/WebCore/platform/Timer.cpp
+++ b/WebCore/platform/Timer.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 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
@@ -28,9 +28,8 @@
#include "SharedTimer.h"
#include "SystemTime.h"
-#include <limits.h>
-#include <limits>
#include <math.h>
+#include <limits>
#include <wtf/HashSet.h>
#include <wtf/Vector.h>
diff --git a/WebCore/platform/Widget.h b/WebCore/platform/Widget.h
index e5c7aac..bd00b9a 100644
--- a/WebCore/platform/Widget.h
+++ b/WebCore/platform/Widget.h
@@ -36,6 +36,10 @@ class NSView;
#endif
#endif
+#ifdef ANDROID_BRIDGE
+class WebCoreViewBridge;
+#endif
+
#if PLATFORM(WIN)
typedef struct HWND__* HWND;
#endif
@@ -206,6 +210,11 @@ protected:
IntPoint convertToScreenCoordinate(NSView*, const IntPoint&);
#endif
+#ifdef ANDROID_BRIDGE
+ WebCoreViewBridge* getWebCoreViewBridge() const;
+ void setWebCoreViewBridge(WebCoreViewBridge*);
+#endif
+
#if PLATFORM(WX)
Widget(wxWindow*);
wxWindow* nativeWindow() const;
diff --git a/WebCore/platform/android/AndroidLog.cpp b/WebCore/platform/android/AndroidLog.cpp
new file mode 100644
index 0000000..aec7491
--- /dev/null
+++ b/WebCore/platform/android/AndroidLog.cpp
@@ -0,0 +1,62 @@
+/*
+ **
+ ** Copyright 2008, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ ** http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#include "config.h"
+#include "AndroidLog.h"
+#include <stdio.h>
+
+#define LOG_TAG "WebCore"
+#undef LOG
+#include <utils/Log.h>
+
+namespace WebCore {
+
+#define BUF_SIZE 1024
+
+void ANDROID_LOGD(const char *fmt, ...) {
+ va_list ap;
+ char buf[BUF_SIZE];
+
+ va_start(ap, fmt);
+ vsnprintf(buf, BUF_SIZE, fmt, ap);
+ va_end(ap);
+
+ LOGD(buf);
+}
+
+void ANDROID_LOGW(const char *fmt, ...) {
+ va_list ap;
+ char buf[BUF_SIZE];
+
+ va_start(ap, fmt);
+ vsnprintf(buf, BUF_SIZE, fmt, ap);
+ va_end(ap);
+
+ LOGW(buf);
+}
+
+void ANDROID_LOGV(const char *fmt, ...) {
+ va_list ap;
+ char buf[BUF_SIZE];
+
+ va_start(ap, fmt);
+ vsnprintf(buf, BUF_SIZE, fmt, ap);
+ va_end(ap);
+
+ LOGV(buf);
+}
+}
diff --git a/WebCore/platform/android/AndroidLog.h b/WebCore/platform/android/AndroidLog.h
new file mode 100644
index 0000000..f191ebf
--- /dev/null
+++ b/WebCore/platform/android/AndroidLog.h
@@ -0,0 +1,29 @@
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef ANDROIDLOG_H_
+#define ANDROIDLOG_H_
+
+namespace WebCore {
+
+ void ANDROID_LOGD(const char *fmt, ...);
+
+ void ANDROID_LOGW(const char *fmt, ...);
+
+ void ANDROID_LOGV(const char *fmt, ...);
+}
+#endif /*ANDROIDLOG_H_*/
diff --git a/WebCore/platform/android/ChromeClientAndroid.cpp b/WebCore/platform/android/ChromeClientAndroid.cpp
new file mode 100644
index 0000000..25cbf95
--- /dev/null
+++ b/WebCore/platform/android/ChromeClientAndroid.cpp
@@ -0,0 +1,213 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "config.h"
+
+#include "ChromeClientAndroid.h"
+#include "CString.h"
+#include "Document.h"
+#include "PlatformString.h"
+#include "FloatRect.h"
+#include "Frame.h"
+#include "FrameAndroid.h"
+#include "FrameLoader.h"
+#include "FrameView.h"
+#include "kjs_proxy.h"
+#include "Page.h"
+#include "Screen.h"
+#include "WebCoreViewBridge.h"
+#include "WindowFeatures.h"
+#include "Settings.h"
+
+#define LOG_TAG "WebCore"
+#undef LOG
+#include <utils/Log.h>
+
+namespace WebCore {
+
+void ChromeClientAndroid::chromeDestroyed()
+{
+ delete this;
+}
+
+void ChromeClientAndroid::setWindowRect(const FloatRect&) { notImplemented(); }
+
+static WebCoreViewBridge* rootViewForFrame(const Frame* frame)
+{
+ if (!frame)
+ return NULL;
+ FrameView* frameView = frame->view();
+ return frameView ? frameView->getWebCoreViewBridge() : NULL;
+}
+
+FloatRect ChromeClientAndroid::windowRect() {
+ ASSERT(m_frame);
+ WebCoreViewBridge* view = rootViewForFrame(m_frame);
+ if (!view)
+ return FloatRect();
+ const WebCore::IntRect& rect = view->getBounds();
+ FloatRect fRect(rect.x(), rect.y(), rect.width(), rect.height());
+ return fRect;
+}
+
+FloatRect ChromeClientAndroid::pageRect() { notImplemented(); return FloatRect(); }
+
+float ChromeClientAndroid::scaleFactor()
+{
+ // only seems to be used for dashboard regions, so just return 1
+ return 1;
+}
+
+void ChromeClientAndroid::focus() {
+ ASSERT(m_frame);
+ // Ask the application to focus this WebView.
+ m_frame->bridge()->requestFocus();
+}
+void ChromeClientAndroid::unfocus() { notImplemented(); }
+
+bool ChromeClientAndroid::canTakeFocus(FocusDirection) { notImplemented(); return false; }
+void ChromeClientAndroid::takeFocus(FocusDirection) { notImplemented(); }
+
+Page* ChromeClientAndroid::createWindow(Frame* frame, const FrameLoadRequest&,
+ const WindowFeatures& features)
+{
+ ASSERT(frame);
+ if (!(frame->settings()->supportMultipleWindows()))
+ // If the client doesn't support multiple windows, just return the current page
+ return frame->page();
+
+ FrameAndroid* frameAndroid = (FrameAndroid*) frame;
+ WebCore::Screen screen(frame);
+ bool dialog = features.dialog || !features.resizable
+ || (features.heightSet && features.height < screen.height()
+ && features.widthSet && features.width < screen.width())
+ || (!features.menuBarVisible && !features.statusBarVisible
+ && !features.toolBarVisible && !features.locationBarVisible
+ && !features.scrollbarsVisible);
+ // fullscreen definitely means no dialog
+ if (features.fullscreen)
+ dialog = false;
+ WebCore::Frame* newFrame = frameAndroid->bridge()->createWindow(dialog,
+ frame->scriptProxy()->processingUserGesture());
+ if (newFrame) {
+ WebCore::Page* page = newFrame->page();
+ page->setGroupName(frameAndroid->page()->groupName());
+ return page;
+ }
+ return NULL;
+}
+
+Page* ChromeClientAndroid::createModalDialog(Frame* , const FrameLoadRequest&) { notImplemented(); return 0; }
+void ChromeClientAndroid::show() { notImplemented(); }
+
+bool ChromeClientAndroid::canRunModal() { notImplemented(); return false; }
+void ChromeClientAndroid::runModal() { notImplemented(); }
+
+void ChromeClientAndroid::setToolbarsVisible(bool) { notImplemented(); }
+bool ChromeClientAndroid::toolbarsVisible() { notImplemented(); return false; }
+
+void ChromeClientAndroid::setStatusbarVisible(bool) { notImplemented(); }
+bool ChromeClientAndroid::statusbarVisible() { notImplemented(); return false; }
+
+void ChromeClientAndroid::setScrollbarsVisible(bool) { notImplemented(); }
+bool ChromeClientAndroid::scrollbarsVisible() { notImplemented(); return false; }
+
+void ChromeClientAndroid::setMenubarVisible(bool) { notImplemented(); }
+bool ChromeClientAndroid::menubarVisible() { notImplemented(); return false; }
+
+void ChromeClientAndroid::setResizable(bool) { notImplemented(); }
+
+// This function is called by the JavaScript bindings to print usually an error to
+// a message console.
+void ChromeClientAndroid::addMessageToConsole(const String& message, unsigned int lineNumber, const String& sourceID) {
+ notImplemented();
+ LOGD("Console: %s line: %d source: %s\n", message.latin1().data(), lineNumber, sourceID.latin1().data());
+}
+
+bool ChromeClientAndroid::canRunBeforeUnloadConfirmPanel() { return true; }
+bool ChromeClientAndroid::runBeforeUnloadConfirmPanel(const String& message, Frame* frame) {
+ String url = frame->document()->documentURI();
+ return frame->view()->getWebCoreViewBridge()->jsUnload(url, message);
+}
+
+void ChromeClientAndroid::closeWindowSoon()
+{
+ ASSERT(m_frame);
+ // This will prevent javascript cross-scripting during unload
+ m_frame->page()->setGroupName(String());
+ // Stop loading but do not send the unload event
+ m_frame->loader()->stopLoading(false);
+ // Cancel all pending loaders
+ m_frame->loader()->stopAllLoaders();
+ // Remove all event listeners so that no javascript can execute as a result
+ // of mouse/keyboard events.
+ m_frame->document()->removeAllEventListenersFromAllNodes();
+ // Close the window.
+ m_frame->bridge()->closeWindow(m_frame->view()->getWebCoreViewBridge());
+}
+
+void ChromeClientAndroid::runJavaScriptAlert(Frame* frame, const String& message)
+{
+ String url = frame->document()->documentURI();
+
+ frame->view()->getWebCoreViewBridge()->jsAlert(url, message);
+}
+
+bool ChromeClientAndroid::runJavaScriptConfirm(Frame* frame, const String& message)
+{
+ String url = frame->document()->documentURI();
+
+ return frame->view()->getWebCoreViewBridge()->jsConfirm(url, message);
+}
+
+/* This function is called for the javascript method Window.prompt(). A dialog should be shown on
+ * the screen with an input put box. First param is the text, the second is the default value for
+ * the input box, third is return param. If the function returns true, the value set in the third parameter
+ * is provided to javascript, else null is returned to the script.
+ */
+bool ChromeClientAndroid::runJavaScriptPrompt(Frame* frame, const String& message, const String& defaultValue, String& result)
+{
+ String url = frame->document()->documentURI();
+
+ return frame->view()->getWebCoreViewBridge()->jsPrompt(url, message, defaultValue, result);
+}
+void ChromeClientAndroid::setStatusbarText(const String&) { notImplemented(); }
+
+// This is called by the JavaScript interpreter when a script has been running for a long
+// time. A dialog should be shown to the user asking them if they would like to cancel the
+// Javascript. If true is returned, the script is cancelled.
+// To make a device more responsive, we default to return true to disallow long running script.
+// This implies that some of scripts will not be completed.
+bool ChromeClientAndroid::shouldInterruptJavaScript() { return true; }
+
+// functions new to Jun-07 tip of tree merge:
+void ChromeClientAndroid::addToDirtyRegion(IntRect const&) {}
+void ChromeClientAndroid::scrollBackingStore(int, int, IntRect const&, IntRect const&) {}
+void ChromeClientAndroid::updateBackingStore() {}
+bool ChromeClientAndroid::tabsToLinks() const { return false; }
+IntRect ChromeClientAndroid::windowResizerRect() const { return IntRect(0, 0, 0, 0); }
+
+// functions new to the Nov-16-08 tip of tree merge:
+void ChromeClientAndroid::mouseDidMoveOverElement(const HitTestResult&, unsigned int) {}
+void ChromeClientAndroid::setToolTip(const String&) {}
+void ChromeClientAndroid::print(Frame*) {}
+bool ChromeClientAndroid::runDatabaseSizeLimitPrompt(Frame*, const String&) { return false; }
+
+// functions new to Feb-19 tip of tree merge:
+void ChromeClientAndroid::exceededDatabaseQuota(Frame*, const String&) {}
+
+}
diff --git a/WebCore/platform/android/ChromeClientAndroid.h b/WebCore/platform/android/ChromeClientAndroid.h
new file mode 100644
index 0000000..5f1dd0b
--- /dev/null
+++ b/WebCore/platform/android/ChromeClientAndroid.h
@@ -0,0 +1,101 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef ChromeClientAndroid_h
+#define ChromeClientAndroid_h
+
+#include "ChromeClient.h"
+
+namespace WebCore {
+
+class FrameAndroid;
+ class ChromeClientAndroid : public ChromeClient {
+ public:
+ ChromeClientAndroid() : m_frame(NULL) {}
+ virtual void chromeDestroyed();
+
+ virtual void setWindowRect(const FloatRect&);
+ virtual FloatRect windowRect();
+
+ virtual FloatRect pageRect();
+
+ virtual float scaleFactor();
+
+ virtual void focus();
+ virtual void unfocus();
+
+ virtual bool canTakeFocus(FocusDirection);
+ virtual void takeFocus(FocusDirection);
+
+ // The Frame pointer provides the ChromeClient with context about which
+ // Frame wants to create the new Page. Also, the newly created window
+ // should not be shown to the user until the ChromeClient of the newly
+ // created Page has its show method called.
+ virtual Page* createWindow(Frame*, const FrameLoadRequest&, const WindowFeatures&);
+ virtual Page* createModalDialog(Frame*, const FrameLoadRequest&);
+ virtual void show();
+
+ virtual bool canRunModal();
+ virtual void runModal();
+
+ virtual void setToolbarsVisible(bool);
+ virtual bool toolbarsVisible();
+
+ virtual void setStatusbarVisible(bool);
+ virtual bool statusbarVisible();
+
+ virtual void setScrollbarsVisible(bool);
+ virtual bool scrollbarsVisible();
+
+ virtual void setMenubarVisible(bool);
+ virtual bool menubarVisible();
+
+ virtual void setResizable(bool);
+
+ virtual void addMessageToConsole(const String& message, unsigned int lineNumber, const String& sourceID);
+
+ virtual bool canRunBeforeUnloadConfirmPanel();
+ virtual bool runBeforeUnloadConfirmPanel(const String& message, Frame* frame);
+
+ virtual void closeWindowSoon();
+
+ virtual void runJavaScriptAlert(Frame*, const String&);
+ virtual bool runJavaScriptConfirm(Frame*, const String&);
+ virtual bool runJavaScriptPrompt(Frame*, const String& message, const String& defaultValue, String& result);
+
+ virtual void setStatusbarText(const String&);
+ virtual bool shouldInterruptJavaScript();
+ virtual bool tabsToLinks() const;
+
+ virtual IntRect windowResizerRect() const;
+ virtual void addToDirtyRegion(const IntRect&);
+ virtual void scrollBackingStore(int dx, int dy, const IntRect& scrollViewRect, const IntRect& clipRect);
+ virtual void updateBackingStore();
+ virtual void mouseDidMoveOverElement(const HitTestResult&, unsigned int);
+ virtual void setToolTip(const String&);
+ virtual void print(Frame*);
+ virtual bool runDatabaseSizeLimitPrompt(Frame*, const String&);
+ virtual void exceededDatabaseQuota(Frame*, const String&);
+ // Android-specific
+ void setFrame(FrameAndroid* frame) { m_frame = frame; }
+ private:
+ FrameAndroid* m_frame;
+ };
+
+}
+
+#endif
diff --git a/WebCore/platform/android/ClipboardAndroid.cpp b/WebCore/platform/android/ClipboardAndroid.cpp
new file mode 100644
index 0000000..d4bf734
--- /dev/null
+++ b/WebCore/platform/android/ClipboardAndroid.cpp
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2006, 2007 Apple 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.
+ */
+
+#include "config.h"
+#include "ClipboardAndroid.h"
+
+#include "CachedImage.h"
+#include "CSSHelper.h"
+#include "CString.h"
+#include "DeprecatedString.h"
+#include "Document.h"
+#include "DragData.h"
+#include "Element.h"
+#include "EventHandler.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "FrameView.h"
+#include "HTMLNames.h"
+#include "Image.h"
+//#include "MimeTypeRegistry.h"
+#include "markup.h"
+#include "Page.h"
+#include "Pasteboard.h"
+#include "PlatformMouseEvent.h"
+#include "PlatformString.h"
+#include "Range.h"
+#include "RenderImage.h"
+#include "ResourceResponse.h"
+#include "StringHash.h"
+
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+// format string for
+static const char szShellDotUrlTemplate[] = "[InternetShortcut]\r\nURL=%s\r\n";
+
+// We provide the IE clipboard types (URL and Text), and the clipboard types specified in the WHATWG Web Applications 1.0 draft
+// see http://www.whatwg.org/specs/web-apps/current-work/ Section 6.3.5.3
+
+enum ClipboardDataType { ClipboardDataTypeNone, ClipboardDataTypeURL, ClipboardDataTypeText };
+
+static ClipboardDataType clipboardTypeFromMIMEType(const String& type)
+{
+ String qType = type.stripWhiteSpace().lower();
+
+ // two special cases for IE compatibility
+ if (qType == "text" || qType == "text/plain" || qType.startsWith("text/plain;"))
+ return ClipboardDataTypeText;
+ if (qType == "url" || qType == "text/uri-list")
+ return ClipboardDataTypeURL;
+
+ return ClipboardDataTypeNone;
+}
+
+ClipboardAndroid::ClipboardAndroid(ClipboardAccessPolicy policy, bool isForDragging)
+ : Clipboard(policy, isForDragging)
+{
+}
+
+ClipboardAndroid::~ClipboardAndroid()
+{
+}
+
+void ClipboardAndroid::clearData(const String& type)
+{
+ //FIXME: Need to be able to write to the system clipboard <rdar://problem/5015941>
+ ASSERT(isForDragging());
+ if (policy() != ClipboardWritable)
+ return;
+
+ ClipboardDataType dataType = clipboardTypeFromMIMEType(type);
+
+ if (dataType == ClipboardDataTypeURL) {
+ }
+ if (dataType == ClipboardDataTypeText) {
+
+ }
+
+}
+
+void ClipboardAndroid::clearAllData()
+{
+ //FIXME: Need to be able to write to the system clipboard <rdar://problem/5015941>
+ ASSERT(isForDragging());
+ if (policy() != ClipboardWritable)
+ return;
+
+}
+
+String ClipboardAndroid::getData(const String& type, bool& success) const
+{
+ success = false;
+ if (policy() != ClipboardReadable) {
+ return "";
+ }
+
+ ClipboardDataType dataType = clipboardTypeFromMIMEType(type);
+ /* if (dataType == ClipboardDataTypeText)
+ return getPlainText(m_dataObject.get(), success);
+ else if (dataType == ClipboardDataTypeURL)
+ return getURL(m_dataObject.get(), success);
+ */
+ return "";
+}
+
+bool ClipboardAndroid::setData(const String &type, const String &data)
+{
+ //FIXME: Need to be able to write to the system clipboard <rdar://problem/5015941>
+ ASSERT(isForDragging());
+ if (policy() != ClipboardWritable)
+ return false;
+
+ ClipboardDataType platformType = clipboardTypeFromMIMEType(type);
+
+ if (platformType == ClipboardDataTypeURL) {
+ KURL url = data.deprecatedString();
+#if 0 && defined ANDROID // FIXME HACK : KURL no longer defines a public method isValid()
+ if (!url.isValid())
+ return false;
+#endif
+ return false; // WebCore::writeURL(m_writableDataObject.get(), url, String(), false, true);
+ } else if ( platformType == ClipboardDataTypeText) {
+ return false;
+ }
+ return false;
+}
+
+
+// extensions beyond IE's API
+HashSet<String> ClipboardAndroid::types() const
+{
+ HashSet<String> results;
+ if (policy() != ClipboardReadable && policy() != ClipboardTypesReadable)
+ return results;
+
+ return results;
+}
+
+void ClipboardAndroid::setDragImage(CachedImage* image, Node *node, const IntPoint &loc)
+{
+ if (policy() != ClipboardImageWritable && policy() != ClipboardWritable)
+ return;
+
+ if (m_dragImage)
+ m_dragImage->deref(this);
+ m_dragImage = image;
+ if (m_dragImage)
+ m_dragImage->ref(this);
+
+ m_dragLoc = loc;
+ m_dragImageElement = node;
+}
+
+void ClipboardAndroid::setDragImage(CachedImage* img, const IntPoint &loc)
+{
+ setDragImage(img, 0, loc);
+}
+
+void ClipboardAndroid::setDragImageElement(Node *node, const IntPoint &loc)
+{
+ setDragImage(0, node, loc);
+}
+
+DragImageRef ClipboardAndroid::createDragImage(IntPoint& loc) const
+{
+ void* result = 0;
+ //FIXME: Need to be able to draw element <rdar://problem/5015942>
+ if (m_dragImage) {
+ result = createDragImageFromImage(m_dragImage->image());
+ loc = m_dragLoc;
+ }
+ return result;
+}
+
+
+void ClipboardAndroid::declareAndWriteDragImage(Element* element, const KURL& url, const String& title, Frame* frame)
+{
+
+}
+
+void ClipboardAndroid::writeURL(const KURL& kurl, const String& titleStr, Frame*)
+{
+
+}
+
+void ClipboardAndroid::writeRange(Range* selectedRange, Frame* frame)
+{
+ ASSERT(selectedRange);
+}
+
+bool ClipboardAndroid::hasData()
+{
+
+ return false;
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/network/mac/ResourceError.h b/WebCore/platform/android/ClipboardAndroid.h
index 5e4a553..45ff5f9 100644
--- a/WebCore/platform/network/mac/ResourceError.h
+++ b/WebCore/platform/android/ClipboardAndroid.h
@@ -1,6 +1,5 @@
-// -*- mode: c++; c-basic-offset: 4 -*-
/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -24,52 +23,46 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ResourceError_h
-#define ResourceError_h
+#ifndef ClipboardAndroid_h
+#define ClipboardAndroid_h
-#include "ResourceErrorBase.h"
-#include <wtf/RetainPtr.h>
+#include "Clipboard.h"
-#ifdef __OBJC__
-@class NSError;
-#else
-class NSError;
-#endif
+#include "CachedResourceClient.h"
namespace WebCore {
- class ResourceError : public ResourceErrorBase {
- public:
- ResourceError()
- : m_dataIsUpToDate(true)
- {
- }
-
- ResourceError(const String& domain, int errorCode, const String& failingURL, const String& localizedDescription)
- : ResourceErrorBase(domain, errorCode, failingURL, localizedDescription)
- , m_dataIsUpToDate(true)
- {
- }
+ class CachedImage;
- ResourceError(NSError* error)
- : m_dataIsUpToDate(false)
- , m_platformError(error)
- {
- m_isNull = !error;
- }
+ class ClipboardAndroid : public Clipboard, public CachedResourceClient {
+ public:
+ ClipboardAndroid(ClipboardAccessPolicy policy, bool isForDragging);
+ ~ClipboardAndroid();
+
+ void clearData(const String& type);
+ void clearAllData();
+ String getData(const String& type, bool& success) const;
+ bool setData(const String& type, const String& data);
+
+ // extensions beyond IE's API
+ HashSet<String> types() const;
+
+ void setDragImage(CachedImage*, const IntPoint&);
+ void setDragImageElement(Node*, const IntPoint&);
+
+ virtual DragImageRef createDragImage(IntPoint& dragLoc) const;
+ virtual void declareAndWriteDragImage(Element*, const KURL&, const String& title, Frame*);
+ virtual void writeURL(const KURL&, const String&, Frame*);
+ virtual void writeRange(Range*, Frame*);
- operator NSError*() const;
+ virtual bool hasData();
private:
- friend class ResourceErrorBase;
-
- void platformLazyInit();
- static bool platformCompare(const ResourceError& a, const ResourceError& b);
-
- bool m_dataIsUpToDate;
- mutable RetainPtr<NSError> m_platformError;
-};
+ void resetFromClipboard();
+ void setDragImage(CachedImage*, Node*, const IntPoint&);
+ Frame* m_frame;
+ };
} // namespace WebCore
-#endif // ResourceError_h_
+#endif // ClipboardAndroid_h
diff --git a/WebCore/platform/android/ContextMenuClientAndroid.cpp b/WebCore/platform/android/ContextMenuClientAndroid.cpp
new file mode 100644
index 0000000..cc7252f
--- /dev/null
+++ b/WebCore/platform/android/ContextMenuClientAndroid.cpp
@@ -0,0 +1,38 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "config.h"
+#include "ContextMenuClientAndroid.h"
+#include "wtf/Assertions.h"
+
+#define notImplemented() ASSERT(0)
+
+namespace WebCore {
+
+void ContextMenuClientAndroid::contextMenuDestroyed() { delete this; }
+
+PlatformMenuDescription ContextMenuClientAndroid::getCustomMenuFromDefaultItems(ContextMenu*) { notImplemented(); return 0; }
+void ContextMenuClientAndroid::contextMenuItemSelected(ContextMenuItem*, const ContextMenu*) { notImplemented(); }
+
+void ContextMenuClientAndroid::downloadURL(const KURL& url) { notImplemented(); }
+void ContextMenuClientAndroid::copyImageToClipboard(const HitTestResult&) { notImplemented(); }
+void ContextMenuClientAndroid::searchWithGoogle(const Frame*) { notImplemented(); }
+void ContextMenuClientAndroid::lookUpInDictionary(Frame*) { notImplemented(); }
+void ContextMenuClientAndroid::speak(const String&) { notImplemented(); }
+void ContextMenuClientAndroid::stopSpeaking() { notImplemented(); }
+
+}
diff --git a/WebCore/platform/android/ContextMenuClientAndroid.h b/WebCore/platform/android/ContextMenuClientAndroid.h
new file mode 100644
index 0000000..0d1e888
--- /dev/null
+++ b/WebCore/platform/android/ContextMenuClientAndroid.h
@@ -0,0 +1,42 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef ContextMenuClientAndroid_h
+#define ContextMenuClientAndroid_h
+
+#include "ContextMenuClient.h"
+
+namespace WebCore {
+
+class ContextMenuClientAndroid : public ContextMenuClient {
+public:
+ virtual void contextMenuDestroyed();
+
+ virtual PlatformMenuDescription getCustomMenuFromDefaultItems(ContextMenu*);
+ virtual void contextMenuItemSelected(ContextMenuItem*, const ContextMenu*);
+
+ virtual void downloadURL(const KURL& url);
+ virtual void copyImageToClipboard(const HitTestResult&);
+ virtual void searchWithGoogle(const Frame*);
+ virtual void lookUpInDictionary(Frame*);
+ virtual void speak(const String&);
+ virtual void stopSpeaking();
+};
+
+}
+
+#endif
diff --git a/WebCore/platform/android/Cookie.cpp b/WebCore/platform/android/Cookie.cpp
new file mode 100644
index 0000000..eeaa4ce
--- /dev/null
+++ b/WebCore/platform/android/Cookie.cpp
@@ -0,0 +1,51 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "config.h"
+#include "JavaSharedClient.h"
+#include "CookieClient.h"
+
+#define LOG_TAG "Cookies"
+#undef LOG
+#include "utils/Log.h"
+
+namespace WebCore {
+
+ class Document;
+
+ void setCookies(Document* , const KURL& url, const KURL& policyBaseURL, const String& value)
+ {
+ if (JavaSharedClient::GetCookieClient())
+ JavaSharedClient::GetCookieClient()->setCookies(url, policyBaseURL, value);
+ }
+
+ String cookies(const Document* , const KURL& url)
+ {
+ if (JavaSharedClient::GetCookieClient())
+ return JavaSharedClient::GetCookieClient()->cookies(url);
+ return String();
+ }
+
+ bool cookiesEnabled(const Document* )
+ {
+ if (JavaSharedClient::GetCookieClient())
+ return JavaSharedClient::GetCookieClient()->cookiesEnabled();
+ return false;
+ }
+
+}
+
diff --git a/WebCore/platform/android/CookieClient.h b/WebCore/platform/android/CookieClient.h
new file mode 100644
index 0000000..0b76932
--- /dev/null
+++ b/WebCore/platform/android/CookieClient.h
@@ -0,0 +1,37 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef COOKIE_CLIENT_H
+#define COOKIE_CLIENT_H
+
+#include "KURL.h"
+#include "PlatformString.h"
+
+namespace WebCore {
+
+ class CookieClient
+ {
+ public:
+ virtual ~CookieClient() {}
+ virtual void setCookies(const KURL& url, const KURL& docURL, const String& value) = 0;
+ virtual String cookies(const KURL& url) = 0;
+ virtual bool cookiesEnabled() = 0;
+ };
+
+}
+#endif
+
diff --git a/WebCore/platform/android/CursorAndroid.cpp b/WebCore/platform/android/CursorAndroid.cpp
new file mode 100644
index 0000000..e3a2562
--- /dev/null
+++ b/WebCore/platform/android/CursorAndroid.cpp
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2004, 2006 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.
+ */
+
+#include "config.h"
+#include "Cursor.h"
+
+#define LOG_TAG "WebCore"
+#undef LOG
+#include "utils/Log.h"
+
+namespace WebCore {
+
+static void notImplemented() { LOGV("Cursor: NotYetImplemented"); }
+
+Cursor::Cursor(Image* image, const IntPoint& )
+{
+ notImplemented();
+}
+
+Cursor::Cursor(const Cursor& other)
+{
+ notImplemented();
+}
+
+Cursor::~Cursor()
+{
+ notImplemented();
+}
+
+Cursor& Cursor::operator=(const Cursor& other)
+{
+ notImplemented();
+ return *this;
+}
+
+const Cursor& pointerCursor()
+{
+ notImplemented();
+ static Cursor c;
+ return c;
+}
+
+const Cursor& crossCursor()
+{
+ notImplemented();
+ static Cursor c;
+ return c;
+}
+
+const Cursor& handCursor()
+{
+ notImplemented();
+ static Cursor c;
+ return c;
+}
+
+const Cursor& moveCursor()
+{
+ notImplemented();
+ static Cursor c;
+ return c;
+}
+
+const Cursor& iBeamCursor()
+{
+ notImplemented();
+ static Cursor c;
+ return c;
+}
+
+const Cursor& waitCursor()
+{
+ notImplemented();
+ static Cursor c;
+ return c;
+}
+
+const Cursor& helpCursor()
+{
+ notImplemented();
+ static Cursor c;
+ return c;
+}
+
+const Cursor& eastResizeCursor()
+{
+ notImplemented();
+ static Cursor c;
+ return c;
+}
+
+const Cursor& northResizeCursor()
+{
+ notImplemented();
+ static Cursor c;
+ return c;
+}
+
+const Cursor& northEastResizeCursor()
+{
+ notImplemented();
+ static Cursor c;
+ return c;
+}
+
+const Cursor& northWestResizeCursor()
+{
+ notImplemented();
+ static Cursor c;
+ return c;
+}
+
+const Cursor& southResizeCursor()
+{
+ notImplemented();
+ static Cursor c;
+ return c;
+}
+
+const Cursor& southEastResizeCursor()
+{
+ notImplemented();
+ static Cursor c;
+ return c;
+}
+
+const Cursor& southWestResizeCursor()
+{
+ notImplemented();
+ static Cursor c;
+ return c;
+}
+
+const Cursor& westResizeCursor()
+{
+ notImplemented();
+ static Cursor c;
+ return c;
+}
+
+const Cursor& northSouthResizeCursor()
+{
+ notImplemented();
+ static Cursor c;
+ return c;
+}
+
+const Cursor& eastWestResizeCursor()
+{
+ notImplemented();
+ static Cursor c;
+ return c;
+}
+
+const Cursor& northEastSouthWestResizeCursor()
+{
+ notImplemented();
+ static Cursor c;
+ return c;
+}
+
+const Cursor& northWestSouthEastResizeCursor()
+{
+ notImplemented();
+ static Cursor c;
+ return c;
+}
+
+const Cursor& columnResizeCursor()
+{
+ notImplemented();
+ static Cursor c;
+ return c;
+}
+
+const Cursor& rowResizeCursor()
+{
+ notImplemented();
+ static Cursor c;
+ return c;
+}
+
+const Cursor& verticalTextCursor()
+{
+ notImplemented();
+ static Cursor c;
+ return c;
+}
+
+const Cursor& cellCursor()
+{
+ notImplemented();
+ static Cursor c;
+ return c;
+}
+
+const Cursor& contextMenuCursor()
+{
+ notImplemented();
+ static Cursor c;
+ return c;
+}
+
+const Cursor& noDropCursor()
+{
+ notImplemented();
+ static Cursor c;
+ return c;
+}
+
+const Cursor& copyCursor()
+{
+ notImplemented();
+ static Cursor c;
+ return c;
+}
+
+const Cursor& progressCursor()
+{
+ notImplemented();
+ static Cursor c;
+ return c;
+}
+
+const Cursor& aliasCursor()
+{
+ notImplemented();
+ static Cursor c;
+ return c;
+}
+
+const Cursor& noneCursor()
+{
+ notImplemented();
+ static Cursor c;
+ return c;
+}
+
+}
diff --git a/WebCore/platform/android/DragClientAndroid.cpp b/WebCore/platform/android/DragClientAndroid.cpp
new file mode 100644
index 0000000..6a9aef1
--- /dev/null
+++ b/WebCore/platform/android/DragClientAndroid.cpp
@@ -0,0 +1,43 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "config.h"
+#include "DragClientAndroid.h"
+#include "wtf/Assertions.h"
+
+#define LOG_TAG "WebCore"
+#undef LOG
+#include <utils/Log.h>
+
+//#define notImplemented() ASSERT(0)
+#define notImplemented() LOGV("%s\n", __PRETTY_FUNCTION__);
+
+namespace WebCore {
+
+void DragClientAndroid::dragControllerDestroyed() { notImplemented(); delete this; }
+
+void DragClientAndroid::willPerformDragDestinationAction(DragDestinationAction, DragData*) { notImplemented(); }
+
+DragDestinationAction DragClientAndroid::actionMaskForDrag(DragData*) { notImplemented(); return DragDestinationActionNone; }
+
+DragSourceAction DragClientAndroid::dragSourceActionMaskForPoint(const IntPoint&) { notImplemented(); return DragSourceActionNone; }
+
+void* DragClientAndroid::createDragImageForLink(KURL&, String const&, Frame*) { return NULL; }
+void DragClientAndroid::willPerformDragSourceAction(DragSourceAction, IntPoint const&, Clipboard*) {}
+void DragClientAndroid::startDrag(void*, IntPoint const&, IntPoint const&, Clipboard*, Frame*, bool) {}
+
+}
diff --git a/WebCore/platform/android/DragClientAndroid.h b/WebCore/platform/android/DragClientAndroid.h
new file mode 100644
index 0000000..fd699e0
--- /dev/null
+++ b/WebCore/platform/android/DragClientAndroid.h
@@ -0,0 +1,41 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef DragClientAndroid_h
+#define DragClientAndroid_h
+
+#include "DragClient.h"
+
+namespace WebCore {
+
+ class DragClientAndroid : public WebCore::DragClient {
+ public:
+ virtual void willPerformDragDestinationAction(DragDestinationAction, DragData*);
+ virtual void willPerformDragSourceAction(DragSourceAction, const IntPoint&, Clipboard*);
+ virtual DragDestinationAction actionMaskForDrag(DragData*);
+ //We work in window rather than view coordinates here
+ virtual DragSourceAction dragSourceActionMaskForPoint(const IntPoint&);
+
+ virtual void startDrag(DragImageRef dragImage, const IntPoint& dragImageOrigin, const IntPoint& eventPos, Clipboard*, Frame*, bool linkDrag = false);
+ virtual DragImageRef createDragImageForLink(KURL&, const String& label, Frame*);
+
+ virtual void dragControllerDestroyed();
+ };
+
+}
+
+#endif
diff --git a/WebCore/platform/android/DragDataAndroid.cpp b/WebCore/platform/android/DragDataAndroid.cpp
new file mode 100644
index 0000000..cac3c4a
--- /dev/null
+++ b/WebCore/platform/android/DragDataAndroid.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2007 Apple 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.
+ */
+
+#include "config.h"
+#include "DragData.h"
+
+#include "Document.h"
+#include "DocumentFragment.h"
+
+namespace WebCore {
+
+bool DragData::canSmartReplace() const
+{
+ return false;
+}
+
+bool DragData::containsColor() const
+{
+ return false;
+}
+
+bool DragData::containsPlainText() const
+{
+ return false;
+}
+
+String DragData::asPlainText() const
+{
+ return String();
+}
+
+Color DragData::asColor() const
+{
+ return Color();
+}
+
+Clipboard* DragData::createClipboard(ClipboardAccessPolicy) const
+{
+ return 0;
+}
+
+bool DragData::containsCompatibleContent() const
+{
+ return false;
+}
+
+bool DragData::containsURL() const
+{
+ return false;
+}
+
+String DragData::asURL(String* title) const
+{
+ return String();
+}
+
+
+PassRefPtr<DocumentFragment> DragData::asFragment(Document*) const
+{
+ return 0;
+}
+
+// functions new to Jun-07 tip of tree merge:
+void DragData::asFilenames(Vector<String>&) const {}
+bool DragData::containsFiles() const { return false; }
+
+}
diff --git a/WebCore/platform/android/EditorAndroid.cpp b/WebCore/platform/android/EditorAndroid.cpp
new file mode 100644
index 0000000..204b23c
--- /dev/null
+++ b/WebCore/platform/android/EditorAndroid.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2006, 2007 Apple 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.
+ */
+
+#include "config.h"
+#include "Editor.h"
+#include "EditorClient.h"
+
+#include "ClipboardAndroid.h"
+#include "Document.h"
+#include "Element.h"
+#include "htmlediting.h"
+#include "NotImplemented.h"
+#include "TextIterator.h"
+#include "visible_units.h"
+
+namespace WebCore {
+
+PassRefPtr<Clipboard> Editor::newGeneralClipboard(ClipboardAccessPolicy policy)
+{
+ return new ClipboardAndroid(policy, false);
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/android/EditorClientAndroid.cpp b/WebCore/platform/android/EditorClientAndroid.cpp
new file mode 100644
index 0000000..b38c542
--- /dev/null
+++ b/WebCore/platform/android/EditorClientAndroid.cpp
@@ -0,0 +1,241 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "config.h"
+#include "Editor.h"
+#include "EditorClientAndroid.h"
+#include "Event.h"
+#include "EventNames.h"
+#include "FocusController.h"
+#include "Frame.h"
+#include "KeyboardCodes.h"
+#include "KeyboardEvent.h"
+#include "PlatformKeyboardEvent.h"
+#include "PlatformString.h"
+#include "wtf/Assertions.h"
+
+#include <assert.h>
+
+#define LOG_TAG "WebCore"
+#undef LOG
+#include <utils/Log.h>
+
+#define notImplemented() LOGV("%s\n", __PRETTY_FUNCTION__)
+#define lowPriority_notImplemented() //printf("%s\n", __PRETTY_FUNCTION__)
+
+namespace WebCore {
+
+void EditorClientAndroid::pageDestroyed() {
+ delete this;
+}
+
+bool EditorClientAndroid::shouldDeleteRange(Range*) { return true; }
+bool EditorClientAndroid::shouldShowDeleteInterface(HTMLElement*) { notImplemented(); return false; }
+bool EditorClientAndroid::smartInsertDeleteEnabled() { notImplemented(); return false; }
+bool EditorClientAndroid::isContinuousSpellCheckingEnabled() { notImplemented(); return false; }
+void EditorClientAndroid::toggleContinuousSpellChecking() { notImplemented(); }
+bool EditorClientAndroid::isGrammarCheckingEnabled() { notImplemented(); return false; }
+void EditorClientAndroid::toggleGrammarChecking() { notImplemented(); }
+int EditorClientAndroid::spellCheckerDocumentTag() { notImplemented(); return -1; }
+
+bool EditorClientAndroid::isEditable() { notImplemented(); return false; }
+
+// Following Qt's implementation. For shouldBeginEditing and shouldEndEditing.
+// Returning true for these fixes issue http://b/issue?id=735185
+bool EditorClientAndroid::shouldBeginEditing(Range*)
+{
+ return true;
+}
+
+bool EditorClientAndroid::shouldEndEditing(Range*)
+{
+ return true;
+}
+
+bool EditorClientAndroid::shouldInsertNode(Node*, Range*, EditorInsertAction) { notImplemented(); return true; }
+bool EditorClientAndroid::shouldInsertText(String, Range*, EditorInsertAction) { return true; }
+bool EditorClientAndroid::shouldApplyStyle(CSSStyleDeclaration*, Range*) { notImplemented(); return true; }
+
+void EditorClientAndroid::didBeginEditing() { notImplemented(); }
+
+// This function is called so that the platform can handle changes to content. It is called
+// after the contents have been edited or unedited (ie undo)
+void EditorClientAndroid::respondToChangedContents() { notImplemented(); }
+
+void EditorClientAndroid::didEndEditing() { notImplemented(); }
+void EditorClientAndroid::didWriteSelectionToPasteboard() { notImplemented(); }
+void EditorClientAndroid::didSetSelectionTypesForPasteboard() { notImplemented(); }
+
+// Copied from the Window's port of WebKit.
+static const unsigned AltKey = 1 << 0;
+static const unsigned ShiftKey = 1 << 1;
+
+struct KeyDownEntry {
+ unsigned virtualKey;
+ unsigned modifiers;
+ const char* name;
+};
+
+struct KeyPressEntry {
+ unsigned charCode;
+ unsigned modifiers;
+ const char* name;
+};
+
+static const KeyDownEntry keyDownEntries[] = {
+ { VK_LEFT, 0, "MoveLeft" },
+ { VK_LEFT, ShiftKey, "MoveLeftAndModifySelection" },
+ { VK_LEFT, AltKey, "MoveWordLeft" },
+ { VK_LEFT, AltKey | ShiftKey, "MoveWordLeftAndModifySelection" },
+ { VK_RIGHT, 0, "MoveRight" },
+ { VK_RIGHT, ShiftKey, "MoveRightAndModifySelection" },
+ { VK_RIGHT, AltKey, "MoveWordRight" },
+ { VK_RIGHT, AltKey | ShiftKey, "MoveWordRightAndModifySelection" },
+ { VK_UP, 0, "MoveUp" },
+ { VK_UP, ShiftKey, "MoveUpAndModifySelection" },
+ { VK_DOWN, 0, "MoveDown" },
+ { VK_DOWN, ShiftKey, "MoveDownAndModifySelection" },
+
+ { VK_BACK, 0, "BackwardDelete" },
+ { VK_BACK, ShiftKey, "ForwardDelete" },
+ { VK_BACK, AltKey, "DeleteWordBackward" },
+ { VK_BACK, AltKey | ShiftKey, "DeleteWordForward" },
+
+ { VK_ESCAPE, 0, "Cancel" },
+ { VK_TAB, 0, "InsertTab" },
+ { VK_TAB, ShiftKey, "InsertBacktab" },
+ { VK_RETURN, 0, "InsertNewline" },
+ { VK_RETURN, AltKey, "InsertNewline" },
+ { VK_RETURN, AltKey | ShiftKey, "InsertNewline" }
+};
+
+static const KeyPressEntry keyPressEntries[] = {
+ { '\t', 0, "InsertTab" },
+ { '\t', ShiftKey, "InsertBackTab" },
+ { '\r', 0, "InsertNewline" },
+ { '\r', AltKey, "InsertNewline" },
+ { '\r', AltKey | ShiftKey, "InsertNewline" }
+};
+
+static const char* interpretKeyEvent(const KeyboardEvent* evt)
+{
+ const PlatformKeyboardEvent* keyEvent = evt->keyEvent();
+
+ static HashMap<int, const char*>* keyDownCommandsMap = 0;
+ static HashMap<int, const char*>* keyPressCommandsMap = 0;
+
+ if (!keyDownCommandsMap) {
+ keyDownCommandsMap = new HashMap<int, const char*>;
+ keyPressCommandsMap = new HashMap<int, const char*>;
+
+ for (unsigned i = 0; i < sizeof(keyDownEntries)/sizeof(KeyDownEntry); i++)
+ keyDownCommandsMap->set(keyDownEntries[i].modifiers << 16 | keyDownEntries[i].virtualKey, keyDownEntries[i].name);
+
+ for (unsigned i = 0; i < sizeof(keyPressEntries)/sizeof(KeyPressEntry); i++)
+ keyPressCommandsMap->set(keyPressEntries[i].modifiers << 16 | keyPressEntries[i].charCode, keyPressEntries[i].name);
+ }
+
+ unsigned modifiers = 0;
+ if (keyEvent->shiftKey())
+ modifiers |= ShiftKey;
+ if (keyEvent->altKey())
+ modifiers |= AltKey;
+
+ if (evt->type() == EventNames::keydownEvent) {
+ int mapKey = modifiers << 16 | evt->keyCode();
+ return mapKey ? keyDownCommandsMap->get(mapKey) : 0;
+ }
+
+ int mapKey = modifiers << 16 | evt->charCode();
+ return mapKey ? keyPressCommandsMap->get(mapKey) : 0;
+}
+
+void EditorClientAndroid::handleKeyboardEvent(KeyboardEvent* event) {
+ assert(m_page);
+ Frame* frame = m_page->focusController()->focusedOrMainFrame();
+ if (!frame)
+ return;
+
+ const PlatformKeyboardEvent* keyEvent = event->keyEvent();
+ // TODO: If the event is not coming from Android Java, e.g. from JavaScript,
+ // PlatformKeyboardEvent is null. We should support this later.
+ if (!keyEvent)
+ return;
+
+ Editor::Command command = frame->editor()->command(interpretKeyEvent(event));
+ if (keyEvent->type() == PlatformKeyboardEvent::RawKeyDown) {
+ if (!command.isTextInsertion() && command.execute(event)) {
+ // This function mimics the Windows version. However, calling event->setDefaultHandled()
+ // prevents the javascript key events for the delete key from happening.
+ // Update: Safari doesn't send delete key events to javascript so
+ // we will mimic that behavior.
+ event->setDefaultHandled();
+ }
+ return;
+ }
+
+ if (command.execute(event)) {
+ event->setDefaultHandled();
+ return;
+ }
+
+ // Don't insert null or control characters as they can result in unexpected behaviour
+ if (event->charCode() < ' ')
+ return;
+
+ if (frame->editor()->insertText(keyEvent->text(), event))
+ event->setDefaultHandled();
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////
+// we just don't support Undo/Redo at the moment
+
+void EditorClientAndroid::registerCommandForUndo(PassRefPtr<EditCommand>) {}
+void EditorClientAndroid::registerCommandForRedo(PassRefPtr<EditCommand>) {}
+void EditorClientAndroid::clearUndoRedoOperations() {}
+bool EditorClientAndroid::canUndo() const { return false; }
+bool EditorClientAndroid::canRedo() const { return false; }
+void EditorClientAndroid::undo() {}
+void EditorClientAndroid::redo() {}
+
+// functions new to Jun-07 tip of tree merge:
+void EditorClientAndroid::showSpellingUI(bool) {}
+void EditorClientAndroid::getGuessesForWord(String const&, Vector<String>&) {}
+bool EditorClientAndroid::spellingUIIsShowing() { return false; }
+void EditorClientAndroid::checkGrammarOfString(unsigned short const*, int, Vector<GrammarDetail>&, int*, int*) {}
+void EditorClientAndroid::checkSpellingOfString(unsigned short const*, int, int*, int*) {}
+void EditorClientAndroid::textFieldDidEndEditing(Element*) {}
+void EditorClientAndroid::textDidChangeInTextArea(Element*) {}
+void EditorClientAndroid::textDidChangeInTextField(Element*) {}
+void EditorClientAndroid::textFieldDidBeginEditing(Element*) {}
+void EditorClientAndroid::ignoreWordInSpellDocument(String const&) {}
+void EditorClientAndroid::respondToChangedSelection() {}
+bool EditorClientAndroid::shouldChangeSelectedRange(Range*, Range*, EAffinity, bool) { return m_notFromClick; }
+bool EditorClientAndroid::doTextFieldCommandFromEvent(Element*, KeyboardEvent*) { return false; }
+void EditorClientAndroid::textWillBeDeletedInTextField(Element*) {}
+void EditorClientAndroid::updateSpellingUIWithGrammarString(String const&, GrammarDetail const&) {}
+void EditorClientAndroid::updateSpellingUIWithMisspelledWord(String const&) {}
+void EditorClientAndroid::learnWord(String const&) {}
+
+// functions new to the Nov-16-08 tip of tree merge:
+bool EditorClientAndroid::shouldMoveRangeAfterDelete(Range*, Range*) { return true; }
+void EditorClientAndroid::setInputMethodState(bool) {}
+
+// functions new to Feb-19 tip of tree merge:
+void EditorClientAndroid::handleInputMethodKeydown(KeyboardEvent*) {}
+
+}
diff --git a/WebCore/platform/android/EditorClientAndroid.h b/WebCore/platform/android/EditorClientAndroid.h
new file mode 100644
index 0000000..1bfd7e6
--- /dev/null
+++ b/WebCore/platform/android/EditorClientAndroid.h
@@ -0,0 +1,103 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef EditorClientAndroid_h
+#define EditorClientAndroid_h
+
+#include "EditorClient.h"
+#include "Page.h"
+
+namespace WebCore {
+
+class EditorClientAndroid : public EditorClient {
+public:
+ EditorClientAndroid() { m_notFromClick = true; }
+ virtual void pageDestroyed();
+
+ virtual bool shouldDeleteRange(Range*);
+ virtual bool shouldShowDeleteInterface(HTMLElement*);
+ virtual bool smartInsertDeleteEnabled();
+ virtual bool isContinuousSpellCheckingEnabled();
+ virtual void toggleContinuousSpellChecking();
+ virtual bool isGrammarCheckingEnabled();
+ virtual void toggleGrammarChecking();
+ virtual int spellCheckerDocumentTag();
+
+ virtual bool isEditable();
+
+ virtual bool shouldBeginEditing(Range*);
+ virtual bool shouldEndEditing(Range*);
+ virtual bool shouldInsertNode(Node*, Range*, EditorInsertAction);
+ virtual bool shouldInsertText(String, Range*, EditorInsertAction);
+ virtual bool shouldChangeSelectedRange(Range* fromRange, Range* toRange, EAffinity, bool stillSelecting);
+
+ virtual bool shouldApplyStyle(CSSStyleDeclaration*, Range*);
+// virtual bool shouldChangeTypingStyle(CSSStyleDeclaration* fromStyle, CSSStyleDeclaration* toStyle);
+// virtual bool doCommandBySelector(SEL selector);
+
+ virtual void didBeginEditing();
+ virtual void respondToChangedContents();
+ virtual void respondToChangedSelection();
+ virtual void didEndEditing();
+ virtual void didWriteSelectionToPasteboard();
+ virtual void didSetSelectionTypesForPasteboard();
+// virtual void didChangeTypingStyle:(NSNotification *)notification;
+// virtual void didChangeSelection:(NSNotification *)notification;
+// virtual NSUndoManager* undoManager:(WebView *)webView;
+
+ virtual void registerCommandForUndo(PassRefPtr<EditCommand>);
+ virtual void registerCommandForRedo(PassRefPtr<EditCommand>);
+ virtual void clearUndoRedoOperations();
+
+ virtual bool canUndo() const;
+ virtual bool canRedo() const;
+
+ virtual void undo();
+ virtual void redo();
+
+ virtual void textFieldDidBeginEditing(Element*);
+ virtual void textFieldDidEndEditing(Element*);
+ virtual void textDidChangeInTextField(Element*);
+ virtual bool doTextFieldCommandFromEvent(Element*, KeyboardEvent*);
+ virtual void textWillBeDeletedInTextField(Element*);
+ virtual void textDidChangeInTextArea(Element*);
+
+ virtual void ignoreWordInSpellDocument(const String&);
+ virtual void learnWord(const String&);
+ virtual void checkSpellingOfString(const UChar*, int length, int* misspellingLocation, int* misspellingLength);
+ virtual void checkGrammarOfString(const UChar*, int length, Vector<GrammarDetail>&, int* badGrammarLocation, int* badGrammarLength);
+ virtual void updateSpellingUIWithGrammarString(const String&, const GrammarDetail& detail);
+ virtual void updateSpellingUIWithMisspelledWord(const String&);
+ virtual void showSpellingUI(bool show);
+ virtual bool spellingUIIsShowing();
+ virtual void getGuessesForWord(const String&, Vector<String>& guesses);
+ virtual bool shouldMoveRangeAfterDelete(Range*, Range*);
+ virtual void setInputMethodState(bool);
+
+ virtual void handleKeyboardEvent(KeyboardEvent*);
+ virtual void handleInputMethodKeydown(KeyboardEvent*);
+ // Android specific:
+ void setPage(Page* page) { m_page = page; }
+ void setFromClick(bool fromClick) { m_notFromClick = !fromClick; }
+private:
+ Page* m_page;
+ bool m_notFromClick;
+};
+
+}
+
+#endif
diff --git a/WebCore/platform/android/FileChooserAndroid.cpp b/WebCore/platform/android/FileChooserAndroid.cpp
new file mode 100644
index 0000000..e613115
--- /dev/null
+++ b/WebCore/platform/android/FileChooserAndroid.cpp
@@ -0,0 +1,67 @@
+/* libs/WebKitLib/WebKit/WebCore/platform/android/FileChooserAndroid.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "config.h"
+#include "FileChooser.h"
+#include "Font.h"
+#include "Icon.h"
+#include "LocalizedStrings.h"
+#include "PlatformString.h"
+
+namespace WebCore {
+
+FileChooser::FileChooser(FileChooserClient* client, const String& initialFilename)
+{
+ m_client = client;
+ if (initialFilename.length() == 0)
+ m_filename = fileButtonNoFileSelectedLabel();
+ else
+ m_filename = initialFilename;
+}
+
+FileChooser::~FileChooser()
+{
+}
+
+void FileChooser::openFileChooser(Document* doc)
+{
+ // FIXME: NEED TO OPEN A FILE CHOOSER OF SOME SORT!!
+ // When it's chosen, set m_filename, call chooseFile(m_filename) and call chooseIcon(m_filename)
+}
+
+String FileChooser::basenameForWidth(const Font& font, int width) const
+{
+ // FIXME: This could be a lot faster, but assuming the data will not often be
+ // much longer than the provided width, this may be fast enough.
+ String output = m_filename.copy();
+ while (font.width(TextRun(output.impl())) > width && output.length() > 4) {
+ output = output.replace(output.length() - 4, 4, String("..."));
+ }
+ return output;
+
+}
+
+
+// The following two strings are used for File Upload form control, ie
+// <input type="file">. The first is the text that appears on the button
+// that when pressed, the user can browse for and select a file. The
+// second string is rendered on the screen when no file has been selected.
+String fileButtonChooseFileLabel() { return String("Uploads Disabled"); }
+String fileButtonNoFileSelectedLabel() { return String("No file selected"); }
+
+} // WebCore
+
diff --git a/WebCore/platform/android/FileSystemAndroid.cpp b/WebCore/platform/android/FileSystemAndroid.cpp
new file mode 100644
index 0000000..1aa8843
--- /dev/null
+++ b/WebCore/platform/android/FileSystemAndroid.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2007 Holger Hans Peter Freyther
+ * 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.
+ */
+
+#include "config.h"
+
+#include "FileSystem.h"
+#include "PlatformString.h"
+#include "CString.h"
+
+namespace WebCore {
+
+CString fileSystemRepresentation(const String& path) {
+ return path.utf8();
+}
+
+}
diff --git a/WebCore/platform/android/FrameLoaderClientAndroid.cpp b/WebCore/platform/android/FrameLoaderClientAndroid.cpp
new file mode 100644
index 0000000..2319bd8
--- /dev/null
+++ b/WebCore/platform/android/FrameLoaderClientAndroid.cpp
@@ -0,0 +1,1173 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "config.h"
+
+#include "android_graphics.h"
+#include "CString.h"
+#include "DocumentLoader.h"
+#include "FrameAndroid.h"
+#include "FrameLoader.h"
+#include "FrameLoaderClientAndroid.h"
+#include "FrameTree.h"
+#include "GraphicsContext.h"
+// HTMLFormElement needed for a bad include
+#include "HTMLFormElement.h"
+#include "HTMLFrameOwnerElement.h"
+#include "IconDatabase.h"
+#include "Page.h"
+#include "PlatformGraphicsContext.h"
+#include "PlatformString.h"
+#include "PluginInfoStore.h"
+#include "PluginDatabaseAndroid.h"
+#include "PluginViewAndroid.h"
+#include "ProgressTracker.h"
+#include "RenderPart.h"
+#include "ResourceError.h"
+#include "SelectionController.h"
+#include "SkCanvas.h"
+#include "SkRect.h"
+#include "Document.h"
+#include "FrameView.h"
+#include "WebCoreViewBridge.h"
+#include "HistoryItem.h"
+#include "ResourceHandle.h"
+#include "ResourceHandleInternal.h"
+#include "WebCoreResourceLoader.h"
+#include "WebCoreViewBridge.h"
+#include "WebHistory.h"
+#include "WebIconDatabase.h"
+#include "Settings.h"
+
+#define LOG_TAG "WebCore"
+#undef LOG
+#include <utils/Log.h>
+#include <utils/AssetManager.h>
+
+//#define notImplemented() LOGV("%s\n", __PRETTY_FUNCTION__)
+#define lowPriority_notImplemented() //printf("%s\n", __PRETTY_FUNCTION__)
+#define verifiedOk() // not a problem that it's not implemented
+static inline void needsBridge(const char name[]) {LOGV("<%s> needs bridge", name);}
+
+extern android::AssetManager* gGlobalAssetMgr;
+
+namespace WebCore {
+
+static const int EXTRA_LAYOUT_DELAY = 1000;
+
+// FIXME: Need some data for how big this should be.
+#define MAX_SESSION_HISTORY 50
+static Vector<KURL> gSessionHistory;
+
+bool historyContains(const UChar* chars, unsigned len) {
+ const KURL url(DeprecatedString(reinterpret_cast<const DeprecatedChar*>(chars), len));
+ Vector<KURL>::const_iterator end = gSessionHistory.end();
+ for (Vector<KURL>::const_iterator i = gSessionHistory.begin(); i != end; ++i) {
+ if (equalIgnoringRef(url, *i))
+ return true;
+ }
+ return false;
+}
+
+void FrameLoaderClientAndroid::frameLoaderDestroyed() {
+ registerForIconNotification(false);
+ m_frame = 0;
+ delete this;
+}
+
+bool FrameLoaderClientAndroid::hasWebView() const {
+ // FIXME,
+ // there is one web view per page, or top frame.
+ // as android's view is created from Java side, it is always there.
+ return true;
+}
+
+bool FrameLoaderClientAndroid::hasFrameView() const {
+ // FIXME,
+ // need to revisit for sub-frame case
+ return true;
+}
+
+bool FrameLoaderClientAndroid::privateBrowsingEnabled() const {
+ // FIXME, are we going to support private browsing?
+ notImplemented();
+ return false;
+}
+
+void FrameLoaderClientAndroid::makeRepresentation(DocumentLoader*) {
+ // don't use representation
+ verifiedOk();
+}
+
+void FrameLoaderClientAndroid::forceLayout() {
+ ASSERT(m_frame);
+ m_frame->forceLayout();
+ // FIXME, should we adjust view size here?
+ m_frame->view()->adjustViewSize();
+}
+
+void FrameLoaderClientAndroid::forceLayoutForNonHTML() {
+ notImplemented();
+}
+
+void FrameLoaderClientAndroid::setCopiesOnScroll() {
+ // this is a hint about whether we need to force redraws, or can
+ // just copy the scrolled content. Since we always force a redraw
+ // anyways, we can ignore this call.
+ verifiedOk();
+}
+
+void FrameLoaderClientAndroid::detachedFromParent2() {
+ // FIXME, ready to detach frame from view
+}
+
+void FrameLoaderClientAndroid::detachedFromParent3() {
+ // FIXME, ready to release view
+ notImplemented();
+}
+
+void FrameLoaderClientAndroid::detachedFromParent4() {
+ // FIXME, ready to release view
+ notImplemented();
+}
+
+void FrameLoaderClientAndroid::loadedFromPageCache() {
+ // don't support page cache
+ verifiedOk();
+}
+
+// This function is responsible for associating the "id" with a given
+// subresource load. The following functions that accept an "id" are
+// called for each subresource, so they should not be dispatched to the m_frame.
+void FrameLoaderClientAndroid::assignIdentifierToInitialRequest(unsigned long id,
+ DocumentLoader*, const ResourceRequest&) {
+ lowPriority_notImplemented();
+}
+
+void FrameLoaderClientAndroid::dispatchWillSendRequest(DocumentLoader*, unsigned long id,
+ ResourceRequest&, const ResourceResponse&) {
+ lowPriority_notImplemented();
+}
+
+void FrameLoaderClientAndroid::dispatchDidReceiveAuthenticationChallenge(DocumentLoader*,
+ unsigned long id, const AuthenticationChallenge&) {
+ lowPriority_notImplemented();
+}
+
+void FrameLoaderClientAndroid::dispatchDidCancelAuthenticationChallenge(DocumentLoader*,
+ unsigned long id, const AuthenticationChallenge&) {
+ lowPriority_notImplemented();
+}
+
+void FrameLoaderClientAndroid::dispatchDidReceiveResponse(DocumentLoader*,
+ unsigned long id, const ResourceResponse&) {
+ lowPriority_notImplemented();
+}
+
+void FrameLoaderClientAndroid::dispatchDidReceiveContentLength(DocumentLoader*,
+ unsigned long id, int lengthReceived) {
+ lowPriority_notImplemented();
+}
+
+void FrameLoaderClientAndroid::dispatchDidFinishLoading(DocumentLoader*,
+ unsigned long id) {
+ lowPriority_notImplemented();
+}
+
+void FrameLoaderClientAndroid::dispatchDidFailLoading(DocumentLoader* docLoader,
+ unsigned long id, const ResourceError&) {
+ lowPriority_notImplemented();
+}
+
+bool FrameLoaderClientAndroid::dispatchDidLoadResourceFromMemoryCache(DocumentLoader*,
+ const ResourceRequest&, const ResourceResponse&, int length) {
+ notImplemented();
+ return false;
+}
+
+void FrameLoaderClientAndroid::dispatchDidHandleOnloadEvents() {
+}
+
+void FrameLoaderClientAndroid::dispatchDidReceiveServerRedirectForProvisionalLoad() {
+ ASSERT(m_frame);
+ // Tell the load it was a redirect.
+ m_frame->bridge()->loadStarted(m_frame);
+}
+
+void FrameLoaderClientAndroid::dispatchDidCancelClientRedirect() {
+ notImplemented();
+}
+
+void FrameLoaderClientAndroid::dispatchWillPerformClientRedirect(const KURL&,
+ double interval, double fireDate) {
+ notImplemented();
+}
+
+void FrameLoaderClientAndroid::dispatchDidChangeLocationWithinPage() {
+ notImplemented();
+}
+
+void FrameLoaderClientAndroid::dispatchWillClose() {
+ notImplemented();
+}
+
+void FrameLoaderClientAndroid::dispatchDidReceiveIcon() {
+ ASSERT(m_frame);
+ if (m_frame->tree() && m_frame->tree()->parent())
+ return;
+ WebCore::String url(m_frame->loader()->url().string());
+ WebCore::Image* icon = WebCore::iconDatabase()->iconForPageURL(url, WebCore::IntSize(16,16));
+ // There is a bug in webkit where cancelling an icon load is treated as a
+ // failure. When this is fixed, we can ASSERT again that we have an icon.
+ if (icon) {
+ m_frame->bridge()->didReceiveIcon(icon);
+ LOGV("Received icon (%p) for %s", icon,
+ m_frame->loader()->url().deprecatedString().ascii());
+ }
+}
+
+void FrameLoaderClientAndroid::dispatchDidStartProvisionalLoad() {
+ notImplemented();
+}
+
+void FrameLoaderClientAndroid::dispatchDidReceiveTitle(const String& title) {
+ ASSERT(m_frame);
+ // Used to check for FrameLoadTypeStandard but we only want to send the title for
+ // the top frame and not sub-frames.
+ if (!m_frame->tree() || !m_frame->tree()->parent()) {
+ m_frame->bridge()->setTitle(title);
+ }
+}
+
+void FrameLoaderClientAndroid::dispatchDidCommitLoad() {
+ ASSERT(m_frame);
+ m_frame->view()->getWebCoreViewBridge()->updateFrameGeneration(m_frame);
+}
+
+void FrameLoaderClientAndroid::dispatchDidFailProvisionalLoad(const ResourceError& error) {
+ ASSERT(m_frame);
+ // Ignore ErrorInterrupted since it is due to a policy interruption. This
+ // is caused by a decision to download the main resource rather than
+ // display it.
+ if (error.errorCode() == InternalErrorInterrupted
+ || error.errorCode() == InternalErrorCancelled)
+ return;
+
+ if (!gGlobalAssetMgr) {
+ gGlobalAssetMgr = new android::AssetManager();
+ gGlobalAssetMgr->addDefaultAssets();
+ }
+
+ // Check to see if the error code was not generated internally
+ const char* errorPage = "webkit/nodomain.html";
+ if ((error.errorCode() == ErrorFile ||
+ error.errorCode() == ErrorFileNotFound) &&
+ (!error.localizedDescription().isEmpty())) {
+ errorPage = "webkit/loaderror.html";
+ }
+
+ // Grab the error page from the asset manager
+ android::Asset* a = gGlobalAssetMgr->open(errorPage,
+ android::Asset::ACCESS_BUFFER);
+ if (!a)
+ return;
+
+ // Take the failing url and encode html entities so javascript urls are not
+ // executed.
+ CString failingUrl = error.failingURL().utf8();
+ Vector<char> url;
+ int len = failingUrl.length();
+ const char* data = failingUrl.data();
+ for (int i = 0; i < len; i++) {
+ char c = data[i];
+ if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
+ || (c >= '0' && c <= '9'))
+ url.append(c);
+ else {
+ char buf[16];
+ int res = sprintf(buf, "&#%d;", c);
+ buf[res] = 0;
+ url.append(buf, res);
+ }
+ }
+
+ // Replace all occurances of %s with the failing url.
+ String s = String((const char*)a->getBuffer(false), a->getLength());
+ s = s.replace("%s", String(url.data(), url.size()));
+
+ // Replace all occurances of %e with the error text
+ s = s.replace("%e", error.localizedDescription());
+
+ // Create the request and the substitute data and tell the FrameLoader to
+ // load with the replacement data.
+ ResourceRequest request(error.failingURL());
+ CString cstr = s.utf8();
+ RefPtr<SharedBuffer> buf = new SharedBuffer(cstr.data(), cstr.length());
+ SubstituteData subData(buf, String("text/html"), String("utf-8"),
+ request.url());
+ m_frame->loader()->load(request, subData);
+
+ // Delete the asset.
+ delete a;
+}
+
+void FrameLoaderClientAndroid::dispatchDidFailLoad(const ResourceError&) {
+ // called when page is completed with error
+ lowPriority_notImplemented();
+ ASSERT(m_frame);
+ m_frame->document()->setExtraLayoutDelay(0);
+}
+
+void FrameLoaderClientAndroid::dispatchDidFinishDocumentLoad() {
+ // called when finishedParsing
+ lowPriority_notImplemented();
+}
+
+void FrameLoaderClientAndroid::dispatchDidFinishLoad() {
+ ASSERT(m_frame);
+ m_frame->document()->setExtraLayoutDelay(0);
+ m_frame->bridge()->didFinishLoad(m_frame);
+}
+
+void FrameLoaderClientAndroid::dispatchDidFirstLayout() {
+ ASSERT(m_frame);
+ m_frame->document()->setExtraLayoutDelay(EXTRA_LAYOUT_DELAY);
+ // FIXME: Need to figure out if we need didLayout or didFirstLayout
+ // see WebViewCore::didLayout
+ m_frame->view()->getWebCoreViewBridge()->didFirstLayout();
+}
+
+Frame* FrameLoaderClientAndroid::dispatchCreatePage() {
+ ASSERT(m_frame);
+ if (m_frame->settings()->supportMultipleWindows())
+ // Always a user gesture since window.open maps to
+ // ChromeClientAndroid::createWindow
+ return m_frame->bridge()->createWindow(false, true);
+ else
+ // If the client doesn't support multiple windows, just replace the
+ // current frame's contents.
+ return m_frame;
+}
+
+void FrameLoaderClientAndroid::dispatchShow() {
+ ASSERT(m_frame);
+ m_frame->view()->invalidate();
+}
+
+
+static bool TreatAsAttachment(const String& content_disposition) {
+ // Some broken sites just send
+ // Content-Disposition: ; filename="file"
+ // screen those out here.
+ if (content_disposition.startsWith(";"))
+ return false;
+
+ if (content_disposition.startsWith("inline", false))
+ return false;
+
+ // Some broken sites just send
+ // Content-Disposition: filename="file"
+ // without a disposition token... screen those out.
+ if (content_disposition.startsWith("filename", false))
+ return false;
+
+ // Also in use is Content-Disposition: name="file"
+ if (content_disposition.startsWith("name", false))
+ return false;
+
+ // We have a content-disposition of "attachment" or unknown.
+ // RFC 2183, section 2.8 says that an unknown disposition
+ // value should be treated as "attachment"
+ return true;
+}
+
+void FrameLoaderClientAndroid::dispatchDecidePolicyForMIMEType(FramePolicyFunction func,
+ const String& MIMEType, const ResourceRequest&) {
+ ASSERT(m_frame);
+ ASSERT(func);
+ // Default to Use (display internally).
+ PolicyAction action = PolicyUse;
+ // Check if we should Download instead.
+ const ResourceResponse& response = m_frame->loader()->activeDocumentLoader()->response();
+ const String& content_disposition = response.httpHeaderField("Content-Disposition");
+ if (!content_disposition.isEmpty()) {
+ // Server wants to override our normal policy.
+ if (TreatAsAttachment(content_disposition)) {
+ // Check to see if we are a sub frame (main frame has no owner element)
+ if (m_frame->ownerElement() != 0)
+ action = PolicyIgnore;
+ else
+ action = PolicyDownload;
+ }
+ } else {
+ // Ask if it can be handled internally.
+ if (!canShowMIMEType(MIMEType)) {
+ // Check to see if we are a sub frame (main frame has no owner element)
+ if (m_frame->ownerElement() != 0)
+ action = PolicyIgnore;
+ else
+ action = PolicyDownload;
+ }
+ }
+ // A status code of 204 indicates no content change. Ignore the result.
+ WebCore::DocumentLoader* docLoader = m_frame->loader()->activeDocumentLoader();
+ if (docLoader->response().httpStatusCode() == 204)
+ action = PolicyIgnore;
+ (m_frame->loader()->*func)(action);
+}
+
+void FrameLoaderClientAndroid::dispatchDecidePolicyForNewWindowAction(FramePolicyFunction func,
+ const NavigationAction&, const ResourceRequest& req, const String& frameName) {
+ ASSERT(m_frame);
+ // If we get to this point it means that a link has a target that was not
+ // found by the frame tree. Instead of creating a new frame, return the
+ // current frame in dispatchCreatePage.
+ if (canHandleRequest(req))
+ (m_frame->loader()->*func)(PolicyUse);
+ else
+ (m_frame->loader()->*func)(PolicyIgnore);
+}
+
+void FrameLoaderClientAndroid::cancelPolicyCheck() {
+ lowPriority_notImplemented();
+}
+
+void FrameLoaderClientAndroid::dispatchUnableToImplementPolicy(const ResourceError&) {
+ notImplemented();
+}
+
+void FrameLoaderClientAndroid::dispatchDecidePolicyForNavigationAction(FramePolicyFunction func,
+ const NavigationAction& action, const ResourceRequest& request) {
+ ASSERT(m_frame);
+ ASSERT(func);
+ if (action.type() == NavigationTypeFormResubmitted) {
+ m_frame->bridge()->decidePolicyForFormResubmission(func);
+ return;
+ } else {
+ (m_frame->loader()->*func)(PolicyUse);
+ }
+}
+
+void FrameLoaderClientAndroid::dispatchWillSubmitForm(FramePolicyFunction func, PassRefPtr<FormState>) {
+ ASSERT(m_frame);
+ ASSERT(func);
+ (m_frame->loader()->*func)(PolicyUse);
+}
+
+void FrameLoaderClientAndroid::dispatchDidLoadMainResource(DocumentLoader*) {
+ notImplemented();
+}
+
+void FrameLoaderClientAndroid::revertToProvisionalState(DocumentLoader*) {
+ notImplemented();
+}
+
+void FrameLoaderClientAndroid::setMainDocumentError(DocumentLoader* docLoader, const ResourceError& error) {
+ ASSERT(m_frame);
+ if (!error.isNull() && error.errorCode() >= InternalErrorLast)
+ m_frame->bridge()->reportError(error.errorCode(),
+ error.localizedDescription(), error.failingURL());
+}
+
+void FrameLoaderClientAndroid::clearUnarchivingState(DocumentLoader*) {
+ notImplemented();
+}
+
+// This function is called right before the progress is updated.
+void FrameLoaderClientAndroid::willChangeEstimatedProgress() {
+ verifiedOk();
+}
+
+// This function is called after the progress has been updated. The bad part
+// about this is that when a page is completed, this function is called after
+// the progress has been reset to 0.
+void FrameLoaderClientAndroid::didChangeEstimatedProgress() {
+ verifiedOk();
+}
+
+// This will give us the initial estimate when the page first starts to load.
+void FrameLoaderClientAndroid::postProgressStartedNotification() {
+ ASSERT(m_frame);
+ if (m_frame->page())
+ m_frame->bridge()->setProgress(m_frame->page()->progress()->estimatedProgress());
+}
+
+// This will give us any updated progress including the final progress.
+void FrameLoaderClientAndroid::postProgressEstimateChangedNotification() {
+ ASSERT(m_frame);
+ if (m_frame->page())
+ m_frame->bridge()->setProgress(m_frame->page()->progress()->estimatedProgress());
+}
+
+// This is just a notification that the progress has finished. Don't call
+// setProgress(1) because postProgressEstimateChangedNotification will do so.
+void FrameLoaderClientAndroid::postProgressFinishedNotification() {
+ m_frame->view()->getWebCoreViewBridge()->notifyProgressFinished();
+}
+
+void FrameLoaderClientAndroid::setMainFrameDocumentReady(bool) {
+ // this is only interesting once we provide an external API for the DOM
+ notImplemented();
+}
+
+void FrameLoaderClientAndroid::startDownload(const ResourceRequest&) {
+ notImplemented();
+}
+
+void FrameLoaderClientAndroid::willChangeTitle(DocumentLoader*) {
+ verifiedOk();
+}
+
+void FrameLoaderClientAndroid::didChangeTitle(DocumentLoader* loader) {
+ verifiedOk();
+}
+
+void FrameLoaderClientAndroid::finishedLoading(DocumentLoader* docLoader) {
+ // Telling the frame we received some data and passing 0 as the data is our
+ // way to get work done that is normally done when the first bit of data is
+ // received, even for the case of a document with no data (like about:blank)
+ committedLoad(docLoader, 0, 0);
+}
+
+void FrameLoaderClientAndroid::finalSetupForReplace(DocumentLoader*) {
+ notImplemented();
+}
+
+void FrameLoaderClientAndroid::updateGlobalHistoryForStandardLoad(const KURL& url) {
+ ASSERT(m_frame);
+ const DeprecatedString dStr = url.deprecatedString();
+ if (!historyContains(reinterpret_cast<const UChar*>(dStr.unicode()), dStr.length())) {
+ if (gSessionHistory.size() == MAX_SESSION_HISTORY)
+ gSessionHistory.remove(0);
+ gSessionHistory.append(url);
+ }
+ m_frame->bridge()->updateVisitedHistory(url, false);
+}
+
+void FrameLoaderClientAndroid::updateGlobalHistoryForReload(const KURL& url) {
+ ASSERT(m_frame);
+ m_frame->bridge()->updateVisitedHistory(url, true);
+}
+
+bool FrameLoaderClientAndroid::shouldGoToHistoryItem(HistoryItem* item) const {
+ // hmmm, seems like we might do a more thoughtful check
+ ASSERT(m_frame);
+ return item != NULL;
+}
+
+void FrameLoaderClientAndroid::committedLoad(DocumentLoader* loader, const char* data, int length) {
+ ASSERT(m_frame);
+ String encoding = loader->overrideEncoding();
+ bool userChosen = !encoding.isNull();
+ if (encoding.isNull())
+ encoding = loader->response().textEncodingName();
+ loader->frameLoader()->setEncoding(encoding, userChosen);
+ Document *doc = m_frame->document();
+ if (doc) {
+ loader->frameLoader()->addData(data, length);
+ }
+}
+
+ResourceError FrameLoaderClientAndroid::cancelledError(const ResourceRequest& request) {
+ return ResourceError(String(), InternalErrorCancelled, String(), String());
+}
+
+ResourceError FrameLoaderClientAndroid::cannotShowURLError(const ResourceRequest& request) {
+ return ResourceError(String(), InternalErrorCannotShowUrl, String(), String());
+}
+
+ResourceError FrameLoaderClientAndroid::interruptForPolicyChangeError(const ResourceRequest& request) {
+ return ResourceError(String(), InternalErrorInterrupted, String(), String());
+}
+
+ResourceError FrameLoaderClientAndroid::cannotShowMIMETypeError(const ResourceResponse& request) {
+ return ResourceError(String(), InternalErrorCannotShowMimeType, String(), String());
+}
+
+ResourceError FrameLoaderClientAndroid::fileDoesNotExistError(const ResourceResponse& request) {
+ return ResourceError(String(), InternalErrorFileDoesNotExist, String(), String());
+}
+
+bool FrameLoaderClientAndroid::shouldFallBack(const ResourceError&) {
+ notImplemented();
+ return false;
+}
+
+void FrameLoaderClientAndroid::setDefersLoading(bool) {
+ notImplemented();
+}
+
+bool FrameLoaderClientAndroid::willUseArchive(ResourceLoader*, const ResourceRequest&,
+ const KURL& originalURL) const {
+ lowPriority_notImplemented();
+ return false;
+}
+
+bool FrameLoaderClientAndroid::isArchiveLoadPending(ResourceLoader*) const {
+ lowPriority_notImplemented();
+ return false;
+}
+
+void FrameLoaderClientAndroid::cancelPendingArchiveLoad(ResourceLoader*) {
+ notImplemented();
+}
+
+void FrameLoaderClientAndroid::clearArchivedResources() {
+ notImplemented();
+}
+
+bool FrameLoaderClientAndroid::canHandleRequest(const ResourceRequest& request) const {
+ ASSERT(m_frame);
+ // Don't allow hijacking of intrapage navigation
+ if (WebCore::equalIgnoringRef(request.url(), m_frame->loader()->url()))
+ return true;
+
+ // Don't allow hijacking of iframe urls that are http or https
+ if (request.url().protocol().startsWith("http", false) &&
+ m_frame->tree() && m_frame->tree()->parent())
+ return true;
+
+ if (m_frame->bridge()->canHandleRequest(request)) {
+#ifdef ANDROID_META_SUPPORT
+ // reset metadata settings for the top frame as they are not preserved cross page
+ if (!m_frame->tree()->parent())
+ m_frame->settings()->resetMetadataSettings();
+#endif
+ return true;
+ }
+ return false;
+}
+
+bool FrameLoaderClientAndroid::canShowMIMEType(const String& mimeType) const {
+ // FIXME: This looks like it has to do with whether or not a type can be
+ // shown "internally" (i.e. inside the browser) regardless of whether
+ // or not the browser is doing the rendering, e.g. a full page plugin.
+ if (mimeType.startsWith("text/plain", false) ||
+ mimeType.startsWith("image/jpeg", false) || // Be specific with supported image formats
+ mimeType.startsWith("image/gif", false) ||
+ mimeType.startsWith("image/png", false) ||
+ mimeType.startsWith("image/bmp", false) ||
+ mimeType.startsWith("image/x-icon", false) ||
+ mimeType.startsWith("image/ico", false) ||
+ mimeType.endsWith("/xml", false) || // text/xml & application/xml
+ mimeType.endsWith("xhtml+xml", false) || // application/xhtml+xml
+ // Checked Safari impl, it seems that the HTTP stack returns
+ // multiple responses, the initial response, and then one for
+ // multipart segment. Each response is sent to the same ResourceLoader
+ // so for us to support this we would need to do the same.
+ // mimeType.startsWith("multipart/x-mixed-replace", false) ||
+ mimeType.endsWith("html", false))
+ return true;
+ return false;
+}
+
+bool FrameLoaderClientAndroid::representationExistsForURLScheme(const String&) const {
+ // don't use representation
+ verifiedOk();
+ return false;
+}
+
+String FrameLoaderClientAndroid::generatedMIMETypeForURLScheme(const String& URLScheme) const {
+ // FIXME, copy from Apple's port
+ String mimetype("x-apple-web-kit/");
+ mimetype.append(URLScheme.lower());
+ return mimetype;
+}
+
+void FrameLoaderClientAndroid::frameLoadCompleted() {
+ // copied from Apple port, without this back with sub-frame will trigger ASSERT
+ ASSERT(m_frame);
+ m_frame->loader()->setPreviousHistoryItem(0);
+}
+
+void FrameLoaderClientAndroid::saveViewStateToItem(HistoryItem* item) {
+#ifdef ANDROID_HISTORY_CLIENT
+ ASSERT(m_frame);
+ ASSERT(item);
+ // We should have added a bridge when the child item was added to its
+ // parent.
+ android::WebHistoryItem* bridge = item->bridge();
+ ASSERT(bridge);
+ // store the current scale
+ bridge->setScale(m_frame->view()->getWebCoreViewBridge()->scale());
+
+ // Store the location of the focus, based on how many traversals it
+ // takes to reach the focus from the document.
+ WebCore::Document* doc = m_frame->document();
+ WebCore::Node* focus = doc->focusedNode();
+ if (focus) {
+ int focusNum = 0;
+ WebCore::Node* node = doc;
+ while (node != focus) {
+ node = node->traverseNextNode(doc);
+ ASSERT(node);
+ focusNum++;
+ }
+ bridge->setTraversals(focusNum);
+ DEBUG_NAV_UI_LOGD("%s focus=%p traversals=%d", __FUNCTION__, focus, focusNum);
+ } else {
+ bridge->setTraversals(-1);
+ DEBUG_NAV_UI_LOGD("%s focus=NULL traversals=-1", __FUNCTION__);
+ }
+ WebCore::notifyHistoryItemChanged(item);
+#endif
+}
+
+void FrameLoaderClientAndroid::restoreViewState() {
+#ifdef ANDROID_HISTORY_CLIENT
+ HistoryItem* item = m_frame->loader()->currentHistoryItem();
+ // restore the scale
+ m_frame->view()->getWebCoreViewBridge()->restoreScale(item->bridge()->scale());
+ // restore the focus
+ if (m_frame->loader()->firstLayoutDone() == false)
+ return;
+ int traversals = item->bridge()->traversals();
+ if (traversals < 0)
+ return;
+ WebCore::Document* doc = m_frame->document();
+ WebCore::Node* node = doc;
+ while (--traversals >= 0) {
+ if ((node = node->traverseNextNode(doc)) == NULL)
+ return;
+ }
+ if (doc->focusedNode() == node)
+ return;
+ DEBUG_NAV_UI_LOGD("%s focus=%p", __FUNCTION__, node);
+ doc->setFocusedNode(node);
+ m_frame->view()->getWebCoreViewBridge()->notifyFocusSet();
+#endif
+}
+
+#ifdef ANDROID_HISTORY_CLIENT
+void FrameLoaderClientAndroid::dispatchDidAddHistoryItem(HistoryItem* item) const {
+ ASSERT(m_frame);
+ m_frame->bridge()->addHistoryItem(item);
+}
+
+void FrameLoaderClientAndroid::dispatchDidRemoveHistoryItem(HistoryItem* item, int index) const {
+ ASSERT(m_frame);
+ m_frame->bridge()->removeHistoryItem(index);
+}
+
+void FrameLoaderClientAndroid::dispatchDidChangeHistoryIndex(
+ BackForwardList* list) const {
+ ASSERT(m_frame);
+ m_frame->bridge()->updateHistoryIndex(list->backListCount());
+}
+#endif
+
+void FrameLoaderClientAndroid::provisionalLoadStarted() {
+ ASSERT(m_frame);
+ m_frame->bridge()->loadStarted(m_frame);
+}
+
+void FrameLoaderClientAndroid::didFinishLoad() {
+ ASSERT(m_frame);
+ m_frame->bridge()->didFinishLoad(m_frame);
+}
+
+void FrameLoaderClientAndroid::prepareForDataSourceReplacement() {
+ ASSERT(m_frame);
+ m_frame->loader()->detachChildren();
+}
+
+PassRefPtr<DocumentLoader> FrameLoaderClientAndroid::createDocumentLoader(
+ const ResourceRequest& request, const SubstituteData& data) {
+ RefPtr<DocumentLoader> loader = new DocumentLoader(request, data);
+ return loader.release();
+}
+
+void FrameLoaderClientAndroid::setTitle(const String& title, const KURL& url) {
+ // Not needed. dispatchDidReceiveTitle is called immediately after this.
+ // url is used to update the Apple port history items.
+ verifiedOk();
+}
+
+String FrameLoaderClientAndroid::userAgent(const KURL& u) {
+ ASSERT(m_frame);
+ return m_frame->bridge()->userAgentForURL(&u);
+}
+
+bool FrameLoaderClientAndroid::canCachePage() const {
+ return true;
+}
+
+void FrameLoaderClientAndroid::download(ResourceHandle* handle, const ResourceRequest&,
+ const ResourceRequest&, const ResourceResponse&) {
+ // Get the C++ side of the load listener and tell it to handle the download
+ android::WebCoreResourceLoader* loader = handle->getInternal()->m_loader;
+ loader->downloadFile();
+}
+
+class ChildFrameViewBridge : public WebCoreViewBridge
+{
+public:
+ ChildFrameViewBridge(WebCoreViewBridge* parent, WebCore::FrameAndroid* frame)
+ : mFrame(frame)
+ {
+ setParent(parent);
+ mFrame->ref();
+ }
+
+ virtual ~ChildFrameViewBridge()
+ {
+ mFrame->deref();
+ }
+
+ virtual void draw(WebCore::GraphicsContext* ctx,
+ const WebCore::IntRect& rect, bool)
+ {
+ // Create a new translated rect from the given rectangle.
+ WebCore::IntRect transRect(rect);
+
+ // Grab the intersection of transRect and the frame's bounds.
+ transRect.intersect(this->getBounds());
+
+ // Move the transRect into the frame's local coordinates.
+ transRect.move(-this->locX(), -this->locY());
+
+ // If the rect is non-empty, translate the canvas, add a clip and draw.
+ SkRect r;
+ android_setrect(&r, transRect);
+ if (r.isEmpty())
+ return;
+ // In Frame::markAllMatchesForText(), it does a fake paint. So we need
+ // to handle the case where platformContext() is null. However, we still
+ // want to call paint, since WebKit must have called the paint for a reason.
+ SkCanvas* canvas = ctx->platformContext() ? ctx->platformContext()->mCanvas : NULL;
+ if (canvas) {
+ canvas->save();
+ canvas->translate(SkIntToScalar(this->locX()), SkIntToScalar(this->locY()));
+ canvas->clipRect(r);
+ }
+ mFrame->paint(ctx, transRect);
+ if (canvas)
+ canvas->restore();
+ }
+
+ // Bubble up Javascript dialogs to the parent. The top level view will
+ // take care of displaying them to the user.
+ virtual void jsAlert(const WebCore::String& url, const WebCore::String& text)
+ {
+ getParent()->jsAlert(url, text);
+ }
+ virtual bool jsConfirm(const WebCore::String& url, const WebCore::String& text)
+ {
+ return getParent()->jsConfirm(url, text);
+ }
+ virtual bool jsPrompt(const WebCore::String& url,
+ const WebCore::String& message,
+ const WebCore::String& defaultValue,
+ WebCore::String& result)
+ {
+ return getParent()->jsPrompt(url, message, defaultValue, result);
+ }
+
+private:
+ WebCore::FrameAndroid* mFrame;
+ typedef WebCoreViewBridge INHERITED;
+};
+
+WTF::PassRefPtr<WebCore::Frame> FrameLoaderClientAndroid::createFrame(const KURL& url, const String& name,
+ HTMLFrameOwnerElement* ownerElement, const String& referrer,
+ bool allowsScrolling, int marginWidth, int marginHeight)
+{
+ Frame* parent = ownerElement->document()->frame();
+ FrameLoaderClientAndroid* loaderC = new FrameLoaderClientAndroid;
+ WebCore::FrameAndroid* newFrame = new WebCore::FrameAndroid(parent->page(), ownerElement, loaderC);
+ loaderC->setFrame(newFrame);
+ // Append the subframe to the parent and set the name of the subframe. The name must be set after
+ // appending the child so that the name becomes unique.
+ parent->tree()->appendChild(newFrame);
+ newFrame->tree()->setName(name);
+ newFrame->setBridge(Android(parent)->bridge());
+ // Create a new FrameView and bridge for the child frame to draw into.
+ WebCore::FrameView* frameView = new WebCore::FrameView(newFrame);
+ ChildFrameViewBridge* view = new ChildFrameViewBridge(parent->view()->getWebCoreViewBridge(), newFrame);
+ frameView->setWebCoreViewBridge(view);
+ // Unref the viewBridge so that frameView is the only reference holder.
+ Release(view);
+ newFrame->setView(frameView);
+ // Frames are initiliazed with a ref count of 1 but since our view bridge is holding onto the frame, deref
+ // it here. setView also refs the frameView so call deref on the frameView as well.
+ newFrame->deref();
+ frameView->deref();
+ newFrame->init();
+ newFrame->selectionController()->setFocused(true);
+ LOGV("::WebCore:: createSubFrame returning %p", newFrame);
+
+ HistoryItem* item = parent->loader()->currentHistoryItem();
+ KURL childUrl = url;
+ FrameLoadType loadType = parent->loader()->loadType();
+ FrameLoadType childLoadType = FrameLoadTypeRedirectWithLockedHistory;
+ // If we are moving in the back/forward list, we might want to replace the
+ // content of this child frame with whatever was there at that point. Reload
+ // will maintain the frame contents, LoadSame will not.
+ HistoryItem* childItem = NULL;
+ if (item && item->children().size() &&
+ (isBackForwardLoadType(loadType) ||
+ loadType == FrameLoadTypeReload ||
+ loadType == FrameLoadTypeReloadAllowingStaleData)) {
+ childItem = item->childItemWithName(newFrame->tree()->name());
+ if (childItem) {
+ // Use the original url to ensure we get all the side-effects, such
+ // as onLoad handlers or redirects.
+ childUrl = childItem->originalURL();
+ childLoadType = loadType;
+ if (isBackForwardLoadType(loadType))
+ // For back/forward, remember this item so we can traverse any
+ // child items as child frames load.
+ newFrame->loader()->setProvisionalHistoryItem(childItem);
+ else
+ // For reload, just reinstall the current item, since a new
+ // child frame was created but we won't be creating a new
+ // history item.
+ newFrame->loader()->setCurrentHistoryItem(childItem);
+ }
+ }
+ RefPtr<Frame> autoFrame = newFrame;
+#ifdef ANDROID_FIX
+ if (childItem && childItem->originalFormData())
+ autoFrame->loader()->postFromHistory(childUrl, childItem->originalFormData(),
+ childItem->originalFormContentType(), childItem->originalFormReferrer(), childLoadType);
+ else
+#endif
+#ifdef ANDROID_USER_GESTURE
+ autoFrame->loader()->load(childUrl, referrer, childLoadType,
+ String(), NULL, NULL, false);
+#else
+ autoFrame->loader()->load(childUrl, referrer, childLoadType,
+ String(), NULL, NULL);
+#endif
+
+ // onLoad may cuase the frame to be removed from the document. Allow the RefPtr to delete the child frame.
+ if (!autoFrame->tree()->parent())
+ return NULL;
+
+ return autoFrame.release();
+}
+
+// YouTube flash url path starts with /v/
+static const char slash_v_slash[] = { '/', 'v', '/' };
+
+static bool isValidYouTubeVideo(const DeprecatedString& path)
+{
+ if (!path.isAllASCII())
+ return false;
+ unsigned int len = path.length();
+ if (len <= sizeof(slash_v_slash)) // check for more than just /v/
+ return false;
+ DeprecatedString str = path.lower();
+ const char* data = str.ascii();
+ if (memcmp(data, slash_v_slash, sizeof(slash_v_slash)) != 0)
+ return false;
+ // Start after /v/
+ for (unsigned int i = sizeof(slash_v_slash); i < len; i++) {
+ char c = data[i];
+ // Check for alpha-numeric characters only.
+ if (WTF::isASCIIAlphanumeric(c))
+ continue;
+ // The url can have more parameters such as &hl=en after the video id.
+ // Once we start seeing extra parameters we can return true.
+ return c == '&' && i > sizeof(slash_v_slash);
+ }
+ return true;
+}
+
+static bool isYouTubeUrl(const KURL& url, const String& mimeType)
+{
+ return url.host().endsWith("youtube.com") && isValidYouTubeVideo(url.path())
+ && equalIgnoringCase(mimeType, "application/x-shockwave-flash");
+}
+
+Widget* FrameLoaderClientAndroid::createPlugin(
+ const IntSize& size,
+ Element* element,
+ const KURL& url,
+ const WTF::Vector<String, 0u>& names,
+ const WTF::Vector<String, 0u>& values,
+ const String& mimeType,
+ bool loadManually) {
+ // Create an iframe for youtube urls.
+ if (isYouTubeUrl(url, mimeType)) {
+ DeprecatedString str("file:///android_asset/webkit/youtube.html?v=");
+ str.append(url.path().mid(sizeof(slash_v_slash))); // grab everything after /v/
+ RefPtr<Frame> frame = createFrame(KURL(str), String(), static_cast<HTMLFrameOwnerElement*>(element),
+ String(), false, 0, 0);
+ return frame ? frame->view() : NULL;
+ }
+ PluginViewAndroid* v =
+ PluginDatabaseAndroid::installedPlugins()->createPluginView(
+ m_frame,
+ size,
+ element,
+ url,
+ names,
+ values,
+ mimeType,
+ loadManually);
+ return v;
+}
+
+void FrameLoaderClientAndroid::redirectDataToPlugin(Widget* pluginWidget) {
+ // don't support plugin yet
+ notImplemented();
+}
+
+Widget* FrameLoaderClientAndroid::createJavaAppletWidget(const IntSize&, Element*,
+ const KURL& baseURL, const Vector<String>& paramNames,
+ const Vector<String>& paramValues) {
+ // don't support widget yet
+ notImplemented();
+ return 0;
+}
+
+// This function is used by the <OBJECT> element to determine the type of
+// the contents and work out if it can render it.
+ObjectContentType FrameLoaderClientAndroid::objectContentType(const KURL& url,
+ const String& mimeType) {
+ if (mimeType.length() == 0)
+ {
+ // Guess the mimeType from the extension
+ if (url.hasPath())
+ {
+ DeprecatedString path = url.path();
+ const char* ascii = path.ascii();
+ const char* lastIndex = strrchr(ascii, '.');
+ static const String image("image/");
+ if (lastIndex)
+ {
+ String mime(lastIndex + 1);
+ mime.insert(image, 0);
+ if (Image::supportsType(mime))
+ return ObjectContentImage;
+ }
+ }
+ return ObjectContentFrame;
+ }
+ if (equalIgnoringCase(mimeType, "text/html") ||
+ equalIgnoringCase(mimeType, "text/xml") ||
+ equalIgnoringCase(mimeType, "text/") ||
+ equalIgnoringCase(mimeType, "application/xml") ||
+ equalIgnoringCase(mimeType, "application/xhtml+xml") ||
+ equalIgnoringCase(mimeType, "application/x-javascript"))
+ return ObjectContentFrame;
+ if (Image::supportsType(mimeType))
+ return ObjectContentImage;
+ return ObjectContentNone;
+}
+
+// This function allows the application to set the correct CSS media
+// style. Android could use it to set the media style 'handheld'. Safari
+// may use it to set the media style to 'print' when the user wants to print
+// a particular web page.
+String FrameLoaderClientAndroid::overrideMediaType() const {
+ lowPriority_notImplemented();
+ return String();
+}
+
+// This function is used to re-attach Javascript<->native code classes.
+void FrameLoaderClientAndroid::windowObjectCleared() {
+ ASSERT(m_frame);
+ LOGV("::WebCore:: windowObjectCleared called on frame %p for %s\n",
+ m_frame, m_frame->loader()->url().string().ascii().data());
+ m_frame->bridge()->windowObjectCleared(m_frame);
+}
+
+// functions new to Jun-07 tip of tree merge:
+ResourceError FrameLoaderClientAndroid::blockedError(ResourceRequest const& request) {
+ return ResourceError(String(), InternalErrorFileDoesNotExist, String(), String());
+}
+
+// functions new to Nov-07 tip of tree merge:
+void FrameLoaderClientAndroid::didPerformFirstNavigation() const {
+ // This seems to be just a notification that the UI can listen to, to
+ // know if the user has performed first navigation action.
+ // It is called from
+ // void FrameLoader::addBackForwardItemClippedAtTarget(bool doClip)
+ // "Navigation" here means a transition from one page to another that
+ // ends up in the back/forward list.
+}
+
+void FrameLoaderClientAndroid::registerForIconNotification(bool listen) {
+ if (listen)
+ android::WebIconDatabase::RegisterForIconNotification(this);
+ else
+ android::WebIconDatabase::UnregisterForIconNotification(this);
+}
+
+// This is the WebIconDatabaseClient method for receiving a notification when we
+// get the icon for the page.
+void FrameLoaderClientAndroid::didAddIconForPageUrl(const String& pageUrl) {
+ registerForIconNotification(false);
+ KURL u(pageUrl.deprecatedString());
+ if (equalIgnoringRef(u, m_frame->loader()->url())) {
+ dispatchDidReceiveIcon();
+ }
+}
+
+// functions new to Feb-19 tip of tree merge:
+// According to the changelog:
+// The very Mac-centric "makeDocumentView", "setDocumentViewFromCachedPage",
+// and "saveDocumentViewToCachedPage" become "transitionToCommittedForNewPage",
+// "transitionToCommittedFromCachedPage", and "savePlatformDataToCachedPage"
+// accordingly
+void FrameLoaderClientAndroid::savePlatformDataToCachedPage(CachedPage*) {
+ // don't support page cache
+ verifiedOk();
+}
+
+void FrameLoaderClientAndroid::transitionToCommittedFromCachedPage(CachedPage*) {
+ // don't support page cache
+ verifiedOk();
+}
+
+void FrameLoaderClientAndroid::transitionToCommittedForNewPage() {
+ ASSERT(m_frame);
+ if (!m_frame->page()->settings()->usesPageCache()) {
+ m_frame->bridge()->transitionToCommitted(m_frame);
+ return;
+ }
+
+ // Remember the old bridge
+ WebCoreViewBridge* bridge = m_frame->view()->getWebCoreViewBridge();
+ Retain(bridge);
+
+ // Remove the old FrameView
+ m_frame->setView(NULL);
+
+ // Create a new one and set the bridge
+ FrameView* view = new FrameView(m_frame);
+ view->setWebCoreViewBridge(bridge);
+ Release(bridge);
+ bridge->setView(view);
+
+ // Give the new FrameView to the Frame
+ m_frame->setView(view);
+
+ // Deref since FrameViews are created with a ref of 1
+ view->deref();
+
+ if (m_frame->ownerRenderer())
+ m_frame->ownerRenderer()->setWidget(view);
+
+ m_frame->view()->initScrollbars();
+
+ m_frame->bridge()->transitionToCommitted(m_frame);
+}
+
+}
diff --git a/WebCore/platform/android/FrameLoaderClientAndroid.h b/WebCore/platform/android/FrameLoaderClientAndroid.h
new file mode 100644
index 0000000..df4657a
--- /dev/null
+++ b/WebCore/platform/android/FrameLoaderClientAndroid.h
@@ -0,0 +1,216 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef FrameLoaderClientAndroid_h
+#define FrameLoaderClientAndroid_h
+
+#include "FrameLoaderClient.h"
+#include "ResourceResponse.h"
+#include "WebIconDatabase.h"
+
+namespace WebCore {
+ class FrameAndroid;
+
+ class FrameLoaderClientAndroid : public FrameLoaderClient,
+ android::WebIconDatabaseClient {
+ public:
+ FrameLoaderClientAndroid() : m_frame(NULL) {}
+ void setFrame(FrameAndroid* frame) { m_frame = frame; }
+
+ virtual void frameLoaderDestroyed();
+
+ virtual bool hasWebView() const; // mainly for assertions
+ virtual bool hasFrameView() const; // ditto
+
+ virtual bool privateBrowsingEnabled() const;
+
+ virtual void makeRepresentation(DocumentLoader*);
+ virtual void forceLayout();
+ virtual void forceLayoutForNonHTML();
+
+ virtual void setCopiesOnScroll();
+
+ virtual void detachedFromParent2();
+ virtual void detachedFromParent3();
+ virtual void detachedFromParent4();
+
+ virtual void loadedFromPageCache();
+
+ virtual void assignIdentifierToInitialRequest(unsigned long identifier, DocumentLoader*, const ResourceRequest&);
+
+ virtual void dispatchWillSendRequest(DocumentLoader*, unsigned long identifier, ResourceRequest&, const ResourceResponse& redirectResponse);
+ virtual void dispatchDidReceiveAuthenticationChallenge(DocumentLoader*, unsigned long identifier, const AuthenticationChallenge&);
+ virtual void dispatchDidCancelAuthenticationChallenge(DocumentLoader*, unsigned long identifier, const AuthenticationChallenge&);
+ virtual void dispatchDidReceiveResponse(DocumentLoader*, unsigned long identifier, const ResourceResponse&);
+ virtual void dispatchDidReceiveContentLength(DocumentLoader*, unsigned long identifier, int lengthReceived);
+ virtual void dispatchDidFinishLoading(DocumentLoader*, unsigned long identifier);
+ virtual void dispatchDidFailLoading(DocumentLoader*, unsigned long identifier, const ResourceError&);
+ virtual bool dispatchDidLoadResourceFromMemoryCache(DocumentLoader*, const ResourceRequest&, const ResourceResponse&, int length);
+
+ virtual void dispatchDidHandleOnloadEvents();
+ virtual void dispatchDidReceiveServerRedirectForProvisionalLoad();
+ virtual void dispatchDidCancelClientRedirect();
+ virtual void dispatchWillPerformClientRedirect(const KURL&, double interval, double fireDate);
+ virtual void dispatchDidChangeLocationWithinPage();
+ virtual void dispatchWillClose();
+ virtual void dispatchDidReceiveIcon();
+ virtual void dispatchDidStartProvisionalLoad();
+ virtual void dispatchDidReceiveTitle(const String& title);
+ virtual void dispatchDidCommitLoad();
+ virtual void dispatchDidFailProvisionalLoad(const ResourceError&);
+ virtual void dispatchDidFailLoad(const ResourceError&);
+ virtual void dispatchDidFinishDocumentLoad();
+ virtual void dispatchDidFinishLoad();
+ virtual void dispatchDidFirstLayout();
+
+ virtual Frame* dispatchCreatePage();
+ virtual void dispatchShow();
+
+ virtual void dispatchDecidePolicyForMIMEType(FramePolicyFunction, const String& MIMEType, const ResourceRequest&);
+ virtual void dispatchDecidePolicyForNewWindowAction(FramePolicyFunction, const NavigationAction&, const ResourceRequest&, const String& frameName);
+ virtual void dispatchDecidePolicyForNavigationAction(FramePolicyFunction, const NavigationAction&, const ResourceRequest&);
+ virtual void cancelPolicyCheck();
+
+ virtual void dispatchUnableToImplementPolicy(const ResourceError&);
+
+ virtual void dispatchWillSubmitForm(FramePolicyFunction, PassRefPtr<FormState>);
+
+ virtual void dispatchDidLoadMainResource(DocumentLoader*);
+ virtual void revertToProvisionalState(DocumentLoader*);
+ virtual void setMainDocumentError(DocumentLoader*, const ResourceError&);
+ virtual void clearUnarchivingState(DocumentLoader*);
+
+ virtual void willChangeEstimatedProgress();
+ virtual void didChangeEstimatedProgress();
+ virtual void postProgressStartedNotification();
+ virtual void postProgressEstimateChangedNotification();
+ virtual void postProgressFinishedNotification();
+
+ virtual void setMainFrameDocumentReady(bool);
+
+ virtual void startDownload(const ResourceRequest&);
+
+ virtual void willChangeTitle(DocumentLoader*);
+ virtual void didChangeTitle(DocumentLoader*);
+
+ virtual void committedLoad(DocumentLoader*, const char*, int);
+ virtual void finishedLoading(DocumentLoader*);
+ virtual void finalSetupForReplace(DocumentLoader*);
+
+ virtual void updateGlobalHistoryForStandardLoad(const KURL&);
+ virtual void updateGlobalHistoryForReload(const KURL&);
+ virtual bool shouldGoToHistoryItem(HistoryItem*) const;
+#ifdef ANDROID_HISTORY_CLIENT
+ virtual void dispatchDidAddHistoryItem(HistoryItem*) const;
+ virtual void dispatchDidRemoveHistoryItem(HistoryItem*, int) const;
+ virtual void dispatchDidChangeHistoryIndex(BackForwardList*) const;
+#endif
+
+ virtual ResourceError cancelledError(const ResourceRequest&);
+ virtual ResourceError blockedError(const ResourceRequest&);
+ virtual ResourceError cannotShowURLError(const ResourceRequest&);
+ virtual ResourceError interruptForPolicyChangeError(const ResourceRequest&);
+
+ virtual ResourceError cannotShowMIMETypeError(const ResourceResponse&);
+ virtual ResourceError fileDoesNotExistError(const ResourceResponse&);
+
+ virtual bool shouldFallBack(const ResourceError&);
+
+ virtual void setDefersLoading(bool);
+
+ virtual bool willUseArchive(ResourceLoader*, const ResourceRequest&, const KURL& originalURL) const;
+ virtual bool isArchiveLoadPending(ResourceLoader*) const;
+ virtual void cancelPendingArchiveLoad(ResourceLoader*);
+ virtual void clearArchivedResources();
+
+ virtual bool canHandleRequest(const ResourceRequest&) const;
+ virtual bool canShowMIMEType(const String& MIMEType) const;
+ virtual bool representationExistsForURLScheme(const String& URLScheme) const;
+ virtual String generatedMIMETypeForURLScheme(const String& URLScheme) const;
+
+ virtual void frameLoadCompleted();
+ virtual void saveViewStateToItem(HistoryItem*);
+ virtual void restoreViewState();
+ virtual void provisionalLoadStarted();
+ virtual void didFinishLoad();
+ virtual void prepareForDataSourceReplacement();
+
+ virtual PassRefPtr<DocumentLoader> createDocumentLoader(const ResourceRequest&, const SubstituteData&);
+ virtual void setTitle(const String& title, const KURL&);
+
+ virtual String userAgent(const KURL&);
+
+ virtual bool canCachePage() const;
+ virtual void download(ResourceHandle*, const ResourceRequest&, const ResourceRequest&, const ResourceResponse&);
+
+ virtual WTF::PassRefPtr<WebCore::Frame> createFrame(const KURL& url, const String& name, HTMLFrameOwnerElement* ownerElement,
+ const String& referrer, bool allowsScrolling, int marginWidth, int marginHeight);
+ virtual Widget* createPlugin(const IntSize&, Element*, const KURL&,
+ const WTF::Vector<WebCore::String, 0u>&, const WTF::Vector<String, 0u>&,
+ const String&, bool);
+ virtual void redirectDataToPlugin(Widget* pluginWidget);
+
+ virtual Widget* createJavaAppletWidget(const IntSize&, Element*, const KURL& baseURL, const Vector<String>& paramNames, const Vector<String>& paramValues);
+
+ virtual ObjectContentType objectContentType(const KURL& url, const String& mimeType);
+ virtual String overrideMediaType() const;
+
+ virtual void windowObjectCleared();
+
+ virtual void didPerformFirstNavigation() const;
+ virtual void registerForIconNotification(bool);
+
+ virtual void savePlatformDataToCachedPage(CachedPage*);
+ virtual void transitionToCommittedFromCachedPage(CachedPage*);
+ virtual void transitionToCommittedForNewPage();
+
+ // WebIconDatabaseClient api
+ virtual void didAddIconForPageUrl(const String& pageUrl);
+ private:
+ FrameAndroid* m_frame;
+ enum ResourceErrors {
+ InternalErrorCancelled = -99,
+ InternalErrorCannotShowUrl,
+ InternalErrorInterrupted,
+ InternalErrorCannotShowMimeType,
+ InternalErrorFileDoesNotExist,
+ InternalErrorLast
+ };
+
+ /* XXX: These must match android.net.http.EventHandler */
+ enum EventHandlerErrors {
+ Error = -1,
+ ErrorLookup = -2,
+ ErrorUnsupportedAuthScheme = -3,
+ ErrorAuth = -4,
+ ErrorProxyAuth = -5,
+ ErrorConnect = -6,
+ ErrorIO = -7,
+ ErrorTimeout = -8,
+ ErrorRedirectLoop = -9,
+ ErrorUnsupportedScheme = -10,
+ ErrorFailedSslHandshake = -11,
+ ErrorBadUrl = -12,
+ ErrorFile = -13,
+ ErrorFileNotFound = -14,
+ ErrorTooManyRequests = -15
+ };
+ };
+
+}
+
+#endif
diff --git a/WebCore/platform/android/InspectorClientAndroid.h b/WebCore/platform/android/InspectorClientAndroid.h
new file mode 100644
index 0000000..fd1493a
--- /dev/null
+++ b/WebCore/platform/android/InspectorClientAndroid.h
@@ -0,0 +1,49 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef InspectorClientAndroid_h
+#define InspectorClientAndroid_h
+
+#include "InspectorClient.h"
+
+namespace WebCore {
+
+class InspectorClientAndroid : public InspectorClient {
+public:
+ virtual ~InspectorClientAndroid() { }
+
+ virtual void inspectorDestroyed() {}
+
+ virtual Page* createPage() { return NULL; }
+
+ virtual void showWindow() {}
+ virtual void closeWindow() {}
+
+ virtual void attachWindow() {}
+ virtual void detachWindow() {}
+
+ virtual void highlight(Node*) {}
+ virtual void hideHighlight() {}
+
+ virtual void inspectedURLChanged(const String& newURL) {}
+// functions new to Feb-19 tip of tree merge:
+ virtual String localizedStringsURL() { return String(); }
+};
+
+}
+
+#endif
diff --git a/WebCore/platform/android/IteratorAndroid.h b/WebCore/platform/android/IteratorAndroid.h
new file mode 100644
index 0000000..d30013d
--- /dev/null
+++ b/WebCore/platform/android/IteratorAndroid.h
@@ -0,0 +1,41 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef ITERATOR_ANDROID_H
+#define ITERATOR_ANDROID_H
+
+#include "stl_iterator_base.h"
+#include "heap.h"
+
+/*
+struct input_iterator_tag {};
+struct forward_iterator_tag : public input_iterator_tag {};
+struct bidirectional_iterator_tag : public forward_iterator_tag {};
+struct random_access_iterator_tag : public bidirectional_iterator_tag {};
+
+template<typename _Category, typename _Tp, typename _Distance = ptrdiff_t,
+ typename _Pointer = _Tp*, typename _Reference = _Tp&>
+struct iterator
+{
+ typedef _Category iterator_category;
+ typedef _Tp value_type;
+ typedef _Distance difference_type;
+ typedef _Pointer pointer;
+ typedef _Reference reference;
+};
+ */
+#endif
diff --git a/WebCore/platform/android/JavaVM/jni.h b/WebCore/platform/android/JavaVM/jni.h
new file mode 100644
index 0000000..429dbc3
--- /dev/null
+++ b/WebCore/platform/android/JavaVM/jni.h
@@ -0,0 +1,24 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef _JNI_COVER_H_
+#define _JNI_COVER_H_
+
+#include "nativehelper/jni.h"
+#define AttachCurrentThread(a, b) AttachCurrentThread((JNIEnv**) a, b)
+
+#endif
diff --git a/WebCore/platform/android/KeyEventAndroid.cpp b/WebCore/platform/android/KeyEventAndroid.cpp
new file mode 100644
index 0000000..ede5ae5
--- /dev/null
+++ b/WebCore/platform/android/KeyEventAndroid.cpp
@@ -0,0 +1,256 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "config.h"
+#include "DeprecatedString.h"
+#include "KeyboardCodes.h"
+#include "NotImplemented.h"
+#include "PlatformKeyboardEvent.h"
+#include <ui/KeycodeLabels.h>
+
+namespace WebCore {
+
+// compare to same function in gdk/KeyEventGdk.cpp
+static int windowsKeyCodeForKeyEvent(unsigned int keyCode) {
+// Does not provide all key codes, and does not handle all keys.
+ switch(keyCode) {
+ case kKeyCodeDel:
+ return VK_BACK;
+ case kKeyCodeTab:
+ return VK_TAB;
+ case kKeyCodeClear:
+ return VK_CLEAR;
+ case kKeyCodeDpadCenter:
+ case kKeyCodeNewline:
+ return VK_RETURN;
+ case kKeyCodeShiftLeft:
+ case kKeyCodeShiftRight:
+ return VK_SHIFT;
+ // back will serve as escape, although we probably do not have access to it
+ case kKeyCodeBack:
+ return VK_ESCAPE;
+ case kKeyCodeSpace:
+ return VK_SPACE;
+ case kKeyCodeHome:
+ return VK_HOME;
+ case kKeyCodeDpadLeft:
+ return VK_LEFT;
+ case kKeyCodeDpadUp:
+ return VK_UP;
+ case kKeyCodeDpadRight:
+ return VK_RIGHT;
+ case kKeyCodeDpadDown:
+ return VK_DOWN;
+ case kKeyCode0:
+ return VK_0;
+ case kKeyCode1:
+ return VK_1;
+ case kKeyCode2:
+ return VK_2;
+ case kKeyCode3:
+ return VK_3;
+ case kKeyCode4:
+ return VK_4;
+ case kKeyCode5:
+ return VK_5;
+ case kKeyCode6:
+ return VK_6;
+ case kKeyCode7:
+ return VK_7;
+ case kKeyCode8:
+ return VK_8;
+ case kKeyCode9:
+ return VK_9;
+ case kKeyCodeA:
+ return VK_A;
+ case kKeyCodeB:
+ return VK_B;
+ case kKeyCodeC:
+ return VK_C;
+ case kKeyCodeD:
+ return VK_D;
+ case kKeyCodeE:
+ return VK_E;
+ case kKeyCodeF:
+ return VK_F;
+ case kKeyCodeG:
+ return VK_G;
+ case kKeyCodeH:
+ return VK_H;
+ case kKeyCodeI:
+ return VK_I;
+ case kKeyCodeJ:
+ return VK_J;
+ case kKeyCodeK:
+ return VK_K;
+ case kKeyCodeL:
+ return VK_L;
+ case kKeyCodeM:
+ return VK_M;
+ case kKeyCodeN:
+ return VK_N;
+ case kKeyCodeO:
+ return VK_O;
+ case kKeyCodeP:
+ return VK_P;
+ case kKeyCodeQ:
+ return VK_Q;
+ case kKeyCodeR:
+ return VK_R;
+ case kKeyCodeS:
+ return VK_S;
+ case kKeyCodeT:
+ return VK_T;
+ case kKeyCodeU:
+ return VK_U;
+ case kKeyCodeV:
+ return VK_V;
+ case kKeyCodeW:
+ return VK_W;
+ case kKeyCodeX:
+ return VK_X;
+ case kKeyCodeY:
+ return VK_Y;
+ case kKeyCodeZ:
+ return VK_Z;
+ // colon
+ case kKeyCodeSemicolon:
+ return VK_OEM_1;
+ case kKeyCodeComma:
+ return VK_OEM_COMMA;
+ case kKeyCodeMinus:
+ return VK_OEM_MINUS;
+ case kKeyCodeEquals:
+ return VK_OEM_PLUS;
+ case kKeyCodePeriod:
+ return VK_OEM_PERIOD;
+ case kKeyCodeSlash:
+ return VK_OEM_2;
+ // maybe not the right choice
+ case kKeyCodeLeftBracket:
+ return VK_OEM_4;
+ case kKeyCodeBackslash:
+ return VK_OEM_5;
+ case kKeyCodeRightBracket:
+ return VK_OEM_6;
+ default:
+ return 0;
+ }
+}
+
+static String keyIdentifierForAndroidKeyCode(int keyCode)
+{
+/* Does not return all of the same key identifiers, and
+ * does not handle all the keys.
+ */
+ switch (keyCode) {
+ case kKeyCodeClear:
+ return "Clear";
+ case kKeyCodeNewline:
+ case kKeyCodeDpadCenter:
+ return "Enter";
+ case kKeyCodeHome:
+ return "Home";
+ case kKeyCodeDpadDown:
+ return "Down";
+ case kKeyCodeDpadLeft:
+ return "Left";
+ case kKeyCodeDpadRight:
+ return "Right";
+ case kKeyCodeDpadUp:
+ return "Up";
+ // Standard says that DEL becomes U+00007F.
+ case kKeyCodeDel:
+ return "U+00007F";
+ default:
+ char upper[16];
+ sprintf(upper, "U+%06X", windowsKeyCodeForKeyEvent(keyCode));
+ return String(upper);
+ }
+}
+
+static inline String singleCharacterString(int c)
+{
+ if (!c)
+ return String();
+ if (c > 0xffff) {
+ UChar lead = U16_LEAD(c);
+ UChar trail = U16_TRAIL(c);
+ UChar utf16[2] = {lead, trail};
+ return String(utf16, 2);
+ }
+ UChar n = (UChar)c;
+ return String(&n, 1);
+}
+
+PlatformKeyboardEvent::PlatformKeyboardEvent(int keyCode, int keyValue, bool down, bool forceAutoRepeat, bool cap, bool fn, bool sym)
+ : m_type(down ? KeyDown : KeyUp)
+ , m_text(singleCharacterString(keyValue))
+ , m_unmodifiedText(singleCharacterString(keyValue))
+ , m_keyIdentifier(keyIdentifierForAndroidKeyCode(keyCode))
+ , m_autoRepeat(forceAutoRepeat)
+ , m_windowsVirtualKeyCode(windowsKeyCodeForKeyEvent(keyCode))
+ , m_isKeypad(false)
+ , m_shiftKey(cap)
+// FIXME: Mapping fn to alt and sym to ctrl. Is this the desired behavior?
+ , m_ctrlKey(sym)
+ , m_altKey(fn)
+ , m_metaKey(false)
+{
+ // Copied from the mac port
+ if (m_windowsVirtualKeyCode == '\r') {
+ m_text = "\r";
+ m_unmodifiedText = "\r";
+ }
+
+ if (m_text == "\x7F")
+ m_text = "\x8";
+ if (m_unmodifiedText == "\x7F")
+ m_unmodifiedText = "\x8";
+
+ if (m_windowsVirtualKeyCode == 9) {
+ m_text = "\x9";
+ m_unmodifiedText = "\x9";
+ }
+}
+
+bool PlatformKeyboardEvent::currentCapsLockState()
+{
+ notImplemented();
+ return false;
+}
+
+// functions new to Feb-19 tip of tree merge:
+void PlatformKeyboardEvent::disambiguateKeyDownEvent(Type type, bool backwardCompatibilityMode)
+{
+ // Copied with modification from the mac port.
+ ASSERT(m_type == KeyDown);
+ ASSERT(type == RawKeyDown || type == Char);
+ m_type = type;
+ if (backwardCompatibilityMode)
+ return;
+
+ if (type == RawKeyDown) {
+ m_text = String();
+ m_unmodifiedText = String();
+ } else {
+ m_keyIdentifier = String();
+ m_windowsVirtualKeyCode = 0;
+ }
+}
+
+} // WebCore
diff --git a/WebCore/platform/android/KeyboardCodes.h b/WebCore/platform/android/KeyboardCodes.h
new file mode 100644
index 0000000..d6820d4
--- /dev/null
+++ b/WebCore/platform/android/KeyboardCodes.h
@@ -0,0 +1,544 @@
+/*
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
+ *
+ * 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.
+ */
+
+#ifndef KeyboardCodes_H
+#define KeyboardCodes_H
+
+namespace WebCore {
+
+// VK_LBUTTON (01) Left mouse button
+// VK_RBUTTON (02) Right mouse button
+// VK_CANCEL (03) Control-break processing
+// VK_MBUTTON (04) Middle mouse button (three-button mouse)
+// VK_XBUTTON1 (05)
+// VK_XBUTTON2 (06)
+
+// VK_BACK (08) BACKSPACE key
+const int VK_BACK = 0x08;
+
+// VK_TAB (09) TAB key
+const int VK_TAB = 0x09;
+
+// VK_CLEAR (0C) CLEAR key
+const int VK_CLEAR = 0x0C;
+
+// VK_RETURN (0D)
+const int VK_RETURN = 0x0D;
+
+// VK_SHIFT (10) SHIFT key
+const int VK_SHIFT = 0x10;
+
+// VK_CONTROL (11) CTRL key
+const int VK_CONTROL = 0x11;
+
+// VK_MENU (12) ALT key
+const int VK_MENU = 0x12;
+
+// VK_PAUSE (13) PAUSE key
+const int VK_PAUSE = 0x13;
+
+// VK_CAPITAL (14) CAPS LOCK key
+const int VK_CAPITAL = 0x14;
+
+// VK_KANA (15) Input Method Editor (IME) Kana mode
+const int VK_KANA = 0x15;
+
+// VK_HANGUEL (15) IME Hanguel mode (maintained for compatibility; use VK_HANGUL)
+// VK_HANGUL (15) IME Hangul mode
+const int VK_HANGUL = 0x15;
+
+// VK_JUNJA (17) IME Junja mode
+const int VK_JUNJA = 0x17;
+
+// VK_FINAL (18) IME final mode
+const int VK_FINAL = 0x18;
+
+// VK_HANJA (19) IME Hanja mode
+const int VK_HANJA = 0x19;
+
+// VK_KANJI (19) IME Kanji mode
+const int VK_KANJI = 0x19;
+
+// VK_ESCAPE (1B) ESC key
+const int VK_ESCAPE = 0x1B;
+
+// VK_CONVERT (1C) IME convert
+const int VK_CONVERT = 0x1C;
+
+// VK_NONCONVERT (1D) IME nonconvert
+const int VK_NONCONVERT = 0x1D;
+
+// VK_ACCEPT (1E) IME accept
+const int VK_ACCEPT = 0x1E;
+
+// VK_MODECHANGE (1F) IME mode change request
+const int VK_MODECHANGE = 0x1F;
+
+// VK_SPACE (20) SPACEBAR
+const int VK_SPACE = 0x20;
+
+// VK_PRIOR (21) PAGE UP key
+const int VK_PRIOR = 0x21;
+
+// VK_NEXT (22) PAGE DOWN key
+const int VK_NEXT = 0x22;
+
+// VK_END (23) END key
+const int VK_END = 0x23;
+
+// VK_HOME (24) HOME key
+const int VK_HOME = 0x24;
+
+// VK_LEFT (25) LEFT ARROW key
+const int VK_LEFT = 0x25;
+
+// VK_UP (26) UP ARROW key
+const int VK_UP = 0x26;
+
+// VK_RIGHT (27) RIGHT ARROW key
+const int VK_RIGHT = 0x27;
+
+// VK_DOWN (28) DOWN ARROW key
+const int VK_DOWN = 0x28;
+
+// VK_SELECT (29) SELECT key
+const int VK_SELECT = 0x29;
+
+// VK_PRINT (2A) PRINT key
+const int VK_PRINT = 0x2A;
+
+// VK_EXECUTE (2B) EXECUTE key
+const int VK_EXECUTE = 0x2B;
+
+// VK_SNAPSHOT (2C) PRINT SCREEN key
+const int VK_SNAPSHOT = 0x2C;
+
+// VK_INSERT (2D) INS key
+const int VK_INSERT = 0x2D;
+
+// VK_DELETE (2E) DEL key
+const int VK_DELETE = 0x2E;
+
+// VK_HELP (2F) HELP key
+const int VK_HELP = 0x2F;
+
+// (30) 0 key
+const int VK_0 = 0x30;
+
+// (31) 1 key
+const int VK_1 = 0x31;
+
+// (32) 2 key
+const int VK_2 = 0x32;
+
+// (33) 3 key
+const int VK_3 = 0x33;
+
+// (34) 4 key
+const int VK_4 = 0x34;
+
+// (35) 5 key;
+
+const int VK_5 = 0x35;
+
+// (36) 6 key
+const int VK_6 = 0x36;
+
+// (37) 7 key
+const int VK_7 = 0x37;
+
+// (38) 8 key
+const int VK_8 = 0x38;
+
+// (39) 9 key
+const int VK_9 = 0x39;
+
+// (41) A key
+const int VK_A = 0x41;
+
+// (42) B key
+const int VK_B = 0x42;
+
+// (43) C key
+const int VK_C = 0x43;
+
+// (44) D key
+const int VK_D = 0x44;
+
+// (45) E key
+const int VK_E = 0x45;
+
+// (46) F key
+const int VK_F = 0x46;
+
+// (47) G key
+const int VK_G = 0x47;
+
+// (48) H key
+const int VK_H = 0x48;
+
+// (49) I key
+const int VK_I = 0x49;
+
+// (4A) J key
+const int VK_J = 0x4A;
+
+// (4B) K key
+const int VK_K = 0x4B;
+
+// (4C) L key
+const int VK_L = 0x4C;
+
+// (4D) M key
+const int VK_M = 0x4D;
+
+// (4E) N key
+const int VK_N = 0x4E;
+
+// (4F) O key
+const int VK_O = 0x4F;
+
+// (50) P key
+const int VK_P = 0x50;
+
+// (51) Q key
+const int VK_Q = 0x51;
+
+// (52) R key
+const int VK_R = 0x52;
+
+// (53) S key
+const int VK_S = 0x53;
+
+// (54) T key
+const int VK_T = 0x54;
+
+// (55) U key
+const int VK_U = 0x55;
+
+// (56) V key
+const int VK_V = 0x56;
+
+// (57) W key
+const int VK_W = 0x57;
+
+// (58) X key
+const int VK_X = 0x58;
+
+// (59) Y key
+const int VK_Y = 0x59;
+
+// (5A) Z key
+const int VK_Z = 0x5A;
+
+// VK_LWIN (5B) Left Windows key (Microsoft Natural keyboard)
+const int VK_LWIN = 0x5B;
+
+// VK_RWIN (5C) Right Windows key (Natural keyboard)
+const int VK_RWIN = 0x5C;
+
+// VK_APPS (5D) Applications key (Natural keyboard)
+const int VK_APPS = 0x5D;
+
+// VK_SLEEP (5F) Computer Sleep key
+const int VK_SLEEP = 0x5F;
+
+// VK_NUMPAD0 (60) Numeric keypad 0 key
+const int VK_NUMPAD0 = 0x60;
+
+// VK_NUMPAD1 (61) Numeric keypad 1 key
+const int VK_NUMPAD1 = 0x61;
+
+// VK_NUMPAD2 (62) Numeric keypad 2 key
+const int VK_NUMPAD2 = 0x62;
+
+// VK_NUMPAD3 (63) Numeric keypad 3 key
+const int VK_NUMPAD3 = 0x63;
+
+// VK_NUMPAD4 (64) Numeric keypad 4 key
+const int VK_NUMPAD4 = 0x64;
+
+// VK_NUMPAD5 (65) Numeric keypad 5 key
+const int VK_NUMPAD5 = 0x65;
+
+// VK_NUMPAD6 (66) Numeric keypad 6 key
+const int VK_NUMPAD6 = 0x66;
+
+// VK_NUMPAD7 (67) Numeric keypad 7 key
+const int VK_NUMPAD7 = 0x67;
+
+// VK_NUMPAD8 (68) Numeric keypad 8 key
+const int VK_NUMPAD8 = 0x68;
+
+// VK_NUMPAD9 (69) Numeric keypad 9 key
+const int VK_NUMPAD9 = 0x69;
+
+// VK_MULTIPLY (6A) Multiply key
+const int VK_MULTIPLY = 0x6A;
+
+// VK_ADD (6B) Add key
+const int VK_ADD = 0x6B;
+
+// VK_SEPARATOR (6C) Separator key
+const int VK_SEPARATOR = 0x6C;
+
+// VK_SUBTRACT (6D) Subtract key
+const int VK_SUBTRACT = 0x6D;
+
+// VK_DECIMAL (6E) Decimal key
+const int VK_DECIMAL = 0x6E;
+
+// VK_DIVIDE (6F) Divide key
+const int VK_DIVIDE = 0x6F;
+
+// VK_F1 (70) F1 key
+const int VK_F1 = 0x70;
+
+// VK_F2 (71) F2 key
+const int VK_F2 = 0x71;
+
+// VK_F3 (72) F3 key
+const int VK_F3 = 0x72;
+
+// VK_F4 (73) F4 key
+const int VK_F4 = 0x73;
+
+// VK_F5 (74) F5 key
+const int VK_F5 = 0x74;
+
+// VK_F6 (75) F6 key
+const int VK_F6 = 0x75;
+
+// VK_F7 (76) F7 key
+const int VK_F7 = 0x76;
+
+// VK_F8 (77) F8 key
+const int VK_F8 = 0x77;
+
+// VK_F9 (78) F9 key
+const int VK_F9 = 0x78;
+
+// VK_F10 (79) F10 key
+const int VK_F10 = 0x79;
+
+// VK_F11 (7A) F11 key
+const int VK_F11 = 0x7A;
+
+// VK_F12 (7B) F12 key
+const int VK_F12 = 0x7B;
+
+// VK_F13 (7C) F13 key
+const int VK_F13 = 0x7C;
+
+// VK_F14 (7D) F14 key
+const int VK_F14 = 0x7D;
+
+// VK_F15 (7E) F15 key
+const int VK_F15 = 0x7E;
+
+// VK_F16 (7F) F16 key
+const int VK_F16 = 0x7F;
+
+// VK_F17 (80H) F17 key
+const int VK_F17 = 0x80;
+
+// VK_F18 (81H) F18 key
+const int VK_F18 = 0x81;
+
+// VK_F19 (82H) F19 key
+const int VK_F19 = 0x82;
+
+// VK_F20 (83H) F20 key
+const int VK_F20 = 0x83;
+
+// VK_F21 (84H) F21 key
+const int VK_F21 = 0x84;
+
+// VK_F22 (85H) F22 key
+const int VK_F22 = 0x85;
+
+// VK_F23 (86H) F23 key
+const int VK_F23 = 0x86;
+
+// VK_F24 (87H) F24 key
+const int VK_F24 = 0x87;
+
+// VK_NUMLOCK (90) NUM LOCK key
+const int VK_NUMLOCK = 0x90;
+
+// VK_SCROLL (91) SCROLL LOCK key
+const int VK_SCROLL = 0x91;
+
+// VK_LSHIFT (A0) Left SHIFT key
+const int VK_LSHIFT = 0xA0;
+
+// VK_RSHIFT (A1) Right SHIFT key
+const int VK_RSHIFT = 0xA1;
+
+// VK_LCONTROL (A2) Left CONTROL key
+const int VK_LCONTROL = 0xA2;
+
+// VK_RCONTROL (A3) Right CONTROL key
+const int VK_RCONTROL = 0xA3;
+
+// VK_LMENU (A4) Left MENU key
+const int VK_LMENU = 0xA4;
+
+// VK_RMENU (A5) Right MENU key
+const int VK_RMENU = 0xA5;
+
+// VK_BROWSER_BACK (A6) Windows 2000/XP: Browser Back key
+const int VK_BROWSER_BACK = 0xA6;
+
+// VK_BROWSER_FORWARD (A7) Windows 2000/XP: Browser Forward key
+const int VK_BROWSER_FORWARD = 0xA7;
+
+// VK_BROWSER_REFRESH (A8) Windows 2000/XP: Browser Refresh key
+const int VK_BROWSER_REFRESH = 0xA8;
+
+// VK_BROWSER_STOP (A9) Windows 2000/XP: Browser Stop key
+const int VK_BROWSER_STOP = 0xA9;
+
+// VK_BROWSER_SEARCH (AA) Windows 2000/XP: Browser Search key
+const int VK_BROWSER_SEARCH = 0xAA;
+
+// VK_BROWSER_FAVORITES (AB) Windows 2000/XP: Browser Favorites key
+const int VK_BROWSER_FAVORITES = 0xAB;
+
+// VK_BROWSER_HOME (AC) Windows 2000/XP: Browser Start and Home key
+const int VK_BROWSER_HOME = 0xAC;
+
+// VK_VOLUME_MUTE (AD) Windows 2000/XP: Volume Mute key
+const int VK_VOLUME_MUTE = 0xAD;
+
+// VK_VOLUME_DOWN (AE) Windows 2000/XP: Volume Down key
+const int VK_VOLUME_DOWN = 0xAE;
+
+// VK_VOLUME_UP (AF) Windows 2000/XP: Volume Up key
+const int VK_VOLUME_UP = 0xAF;
+
+// VK_MEDIA_NEXT_TRACK (B0) Windows 2000/XP: Next Track key
+const int VK_MEDIA_NEXT_TRACK = 0xB0;
+
+// VK_MEDIA_PREV_TRACK (B1) Windows 2000/XP: Previous Track key
+const int VK_MEDIA_PREV_TRACK = 0xB1;
+
+// VK_MEDIA_STOP (B2) Windows 2000/XP: Stop Media key
+const int VK_MEDIA_STOP = 0xB2;
+
+// VK_MEDIA_PLAY_PAUSE (B3) Windows 2000/XP: Play/Pause Media key
+const int VK_MEDIA_PLAY_PAUSE = 0xB3;
+
+// VK_LAUNCH_MAIL (B4) Windows 2000/XP: Start Mail key
+const int VK_MEDIA_LAUNCH_MAIL = 0xB4;
+
+// VK_LAUNCH_MEDIA_SELECT (B5) Windows 2000/XP: Select Media key
+const int VK_MEDIA_LAUNCH_MEDIA_SELECT = 0xB5;
+
+// VK_LAUNCH_APP1 (B6) Windows 2000/XP: Start Application 1 key
+const int VK_MEDIA_LAUNCH_APP1 = 0xB6;
+
+// VK_LAUNCH_APP2 (B7) Windows 2000/XP: Start Application 2 key
+const int VK_MEDIA_LAUNCH_APP2 = 0xB7;
+
+// VK_OEM_1 (BA) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the ';:' key
+const int VK_OEM_1 = 0xBA;
+
+// VK_OEM_PLUS (BB) Windows 2000/XP: For any country/region, the '+' key
+const int VK_OEM_PLUS = 0xBB;
+
+// VK_OEM_COMMA (BC) Windows 2000/XP: For any country/region, the ',' key
+const int VK_OEM_COMMA = 0xBC;
+
+// VK_OEM_MINUS (BD) Windows 2000/XP: For any country/region, the '-' key
+const int VK_OEM_MINUS = 0xBD;
+
+// VK_OEM_PERIOD (BE) Windows 2000/XP: For any country/region, the '.' key
+const int VK_OEM_PERIOD = 0xBE;
+
+// VK_OEM_2 (BF) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '/?' key
+const int VK_OEM_2 = 0xBF;
+
+// VK_OEM_3 (C0) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '`~' key
+const int VK_OEM_3 = 0xC0;
+
+// VK_OEM_4 (DB) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '[{' key
+const int VK_OEM_4 = 0xDB;
+
+// VK_OEM_5 (DC) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the '\|' key
+const int VK_OEM_5 = 0xDC;
+
+// VK_OEM_6 (DD) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the ']}' key
+const int VK_OEM_6 = 0xDD;
+
+// VK_OEM_7 (DE) Used for miscellaneous characters; it can vary by keyboard. Windows 2000/XP: For the US standard keyboard, the 'single-quote/double-quote' key
+const int VK_OEM_7 = 0xDE;
+
+// VK_OEM_8 (DF) Used for miscellaneous characters; it can vary by keyboard.
+const int VK_OEM_8 = 0xDF;
+
+// VK_OEM_102 (E2) Windows 2000/XP: Either the angle bracket key or the backslash key on the RT 102-key keyboard
+const int VK_OEM_102 = 0xE2;
+
+// VK_PROCESSKEY (E5) Windows 95/98/Me, Windows NT 4.0, Windows 2000/XP: IME PROCESS key
+const int VK_PROCESSKEY = 0xE5;
+
+// VK_PACKET (E7) Windows 2000/XP: Used to pass Unicode characters as if they were keystrokes. The VK_PACKET key is the low word of a 32-bit Virtual Key value used for non-keyboard input methods. For more information, see Remark in KEYBDINPUT,SendInput, WM_KEYDOWN, and WM_KEYUP
+const int VK_PACKET = 0xE7;
+
+// VK_ATTN (F6) Attn key
+const int VK_ATTN = 0xF6;
+
+// VK_CRSEL (F7) CrSel key
+const int VK_CRSEL = 0xF7;
+
+// VK_EXSEL (F8) ExSel key
+const int VK_EXSEL = 0xF8;
+
+// VK_EREOF (F9) Erase EOF key
+const int VK_EREOF = 0xF9;
+
+// VK_PLAY (FA) Play key
+const int VK_PLAY = 0xFA;
+
+// VK_ZOOM (FB) Zoom key
+const int VK_ZOOM = 0xFB;
+
+// VK_NONAME (FC) Reserved for future use
+const int VK_NONAME = 0xFC;
+
+// VK_PA1 (FD) PA1 key
+const int VK_PA1 = 0xFD;
+
+// VK_OEM_CLEAR (FE) Clear key
+const int VK_OEM_CLEAR = 0xFE;
+
+const int VK_UNKNOWN = 0;
+
+}
+
+#endif
diff --git a/WebCore/platform/network/curl/AuthenticationChallenge.h b/WebCore/platform/android/LocalizedStringsAndroid.cpp
index 753ac6f..6c0255e 100644
--- a/WebCore/platform/network/curl/AuthenticationChallenge.h
+++ b/WebCore/platform/android/LocalizedStringsAndroid.cpp
@@ -1,5 +1,8 @@
/*
- * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
+ * Copyright (C) 2007 Holger Hans Peter Freyther
+ * All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -22,25 +25,22 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef AuthenticationChallenge_h
-#define AuthenticationChallenge_h
-#include "AuthenticationChallengeBase.h"
+#include "config.h"
-namespace WebCore {
+#include "LocalizedStrings.h"
+#include "PlatformString.h"
-class AuthenticationChallenge : public AuthenticationChallengeBase {
-public:
- AuthenticationChallenge()
- {
- }
+namespace WebCore {
- AuthenticationChallenge(const ProtectionSpace& protectionSpace, const Credential& proposedCredential, unsigned previousFailureCount, const ResourceResponse& response, const ResourceError& error)
- : AuthenticationChallengeBase(protectionSpace, proposedCredential, previousFailureCount, response, error)
- {
- }
-};
+String contextMenuItemTagInspectElement()
+{
+ return String::fromUTF8("Inspect Element");
+}
+String unknownFileSizeText()
+{
+ return String::fromUTF8("Unknown");
}
-#endif
+}
diff --git a/WebCore/platform/android/PlatformScrollBar.h b/WebCore/platform/android/PlatformScrollBar.h
new file mode 100644
index 0000000..e552c8b
--- /dev/null
+++ b/WebCore/platform/android/PlatformScrollBar.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2004, 2006 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.
+ */
+
+#ifndef PlatformScrollBar_h
+#define PlatformScrollBar_h
+
+#include "Widget.h"
+#include "ScrollBar.h"
+
+namespace WebCore {
+
+class PlatformScrollbar : public Widget, public Scrollbar {
+public:
+ PlatformScrollbar(ScrollbarClient*, ScrollbarOrientation, ScrollbarControlSize);
+ virtual ~PlatformScrollbar();
+
+ virtual bool isWidget() const { return true; }
+
+ virtual int width() const;
+ virtual int height() const;
+ virtual void setRect(const IntRect&);
+ virtual void setEnabled(bool);
+ virtual void paint(GraphicsContext*, const IntRect& damageRect);
+
+ static int horizontalScrollbarHeight() { return 8; }
+ static int verticalScrollbarWidth() { return 8; }
+
+protected:
+ virtual void updateThumbPosition();
+ virtual void updateThumbProportion();
+
+};
+
+}
+
+#endif // PlatformScrollBar_h
diff --git a/WebCore/platform/android/PlatformScrollBarAndroid.cpp b/WebCore/platform/android/PlatformScrollBarAndroid.cpp
new file mode 100644
index 0000000..a087aed
--- /dev/null
+++ b/WebCore/platform/android/PlatformScrollBarAndroid.cpp
@@ -0,0 +1,80 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "config.h"
+#include "Color.h"
+#include "GraphicsContext.h"
+#include "PlatformScrollBar.h"
+#include "WebCoreViewBridge.h"
+
+#define MINIMUM_SCROLL_KNOB_HEIGHT 10
+#define SCROLL_BAR_ROUNDING 5
+
+class ScrollBarView {
+public:
+
+private:
+ int m_height;
+ int m_width;
+};
+
+namespace WebCore {
+
+PlatformScrollbar::PlatformScrollbar(ScrollbarClient* client, ScrollbarOrientation o,
+ ScrollbarControlSize s) : Scrollbar(client, o, s)
+{
+
+}
+
+PlatformScrollbar::~PlatformScrollbar()
+{
+
+}
+
+int PlatformScrollbar::width() const
+{
+ return 8;
+
+}
+
+int PlatformScrollbar::height() const {
+ return 8;
+
+}
+
+void PlatformScrollbar::setRect(const IntRect& r)
+{
+}
+
+void PlatformScrollbar::setEnabled(bool)
+{
+
+}
+
+void PlatformScrollbar::paint(GraphicsContext* gc, const IntRect& damageRect)
+{
+}
+
+void PlatformScrollbar::updateThumbPosition()
+{
+}
+
+void PlatformScrollbar::updateThumbProportion()
+{
+}
+
+}
diff --git a/WebCore/platform/android/PopupMenuAndroid.cpp b/WebCore/platform/android/PopupMenuAndroid.cpp
new file mode 100644
index 0000000..b8bbd2d
--- /dev/null
+++ b/WebCore/platform/android/PopupMenuAndroid.cpp
@@ -0,0 +1,55 @@
+/*
+ * This file is part of the popup menu implementation for <select> elements in WebCore.
+ *
+ * Copyright (C) 2006 Apple Computer, Inc.
+ * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+#include "PopupMenu.h"
+
+namespace WebCore {
+
+// Now we handle all of this in WebViewCore.cpp
+PopupMenu::PopupMenu(PopupMenuClient* menuList) : m_popupClient(menuList)
+{
+}
+
+PopupMenu::~PopupMenu()
+{
+}
+
+void PopupMenu::show(const IntRect& rect, FrameView* view, int index)
+{
+
+}
+
+void PopupMenu::hide()
+{
+}
+
+void PopupMenu::updateFromElement()
+{
+}
+
+// functions new to Jun-07 tip of tree merge:
+bool PopupMenu::itemWritingDirectionIsNatural() { return false; }
+
+}
+
diff --git a/WebCore/platform/android/QLineEditAndroid.cpp b/WebCore/platform/android/QLineEditAndroid.cpp
new file mode 100644
index 0000000..b31baf5
--- /dev/null
+++ b/WebCore/platform/android/QLineEditAndroid.cpp
@@ -0,0 +1,120 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "config.h"
+
+#include "KWQLineEdit.h"
+#include "IntPoint.h"
+
+#define LOG_TAG "WebCore"
+#undef LOG
+#include <utils/Log.h>
+
+using namespace WebCore;
+
+class KWQTextFieldController {
+public:
+ int m_maxLength;
+ int m_cursorPosition;
+ bool m_edited;
+ String m_placeholderString;
+ String m_text;
+};
+
+QLineEdit::QLineEdit(Type type) : m_type(type)
+{
+ printf("============ QLineEdit %d\n", type);
+
+ m_controller = new KWQTextFieldController;
+
+ m_controller->m_maxLength = 32; // ???
+ m_controller->m_cursorPosition = 0;
+ m_controller->m_edited = false;
+}
+
+QLineEdit::~QLineEdit()
+{
+ delete m_controller;
+}
+
+int QLineEdit::maxLength() const
+{
+ return m_controller->m_maxLength;
+}
+
+void QLineEdit::setMaxLength(int ml)
+{
+ m_controller->m_maxLength = ml;
+}
+
+String QLineEdit::text() const
+{
+ return m_controller->m_text;
+}
+
+void QLineEdit::setText(String const& text)
+{
+ m_controller->m_text = text;
+}
+
+int QLineEdit::cursorPosition() const
+{
+ return m_controller->m_cursorPosition;
+}
+
+void QLineEdit::setCursorPosition(int cp)
+{
+ m_controller->m_cursorPosition = cp;
+}
+
+void QLineEdit::setPlaceholderString(String const& ph)
+{
+ m_controller->m_placeholderString = ph;
+}
+
+bool QLineEdit::edited() const
+{
+ return m_controller->m_edited;
+}
+
+void QLineEdit::setEdited(bool edited)
+{
+ m_controller->m_edited = edited;
+}
+
+void QLineEdit::setFont(Font const&) { }
+void QLineEdit::setAlignment(HorizontalAlignment) { }
+void QLineEdit::setWritingDirection(TextDirection) { }
+void QLineEdit::setReadOnly(bool) { }
+void QLineEdit::setColors(Color const&, Color const&) { }
+IntSize QLineEdit::sizeForCharacterWidth(int) const { return IntSize(); }
+int QLineEdit::baselinePosition(int) const { return 0; }
+void QLineEdit::setLiveSearch(bool) { }
+
+#define notImplemented() { LOGV("%s: Not Implemented", __FUNCTION__); }
+
+void QLineEdit::selectAll() { notImplemented(); }
+void QLineEdit::addSearchResult() { notImplemented(); }
+int QLineEdit::selectionStart() const { notImplemented(); return 0; }
+bool QLineEdit::hasSelectedText() const { notImplemented(); return 0; }
+String QLineEdit::selectedText() const { notImplemented(); return String(); }
+void QLineEdit::setAutoSaveName(String const&) { notImplemented(); }
+bool QLineEdit::checksDescendantsForFocus() const { notImplemented(); return false; }
+void QLineEdit::setSelection(int,int) { notImplemented(); }
+void QLineEdit::setMaxResults(int) { notImplemented(); }
+
+Widget::FocusPolicy QLineEdit::focusPolicy() const { notImplemented(); return NoFocus; }
diff --git a/WebCore/platform/android/RenderSkinAndroid.cpp b/WebCore/platform/android/RenderSkinAndroid.cpp
new file mode 100644
index 0000000..fc256d2
--- /dev/null
+++ b/WebCore/platform/android/RenderSkinAndroid.cpp
@@ -0,0 +1,65 @@
+/* libs/WebKitLib/WebKit/WebCore/rendering/RenderSkinAndroid.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "config.h"
+#include "RenderSkinAndroid.h"
+#include "RenderSkinButton.h"
+#include "RenderSkinCombo.h"
+#include "RenderSkinRadio.h"
+#include "SkImageDecoder.h"
+
+#define LOG_TAG "WebCore"
+#undef LOG
+#include "utils/Log.h"
+#include "utils/AssetManager.h"
+#include "utils/Asset.h"
+
+namespace WebCore {
+
+RenderSkinAndroid::RenderSkinAndroid()
+ : m_height(0)
+ , m_width(0)
+{}
+
+void RenderSkinAndroid::Init(android::AssetManager* am)
+{
+ RenderSkinButton::Init(am);
+ RenderSkinCombo::Init(am);
+ RenderSkinRadio::Init(am);
+}
+
+bool RenderSkinAndroid::DecodeBitmap(android::AssetManager* am, const char* fileName, SkBitmap* bitmap)
+{
+ android::Asset* asset = am->open(fileName, android::Asset::ACCESS_BUFFER);
+ if (!asset) {
+ asset = am->openNonAsset(fileName, android::Asset::ACCESS_BUFFER);
+ if (!asset) {
+ LOGD("RenderSkinAndroid: File \"%s\" not found.\n", fileName);
+ return false;
+ }
+ }
+
+ bool success = SkImageDecoder::DecodeMemory(asset->getBuffer(false), asset->getLength(), bitmap);
+ if (!success) {
+ LOGD("RenderSkinAndroid: Failed to decode %s\n", fileName);
+ }
+
+ delete asset;
+ return success;
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/android/RenderSkinAndroid.h b/WebCore/platform/android/RenderSkinAndroid.h
new file mode 100644
index 0000000..2226e7f
--- /dev/null
+++ b/WebCore/platform/android/RenderSkinAndroid.h
@@ -0,0 +1,83 @@
+/* libs/WebKitLib/WebKit/WebCore/rendering/RenderSkinAndroid.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef RenderSkinAndroid_h
+#define RenderSkinAndroid_h
+
+namespace android {
+ class AssetManager;
+}
+
+class SkBitmap;
+
+namespace WebCore {
+class Node;
+class PlatformGraphicsContext;
+
+/* RenderSkinAndroid is the base class for all RenderSkins. Form elements each have a
+ * subclass for drawing themselves.
+ */
+class RenderSkinAndroid
+{
+public:
+ RenderSkinAndroid();
+ virtual ~RenderSkinAndroid() {}
+
+ enum State {
+ kDisabled,
+ kNormal,
+ kFocused,
+
+ kNumStates
+ };
+
+ /**
+ * Initialize the Android skinning system. The AssetManager may be used to find resources used
+ * in rendering.
+ */
+ static void Init(android::AssetManager*);
+
+ /* DecodeBitmap determines which file to use, with the given fileName of the form
+ * "images/bitmap.png", and uses the asset manager to select the exact one. It
+ * returns true if it successfully decoded the bitmap, false otherwise.
+ */
+ static bool DecodeBitmap(android::AssetManager* am, const char* fileName, SkBitmap* bitmap);
+
+ /* draw() tells the skin to draw itself, and returns true if the skin needs
+ * a redraw to animations, false otherwise
+ */
+ virtual bool draw(PlatformGraphicsContext*) { return false; }
+
+ /* notifyState() checks to see if the element is checked, focused, and enabled
+ * it must be implemented in the subclass
+ */
+ virtual void notifyState(Node* element) { }
+
+ /* setDim() tells the skin its width and height
+ */
+ virtual void setDim(int width, int height) { m_width = width; m_height = height; }
+
+protected:
+ int m_height;
+ int m_width;
+
+};
+
+} // WebCore
+
+#endif
+
diff --git a/WebCore/platform/android/RenderSkinButton.cpp b/WebCore/platform/android/RenderSkinButton.cpp
new file mode 100644
index 0000000..73e6ea0
--- /dev/null
+++ b/WebCore/platform/android/RenderSkinButton.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2006, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "config.h"
+#include "AndroidLog.h"
+#include "android_graphics.h"
+#include "Document.h"
+#include "IntRect.h"
+#include "Node.h"
+#include "RenderSkinButton.h"
+#include "SkCanvas.h"
+#include "SkNinePatch.h"
+#include "SkRect.h"
+#include "utils/Debug.h"
+
+struct PatchData {
+ const char* name;
+ int8_t outset, margin;
+};
+
+static const PatchData gFiles[] =
+ {
+ { "res/drawable/btn_default_normal_disable.9.png", 2, 7 },
+ { "res/drawable/btn_default_normal.9.png", 2, 7 },
+ { "res/drawable/btn_default_selected.9.png", 2, 7 }
+ };
+
+static SkBitmap gButton[sizeof(gFiles)/sizeof(gFiles[0])];
+static bool gDecoded;
+
+namespace WebCore {
+
+void RenderSkinButton::Init(android::AssetManager* am)
+{
+ static bool gInited;
+ if (gInited)
+ return;
+
+ gInited = true;
+ gDecoded = true;
+ for (size_t i = 0; i < sizeof(gFiles)/sizeof(gFiles[0]); i++) {
+ if (!RenderSkinAndroid::DecodeBitmap(am, gFiles[i].name, &gButton[i])) {
+ gDecoded = false;
+ ANDROID_LOGD("RenderSkinButton::Init: button assets failed to decode\n\tBrowser buttons will not draw");
+ break;
+ }
+ }
+
+ // Ensure our enums properly line up with our arrays.
+ android::CompileTimeAssert<(RenderSkinAndroid::kDisabled == 0)> a1;
+ android::CompileTimeAssert<(RenderSkinAndroid::kNormal == 1)> a2;
+ android::CompileTimeAssert<(RenderSkinAndroid::kFocused == 2)> a3;
+}
+
+void RenderSkinButton::Draw(SkCanvas* canvas, const IntRect& r, RenderSkinAndroid::State newState)
+{
+ // If we failed to decode, do nothing. This way the browser still works,
+ // and webkit will still draw the label and layout space for us.
+ if (!gDecoded) {
+ return;
+ }
+
+ // Ensure that the state is within the valid range of our array.
+ SkASSERT(newState < RenderSkinAndroid::kNumStates && newState >= 0);
+
+ // Set up the ninepatch information for drawing.
+ SkRect bounds;
+ android_setrect(&bounds, r);
+ const PatchData& pd = gFiles[newState];
+ int marginValue = pd.margin + pd.outset;
+
+ SkIRect margin;
+
+ margin.set(marginValue, marginValue, marginValue, marginValue);
+
+ // Draw to the canvas.
+ SkNinePatch::DrawNine(canvas, bounds, gButton[newState], margin);
+}
+
+} //WebCore
+
diff --git a/WebCore/platform/android/RenderSkinButton.h b/WebCore/platform/android/RenderSkinButton.h
new file mode 100644
index 0000000..3089a0b
--- /dev/null
+++ b/WebCore/platform/android/RenderSkinButton.h
@@ -0,0 +1,44 @@
+/* libs/WebKitLib/WebKit/WebCore/platform/android/RenderSkinButton.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef RenderSkinButton_h
+#define RenderSkinButton_h
+
+#include "RenderSkinAndroid.h"
+
+class SkCanvas;
+
+namespace WebCore {
+class IntRect;
+class RenderSkinButton
+{
+public:
+ /**
+ * Initialize the class before use. Uses the AssetManager to initialize any
+ * bitmaps the class may use.
+ */
+ static void Init(android::AssetManager*);
+ /**
+ * Draw the skin to the canvas, using the rectangle for its bounds and the
+ * State to determine which skin to use, i.e. focused or not focused.
+ */
+ static void Draw(SkCanvas* , const IntRect& , RenderSkinAndroid::State);
+};
+
+} // WebCore
+#endif
+
diff --git a/WebCore/platform/android/RenderSkinCombo.cpp b/WebCore/platform/android/RenderSkinCombo.cpp
new file mode 100644
index 0000000..527cb10
--- /dev/null
+++ b/WebCore/platform/android/RenderSkinCombo.cpp
@@ -0,0 +1,84 @@
+/* libs/WebKitLib/WebKit/WebCore/platform/android/RenderSkinCombo.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "config.h"
+#include "Document.h"
+#include "Node.h"
+#include "PlatformGraphicsContext.h"
+#include "RenderSkinCombo.h"
+#include "SkCanvas.h"
+#include "SkNinePatch.h"
+
+namespace WebCore {
+
+static const int margin = 2;
+static const SkIRect mar = { margin, margin, RenderSkinCombo::extraWidth(), margin };
+
+SkBitmap RenderSkinCombo::m_bitmap[2];
+bool RenderSkinCombo::m_decoded;
+
+RenderSkinCombo::RenderSkinCombo()
+{
+ m_height = 20;
+ m_width = 75;
+ m_state = kNormal;
+ m_bounds.set(0, 0, SkIntToScalar(m_width), SkIntToScalar(m_height));
+}
+
+void RenderSkinCombo::Init(android::AssetManager* am)
+{
+ if (m_decoded)
+ return;
+ // Maybe short circuiting is fine, since I don't even draw if one state is not decoded properly
+ // but is that necessary in the final version?
+ m_decoded = RenderSkinAndroid::DecodeBitmap(am, "images/combobox-noHighlight.png", &m_bitmap[kNormal]);
+ m_decoded = RenderSkinAndroid::DecodeBitmap(am, "images/combobox-disabled.png", &m_bitmap[kDisabled]) && m_decoded;
+}
+
+
+bool RenderSkinCombo::draw(PlatformGraphicsContext *p)
+{
+ // The text is drawn right next to the left side - should I draw the box slightly to the left?
+ if (!m_decoded)
+ return false;
+ SkCanvas* canvas = p->mCanvas;
+ SkNinePatch::DrawNine(canvas, m_bounds, m_bitmap[m_state], mar);
+ return false;
+}
+
+void RenderSkinCombo::notifyState(Node* element)
+{
+ m_state = kDisabled;
+ if (!element)
+ return;
+ if (element->isEnabled())
+ m_state = kNormal;
+}
+
+void RenderSkinCombo::setDim(int width, int height)
+{
+ if (width != m_width || height != m_height) {
+ m_width = width;
+ if (height < (margin<<1) + 1)
+ height = (margin<<1) + 1;
+ else
+ m_height = height;
+ m_bounds.set(0, 0, SkIntToScalar(m_width), SkIntToScalar(m_height));
+ }
+}
+
+} //WebCore
diff --git a/WebCore/platform/android/RenderSkinCombo.h b/WebCore/platform/android/RenderSkinCombo.h
new file mode 100644
index 0000000..f962fcc
--- /dev/null
+++ b/WebCore/platform/android/RenderSkinCombo.h
@@ -0,0 +1,61 @@
+/* libs/WebKitLib/WebKit/WebCore/platform/android/RenderSkinCombo.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef RenderSkinCombo_h
+#define RenderSkinCombo_h
+
+#include "RenderSkinAndroid.h"
+#include "SkBitmap.h"
+#include "SkPaint.h"
+#include "SkRect.h"
+
+namespace WebCore {
+
+// This is very similar to RenderSkinButton - maybe they should be the same class?
+class RenderSkinCombo : public RenderSkinAndroid
+{
+public:
+ RenderSkinCombo();
+ virtual ~RenderSkinCombo() {}
+
+ /**
+ * Initialize the class before use. Uses the AssetManager to initialize any bitmaps the class may use.
+ */
+ static void Init(android::AssetManager*);
+
+ virtual bool draw(PlatformGraphicsContext*);
+ virtual void notifyState(Node* element);
+ virtual void setDim(int width, int height);
+
+ // The image is an extra 30 pixels wider than the RenderObject, so this accounts for that.
+ static int extraWidth() { return arrowMargin; }
+
+private:
+ SkRect m_bounds; // Maybe this should become a protected member of RenderSkinAndroid...
+ static SkBitmap m_bitmap[2]; // Collection of assets for a combo box
+ static bool m_decoded; // True if all assets were decoded
+ SkPaint m_paint;
+ // Could probably move m_state into RenderSkinAndroid...
+ // Although notice that the state for RenderSkinRadio is just an integer, and it behaves differently
+ State m_state;
+
+ static const int arrowMargin = 30;
+};
+
+} // WebCore
+
+#endif
diff --git a/WebCore/platform/android/RenderSkinRadio.cpp b/WebCore/platform/android/RenderSkinRadio.cpp
new file mode 100644
index 0000000..d610fa7
--- /dev/null
+++ b/WebCore/platform/android/RenderSkinRadio.cpp
@@ -0,0 +1,83 @@
+/* libs/WebKitLib/WebKit/WebCore/platform/android/RenderSkinRadio.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "config.h"
+#include "Document.h"
+#include "Node.h"
+#include "PlatformGraphicsContext.h"
+#include "RenderSkinRadio.h"
+#include "SkCanvas.h"
+
+static const char* checks[] = { "res/drawable/checkbox_off_background.png", "res/drawable/checkbox_on_background.png",
+ "res/drawable/radiobutton_off_background.png", "res/drawable/radiobutton_on_background.png"};
+static const SkScalar SIZE = SkIntToScalar(19); // Default height and width - corresponds with the bitmap - perhaps we should query the bitmap.
+
+namespace WebCore {
+
+SkBitmap RenderSkinRadio::m_bitmap[4];
+bool RenderSkinRadio::m_decoded;
+
+RenderSkinRadio::RenderSkinRadio(bool isCheckBox)
+{
+ m_checked = false;
+ m_enabled = true;
+ m_isCheckBox = isCheckBox;
+}
+
+void RenderSkinRadio::Init(android::AssetManager* am)
+{
+ if (m_decoded)
+ return;
+ m_decoded = RenderSkinAndroid::DecodeBitmap(am, checks[0], &m_bitmap[0]);
+ m_decoded = RenderSkinAndroid::DecodeBitmap(am, checks[1], &m_bitmap[1]) && m_decoded;
+ m_decoded = RenderSkinAndroid::DecodeBitmap(am, checks[2], &m_bitmap[2]) && m_decoded;
+ m_decoded = RenderSkinAndroid::DecodeBitmap(am, checks[3], &m_bitmap[3]) && m_decoded;
+}
+
+
+bool RenderSkinRadio::draw(PlatformGraphicsContext* pgc)
+{
+ if (!m_decoded) // Seems like an unnecessary slowdown, since it should always decode
+ return false;
+ SkCanvas* canvas = pgc->mCanvas;
+ if (!m_enabled) {
+ SkRect r;
+ r.set(0, 0, m_size, m_size);
+ canvas->saveLayerAlpha(&r, 0x80);
+ } else {
+ canvas->save();
+ }
+ if (SIZE != m_size) {
+ SkScalar scale = SkScalarDiv(m_size, SIZE);
+ canvas->scale(scale, scale);
+ }
+ canvas->drawBitmap(m_bitmap[m_checked + 2*(!m_isCheckBox)], 0, 0, &m_paint);
+ canvas->restore();
+ return false; // True if we need to redraw
+}
+
+void RenderSkinRadio::notifyState(Node* element)
+{
+ if (!element) {
+ return;
+ }
+ m_checked = element->isChecked();
+ m_enabled = element->isEnabled();
+}
+
+} //WebCore
+
diff --git a/WebCore/platform/android/RenderSkinRadio.h b/WebCore/platform/android/RenderSkinRadio.h
new file mode 100644
index 0000000..918cdf5
--- /dev/null
+++ b/WebCore/platform/android/RenderSkinRadio.h
@@ -0,0 +1,59 @@
+/* libs/WebKitLib/WebKit/WebCore/platform/android/RenderSkinRadio.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef RenderSkinRadio_h
+#define RenderSkinRadio_h
+
+#include "RenderSkinAndroid.h"
+#include "SkBitmap.h"
+#include "SkPaint.h"
+#include "SkRect.h"
+
+namespace WebCore {
+
+class Node;
+
+/* RenderSkin for a radio button or a checkbox
+ */
+class RenderSkinRadio : public RenderSkinAndroid
+{
+public:
+ /* This skin represents a checkbox if isCheckBox is true, otherwise it is a radio button */
+ RenderSkinRadio(bool isCheckBox);
+ virtual ~RenderSkinRadio() {}
+
+ /**
+ * Initialize the class before use. Uses the AssetManager to initialize any bitmaps the class may use.
+ */
+ static void Init(android::AssetManager*);
+
+ virtual bool draw(PlatformGraphicsContext*);
+ virtual void notifyState(Node* element);
+ virtual void setDim(int width, int height) { RenderSkinAndroid::setDim(width, height); m_size = SkIntToScalar(height); }
+
+protected:
+ static SkBitmap m_bitmap[4]; // Bitmaps representing all states
+ static bool m_decoded; // True if all assets were decoded.
+ bool m_isCheckBox;
+ bool m_checked;
+ bool m_enabled;
+ SkPaint m_paint;
+ SkScalar m_size;
+};
+
+} // WebCore
+#endif
diff --git a/WebCore/platform/android/RenderThemeAndroid.cpp b/WebCore/platform/android/RenderThemeAndroid.cpp
new file mode 100644
index 0000000..2e8cb86
--- /dev/null
+++ b/WebCore/platform/android/RenderThemeAndroid.cpp
@@ -0,0 +1,313 @@
+/* libs/WebKitLib/WebKit/WebCore/rendering/RenderThemeAndroid.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "config.h"
+#include "RenderThemeAndroid.h"
+#include "PopupMenu.h"
+#include "RenderSkinAndroid.h"
+#include "RenderSkinButton.h"
+#include "RenderSkinCombo.h"
+#include "RenderSkinRadio.h"
+
+#include "GraphicsContext.h"
+#include "PlatformGraphicsContext.h"
+
+#include "SkCanvas.h"
+
+#define MAX_COMBO_HEIGHT 20
+
+// Add a constant amount of padding to the textsize to get the final height of buttons,
+// so that our button images are large enough to properly fit the text.
+#define BUTTON_PADDING 18
+
+namespace WebCore {
+static SkCanvas* getCanvasFromInfo(const RenderObject::PaintInfo& info)
+{
+ return info.context->platformContext()->mCanvas;
+}
+
+/* Helper function that paints the RenderObject
+ * paramters:
+ * the skin to use,
+ * the object to be painted, the PaintInfo, from which we get the canvas, the bounding rectangle,
+ * returns false, meaning no one else has to paint it
+*/
+
+static bool paintBrush(RenderSkinAndroid* rSkin, RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& ir)
+{
+ Node* element = o->element();
+ SkCanvas* canvas = getCanvasFromInfo(i);
+ canvas->save();
+ canvas->translate(SkIntToScalar(ir.x()), SkIntToScalar(ir.y()));
+ rSkin->setDim(ir.width(), ir.height());
+ rSkin->notifyState(element);
+ rSkin->draw(i.context->platformContext());
+ canvas->restore();
+ return false;
+}
+
+
+RenderTheme* theme()
+{
+ static RenderThemeAndroid androidTheme;
+ return &androidTheme;
+}
+
+RenderThemeAndroid::RenderThemeAndroid()
+{
+ m_radio = new RenderSkinRadio(false);
+ m_checkbox = new RenderSkinRadio(true);
+ m_combo = new RenderSkinCombo();
+}
+
+RenderThemeAndroid::~RenderThemeAndroid()
+{
+ delete m_radio;
+ delete m_checkbox;
+ delete m_combo;
+}
+
+void RenderThemeAndroid::close()
+{
+
+}
+
+bool RenderThemeAndroid::stateChanged(RenderObject* o, ControlState state) const
+{
+ if (CheckedState == state) {
+ o->repaint();
+ return true;
+ }
+ return false;
+}
+
+Color RenderThemeAndroid::platformActiveSelectionBackgroundColor() const
+{
+ return Color(46, 251, 0);
+}
+
+Color RenderThemeAndroid::platformInactiveSelectionBackgroundColor() const
+{
+ return Color(255, 255, 0, 255);
+}
+
+Color RenderThemeAndroid::platformActiveSelectionForegroundColor() const
+{
+ return Color::black;
+}
+
+Color RenderThemeAndroid::platformInactiveSelectionForegroundColor() const
+{
+ return Color::black;
+}
+
+Color RenderThemeAndroid::platformTextSearchHighlightColor() const
+{
+ return Color(192, 192, 192);
+}
+
+short RenderThemeAndroid::baselinePosition(const RenderObject* obj) const
+{
+ // From the description of this function in RenderTheme.h:
+ // A method to obtain the baseline position for a "leaf" control. This will only be used if a baseline
+ // position cannot be determined by examining child content. Checkboxes and radio buttons are examples of
+ // controls that need to do this.
+ //
+ // Our checkboxes and radio buttons need to be offset to line up properly.
+ return RenderTheme::baselinePosition(obj) - 5;
+}
+
+void RenderThemeAndroid::addIntrinsicMargins(RenderStyle* style) const
+{
+ // Cut out the intrinsic margins completely if we end up using a small font size
+ if (style->fontSize() < 11)
+ return;
+
+ // Intrinsic margin value.
+ const int m = 2;
+
+ // FIXME: Using width/height alone and not also dealing with min-width/max-width is flawed.
+ if (style->width().isIntrinsicOrAuto()) {
+ if (style->marginLeft().quirk())
+ style->setMarginLeft(Length(m, Fixed));
+ if (style->marginRight().quirk())
+ style->setMarginRight(Length(m, Fixed));
+ }
+
+ if (style->height().isAuto()) {
+ if (style->marginTop().quirk())
+ style->setMarginTop(Length(m, Fixed));
+ if (style->marginBottom().quirk())
+ style->setMarginBottom(Length(m, Fixed));
+ }
+}
+
+bool RenderThemeAndroid::supportsFocus(EAppearance appearance)
+{
+ switch (appearance) {
+ case PushButtonAppearance:
+ case ButtonAppearance:
+ case TextFieldAppearance:
+ return true;
+ default:
+ return false;
+ }
+
+ return false;
+}
+
+void RenderThemeAndroid::adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* style, WebCore::Element* e) const
+{
+ // Padding code is taken from RenderThemeSafari.cpp
+ // It makes sure we have enough space for the button text.
+ const int padding = 12;
+ style->setPaddingLeft(Length(padding, Fixed));
+ style->setPaddingRight(Length(padding, Fixed));
+ style->setMinHeight(Length(style->fontSize() + BUTTON_PADDING, Fixed));
+}
+
+bool RenderThemeAndroid::paintCheckbox(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& ir)
+{
+ return paintBrush(m_checkbox, o, i, ir);
+}
+
+bool RenderThemeAndroid::paintButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& ir)
+{
+ // If it is a disabled button, simply paint it to the master picture.
+ Node* element = o->element();
+ if (!element->isEnabled()) {
+ RenderSkinButton::Draw(getCanvasFromInfo(i), ir, RenderSkinAndroid::kDisabled);
+ } else {
+ // Store all the important information in the platform context.
+ i.context->platformContext()->storeButtonInfo(element, ir);
+ }
+ // We always return false so we do not request to be redrawn.
+ return false;
+}
+
+bool RenderThemeAndroid::paintRadio(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& ir)
+{
+ return paintBrush(m_radio, o, i, ir);
+}
+
+void RenderThemeAndroid::setCheckboxSize(RenderStyle* style) const
+{
+ style->setWidth(Length(19, Fixed));
+ style->setHeight(Length(19, Fixed));
+}
+
+void RenderThemeAndroid::setRadioSize(RenderStyle* style) const
+{
+ // This is the same as checkboxes.
+ setCheckboxSize(style);
+}
+
+void RenderThemeAndroid::adjustTextFieldStyle(CSSStyleSelector* selector, RenderStyle* style, WebCore::Element* e) const
+{
+ addIntrinsicMargins(style);
+}
+
+bool RenderThemeAndroid::paintTextField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& ir)
+{
+ return true;
+}
+
+void RenderThemeAndroid::adjustTextAreaStyle(CSSStyleSelector* selector, RenderStyle* style, WebCore::Element* e) const
+{
+ addIntrinsicMargins(style);
+}
+
+bool RenderThemeAndroid::paintTextArea(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& ir)
+{
+ if (o->isMenuList()) {
+ return paintCombo(o, i, ir);
+ }
+ return true;
+}
+
+void RenderThemeAndroid::adjustSearchFieldStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+{
+ addIntrinsicMargins(style);
+}
+
+bool RenderThemeAndroid::paintSearchField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& ir)
+{
+ return true;
+}
+
+void RenderThemeAndroid::adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+{
+ style->setPaddingRight(Length(RenderSkinCombo::extraWidth(), Fixed));
+ addIntrinsicMargins(style);
+}
+
+bool RenderThemeAndroid::paintCombo(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& ir)
+{
+ if (o->style() && o->style()->backgroundColor().alpha() == 0)
+ return true;
+ Node* element = o->element();
+ SkCanvas* canvas = getCanvasFromInfo(i);
+ m_combo->notifyState(element);
+ canvas->save();
+ int height = ir.height();
+ int y = ir.y();
+ // If the combo box is too large, leave it at its max height, and center it.
+ if (height > MAX_COMBO_HEIGHT) {
+ y += (height - MAX_COMBO_HEIGHT) >> 1;
+ height = MAX_COMBO_HEIGHT;
+ }
+ canvas->translate(SkIntToScalar(ir.x()), SkIntToScalar(y));
+ m_combo->setDim(ir.width(), height);
+ m_combo->draw(i.context->platformContext());
+ canvas->restore();
+ return false;
+}
+
+bool RenderThemeAndroid::paintMenuList(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& ir)
+{
+ return paintCombo(o, i, ir);
+}
+
+void RenderThemeAndroid::adjustMenuListButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const
+{
+ style->setPaddingRight(Length(RenderSkinCombo::extraWidth(), Fixed));
+ addIntrinsicMargins(style);
+}
+
+bool RenderThemeAndroid::paintMenuListButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& ir)
+{
+ return paintCombo(o, i, ir);
+}
+
+bool RenderThemeAndroid::supportsFocusRing(const RenderStyle* style) const
+{
+ return (style->opacity() > 0 && style->hasAppearance()
+ && style->appearance() != TextFieldAppearance
+ && style->appearance() != SearchFieldAppearance
+ && style->appearance() != TextAreaAppearance
+ && style->appearance() != CheckboxAppearance
+ && style->appearance() != RadioAppearance
+ && style->appearance() != PushButtonAppearance
+ && style->appearance() != SquareButtonAppearance
+ && style->appearance() != ButtonAppearance
+ && style->appearance() != ButtonBevelAppearance
+ && style->appearance() != MenulistAppearance
+ && style->appearance() != MenulistButtonAppearance
+ );
+}
+
+}
diff --git a/WebCore/platform/android/RenderThemeAndroid.h b/WebCore/platform/android/RenderThemeAndroid.h
new file mode 100644
index 0000000..4233f6f
--- /dev/null
+++ b/WebCore/platform/android/RenderThemeAndroid.h
@@ -0,0 +1,102 @@
+/* libs/WebKitLib/WebKit/WebCore/rendering/RenderThemeAndroid.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef RenderThemeAndroid_h
+#define RenderThemeAndroid_h
+
+#include "RenderTheme.h"
+
+namespace WebCore {
+
+class PopupMenu;
+class RenderSkinButton;
+class RenderSkinRadio;
+class RenderSkinCombo;
+
+struct ThemeData {
+ ThemeData() :m_part(0), m_state(0) {}
+
+ unsigned m_part;
+ unsigned m_state;
+};
+
+class RenderThemeAndroid : public RenderTheme {
+public:
+ RenderThemeAndroid();
+ ~RenderThemeAndroid();
+
+ virtual bool stateChanged(RenderObject*, ControlState) const;
+
+ virtual bool supportsFocusRing(const RenderStyle* style) const;
+ // A method asking if the theme's controls actually care about redrawing when hovered.
+ virtual bool supportsHover(const RenderStyle* style) const { return style->affectedByHoverRules(); }
+
+ virtual short baselinePosition(const RenderObject*) const;
+
+ virtual Color platformActiveSelectionBackgroundColor() const;
+ virtual Color platformInactiveSelectionBackgroundColor() const;
+ virtual Color platformActiveSelectionForegroundColor() const;
+ virtual Color platformInactiveSelectionForegroundColor() const;
+ virtual Color platformTextSearchHighlightColor() const;
+
+ virtual void systemFont(int, WebCore::FontDescription&) const {}
+
+ virtual int minimumMenuListSize(RenderStyle*) const { return 0; }
+
+protected:
+ virtual bool paintCheckbox(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r);
+ virtual void setCheckboxSize(RenderStyle* style) const;
+
+ virtual bool paintRadio(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r);
+ virtual void setRadioSize(RenderStyle* style) const;
+
+ virtual void adjustButtonStyle(CSSStyleSelector* selector, RenderStyle* style, WebCore::Element* e) const;
+ virtual bool paintButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r);
+
+ virtual void adjustTextFieldStyle(CSSStyleSelector* selector, RenderStyle* style, WebCore::Element* e) const;
+ virtual bool paintTextField(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r);
+
+ virtual void adjustTextAreaStyle(CSSStyleSelector* selector, RenderStyle* style, WebCore::Element* e) const;
+ virtual bool paintTextArea(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r);
+
+ bool paintCombo(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& ir);
+
+ virtual void adjustMenuListStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const;
+ virtual bool paintMenuList(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r);
+
+ virtual void adjustMenuListButtonStyle(CSSStyleSelector* selector, RenderStyle* style, Element* e) const;
+ virtual bool paintMenuListButton(RenderObject* o, const RenderObject::PaintInfo& i, const IntRect& r);
+
+ virtual void adjustSearchFieldStyle(CSSStyleSelector*, RenderStyle*, Element*) const;
+ virtual bool paintSearchField(RenderObject*, const RenderObject::PaintInfo&, const IntRect&);
+
+
+private:
+ void addIntrinsicMargins(RenderStyle* style) const;
+ void close();
+
+ bool supportsFocus(EAppearance appearance);
+ // FIXME: There should be a way to use one RenderSkinRadio for both radio and checkbox
+ RenderSkinRadio* m_radio;
+ RenderSkinRadio* m_checkbox;
+ RenderSkinCombo* m_combo;
+};
+
+};
+
+#endif
+
diff --git a/WebCore/platform/android/ScreenAndroid.cpp b/WebCore/platform/android/ScreenAndroid.cpp
new file mode 100644
index 0000000..6cf8bc9
--- /dev/null
+++ b/WebCore/platform/android/ScreenAndroid.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+#include "config.h"
+#include "Screen.h"
+
+#include "FloatRect.h"
+#include "Widget.h"
+
+#define LOG_TAG "WebCore"
+#include "utils/Log.h"
+
+#include "ui/SurfaceComposerClient.h"
+#include "ui/PixelFormat.h"
+#include "ui/DisplayInfo.h"
+
+namespace WebCore {
+
+int screenDepth(Widget* page)
+{
+ android::DisplayInfo info;
+ android::SurfaceComposerClient::getDisplayInfo(android::DisplayID(0), &info);
+ return info.pixelFormatInfo.bitsPerPixel;
+}
+
+int screenDepthPerComponent(Widget* page)
+{
+ android::DisplayInfo info;
+ android::SurfaceComposerClient::getDisplayInfo(android::DisplayID(0), &info);
+ return info.pixelFormatInfo.bitsPerPixel;
+}
+
+bool screenIsMonochrome(Widget* page)
+{
+ return false;
+}
+
+#ifdef ANDROID_ORIENTATION_SUPPORT
+int Screen::orientation() const
+{
+ android::DisplayInfo info;
+ android::SurfaceComposerClient::getDisplayInfo(android::DisplayID(0), &info);
+ return info.orientation;
+}
+#endif
+
+// The only place I have seen these values used is
+// positioning popup windows. If we support multiple windows
+// they will be most likely full screen. Therefore,
+// the accuracy of these number are not too important.
+FloatRect screenRect(Widget* page)
+{
+ android::DisplayInfo info;
+ android::SurfaceComposerClient::getDisplayInfo(android::DisplayID(0), &info);
+ return FloatRect(0.0, 0.0, info.w, info.h);
+}
+
+/*
+Scale functions don't seem to be needed. There is no code that
+call them, and they seem to only exist in ports and not in the core
+WebKit code - davidc
+FloatRect usableScreenRect(Widget* page)
+{
+ return FloatRect();;
+}
+
+FloatRect scaleScreenRectToPageCoordinates(const FloatRect&, Widget*)
+{
+ return FloatRect();;
+}
+
+FloatRect scalePageRectToScreenCoordinates(const FloatRect&, Widget*)
+{
+ return FloatRect();;
+}
+
+float scaleFactor(Widget*)
+{
+ return 1.0f;
+}
+*/
+
+// Similar screenRect, this function is commonly used by javascripts
+// to position and resize windows (usually to full screen).
+FloatRect screenAvailableRect(Widget*)
+{
+ android::DisplayInfo info;
+ android::SurfaceComposerClient::getDisplayInfo(android::DisplayID(0), &info);
+ return FloatRect(0.0, 0.0, info.w, info.h);
+}
+
+}
diff --git a/WebCore/platform/android/ScrollViewAndroid.cpp b/WebCore/platform/android/ScrollViewAndroid.cpp
new file mode 100644
index 0000000..1ac819d
--- /dev/null
+++ b/WebCore/platform/android/ScrollViewAndroid.cpp
@@ -0,0 +1,334 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "config.h"
+#include "ScrollView.h"
+
+#include "FloatRect.h"
+#include "IntRect.h"
+
+#include "WebCoreViewBridge.h"
+
+#define LOG_TAG "WebCore"
+#undef LOG
+#include "utils/Log.h"
+
+/* hack to allow the DOM to communicate how to interpret inval requests, since
+ it doesn't have the notion of distinguishing between the screen and the DOM
+ but we do, since we have a copy of the display in our picture, and we don't
+ want to rebuild the picture unless the DOM has actually been changed.
+*/
+bool gAndroid_treatInvalForScreen;
+
+#define verifiedOk() // no need to do anything in this function
+
+/*
+ This class implementation does NOT actually emulate the Qt ScrollView.
+ It does provide an implementation that khtml will use to interact with
+ WebKit's WebFrameView documentView and our NSScrollView subclass.
+
+ ScrollView's view is a NSScrollView (or subclass of NSScrollView)
+ in most cases. That scrollview is a subview of an
+ WebCoreFrameView. The WebCoreFrameView's documentView will also be
+ the scroll view's documentView.
+
+ The WebCoreFrameView's size is the frame size. The WebCoreFrameView's documentView
+ corresponds to the frame content size. The scrollview itself is autosized to the
+ WebCoreFrameView's size (see Widget::resize).
+*/
+
+namespace WebCore {
+
+struct ScrollView::ScrollViewPrivate
+{
+public:
+ ScrollViewPrivate() :
+ hasStaticBackground(false), ignoreUpdateContents(false),
+ vScrollbarMode(ScrollbarAuto),
+ hScrollbarMode(ScrollbarAuto) {}
+ IntSize contentsSize;
+ bool hasStaticBackground;
+ bool ignoreUpdateContents;
+ ScrollbarMode vScrollbarMode;
+ ScrollbarMode hScrollbarMode;
+};
+
+ScrollView::ScrollView()
+{
+ m_data = new ScrollViewPrivate;
+}
+
+ScrollView::~ScrollView()
+{
+ delete m_data;
+}
+
+int ScrollView::visibleWidth() const
+{
+ LOG_ASSERT(this->getWebCoreViewBridge(), "ScrollView does not have a WebCoreViewBridge");
+ return this->getWebCoreViewBridge()->width();
+}
+
+int ScrollView::visibleHeight() const
+{
+ LOG_ASSERT(this->getWebCoreViewBridge(), "ScrollView does not have a WebCoreViewBridge");
+ return this->getWebCoreViewBridge()->height();
+}
+
+FloatRect ScrollView::visibleContentRect() const
+{
+ LOG_ASSERT(this->getWebCoreViewBridge(), "ScrollView does not have a WebCoreViewBridge");
+ IntRect rect = this->getWebCoreViewBridge()->getBounds();
+ // FIXME: This is a hack to get subframes drawing correctly. Since subframes cannot
+ // scroll, we know that if this view has a parent, the visible rect is (0, 0, w, h)
+ if (this->getWebCoreViewBridge()->getParent())
+ return FloatRect(0, 0, rect.width(), rect.height());
+ return FloatRect(rect.x(), rect.y(), rect.width(), rect.height());
+}
+
+int ScrollView::contentsWidth() const
+{
+ return m_data->contentsSize.width();
+}
+
+int ScrollView::contentsHeight() const
+{
+ return m_data->contentsSize.height();
+}
+
+int ScrollView::contentsX() const
+{
+ return scrollOffset().width();
+}
+
+int ScrollView::contentsY() const
+{
+ return scrollOffset().height();
+}
+
+IntSize ScrollView::scrollOffset() const
+{
+ LOG_ASSERT(this->getWebCoreViewBridge(), "ScrollView does not have a WebCoreViewBridge");
+ WebCoreViewBridge* bridge = this->getWebCoreViewBridge();
+ // FIXME: This is a hack to get subframes drawing correctly. Since subframes cannot
+ // scroll, we know that if this view has a parent, the scroll offset is always (0, 0)
+ if (bridge->getParent())
+ return IntSize(0, 0);
+ return IntSize(bridge->locX(), bridge->locY());
+}
+
+void ScrollView::scrollBy(int dx, int dy)
+{
+ LOG_ASSERT(this->getWebCoreViewBridge(), "ScrollView does not have a WebCoreViewBridge");
+ this->getWebCoreViewBridge()->scrollBy(dx, dy);
+}
+
+void WebCore::ScrollView::update()
+{
+ LOG_ASSERT(this->getWebCoreViewBridge(), "ScrollView does not have a WebCoreViewBridge");
+ this->getWebCoreViewBridge()->contentInvalidate();
+}
+
+void WebCore::ScrollView::scrollRectIntoViewRecursively(WebCore::IntRect const& r)
+{
+ LOG_ASSERT(this->getWebCoreViewBridge(), "ScrollView does not have a WebCoreViewBridge");
+ int x = r.x();
+ int y = r.y();
+ IntPoint p(x > 0 ? x : 0, y > 0 ? y : 0);
+ ScrollView* view = this;
+ while (view) {
+ view->setContentsPos(p.x(), p.y());
+ p.move(view->x() - view->scrollOffset().width(), view->y() - view->scrollOffset().height());
+ if (view->getWebCoreViewBridge()->getParent())
+ view = static_cast<ScrollView*>(view->getWebCoreViewBridge()->getParent()->widget());
+ else
+ view = NULL;
+ }
+}
+
+WebCore::FloatRect WebCore::ScrollView::visibleContentRectConsideringExternalScrollers() const {
+ return FloatRect(contentsX(), contentsY(), contentsWidth(), contentsHeight());
+}
+
+void ScrollView::setContentsPos(int x, int y)
+{
+ LOG_ASSERT(this->getWebCoreViewBridge(), "ScrollView does not have a WebCoreViewBridge");
+ this->getWebCoreViewBridge()->scrollTo(x, y);
+}
+
+//---------------------------------------------------------------------
+// Scroll bar methods
+//
+// These methods are largely unimplemented meaning that the
+// state of the scroll bars in the only data maintained. If
+// a scroll bar is needed, the set(V|H)ScrollbarMode methods
+// need to update the scroll bar widget through the java
+// layer and display the new scroll bars.
+//
+//---------------------------------------------------------------------
+
+void ScrollView::setVScrollbarMode(ScrollbarMode vMode)
+{
+ m_data->vScrollbarMode = vMode;
+}
+
+void ScrollView::setHScrollbarMode(ScrollbarMode hMode)
+{
+ m_data->hScrollbarMode = hMode;
+}
+
+void ScrollView::setScrollbarsMode(ScrollbarMode mode)
+{
+ m_data->hScrollbarMode = mode;
+ m_data->vScrollbarMode = mode;
+}
+
+ScrollbarMode ScrollView::vScrollbarMode() const
+{
+ return m_data->vScrollbarMode;
+}
+
+ScrollbarMode ScrollView::hScrollbarMode() const
+{
+ return m_data->hScrollbarMode;
+}
+
+void ScrollView::suppressScrollbars(bool suppressed, bool repaintOnUnsuppress)
+{
+ verifiedOk();
+}
+
+//---------------------------------------------------------------------
+// End Scroll bar methods
+//---------------------------------------------------------------------
+
+void ScrollView::addChild(Widget* child)
+{
+ LOG_ASSERT(this->getWebCoreViewBridge(), "ScrollView does not have a WebCoreViewBridge");
+ WebCoreViewBridge* childBridge = child->getWebCoreViewBridge();
+ // FIXME: For now just check this, it should be an assert down the road.
+ if (!childBridge)
+ {
+ LOGV("childBridge is not set");
+ return;
+ }
+ LOG_ASSERT(child != this, "Child has no view bridge or child == this!");
+ WebCoreViewBridge* thisBridge = this->getWebCoreViewBridge();
+ LOG_ASSERT(thisBridge && thisBridge != childBridge, "Our bridge is not set or thisBridge == childBridge!");
+ LOGV("Adding parent");
+ childBridge->setParent(thisBridge);
+}
+
+void ScrollView::ignoreUpdateContents(bool ignore)
+{
+ m_data->ignoreUpdateContents = ignore;
+}
+
+void ScrollView::removeChild(Widget* child)
+{
+ // FIXME: Make this only an assert once all widgets have views
+ if (!child->getWebCoreViewBridge())
+ {
+ LOGV("child has no bridge");
+ return;
+ }
+ LOG_ASSERT(child->getWebCoreViewBridge(), "Child has no view bridge");
+ child->getWebCoreViewBridge()->setParent(NULL);
+}
+
+void ScrollView::resizeContents(int w, int h)
+{
+ LOG_ASSERT(this->getWebCoreViewBridge(), "ScrollView does not have a WebCoreViewBridge");
+ if (w < 0)
+ w = 0;
+ if (h < 0)
+ h = 0;
+
+ IntSize newSize(w, h);
+ m_data->contentsSize = newSize;
+}
+
+void ScrollView::updateContents(const IntRect &rect, bool now)
+{
+ LOG_ASSERT(this->getWebCoreViewBridge(),
+ "ScrollView does not have a WebCoreViewBridge");
+
+ WebCoreViewBridge* bridge = this->getWebCoreViewBridge();
+
+ if (gAndroid_treatInvalForScreen) {
+// SkDebugf("------ contentInvalidate sent to viewInvalidate [%d %d]\n", rect.width(), rect.height());
+ bridge->viewInvalidate();
+ } else if (m_data->ignoreUpdateContents == false) {
+ bridge->contentInvalidate(rect);
+ }
+}
+
+IntPoint ScrollView::windowToContents(const IntPoint& contentsPoint) const
+{
+ WebCoreViewBridge* bridge = this->getWebCoreViewBridge();
+ WebCoreViewBridge* parent = bridge->getParent();
+ int x = 0, y= 0;
+ while (parent) {
+ x += bridge->locX();
+ y += bridge->locY();
+ bridge = parent;
+ parent = bridge->getParent();
+ }
+ return IntPoint(contentsPoint.x() - x, contentsPoint.y() - y);
+}
+
+IntPoint ScrollView::contentsToWindow(const IntPoint& viewportPoint) const
+{
+ WebCoreViewBridge* bridge = this->getWebCoreViewBridge();
+ WebCoreViewBridge* parent = bridge->getParent();
+ int x = 0, y= 0;
+ while (parent) {
+ x += bridge->locX();
+ y += bridge->locY();
+ bridge = parent;
+ parent = bridge->getParent();
+ }
+ return IntPoint(viewportPoint.x() + x, viewportPoint.y() + y);
+}
+
+void ScrollView::setStaticBackground(bool)
+{
+ // we don't have any optimizations for this
+ verifiedOk();
+}
+
+bool ScrollView::inWindow() const
+{
+ LOGV("inWindow Unimplemented");
+#if 0
+ return [getView() window];
+#endif
+ return true;
+}
+
+void ScrollView::wheelEvent(PlatformWheelEvent&)
+{
+ verifiedOk();
+}
+
+PlatformScrollbar* ScrollView::scrollbarUnderMouse(const PlatformMouseEvent& mouseEvent)
+{
+ verifiedOk();
+ return NULL;
+}
+
+}
diff --git a/WebCore/platform/android/SearchPopupMenuAndroid.cpp b/WebCore/platform/android/SearchPopupMenuAndroid.cpp
new file mode 100644
index 0000000..0c9075f
--- /dev/null
+++ b/WebCore/platform/android/SearchPopupMenuAndroid.cpp
@@ -0,0 +1,57 @@
+/*
+** libs/WebKitLib/WebKit/WebCore/platform/android/SearchPopupMenuAndroid.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef SearchPopupMenuAndroid_h
+#define SearchPopupMenuAndroid_h
+
+#include "config.h"
+#include "SearchPopupMenu.h"
+
+namespace WebCore {
+
+// Save the past searches stored in 'searchItems' to a database associated with 'name'
+void SearchPopupMenu::saveRecentSearches(const AtomicString& name, const Vector<String>& searchItems)
+{
+
+ //ASSERT(0); //notImplemented();
+
+}
+
+// Load past searches associated with 'name' from the database to 'searchItems'
+void SearchPopupMenu::loadRecentSearches(const AtomicString& name, Vector<String>& searchItems)
+{
+
+ //ASSERT(0); //notImplemented();
+
+}
+
+// Create a search popup menu - not sure what else we have to do here
+SearchPopupMenu::SearchPopupMenu(PopupMenuClient* client) : PopupMenu(client)
+{
+
+ //ASSERT(0); //notImplemented();
+
+}
+
+// functions new to Jun-07 tip of tree merge:
+bool SearchPopupMenu::enabled() { return false; }
+
+} // WebCore
+
+#endif
+
diff --git a/WebCore/platform/android/SharedTimerAndroid.cpp b/WebCore/platform/android/SharedTimerAndroid.cpp
new file mode 100644
index 0000000..756d636
--- /dev/null
+++ b/WebCore/platform/android/SharedTimerAndroid.cpp
@@ -0,0 +1,57 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "config.h"
+#include "SharedTimer.h"
+#include "SystemTime.h"
+#include "JavaSharedClient.h"
+#include "TimerClient.h"
+#define LOG_TAG "Timers"
+#undef LOG
+#include "utils/Log.h"
+
+namespace WebCore {
+
+ // Single timer, shared to implement all the timers managed by the Timer class.
+ // Not intended to be used directly; use the Timer class instead.
+
+ void setSharedTimerFiredFunction(void (*f)())
+ {
+ if (JavaSharedClient::GetTimerClient())
+ JavaSharedClient::GetTimerClient()->setSharedTimerCallback(f);
+ }
+
+ // The fire time is relative to the classic POSIX epoch of January 1, 1970,
+ // as the result of currentTime() is.
+
+ void setSharedTimerFireTime(double fireTime)
+ {
+ long long timeInMS = (long long)((fireTime - currentTime()) * 1000);
+
+ LOGV("setSharedTimerFireTime: in %ld millisec", timeInMS);
+ if (JavaSharedClient::GetTimerClient())
+ JavaSharedClient::GetTimerClient()->setSharedTimer(timeInMS);
+ }
+
+ void stopSharedTimer()
+ {
+ if (JavaSharedClient::GetTimerClient())
+ JavaSharedClient::GetTimerClient()->stopSharedTimer();
+ }
+
+}
+
diff --git a/WebCore/platform/android/SystemTimeAndroid.cpp b/WebCore/platform/android/SystemTimeAndroid.cpp
new file mode 100644
index 0000000..3dfc433
--- /dev/null
+++ b/WebCore/platform/android/SystemTimeAndroid.cpp
@@ -0,0 +1,52 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "config.h"
+#include "SystemTime.h"
+#include <sys/time.h>
+
+namespace WebCore {
+
+double currentTime()
+{
+ struct timeval tv;
+
+ gettimeofday(&tv, (struct timezone *) NULL);
+ double now = tv.tv_sec + (tv.tv_usec / 1000000.0);
+
+ return now;
+}
+
+#ifdef ANDROID_INSTRUMENT
+uint32_t get_thread_msec()
+{
+#if defined(HAVE_POSIX_CLOCKS)
+ struct timespec tm;
+
+ clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tm);
+
+ return tm.tv_sec * 1000LL + tm.tv_nsec / 1000000;
+#else
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+ return tv.tv_sec * 1000LL + tv.tv_usec / 1000;
+#endif
+}
+#endif
+
+}
diff --git a/WebCore/platform/android/TemporaryLinkStubs.cpp b/WebCore/platform/android/TemporaryLinkStubs.cpp
new file mode 100644
index 0000000..74712f5
--- /dev/null
+++ b/WebCore/platform/android/TemporaryLinkStubs.cpp
@@ -0,0 +1,290 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "config.h"
+
+#define ANDROID_COMPILE_HACK
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "AXObjectCache.h"
+#include "CachedPage.h"
+#include "CachedResource.h"
+#include "CookieJar.h"
+#include "ContextMenu.h"
+#include "ContextMenuItem.h"
+#include "Clipboard.h"
+#include "CString.h"
+#include "Cursor.h"
+#include "DocumentFragment.h"
+#include "DocumentLoader.h"
+#include "EditCommand.h"
+#include "Editor.h"
+#include "Font.h"
+#include "FrameLoader.h"
+#include "FrameLoadRequest.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "HTMLFrameOwnerElement.h"
+#include "HTMLKeygenElement.h"
+#include "History.h"
+#include "Icon.h"
+#include "IconDatabase.h"
+#include "IconLoader.h"
+#include "IntPoint.h"
+#include "KURL.h"
+#include "Language.h"
+#include "loader.h"
+#include "LocalizedStrings.h"
+#include "MainResourceLoader.h"
+#include "MIMETypeRegistry.h"
+#include "Node.h"
+#include "PageCache.h"
+#include "Pasteboard.h"
+#include "Path.h"
+#include "PlatformScrollBar.h"
+#include "PluginInfoStore.h"
+#include "ResourceError.h"
+#include "ResourceHandle.h"
+#include "ResourceLoader.h"
+#include "Screen.h"
+#include "ScrollBar.h"
+#include "SmartReplace.h"
+#include "Widget.h"
+
+#undef LOG
+#define LOG_TAG "WebCore"
+#include "utils/Log.h"
+
+using namespace WebCore;
+
+//static inline void notImplemented() { LOGV("LinkStubs: Not Implemented %s\n", __PRETTY_FUNCTION__); }
+//static inline void notImplemented(const char name[]) { LOGV("LinkStubs: Not Implemented %s\n", name); }
+static inline void verifiedOk() { } // not a problem that it's not implemented
+
+// This function is called when the frame view has changed the state of it's border.
+// iFrames, which are have a FrameView, are drawn with a 1px left/right border and 2px top/bottom border
+// Check function _shouldDrawBorder in WebFrameView.mm
+// We don't draw borders unless css draws them.
+// void FrameView::updateBorder() { verifiedOk(); }
+
+//int WebCore::screenDepthPerComponent(Widget*) { ASSERT(0); notImplemented(); return 0; }
+//bool WebCore::screenIsMonochrome(Widget*) { ASSERT(0); notImplemented(); return false; }
+
+/********************************************************/
+/* Completely empty stubs (mostly to allow DRT to run): */
+/********************************************************/
+// This value turns on or off the Mac specific Accessibility support.
+// bool AXObjectCache::gAccessibilityEnabled = false;
+
+// This function is used by Javascript to find out what the default language
+// the user has selected. It is used by the JS object Navigator.language
+// I guess this information should be mapped with the Accept-Language: HTTP header.
+String WebCore::defaultLanguage() { verifiedOk(); return "en"; }
+
+namespace WebCore {
+
+#if !defined(ANDROID_PLUGINS)
+// If plugins support is turned on, don't use these stubs.
+
+// Except for supportsMIMEType(), these Plugin functions are used by javascript's
+// navigator.plugins[] object to provide the list of available plugins. This is most
+// often used with to check to see if the browser supports Flash or which video
+// codec to use.
+// The supportsMIMEType() is used by the Frame to determine if a full screen instance
+// of a plugin can be used to render a mimetype that is not native to the browser.
+PluginInfo* PluginInfoStore::createPluginInfoForPluginAtIndex(unsigned) { ASSERT(0); return 0;}
+unsigned PluginInfoStore::pluginCount() const { verifiedOk(); return 0; }
+// FIXME, return false for now.
+String PluginInfoStore::pluginNameForMIMEType(const String& ) { notImplemented(); return String(); }
+bool PluginInfoStore::supportsMIMEType(const String& ) { verifiedOk(); return false; }
+void refreshPlugins(bool) { verifiedOk(); }
+#endif // !defined(ANDROID_PLUGINS)
+
+// This function tells the bridge that a resource was loaded from the cache and thus
+// the app may update progress with the amount of data loaded.
+void CheckCacheObjectStatus(DocLoader*, CachedResource*) { ASSERT(0); notImplemented();}
+
+// This class is used in conjunction with the File Upload form element, and
+// therefore relates to the above. When a file has been selected, an icon
+// representing the file type can be rendered next to the filename on the
+// web page. The icon for the file is encapsulated within this class.
+Icon::Icon() { notImplemented(); }
+Icon::~Icon() { }
+PassRefPtr<Icon> Icon::newIconForFile(const String& filename){ notImplemented(); return PassRefPtr<Icon>(new Icon()); }
+void Icon::paint(GraphicsContext*, const IntRect&) { }
+
+// *** The following strings should be localized *** //
+
+// The following functions are used to fetch localized text for HTML form
+// elements submit and reset. These strings are used when the page author
+// has not specified any text for these buttons.
+String submitButtonDefaultLabel() { verifiedOk(); return "Submit"; }
+String resetButtonDefaultLabel() { verifiedOk(); return "Reset"; }
+
+// The alt text for an input element is not used visually, but rather is
+// used for accessability - eg reading the web page. See
+// HTMLInputElement::altText() for more information.
+String inputElementAltText() { notImplemented(); return String(); }
+
+// This is the string that appears before an input box when the HTML element
+// <ISINDEX> is used. The returned string is used if no PROMPT attribute is
+// provided.
+// note: Safari and FireFox use (too long for us imho) "This is a searchable index. Enter search keywords:"
+String searchableIndexIntroduction() { verifiedOk(); return String("Enter search:"); }
+
+}
+
+// This function provides the default value for the CSS property:
+// -webkit-focus-ring-color
+// It is also related to the CSS property outline-color:
+Color WebCore::focusRingColor() { verifiedOk(); return 0xFF0000FF; }
+
+// The following functions are used on the Mac to register for and handle
+// platform colour changes. The later function simply tells the view to
+// reapply style and relayout.
+void WebCore::setFocusRingColorChangeFunction(void (*)()) { verifiedOk(); }
+
+// LocalizedStrings
+String WebCore::contextMenuItemTagOpenLinkInNewWindow() { ASSERT(0); return String(); }
+String WebCore::contextMenuItemTagDownloadLinkToDisk() { ASSERT(0); return String(); }
+String WebCore::contextMenuItemTagCopyLinkToClipboard() { ASSERT(0); return String(); }
+String WebCore::contextMenuItemTagOpenImageInNewWindow() { ASSERT(0); return String(); }
+String WebCore::contextMenuItemTagDownloadImageToDisk() { ASSERT(0); return String(); }
+String WebCore::contextMenuItemTagCopyImageToClipboard() { ASSERT(0); return String(); }
+String WebCore::contextMenuItemTagOpenFrameInNewWindow() { ASSERT(0); return String(); }
+String WebCore::contextMenuItemTagCopy() { ASSERT(0); return String(); }
+String WebCore::contextMenuItemTagGoBack() { ASSERT(0); return String(); }
+String WebCore::contextMenuItemTagGoForward() { ASSERT(0); return String(); }
+String WebCore::contextMenuItemTagStop() { ASSERT(0); return String(); }
+String WebCore::contextMenuItemTagReload() { ASSERT(0); return String(); }
+String WebCore::contextMenuItemTagCut() { ASSERT(0); return String(); }
+String WebCore::contextMenuItemTagPaste() { ASSERT(0); return String(); }
+String WebCore::contextMenuItemTagNoGuessesFound() { ASSERT(0); return String(); }
+String WebCore::contextMenuItemTagIgnoreSpelling() { ASSERT(0); return String(); }
+String WebCore::contextMenuItemTagLearnSpelling() { ASSERT(0); return String(); }
+String WebCore::contextMenuItemTagSearchWeb() { ASSERT(0); return String(); }
+String WebCore::contextMenuItemTagLookUpInDictionary() { ASSERT(0); return String(); }
+String WebCore::contextMenuItemTagOpenLink() { ASSERT(0); return String(); }
+String WebCore::contextMenuItemTagIgnoreGrammar() { ASSERT(0); return String(); }
+String WebCore::contextMenuItemTagSpellingMenu() { ASSERT(0); return String(); }
+String WebCore::contextMenuItemTagShowSpellingPanel(bool show) { ASSERT(0); return String(); }
+String WebCore::contextMenuItemTagCheckSpelling() { ASSERT(0); return String(); }
+String WebCore::contextMenuItemTagCheckSpellingWhileTyping() { ASSERT(0); return String(); }
+String WebCore::contextMenuItemTagCheckGrammarWithSpelling() { ASSERT(0); return String(); }
+String WebCore::contextMenuItemTagFontMenu() { ASSERT(0); return String(); }
+String WebCore::contextMenuItemTagBold() { ASSERT(0); return String(); }
+String WebCore::contextMenuItemTagItalic() { ASSERT(0); return String(); }
+String WebCore::contextMenuItemTagUnderline() { ASSERT(0); return String(); }
+String WebCore::contextMenuItemTagOutline() { ASSERT(0); return String(); }
+String WebCore::contextMenuItemTagWritingDirectionMenu() { ASSERT(0); return String(); }
+String WebCore::contextMenuItemTagDefaultDirection() { ASSERT(0); return String(); }
+String WebCore::contextMenuItemTagLeftToRight() { ASSERT(0); return String(); }
+String WebCore::contextMenuItemTagRightToLeft() { ASSERT(0); return String(); }
+
+// FIXME, no support for spelling yet.
+Pasteboard* Pasteboard::generalPasteboard() { return new Pasteboard(); }
+void Pasteboard::writeSelection(Range*, bool canSmartCopyOrDelete, Frame*) { notImplemented(); }
+void Pasteboard::writeURL(const KURL&, const String&, Frame*) { notImplemented(); }
+void Pasteboard::clear() { notImplemented(); }
+bool Pasteboard::canSmartReplace() { notImplemented(); return false; }
+PassRefPtr<DocumentFragment> Pasteboard::documentFragment(Frame*, PassRefPtr<Range>, bool allowPlainText, bool& chosePlainText) { notImplemented(); return 0; }
+String Pasteboard::plainText(Frame* frame) { notImplemented(); return String(); }
+Pasteboard::Pasteboard() { notImplemented(); }
+Pasteboard::~Pasteboard() { notImplemented(); }
+
+ContextMenu::ContextMenu(const HitTestResult& result) : m_hitTestResult(result) { ASSERT(0); notImplemented(); }
+ContextMenu::~ContextMenu() { ASSERT(0); notImplemented(); }
+void ContextMenu::appendItem(ContextMenuItem&) { ASSERT(0); notImplemented(); }
+void ContextMenu::setPlatformDescription(PlatformMenuDescription menu) { ASSERT(0); m_platformDescription = menu; }
+PlatformMenuDescription ContextMenu::platformDescription() const { ASSERT(0); return m_platformDescription; }
+
+ContextMenuItem::ContextMenuItem(PlatformMenuItemDescription) { ASSERT(0); notImplemented(); }
+ContextMenuItem::ContextMenuItem(ContextMenu*) { ASSERT(0); notImplemented(); }
+ContextMenuItem::ContextMenuItem(ContextMenuItemType type, ContextMenuAction action, const String& title, ContextMenu* subMenu) { ASSERT(0); notImplemented(); }
+ContextMenuItem::~ContextMenuItem() { ASSERT(0); notImplemented(); }
+PlatformMenuItemDescription ContextMenuItem::releasePlatformDescription() { ASSERT(0); notImplemented(); return m_platformDescription; }
+ContextMenuItemType ContextMenuItem::type() const { ASSERT(0); notImplemented(); return ActionType; }
+void ContextMenuItem::setType(ContextMenuItemType) { ASSERT(0); notImplemented(); }
+ContextMenuAction ContextMenuItem::action() const { ASSERT(0); notImplemented(); return ContextMenuItemTagNoAction; }
+void ContextMenuItem::setAction(ContextMenuAction) { ASSERT(0); notImplemented(); }
+String ContextMenuItem::title() const { ASSERT(0); notImplemented(); return String(); }
+void ContextMenuItem::setTitle(const String&) { ASSERT(0); notImplemented(); }
+PlatformMenuDescription ContextMenuItem::platformSubMenu() const { ASSERT(0); notImplemented(); return 0; }
+void ContextMenuItem::setSubMenu(ContextMenu*) { ASSERT(0); notImplemented(); }
+void ContextMenuItem::setChecked(bool) { ASSERT(0); notImplemented(); }
+void ContextMenuItem::setEnabled(bool) { ASSERT(0); notImplemented(); }
+
+namespace WebCore {
+float userIdleTime() { notImplemented(); return 0; }
+// systemBeep() is called by the Editor to indicate that there was nothing to copy, and may be called from
+// other places too.
+void systemBeep() { notImplemented(); }
+}
+
+// functions new to Jun-07 tip of tree merge:
+
+// void WebCore::CachedPage::close() {}
+
+//void WebCore::Frame::print() {}
+// void WebCore::Frame::issueTransposeCommand() {}
+//void WebCore::Frame::cleanupPlatformScriptObjects() {}
+void WebCore::Frame::dashboardRegionsChanged() {}
+//bool WebCore::Frame::isCharacterSmartReplaceExempt(unsigned short, bool) { return false; }
+void* WebCore::Frame::dragImageForSelection() { return NULL; }
+
+WebCore::String WebCore::MIMETypeRegistry::getMIMETypeForExtension(WebCore::String const&) {
+ return WebCore::String();
+}
+
+void WebCore::Pasteboard::writeImage(WebCore::Node*, WebCore::KURL const&, WebCore::String const&) {}
+
+namespace WebCore {
+IntSize dragImageSize(void*) { return IntSize(0, 0); }
+void deleteDragImage(void*) {}
+void* createDragImageFromImage(Image*) { return NULL; }
+void* dissolveDragImageToFraction(void*, float) { return NULL; }
+void* createDragImageIconForCachedImage(CachedImage*) { return NULL; }
+Cursor dummyCursor;
+const Cursor& zoomInCursor() { return dummyCursor; }
+const Cursor& zoomOutCursor() { return dummyCursor; }
+const Cursor& notAllowedCursor() { return dummyCursor; }
+void* scaleDragImage(void*, FloatSize) { return NULL; }
+String searchMenuRecentSearchesText() { return String(); }
+String searchMenuNoRecentSearchesText() { return String(); }
+String searchMenuClearRecentSearchesText() { return String(); }
+Vector<String> supportedKeySizes() { notImplemented(); return Vector<String>(); }
+String signedPublicKeyAndChallengeString(unsigned int, String const&, WebCore::KURL const&) { return String(); }
+
+}
+
+// added for Nov-16-07 ToT integration
+namespace WebCore {
+void Frame::clearPlatformScriptObjects() { notImplemented(); }
+}
+
+// functions new to Feb-19 tip of tree merge:
+namespace WebCore {
+// isCharacterSmartReplaceExempt is defined in SmartReplaceICU.cpp; in theory, we could use that one
+// but we don't support all of the required icu functions
+bool isCharacterSmartReplaceExempt(UChar32 , bool ) { notImplemented(); return false; }
+}
+
+int MakeDataExecutable;
+
+// functions new to Mar-2 tip of tree merge:
+String KURL::fileSystemPath() const { notImplemented(); return String(); }
diff --git a/WebCore/platform/android/TextBoundaries.cpp b/WebCore/platform/android/TextBoundaries.cpp
new file mode 100644
index 0000000..e4f8c58
--- /dev/null
+++ b/WebCore/platform/android/TextBoundaries.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2006, 2007 Apple 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.
+ */
+
+#include "config.h"
+#include "TextBoundaries.h"
+
+#include <unicode/ubrk.h>
+
+#include "TextBreakIterator.h"
+
+namespace WebCore {
+
+int findNextWordFromIndex(const UChar* chars, int len, int position, bool forward)
+{
+ UBreakIterator* it = wordBreakIterator(chars, len);
+
+ int newPosition = position;
+
+ if (forward) {
+ position = ubrk_following(it, position);
+ while (position != UBRK_DONE) {
+ // We stop searching when the character preceeding the break
+ // is alphanumeric.
+ if (position < len && u_isalnum(chars[position - 1]))
+ return position;
+
+ position = ubrk_following(it, position);
+ }
+
+ return len;
+ } else {
+ position = ubrk_preceding(it, position);
+ while (position != UBRK_DONE) {
+ // We stop searching when the character following the break
+ // is alphanumeric.
+ if (position > 0 && u_isalnum(chars[position]))
+ return position;
+
+ position = ubrk_preceding(it, position);
+ }
+
+ return 0;
+ }
+}
+
+void findWordBoundary(const UChar* chars, int len, int position, int* start, int* end)
+{
+ UBreakIterator* it = wordBreakIterator(chars, len);
+ *end = ubrk_following(it, position);
+ if (*end < 0)
+ *end = ubrk_last(it);
+ *start = ubrk_previous(it);
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/android/TextBreakIteratorInternalICU.cpp b/WebCore/platform/android/TextBreakIteratorInternalICU.cpp
new file mode 100644
index 0000000..19f33e5
--- /dev/null
+++ b/WebCore/platform/android/TextBreakIteratorInternalICU.cpp
@@ -0,0 +1,28 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "config.h"
+#include "TextBreakIteratorInternalICU.h"
+
+namespace WebCore {
+
+const char* currentTextBreakLocaleID()
+{
+ return "en_us";
+}
+
+}
diff --git a/WebCore/platform/android/TextEditAndroid.cpp b/WebCore/platform/android/TextEditAndroid.cpp
new file mode 100644
index 0000000..a946465
--- /dev/null
+++ b/WebCore/platform/android/TextEditAndroid.cpp
@@ -0,0 +1,377 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "config.h"
+#include "KWQTextEdit.h"
+#include "Font.h"
+#include "IntSize.h"
+#include "WebCoreViewBridge.h"
+#include "GraphicsContext.h"
+#include "PlatformGraphicsContext.h"
+
+#include "SkCanvas.h"
+#include "SkString.h"
+#include "SkUtils.h"
+#include "SkPaint.h"
+
+#undef LOG
+#define LOG_TAG "WebCore"
+#undef LOGI
+#undef LOG
+#include "utils/Log.h"
+
+static void setstr(SkString* dst, const WebCore::String& src)
+{
+ if (src.length()) {
+ const uint16_t* uni = (const uint16_t*)src.characters();
+ size_t size = SkUTF16_ToUTF8(uni, src.length(), 0);
+
+ dst->resize(size);
+ SkUTF16_ToUTF8(uni, src.length(), dst->writable_str());
+ }
+}
+
+class TextEditViewBridge : public WebCoreViewBridge {
+public:
+ TextEditViewBridge(QTextEdit* te);
+
+ virtual void draw(WebCore::GraphicsContext* ctx, const IntRect& rect);
+ virtual bool isEnabled() const;
+ virtual void setEnabled(bool);
+ virtual bool hasFocus() const;
+ virtual void setFocus(bool);
+
+private:
+ QTextEdit* m_te;
+ bool m_enabled;
+ bool m_focused;
+};
+
+TextEditViewBridge::TextEditViewBridge(QTextEdit* te)
+{
+ m_te = te;
+ this->setBounds(0,0,0,0);
+ m_enabled = true;
+ m_focused = false;
+}
+
+void TextEditViewBridge::draw(WebCore::GraphicsContext* ctx, const IntRect& rect)
+{
+ SkCanvas* canvas = ctx->platformContext()->mCanvas;
+ SkPaint paint;
+ SkRect r;
+
+ paint.setColor(m_focused ? SK_ColorGREEN : SK_ColorBLUE);
+ r.set( SkIntToScalar(rect.x()), SkIntToScalar(rect.y()),
+ SkIntToScalar(rect.right()), SkIntToScalar(rect.bottom()));
+ canvas->drawRect(r, paint);
+}
+
+bool TextEditViewBridge::isEnabled() const { return m_enabled; }
+void TextEditViewBridge::setEnabled(bool e) { m_enabled = e; }
+
+bool TextEditViewBridge::hasFocus() const { return m_focused; }
+void TextEditViewBridge::setFocus(bool f) { m_focused = f; }
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////
+
+using namespace WebCore;
+
+QTextEdit::QTextEdit(Widget *parent)
+{
+ this->setWebCoreViewBridge(new TextEditViewBridge(this));
+
+#if 0
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+ WebCoreTextArea *textView = [[WebCoreTextArea alloc] initWithQTextEdit:this];
+ setView(textView);
+ [textView release];
+ END_BLOCK_OBJC_EXCEPTIONS;
+#endif
+}
+
+QTextEdit::~QTextEdit()
+{
+ delete this->getWebCoreViewBridge();
+
+#if 0
+ WebCoreTextArea *textArea = (WebCoreTextArea *)getView();
+ [textArea detachQTextEdit];
+#endif
+}
+
+void QTextEdit::setText(const String& string)
+{
+ SkString str;
+
+ setstr(&str, string);
+ LOGI("%p QTextEdit::setText(%s)\n", this, str.c_str());
+}
+
+String QTextEdit::text() const
+{
+ return String("ATextEdit::text");
+}
+
+String QTextEdit::textWithHardLineBreaks() const
+{
+ return String("ATextEdit::textWithHardLineBreaks");
+}
+
+void QTextEdit::getCursorPosition(int *paragraph, int *index) const
+{
+// WebCoreTextArea *textView = (WebCoreTextArea *)getView();
+ if (index)
+ *index = 0;
+ if (paragraph)
+ *paragraph = 0;
+}
+
+void QTextEdit::setCursorPosition(int paragraph, int index)
+{
+LOGI("QTextEdit::setCursorPosition(%d, %d)\n", paragraph, index);
+}
+
+QTextEdit::WrapStyle QTextEdit::wordWrap() const
+{
+// return [textView wordWrap] ? WidgetWidth : NoWrap;
+ return NoWrap;
+}
+
+void QTextEdit::setWordWrap(WrapStyle style)
+{
+}
+
+void QTextEdit::setScrollBarModes(ScrollBarMode hMode, ScrollBarMode vMode)
+{
+#if 0
+ WebCoreTextArea *textView = (WebCoreTextArea *)getView();
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+ // this declaration must be inside the BEGIN_BLOCK_OBJC_EXCEPTIONS block or the deployment build fails
+ bool autohides = hMode == ScrollBarAuto || vMode == ScrollBarAuto;
+
+ ASSERT(!autohides || hMode != ScrollBarAlwaysOn);
+ ASSERT(!autohides || vMode != ScrollBarAlwaysOn);
+
+ [textView setHasHorizontalScroller:hMode != ScrollBarAlwaysOff];
+ [textView setHasVerticalScroller:vMode != ScrollBarAlwaysOff];
+ [textView setAutohidesScrollers:autohides];
+
+ END_BLOCK_OBJC_EXCEPTIONS;
+#endif
+}
+
+bool QTextEdit::isReadOnly() const
+{
+ return false;
+}
+
+void QTextEdit::setReadOnly(bool flag)
+{
+}
+
+bool QTextEdit::isDisabled() const
+{
+ return false;
+}
+
+void QTextEdit::setDisabled(bool flag)
+{
+}
+
+int QTextEdit::selectionStart()
+{
+ return 0;
+}
+
+int QTextEdit::selectionEnd()
+{
+ return 0;
+}
+
+void QTextEdit::setSelectionStart(int start)
+{
+#if 0
+ WebCoreTextArea *textView = (WebCoreTextArea *)getView();
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+ NSRange range = [textView selectedRange];
+ if (range.location == NSNotFound) {
+ range.location = 0;
+ range.length = 0;
+ }
+
+ // coerce start to a valid value
+ int maxLength = [[textView text] length];
+ int newStart = start;
+ if (newStart < 0)
+ newStart = 0;
+ if (newStart > maxLength)
+ newStart = maxLength;
+
+ if ((unsigned)newStart < range.location + range.length) {
+ // If we're expanding or contracting, but not collapsing the selection
+ range.length += range.location - newStart;
+ range.location = newStart;
+ } else {
+ // ok, we're collapsing the selection
+ range.location = newStart;
+ range.length = 0;
+ }
+
+ [textView setSelectedRange:range];
+ END_BLOCK_OBJC_EXCEPTIONS;
+#endif
+}
+
+void QTextEdit::setSelectionEnd(int end)
+{
+#if 0
+ WebCoreTextArea *textView = (WebCoreTextArea *)getView();
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+ NSRange range = [textView selectedRange];
+ if (range.location == NSNotFound) {
+ range.location = 0;
+ range.length = 0;
+ }
+
+ // coerce end to a valid value
+ int maxLength = [[textView text] length];
+ int newEnd = end;
+ if (newEnd < 0)
+ newEnd = 0;
+ if (newEnd > maxLength)
+ newEnd = maxLength;
+
+ if ((unsigned)newEnd >= range.location) {
+ // If we're just changing the selection length, but not location..
+ range.length = newEnd - range.location;
+ } else {
+ // ok, we've collapsed the selection and are moving it
+ range.location = newEnd;
+ range.length = 0;
+ }
+
+ [textView setSelectedRange:range];
+ END_BLOCK_OBJC_EXCEPTIONS;
+#endif
+}
+
+bool QTextEdit::hasSelectedText() const
+{
+ return false;
+}
+
+void QTextEdit::selectAll()
+{
+}
+
+void QTextEdit::setSelectionRange(int start, int length)
+{
+#if 0
+ WebCoreTextArea *textView = (WebCoreTextArea *)getView();
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+ int newStart = start;
+ int newLength = length;
+ if (newStart < 0) {
+ // truncate the length by the negative start
+ newLength = length + newStart;
+ newStart = 0;
+ }
+ if (newLength < 0) {
+ newLength = 0;
+ }
+ int maxlen = [[textView text] length];
+ if (newStart > maxlen) {
+ newStart = maxlen;
+ }
+ if (newStart + newLength > maxlen) {
+ newLength = maxlen - newStart;
+ }
+ NSRange tempRange = {newStart, newLength}; // 4213314
+ [textView setSelectedRange:tempRange];
+ END_BLOCK_OBJC_EXCEPTIONS;
+#endif
+}
+
+void QTextEdit::setFont(const Font& font)
+{
+ Widget::setFont(font);
+#if 0
+ WebCoreTextArea *textView = (WebCoreTextArea *)getView();
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+ [textView setFont:font.getNSFont()];
+ END_BLOCK_OBJC_EXCEPTIONS;
+#endif
+}
+
+void QTextEdit::setAlignment(HorizontalAlignment alignment)
+{
+}
+
+void QTextEdit::setLineHeight(int lineHeight)
+{
+}
+
+void QTextEdit::setWritingDirection(TextDirection direction)
+{
+#if 0
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+
+ WebCoreTextArea *textArea = static_cast<WebCoreTextArea *>(getView());
+ [textArea setBaseWritingDirection:(direction == RTL ? NSWritingDirectionRightToLeft : NSWritingDirectionLeftToRight)];
+
+ END_BLOCK_OBJC_EXCEPTIONS;
+#endif
+}
+
+IntSize QTextEdit::sizeWithColumnsAndRows(int numColumns, int numRows) const
+{
+#if 0
+ WebCoreTextArea *textArea = static_cast<WebCoreTextArea *>(getView());
+ NSSize size = {0,0};
+
+ BEGIN_BLOCK_OBJC_EXCEPTIONS;
+ size = [textArea sizeWithColumns:numColumns rows:numRows];
+ END_BLOCK_OBJC_EXCEPTIONS;
+
+ return IntSize((int)ceil(size.width), (int)ceil(size.height));
+#else
+ return IntSize(0, 0);
+#endif
+}
+
+Widget::FocusPolicy QTextEdit::focusPolicy() const
+{
+ FocusPolicy policy = ScrollView::focusPolicy();
+ return policy == TabFocus ? StrongFocus : policy;
+}
+
+bool QTextEdit::checksDescendantsForFocus() const
+{
+ return true;
+}
+
+void QTextEdit::setColors(const Color& background, const Color& foreground)
+{
+}
+
diff --git a/WebCore/platform/gtk/MainThreadGtk.cpp b/WebCore/platform/android/ThreadingAndroid.cpp
index db3a583..6317dab 100644
--- a/WebCore/platform/gtk/MainThreadGtk.cpp
+++ b/WebCore/platform/android/ThreadingAndroid.cpp
@@ -1,19 +1,18 @@
/*
- * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
- * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)
+ * Copyright (C) 2007 Apple 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.
+ * 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.
+ * documentation and/or other materials provided with the distribution.
* 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
+ * from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
@@ -28,33 +27,20 @@
*/
#include "config.h"
-#include "MainThread.h"
-
-#include <glib.h>
+#include "Threading.h"
+#include "JavaSharedClient.h"
+#include "TimerClient.h"
namespace WebCore {
-struct FunctionWithContext {
- MainThreadFunction* function;
- void* context;
-};
-
-static gboolean callFunctionOnMainThread(gpointer data)
-{
- FunctionWithContext* functionWithContext = static_cast<FunctionWithContext*>(data);
- functionWithContext->function(functionWithContext->context);
- delete functionWithContext;
- return FALSE;
-}
-
-void callOnMainThread(MainThreadFunction* function, void* context)
+void callOnMainThread(void (*function)(void* ), void* context)
{
- ASSERT(function);
- FunctionWithContext* functionWithContext = new FunctionWithContext;
- functionWithContext->function = function;
- functionWithContext->context = context;
- g_timeout_add(0, callFunctionOnMainThread, functionWithContext);
+ // Through some investigation, this method is used to notify the frame
+ // loader that the favicon load decision has been made. This is not
+ // necessary as the frame loader will always attempt to the load the favicon
+ // at the end of the load.
+ // The other use for this function is to call a DatabaseCallback
+ // implementation which we do not implement.
}
-
}
diff --git a/WebCore/platform/android/TimerClient.h b/WebCore/platform/android/TimerClient.h
new file mode 100644
index 0000000..e4f36a0
--- /dev/null
+++ b/WebCore/platform/android/TimerClient.h
@@ -0,0 +1,34 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef TIMER_CLIENT_H
+#define TIMER_CLIENT_H
+
+namespace WebCore {
+
+ class TimerClient
+ {
+ public:
+ virtual ~TimerClient() {}
+ virtual void setSharedTimerCallback(void(*f)()) = 0;
+ virtual void setSharedTimer(long long timemillis) = 0;
+ virtual void stopSharedTimer() = 0;
+ };
+
+}
+#endif
+
diff --git a/WebCore/platform/android/WidgetAndroid.cpp b/WebCore/platform/android/WidgetAndroid.cpp
new file mode 100644
index 0000000..3ed3abc
--- /dev/null
+++ b/WebCore/platform/android/WidgetAndroid.cpp
@@ -0,0 +1,161 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "config.h"
+#include "Widget.h"
+#include "WebCoreViewBridge.h"
+#include "WidgetClient.h"
+#include "Font.h"
+#include "IntRect.h"
+#include "GraphicsContext.h"
+#include "FrameAndroid.h"
+#include "WebCoreFrameBridge.h"
+#include "Document.h"
+#include "Element.h"
+
+#define LOG_TAG "WebCore"
+#undef LOG
+#include "utils/Log.h"
+
+namespace WebCore {
+
+#define notImplemented() LOGV("WidgetAndroid: NotYetImplemented")
+
+ class WidgetPrivate
+ {
+ public:
+ Font m_font;
+ WebCoreViewBridge* m_viewbridge; // we point to this, but don't delete it (unless we had refcounting...)
+ WidgetClient* m_client;
+ bool m_visible;
+ };
+
+ Widget::Widget() : data(new WidgetPrivate)
+ {
+ data->m_viewbridge = NULL;
+ data->m_client = NULL;
+ data->m_visible = false;
+ }
+
+ Widget::~Widget()
+ {
+ Release(data->m_viewbridge);
+ delete data;
+ }
+
+ void Widget::setEnabled(bool enabled)
+ {
+ WebCoreViewBridge* view = data->m_viewbridge;
+ ASSERT(data->m_viewbridge);
+ if (view)
+ view->setEnabled(enabled);
+ }
+
+ bool Widget::isEnabled() const
+ {
+ ASSERT(data->m_viewbridge);
+ return data->m_viewbridge->isEnabled();
+ }
+
+ IntRect Widget::frameGeometry() const
+ {
+ ASSERT(data->m_viewbridge);
+ return data->m_viewbridge->getBounds();
+ }
+
+ void Widget::setFocus()
+ {
+ ASSERT(data->m_viewbridge);
+ data->m_viewbridge->setFocus(true);
+ }
+
+ void Widget::paint(GraphicsContext* ctx, const IntRect& r)
+ {
+ WebCoreViewBridge* viewBridge = data->m_viewbridge;
+ ASSERT(viewBridge);
+ viewBridge->layout();
+ viewBridge->draw(ctx, r, true);
+ }
+
+ void Widget::setCursor(const Cursor& cursor)
+ {
+ notImplemented();
+ }
+
+ void Widget::show()
+ {
+ if (!data || data->m_visible)
+ return;
+
+ data->m_visible = true;
+ }
+
+ void Widget::hide()
+ {
+ notImplemented();
+ }
+
+ void Widget::setFrameGeometry(const IntRect& rect)
+ {
+ ASSERT(data->m_viewbridge);
+ data->m_viewbridge->setBounds(rect.x(), rect.y(), rect.x() + rect.width(), rect.y() + rect.height());
+ }
+
+ void Widget::setIsSelected(bool isSelected)
+ {
+ notImplemented();
+ }
+
+ void Widget::invalidate()
+ {
+ notImplemented();
+ }
+
+ void Widget::invalidateRect(const IntRect&)
+ {
+ notImplemented();
+ }
+
+ void Widget::removeFromParent()
+ {
+ notImplemented();
+ }
+
+ void Widget::setClient(WidgetClient* c)
+ {
+ data->m_client = c;
+ }
+
+ WidgetClient* Widget::client() const
+ {
+ return data->m_client;
+ }
+
+ WebCoreViewBridge* Widget::getWebCoreViewBridge() const
+ {
+ return data->m_viewbridge;
+ }
+
+ void Widget::setWebCoreViewBridge(WebCoreViewBridge* view)
+ {
+ Release(data->m_viewbridge);
+ data->m_viewbridge = view;
+ view->setWidget(this);
+ Retain(data->m_viewbridge);
+ }
+
+} // WebCore namepsace
diff --git a/WebCore/platform/android/android-encodings.txt b/WebCore/platform/android/android-encodings.txt
new file mode 100644
index 0000000..0cc346d
--- /dev/null
+++ b/WebCore/platform/android/android-encodings.txt
@@ -0,0 +1,44 @@
+##
+## Copyright 2007, The Android Open Source Project
+##
+## Licensed under the Apache License, Version 2.0 (the "License");
+## you may not use this file except in compliance with the License.
+## You may obtain a copy of the License at
+##
+## http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing, software
+## distributed under the License is distributed on an "AS IS" BASIS,
+## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+## See the License for the specific language governing permissions and
+## limitations under the License.
+#
+
+# The items on the left are names of TextEncodingID values
+# The items on the right are IANA character set names. Names listed in character-sets.txt are not
+# repeated here; mentioning any one character set from a group in there pulls in all the aliases in
+# that group.
+
+# XXX: This needs to be kept in sync with AndroidUnicode.h in utils.
+# XXX: These are not the supported encodings, they are just the available encodings
+# that WebCore will recognize. Support is determined by carriers.
+
+ASCII: US-ASCII, isoir6us
+ISO_8859_1: ISO-8859-1, 88591
+ISO_8859_5: ISO-8859-5
+ISO_8859_8: ISO-8859-8-I, iso88598
+UTF8: UTF-8
+UTF16: UTF-16
+SHIFT_JIS: Shift_JIS, sjis, xsjis
+BIG5: Big5, xxbig5
+EUC_JP: EUC-JP, xeuc, xeucjp
+EUC_CN: EUC-CN, gb2312, gb231280, gbk, xeuccn, xgbk
+WINDOWS_1251: windows-1251, cp1251
+WINDOWS_1252: windows-1252
+WINDOWS_1255: windows-1255
+KOI8_R: KOI8-R
+KOI8_U: KOI8-U
+NEXT_STEP: x-nextstep
+MACINTOSH: macintosh
+THAI: TIS-620, cp874, iso885911, windows874
+INVALID: cp864, iso2022jp, windows1250, windows1253, windows1254, windows1256, windows1257, windows1258
diff --git a/WebCore/platform/android/jni/JavaBridge.cpp b/WebCore/platform/android/jni/JavaBridge.cpp
new file mode 100644
index 0000000..27b2bb2
--- /dev/null
+++ b/WebCore/platform/android/jni/JavaBridge.cpp
@@ -0,0 +1,332 @@
+/*
+** Copyright 2006-2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#define LOG_TAG "webcoreglue"
+
+#include <config.h>
+#include <wtf/Platform.h>
+
+#include "Cache.h"
+#include "CookieClient.h"
+#include "JavaSharedClient.h"
+#include "KURL.h"
+#include "Timer.h"
+#include "TimerClient.h"
+
+#ifdef ANDROID_INSTRUMENT
+#include "Frame.h"
+#include "SystemTime.h"
+#endif
+
+#undef LOG
+#include <jni.h>
+#include <JNIHelp.h>
+#include <SkImageRef_GlobalPool.h>
+#include <SkUtils.h>
+#include <utils/Log.h>
+#include <utils/misc.h>
+
+// maximum bytes used to cache decoded images
+// (not including big images using ashmem)
+#define IMAGE_POOL_BUDGET (512 * 1024)
+
+#ifdef ANDROID_INSTRUMENT
+static uint32_t sTotalTimeUsed = 0;
+
+namespace WebCore {
+void Frame::resetSharedTimerTimeCounter()
+{
+ sTotalTimeUsed = 0;
+}
+
+void Frame::reportSharedTimerTimeCounter()
+{
+ LOG(LOG_DEBUG, "WebCore", "*-* Total native 2 (shared timer) time: %d ms\n",
+ sTotalTimeUsed);
+}
+}
+#endif
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+static jfieldID gJavaBridge_ObjectID;
+
+static bool checkException(JNIEnv* env)
+{
+ if (env->ExceptionCheck() != 0)
+ {
+ LOGE("*** Uncaught exception returned from Java call!\n");
+ env->ExceptionDescribe();
+ return true;
+ }
+ return false;
+}
+
+// ----------------------------------------------------------------------------
+
+extern JavaVM* jnienv_to_javavm(JNIEnv* env);
+extern JNIEnv* javavm_to_jnienv(JavaVM* vm);
+
+// ----------------------------------------------------------------------------
+
+class JavaBridge : public WebCore::TimerClient, public WebCore::CookieClient
+{
+public:
+ JavaBridge(JNIEnv* env, jobject obj);
+ virtual ~JavaBridge();
+
+ /*
+ * WebCore -> Java API
+ */
+ virtual void setSharedTimer(long long timemillis);
+ virtual void stopSharedTimer();
+
+ virtual void setCookies(WebCore::KURL const& url, WebCore::KURL const& docURL, WebCore::String const& value);
+ virtual WebCore::String cookies(WebCore::KURL const& url);
+ virtual bool cookiesEnabled();
+
+ ////////////////////////////////////////////
+
+ virtual void setSharedTimerCallback(void (*f)());
+
+ ////////////////////////////////////////////
+
+ void signalServiceFuncPtrQueue();
+
+ // jni functions
+ static void Constructor(JNIEnv* env, jobject obj);
+ static void Finalize(JNIEnv* env, jobject obj);
+ static void SharedTimerFired(JNIEnv* env, jobject);
+ static void SetCacheSize(JNIEnv* env, jobject obj, jint bytes);
+ static void SetDeferringTimers(JNIEnv* env, jobject obj, jboolean defer);
+ static void ServiceFuncPtrQueue(JNIEnv*);
+
+private:
+ JavaVM* mJvm;
+ jobject mJavaObject;
+ jmethodID mSetSharedTimer;
+ jmethodID mStopSharedTimer;
+ jmethodID mSetCookies;
+ jmethodID mCookies;
+ jmethodID mCookiesEnabled;
+ jmethodID mSignalFuncPtrQueue;
+};
+
+static void (*sSharedTimerFiredCallback)();
+static JavaBridge* gJavaBridge;
+
+JavaBridge::JavaBridge(JNIEnv* env, jobject obj)
+{
+ mJvm = jnienv_to_javavm(env);
+ mJavaObject = env->NewGlobalRef(obj);
+ jclass clazz = env->GetObjectClass(obj);
+
+ mSetSharedTimer = env->GetMethodID(clazz, "setSharedTimer", "(J)V");
+ mStopSharedTimer = env->GetMethodID(clazz, "stopSharedTimer", "()V");
+ mSetCookies = env->GetMethodID(clazz, "setCookies", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
+ mCookies = env->GetMethodID(clazz, "cookies", "(Ljava/lang/String;)Ljava/lang/String;");
+ mCookiesEnabled = env->GetMethodID(clazz, "cookiesEnabled", "()Z");
+ mSignalFuncPtrQueue = env->GetMethodID(clazz, "signalServiceFuncPtrQueue", "()V");
+
+ LOG_ASSERT(mSetSharedTimer, "Could not find method setSharedTimer");
+ LOG_ASSERT(mStopSharedTimer, "Could not find method stopSharedTimer");
+ LOG_ASSERT(mSetCookies, "Could not find method setCookies");
+ LOG_ASSERT(mCookies, "Could not find method cookies");
+ LOG_ASSERT(mCookiesEnabled, "Could not find method cookiesEnabled");
+
+ WebCore::JavaSharedClient::SetTimerClient(this);
+ WebCore::JavaSharedClient::SetCookieClient(this);
+ gJavaBridge = this;
+}
+
+JavaBridge::~JavaBridge()
+{
+ if (mJavaObject) {
+ JNIEnv* env = javavm_to_jnienv(mJvm);
+ env->DeleteGlobalRef(mJavaObject);
+ mJavaObject = 0;
+ }
+
+ WebCore::JavaSharedClient::SetTimerClient(NULL);
+ WebCore::JavaSharedClient::SetCookieClient(NULL);
+}
+
+void
+JavaBridge::setSharedTimer(long long timemillis)
+{
+ JNIEnv* env = javavm_to_jnienv(mJvm);
+ env->CallVoidMethod(mJavaObject, mSetSharedTimer, timemillis);
+}
+
+void
+JavaBridge::stopSharedTimer()
+{
+ JNIEnv* env = javavm_to_jnienv(mJvm);
+ env->CallVoidMethod(mJavaObject, mStopSharedTimer);
+}
+
+void
+JavaBridge::setCookies(WebCore::KURL const& url, WebCore::KURL const& docUrl, WebCore::String const& value)
+{
+ JNIEnv* env = javavm_to_jnienv(mJvm);
+ const WebCore::DeprecatedString& urlStr = url.deprecatedString();
+ jstring jUrlStr = env->NewString((unsigned short *)urlStr.unicode(), urlStr.length());
+ const WebCore::DeprecatedString& docUrlStr = docUrl.deprecatedString();
+ jstring jDocUrlStr = env->NewString((unsigned short *)docUrlStr.unicode(), docUrlStr.length());
+ jstring jValueStr = env->NewString((unsigned short *)value.characters(), value.length());
+
+ env->CallVoidMethod(mJavaObject, mSetCookies, jUrlStr, jDocUrlStr, jValueStr);
+ env->DeleteLocalRef(jUrlStr);
+ env->DeleteLocalRef(jDocUrlStr);
+ env->DeleteLocalRef(jValueStr);
+}
+
+WebCore::String
+JavaBridge::cookies(WebCore::KURL const& url)
+{
+ JNIEnv* env = javavm_to_jnienv(mJvm);
+ const WebCore::DeprecatedString& urlStr = url.deprecatedString();
+ jstring jUrlStr = env->NewString((unsigned short *)urlStr.unicode(), urlStr.length());
+
+ jstring string = (jstring)(env->CallObjectMethod(mJavaObject, mCookies, jUrlStr));
+
+ if (string == NULL || checkException(env))
+ return WebCore::String();
+
+ const jchar* str = env->GetStringChars(string, NULL);
+ WebCore::String ret = WebCore::String((const UChar*)str, env->GetStringLength(string));
+ env->ReleaseStringChars(string, str);
+ env->DeleteLocalRef(jUrlStr);
+ env->DeleteLocalRef(string);
+ return ret;
+}
+
+bool
+JavaBridge::cookiesEnabled()
+{
+ JNIEnv* env = javavm_to_jnienv(mJvm);
+ jboolean ret = env->CallBooleanMethod(mJavaObject, mCookiesEnabled);
+ return (ret != 0);
+}
+
+void
+JavaBridge::setSharedTimerCallback(void (*f)())
+{
+ LOG_ASSERT(!sSharedTimerFiredCallback || sSharedTimerFiredCallback==f,
+ "Shared timer callback may already be set or null!");
+
+ sSharedTimerFiredCallback = f;
+}
+
+void JavaBridge::signalServiceFuncPtrQueue()
+{
+ javavm_to_jnienv(mJvm)->CallVoidMethod(mJavaObject, mSignalFuncPtrQueue);
+}
+
+// ----------------------------------------------------------------------------
+
+// visible to Shared
+void AndroidSignalServiceFuncPtrQueue()
+{
+ gJavaBridge->signalServiceFuncPtrQueue();
+}
+
+// ----------------------------------------------------------------------------
+
+void JavaBridge::Constructor(JNIEnv* env, jobject obj)
+{
+ JavaBridge* javaBridge = new JavaBridge(env, obj);
+ env->SetIntField(obj, gJavaBridge_ObjectID, (jint)javaBridge);
+}
+
+void JavaBridge::Finalize(JNIEnv* env, jobject obj)
+{
+ JavaBridge* javaBridge = (JavaBridge*)
+ (env->GetIntField(obj, gJavaBridge_ObjectID));
+ LOG_ASSERT(javaBridge, "Finalize should not be called twice for the same java bridge!");
+ LOGV("webcore_javabridge::nativeFinalize(%p)\n", javaBridge);
+ delete javaBridge;
+ env->SetIntField(obj, gJavaBridge_ObjectID, 0);
+}
+
+// we don't use the java bridge object, as we're just looking at a global
+void JavaBridge::SharedTimerFired(JNIEnv* env, jobject)
+{
+ if (sSharedTimerFiredCallback)
+ {
+#ifdef ANDROID_INSTRUMENT
+ uint32_t startTime = WebCore::get_thread_msec();
+#endif
+ SkAutoMemoryUsageProbe mup("JavaBridge::sharedTimerFired");
+ sSharedTimerFiredCallback();
+#ifdef ANDROID_INSTRUMENT
+ sTotalTimeUsed += WebCore::get_thread_msec() - startTime;
+#endif
+ }
+}
+
+void JavaBridge::SetCacheSize(JNIEnv* env, jobject obj, jint bytes)
+{
+ WebCore::cache()->setCapacities(0, bytes/2, bytes);
+ SkImageRef_GlobalPool::SetRAMBudget(IMAGE_POOL_BUDGET);
+ LOGV("--- set ImageRef budget %d\n", SkImageRef_GlobalPool::GetRAMBudget());
+}
+
+void JavaBridge::SetDeferringTimers(JNIEnv* env, jobject obj, jboolean defer)
+{
+ WebCore::setDeferringTimers(defer);
+}
+
+void JavaBridge::ServiceFuncPtrQueue(JNIEnv*)
+{
+ WebCore::JavaSharedClient::ServiceFunctionPtrQueue();
+}
+
+// ----------------------------------------------------------------------------
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gWebCoreJavaBridgeMethods[] = {
+ /* name, signature, funcPtr */
+ { "nativeConstructor", "()V",
+ (void*) JavaBridge::Constructor },
+ { "nativeFinalize", "()V",
+ (void*) JavaBridge::Finalize },
+ { "sharedTimerFired", "()V",
+ (void*) JavaBridge::SharedTimerFired },
+ { "setCacheSize", "(I)V",
+ (void*) JavaBridge::SetCacheSize },
+ { "setDeferringTimers", "(Z)V",
+ (void*) JavaBridge::SetDeferringTimers },
+ { "nativeServiceFuncPtrQueue", "()V",
+ (void*) JavaBridge::ServiceFuncPtrQueue },
+};
+
+int register_javabridge(JNIEnv* env)
+{
+ jclass javaBridge = env->FindClass("android/webkit/JWebCoreJavaBridge");
+ LOG_FATAL_IF(javaBridge == NULL, "Unable to find class android/webkit/JWebCoreJavaBridge");
+ gJavaBridge_ObjectID = env->GetFieldID(javaBridge, "mNativeBridge", "I");
+ LOG_FATAL_IF(gJavaBridge_ObjectID == NULL, "Unable to find android/webkit/JWebCoreJavaBridge.mNativeBridge");
+
+ return jniRegisterNativeMethods(env, "android/webkit/JWebCoreJavaBridge",
+ gWebCoreJavaBridgeMethods, NELEM(gWebCoreJavaBridgeMethods));
+}
+
+} /* namespace android */
diff --git a/WebCore/platform/android/jni/JavaSharedClient.cpp b/WebCore/platform/android/jni/JavaSharedClient.cpp
new file mode 100644
index 0000000..aaefd72
--- /dev/null
+++ b/WebCore/platform/android/jni/JavaSharedClient.cpp
@@ -0,0 +1,106 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "config.h"
+#include "JavaSharedClient.h"
+#define LOG_TAG "JavaSharedClient"
+#include "utils/Log.h"
+#include "SkDeque.h"
+#include "SkThread.h"
+
+namespace android {
+ void AndroidSignalServiceFuncPtrQueue();
+}
+
+namespace WebCore {
+
+ TimerClient* JavaSharedClient::GetTimerClient()
+ {
+ //LOG_ASSERT(gTimerClient != NULL, "gTimerClient not initialized!!!");
+ return gTimerClient;
+ }
+
+ CookieClient* JavaSharedClient::GetCookieClient()
+ {
+ //LOG_ASSERT(gCookieClient != NULL, "gCookieClient not initialized!!!");
+ return gCookieClient;
+ }
+
+ void JavaSharedClient::SetTimerClient(TimerClient* client)
+ {
+ //LOG_ASSERT(gTimerClient == NULL || client == NULL, "gTimerClient already set, aborting...");
+ gTimerClient = client;
+ }
+
+ void JavaSharedClient::SetCookieClient(CookieClient* client)
+ {
+ //LOG_ASSERT(gCookieClient == NULL || client == NULL, "gCookieClient already set, aborting...");
+ gCookieClient = client;
+ }
+
+ TimerClient* JavaSharedClient::gTimerClient = NULL;
+ CookieClient* JavaSharedClient::gCookieClient = NULL;
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ struct FuncPtrRec {
+ void (*fProc)(void* payload);
+ void* fPayload;
+ };
+
+ static SkMutex gFuncPtrQMutex;
+ static SkDeque gFuncPtrQ(sizeof(FuncPtrRec));
+
+ void JavaSharedClient::EnqueueFunctionPtr(void (*proc)(void* payload),
+ void* payload)
+ {
+ gFuncPtrQMutex.acquire();
+
+ FuncPtrRec* rec = (FuncPtrRec*)gFuncPtrQ.push_back();
+ rec->fProc = proc;
+ rec->fPayload = payload;
+
+ gFuncPtrQMutex.release();
+
+ android::AndroidSignalServiceFuncPtrQueue();
+ }
+
+ void JavaSharedClient::ServiceFunctionPtrQueue()
+ {
+ for (;;) {
+ void (*proc)(void*);
+ void* payload;
+ const FuncPtrRec* rec;
+
+ // we have to copy the proc/payload (if present). we do this so we
+ // don't call the proc inside the mutex (possible deadlock!)
+ gFuncPtrQMutex.acquire();
+ rec = (const FuncPtrRec*)gFuncPtrQ.front();
+ if (NULL != rec) {
+ proc = rec->fProc;
+ payload = rec->fPayload;
+ gFuncPtrQ.pop_front();
+ }
+ gFuncPtrQMutex.release();
+
+ if (NULL == rec) {
+ break;
+ }
+ proc(payload);
+ }
+ }
+}
diff --git a/WebCore/platform/android/jni/JavaSharedClient.h b/WebCore/platform/android/jni/JavaSharedClient.h
new file mode 100644
index 0000000..470c4dd
--- /dev/null
+++ b/WebCore/platform/android/jni/JavaSharedClient.h
@@ -0,0 +1,45 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef JAVA_SHARED_CLIENT_H
+#define JAVA_SHARED_CLIENT_H
+
+namespace WebCore {
+
+ class TimerClient;
+ class CookieClient;
+
+ class JavaSharedClient
+ {
+ public:
+ static TimerClient* GetTimerClient();
+ static CookieClient* GetCookieClient();
+
+ static void SetTimerClient(TimerClient* client);
+ static void SetCookieClient(CookieClient* client);
+
+ // can be called from any thread, to be executed in webkit thread
+ static void EnqueueFunctionPtr(void (*proc)(void*), void* payload);
+ // only call this from webkit thread
+ static void ServiceFunctionPtrQueue();
+
+ private:
+ static TimerClient* gTimerClient;
+ static CookieClient* gCookieClient;
+ };
+}
+#endif
diff --git a/WebCore/platform/android/jni/WebCoreFrameBridge.cpp b/WebCore/platform/android/jni/WebCoreFrameBridge.cpp
new file mode 100644
index 0000000..55c9c88
--- /dev/null
+++ b/WebCore/platform/android/jni/WebCoreFrameBridge.cpp
@@ -0,0 +1,1249 @@
+/*
+** Copyright 2006-2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#define LOG_TAG "webcoreglue"
+
+#include <config.h>
+#include <wtf/Platform.h>
+
+#include "android_graphics.h"
+#include "Arena.h"
+#include "AtomicString.h"
+#include "Cache.h"
+#include "ChromeClientAndroid.h"
+#include "ContextMenuClientAndroid.h"
+#include "DeprecatedString.h"
+#include "Document.h"
+#include "DocumentLoader.h"
+#include "DragClientAndroid.h"
+#include "EditorClientAndroid.h"
+#include "Element.h"
+#include "Font.h"
+#include "FrameAndroid.h"
+#include "FrameLoader.h"
+#include "FrameLoaderClientAndroid.h"
+#include "FrameTree.h"
+#include "FrameView.h"
+#include "GCController.h"
+#include "GraphicsContext.h"
+#include "HistoryItem.h"
+#include "HTMLElement.h"
+#include "HTMLFormElement.h"
+#include "HTMLInputElement.h"
+#include "HTMLNames.h"
+#include "IconDatabase.h"
+#include "Image.h"
+#include "InspectorClientAndroid.h"
+#include "KURL.h"
+#include "Page.h"
+#include "PageCache.h"
+#include "PlatformString.h"
+#include "RenderPart.h"
+#include "RenderSkinAndroid.h"
+#include "RenderTreeAsText.h"
+#include "ResourceHandle.h"
+#include "SelectionController.h"
+#include "Settings.h"
+#include "SubstituteData.h"
+#include "WebCoreFrameBridge.h"
+#include "WebCoreResourceLoader.h"
+#include "WebHistory.h"
+#include "WebIconDatabase.h"
+#include "WebViewCore.h"
+
+#ifdef LOG
+#undef LOG
+#endif
+
+#include <JNIHelp.h>
+#include <SkGraphics.h>
+#include <SkImageRef_GlobalPool.h>
+#include <utils/Log.h>
+#include <utils/misc.h>
+#include <utils/AssetManager.h>
+#include <android_runtime/android_util_AssetManager.h>
+
+#ifdef ANDROID_INSTRUMENT
+#include "SystemTime.h"
+
+static uint32_t sTotalJavaTimeUsed = 0;
+static uint32_t sTotalNativeTimeUsed = 0;
+
+namespace WebCore {
+void Frame::resetFramebridgeTimeCounter()
+{
+ sTotalJavaTimeUsed = 0;
+ sTotalNativeTimeUsed = 0;
+}
+
+void Frame::reportFramebridgeTimeCounter()
+{
+ LOG(LOG_DEBUG, "WebCore", "*-* Total Java callback (frame bridge) time: %d ms\n",
+ sTotalJavaTimeUsed);
+ LOG(LOG_DEBUG, "WebCore", "*-* Total native 1 (frame bridge) time: %d ms\n",
+ sTotalNativeTimeUsed);
+}
+}
+#endif
+
+namespace android {
+
+#ifdef ANDROID_INSTRUMENT
+class TimeCounterFB {
+public:
+ TimeCounterFB(bool native = false) {
+ mNative = native;
+ mStartTime = WebCore::get_thread_msec();
+ }
+
+ ~TimeCounterFB() {
+ if (mNative)
+ sTotalNativeTimeUsed += WebCore::get_thread_msec() - mStartTime;
+ else
+ sTotalJavaTimeUsed += WebCore::get_thread_msec() - mStartTime;
+ }
+private:
+ bool mNative;
+ uint32_t mStartTime;
+};
+#endif
+
+// ----------------------------------------------------------------------------
+
+#define WEBCORE_MEMORY_CAP 15 * 1024 * 1024
+
+// ----------------------------------------------------------------------------
+
+JavaVM* jnienv_to_javavm(JNIEnv* env)
+{
+ JavaVM* vm;
+ return env->GetJavaVM(&vm) >= 0 ? vm : NULL;
+}
+
+JNIEnv* javavm_to_jnienv(JavaVM* vm)
+{
+ JNIEnv* env;
+ return vm->GetEnv((void **)&env, JNI_VERSION_1_4) >= 0 ? env : NULL;
+}
+
+// ----------------------------------------------------------------------------
+
+struct WebCoreFrameBridge::JavaBrowserFrame
+{
+ JavaVM* mJVM;
+ jobject mObj;
+ jobject mHistoryList; // WebBackForwardList object
+ jmethodID mStartLoadingResource;
+ jmethodID mLoadStarted;
+ jmethodID mTransitionToCommitted;
+ jmethodID mLoadFinished;
+ jmethodID mReportError;
+ jmethodID mSetTitle;
+ jmethodID mWindowObjectCleared;
+ jmethodID mSetProgress;
+ jmethodID mDidReceiveIcon;
+ jmethodID mUpdateVisitedHistory;
+ jmethodID mHandleUrl;
+ jmethodID mCreateWindow;
+ jmethodID mCloseWindow;
+ jmethodID mDecidePolicyForFormResubmission;
+ jmethodID mRequestFocus;
+};
+
+static jfieldID gFrameAndroidField;
+#define GET_NATIVE_FRAME(env, obj) ((WebCore::FrameAndroid*)env->GetIntField(obj, gFrameAndroidField))
+#define SET_NATIVE_FRAME(env, obj, frame) (env->SetIntField(obj, gFrameAndroidField, frame))
+
+// ----------------------------------------------------------------------------
+
+/**
+ * Helper method for checking java exceptions
+ * @return true if an exception occurred.
+ */
+static bool checkException(JNIEnv* env)
+{
+ if (env->ExceptionCheck() != 0)
+ {
+ LOGE("*** Uncaught exception returned from Java call!\n");
+ env->ExceptionDescribe();
+ return true;
+ }
+ return false;
+}
+
+// ----------------------------------------------------------------------------
+
+WebCoreFrameBridge::WebCoreFrameBridge(JNIEnv* env, jobject obj, jobject historyList)
+{
+ jclass clazz = env->GetObjectClass(obj);
+ mJavaFrame = new JavaBrowserFrame;
+ mJavaFrame->mJVM = jnienv_to_javavm(env);
+ mJavaFrame->mObj = env->NewGlobalRef(obj);
+ mJavaFrame->mHistoryList = env->NewGlobalRef(historyList);
+ mJavaFrame->mStartLoadingResource = env->GetMethodID(clazz, "startLoadingResource",
+ "(ILjava/lang/String;Ljava/lang/String;Ljava/util/HashMap;Ljava/lang/String;IZZ)Landroid/webkit/LoadListener;");
+ mJavaFrame->mLoadStarted = env->GetMethodID(clazz, "loadStarted",
+ "(Ljava/lang/String;Landroid/graphics/Bitmap;IZ)V");
+ mJavaFrame->mTransitionToCommitted = env->GetMethodID(clazz, "transitionToCommitted",
+ "(IZ)V");
+ mJavaFrame->mLoadFinished = env->GetMethodID(clazz, "loadFinished",
+ "(Ljava/lang/String;IZ)V");
+ mJavaFrame->mReportError = env->GetMethodID(clazz, "reportError",
+ "(ILjava/lang/String;Ljava/lang/String;)V");
+ mJavaFrame->mSetTitle = env->GetMethodID(clazz, "setTitle",
+ "(Ljava/lang/String;)V");
+ mJavaFrame->mWindowObjectCleared = env->GetMethodID(clazz, "windowObjectCleared",
+ "(I)V");
+ mJavaFrame->mSetProgress = env->GetMethodID(clazz, "setProgress",
+ "(I)V");
+ mJavaFrame->mDidReceiveIcon = env->GetMethodID(clazz, "didReceiveIcon",
+ "(Landroid/graphics/Bitmap;)V");
+ mJavaFrame->mUpdateVisitedHistory = env->GetMethodID(clazz, "updateVisitedHistory",
+ "(Ljava/lang/String;Z)V");
+ mJavaFrame->mHandleUrl = env->GetMethodID(clazz, "handleUrl",
+ "(Ljava/lang/String;)Z");
+ mJavaFrame->mCreateWindow = env->GetMethodID(clazz, "createWindow",
+ "(ZZ)Landroid/webkit/BrowserFrame;");
+ mJavaFrame->mCloseWindow = env->GetMethodID(clazz, "closeWindow",
+ "(Landroid/webkit/WebViewCore;)V");
+ mJavaFrame->mDecidePolicyForFormResubmission = env->GetMethodID(clazz,
+ "decidePolicyForFormResubmission", "(I)V");
+ mJavaFrame->mRequestFocus = env->GetMethodID(clazz, "requestFocus",
+ "()V");
+
+ LOG_ASSERT(mJavaFrame->mStartLoadingResource, "Could not find method startLoadingResource");
+ LOG_ASSERT(mJavaFrame->mLoadStarted, "Could not find method loadStarted");
+ LOG_ASSERT(mJavaFrame->mTransitionToCommitted, "Could not find method transitionToCommitted");
+ LOG_ASSERT(mJavaFrame->mLoadFinished, "Could not find method loadFinished");
+ LOG_ASSERT(mJavaFrame->mReportError, "Could not find method reportError");
+ LOG_ASSERT(mJavaFrame->mSetTitle, "Could not find method setTitle");
+ LOG_ASSERT(mJavaFrame->mWindowObjectCleared, "Could not find method windowObjectCleared");
+ LOG_ASSERT(mJavaFrame->mSetProgress, "Could not find method setProgress");
+ LOG_ASSERT(mJavaFrame->mDidReceiveIcon, "Could not find method didReceiveIcon");
+ LOG_ASSERT(mJavaFrame->mUpdateVisitedHistory, "Could not find method updateVisitedHistory");
+ LOG_ASSERT(mJavaFrame->mHandleUrl, "Could not find method handleUrl");
+ LOG_ASSERT(mJavaFrame->mCreateWindow, "Could not find method createWindow");
+ LOG_ASSERT(mJavaFrame->mCloseWindow, "Could not find method closeWindow");
+ LOG_ASSERT(mJavaFrame->mDecidePolicyForFormResubmission, "Could not find method decidePolicyForFormResubmission");
+ LOG_ASSERT(mJavaFrame->mRequestFocus, "Could not find method requestFocus");
+
+ mUserAgent = WebCore::String();
+ mInKeyHandler = false;
+}
+
+WebCoreFrameBridge::~WebCoreFrameBridge()
+{
+ if (mJavaFrame->mObj) {
+ JNIEnv* env = javavm_to_jnienv(mJavaFrame->mJVM);
+ env->DeleteGlobalRef(mJavaFrame->mObj);
+ env->DeleteGlobalRef(mJavaFrame->mHistoryList);
+ mJavaFrame->mObj = 0;
+ }
+ delete mJavaFrame;
+}
+
+static jobject createJavaMapFromHTTPHeaders(JNIEnv* env, const WebCore::HTTPHeaderMap& map)
+{
+ jclass mapClass = env->FindClass("java/util/HashMap");
+ LOG_ASSERT(mapClass, "Could not find HashMap class!");
+ jmethodID init = env->GetMethodID(mapClass, "<init>", "(I)V");
+ LOG_ASSERT(init, "Could not find constructor for HashMap");
+ jobject hashMap = env->NewObject(mapClass, init, map.size());
+ LOG_ASSERT(hashMap, "Could not create a new HashMap");
+ jmethodID put = env->GetMethodID(mapClass, "put",
+ "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
+ LOG_ASSERT(put, "Could not find put method on HashMap");
+
+ WebCore::HTTPHeaderMap::const_iterator end = map.end();
+ for (WebCore::HTTPHeaderMap::const_iterator i = map.begin(); i != end; ++i) {
+ jstring key = env->NewString((unsigned short *)i->first.characters(), i->first.length());
+ jstring val = env->NewString((unsigned short *)i->second.characters(), i->second.length());
+ if (key && val) {
+ env->CallObjectMethod(hashMap, put, key, val);
+ env->DeleteLocalRef(key);
+ env->DeleteLocalRef(val);
+ }
+ }
+ env->DeleteLocalRef(mapClass);
+
+ return hashMap;
+}
+
+WebCoreResourceLoader*
+WebCoreFrameBridge::startLoadingResource(WebCore::ResourceHandle* loader,
+ const WebCore::ResourceRequest& request,
+ bool isHighPriority, bool synchronous)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterFB counter;
+#endif
+ LOGV("::WebCore:: startLoadingResource(%p, %s)",
+ loader, request.url().string().ascii().data());
+
+ WebCore::String method = request.httpMethod();
+ WebCore::String postData;
+ if (request.httpBody())
+ postData = request.httpBody()->flattenToString();
+ WebCore::HTTPHeaderMap headers = request.httpHeaderFields();
+
+ JNIEnv* env = javavm_to_jnienv(mJavaFrame->mJVM);
+ WebCore::DeprecatedString urlStr = request.url().deprecatedString();
+ jstring jUrlStr = env->NewString((unsigned short *)urlStr.unicode(), urlStr.length());
+ jstring jMethodStr = NULL;
+ if (!method.isEmpty())
+ jMethodStr = env->NewString((unsigned short *)method.characters(), method.length());
+ jstring jPostDataStr = NULL;
+ if (!postData.isEmpty())
+ jPostDataStr =
+ env->NewString((unsigned short *)postData.characters(), postData.length());
+
+ jobject jHeaderMap = createJavaMapFromHTTPHeaders(env, headers);
+
+ // Convert the WebCore Cache Policy to a WebView Cache Policy.
+ int cacheMode = 0; // WebView.LOAD_NORMAL
+ switch (request.cachePolicy()) {
+ case WebCore::ReloadIgnoringCacheData:
+ cacheMode = 2; // WebView.LOAD_NO_CACHE
+ break;
+ case WebCore::ReturnCacheDataDontLoad:
+ cacheMode = 3; // WebView.LOAD_CACHE_ONLY
+ break;
+ case WebCore::ReturnCacheDataElseLoad:
+ cacheMode = 1; // WebView.LOAD_CACHE_ELSE_NETWORK
+ break;
+ case WebCore::UseProtocolCachePolicy:
+ default:
+ break;
+ }
+
+ LOGV("::WebCore:: startLoadingResource %s with cacheMode %d", urlStr.ascii(), cacheMode);
+
+
+ jobject jLoadListener =
+ env->CallObjectMethod(mJavaFrame->mObj, mJavaFrame->mStartLoadingResource,
+ (int)loader, jUrlStr, jMethodStr, jHeaderMap,
+ jPostDataStr, cacheMode, isHighPriority, synchronous);
+
+ env->DeleteLocalRef(jUrlStr);
+ env->DeleteLocalRef(jMethodStr);
+ env->DeleteLocalRef(jPostDataStr);
+ env->DeleteLocalRef(jHeaderMap);
+ if (checkException(env))
+ return NULL;
+
+ WebCoreResourceLoader* h = NULL;
+ if (jLoadListener)
+ h = new WebCoreResourceLoader(env, jLoadListener);
+ env->DeleteLocalRef(jLoadListener);
+ return h;
+}
+
+void
+WebCoreFrameBridge::reportError(int errorCode, const WebCore::String& description,
+ const WebCore::String& failingUrl)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterFB counter;
+#endif
+ LOGV("::WebCore:: reportError(%d, %s)", errorCode, description.ascii().data());
+ JNIEnv* env = javavm_to_jnienv(mJavaFrame->mJVM);
+
+ jstring descStr = env->NewString((unsigned short*)description.characters(), description.length());
+ jstring failUrl = env->NewString((unsigned short*)failingUrl.characters(), failingUrl.length());
+ env->CallVoidMethod(mJavaFrame->mObj, mJavaFrame->mReportError, errorCode, descStr, failUrl);
+ env->DeleteLocalRef(descStr);
+ env->DeleteLocalRef(failUrl);
+}
+
+void
+WebCoreFrameBridge::loadStarted(WebCore::FrameAndroid* frame)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterFB counter;
+#endif
+ const WebCore::KURL& url = frame->loader()->activeDocumentLoader()->url();
+ if (url.isEmpty())
+ return;
+ LOGV("::WebCore:: loadStarted %s", url.string().ascii().data());
+
+ bool isMainFrame = (!frame->tree() || !frame->tree()->parent());
+ WebCore::FrameLoadType loadType = frame->loader()->loadType();
+
+ if (loadType == WebCore::FrameLoadTypeReplace ||
+ loadType == WebCore::FrameLoadTypeSame ||
+ (loadType == WebCore::FrameLoadTypeRedirectWithLockedHistory &&
+ !isMainFrame))
+ return;
+
+ JNIEnv* env = javavm_to_jnienv(mJavaFrame->mJVM);
+ WebCore::String urlString(url.string());
+ // If this is the main frame and we already have a favicon in the database,
+ // send it along with the page started notification.
+ jobject favicon = NULL;
+ if (isMainFrame) {
+ WebCore::Image* icon = WebCore::iconDatabase()->iconForPageURL(urlString, WebCore::IntSize(16, 16));
+ if (icon)
+ favicon = webcoreImageToJavaBitmap(env, icon);
+ LOGV("favicons", "Starting load with icon %p for %s", icon, url.deprecatedString().ascii());
+ }
+ jstring urlStr = env->NewString((unsigned short*)urlString.characters(), urlString.length());
+
+ env->CallVoidMethod(mJavaFrame->mObj, mJavaFrame->mLoadStarted, urlStr, favicon,
+ (int)loadType, isMainFrame);
+ checkException(env);
+ env->DeleteLocalRef(urlStr);
+ if (favicon)
+ env->DeleteLocalRef(favicon);
+}
+
+void
+WebCoreFrameBridge::transitionToCommitted(WebCore::Frame* frame)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterFB counter;
+#endif
+ JNIEnv* env = javavm_to_jnienv(mJavaFrame->mJVM);
+ WebCore::FrameLoadType loadType = frame->loader()->loadType();
+ bool isMainFrame = (!frame->tree() || !frame->tree()->parent());
+ env->CallVoidMethod(mJavaFrame->mObj, mJavaFrame->mTransitionToCommitted,
+ (int)loadType, isMainFrame);
+ checkException(env);
+}
+
+void
+WebCoreFrameBridge::didFinishLoad(WebCore::Frame* frame)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterFB counter;
+#endif
+ JNIEnv* env = javavm_to_jnienv(mJavaFrame->mJVM);
+ WebCore::FrameLoader* loader = frame->loader();
+ const WebCore::KURL& url = loader->activeDocumentLoader()->url();
+ if (url.isEmpty())
+ return;
+ LOGV("::WebCore:: didFinishLoad %s", url.string().ascii().data());
+
+ bool isMainFrame = (!frame->tree() || !frame->tree()->parent());
+ WebCore::FrameLoadType loadType = loader->loadType();
+ WebCore::String urlString(url.string());
+ jstring urlStr = env->NewString((unsigned short*)urlString.characters(), urlString.length());
+ env->CallVoidMethod(mJavaFrame->mObj, mJavaFrame->mLoadFinished, urlStr,
+ (int)loadType, isMainFrame);
+ checkException(env);
+ env->DeleteLocalRef(urlStr);
+}
+
+void
+WebCoreFrameBridge::addHistoryItem(WebCore::HistoryItem* item)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterFB counter;
+#endif
+ LOGV("::WebCore:: addHistoryItem");
+ JNIEnv* env = javavm_to_jnienv(mJavaFrame->mJVM);
+ WebHistory::AddItem(env, mJavaFrame->mHistoryList, item);
+}
+
+void
+WebCoreFrameBridge::removeHistoryItem(int index)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterFB counter;
+#endif
+ LOGV("::WebCore:: removeHistoryItem at %d", index);
+ JNIEnv* env = javavm_to_jnienv(mJavaFrame->mJVM);
+ WebHistory::RemoveItem(env, mJavaFrame->mHistoryList, index);
+}
+
+void
+WebCoreFrameBridge::updateHistoryIndex(int newIndex)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterFB counter;
+#endif
+ LOGV("::WebCore:: updateHistoryIndex to %d", newIndex);
+ JNIEnv* env = javavm_to_jnienv(mJavaFrame->mJVM);
+ WebHistory::UpdateHistoryIndex(env, mJavaFrame->mHistoryList, newIndex);
+}
+
+void
+WebCoreFrameBridge::setTitle(const WebCore::String& title)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterFB counter;
+#endif
+#ifndef NDEBUG
+ LOGV("setTitle(%s)", title.ascii().data());
+#endif
+ JNIEnv* env = javavm_to_jnienv(mJavaFrame->mJVM);
+ jstring jTitleStr = env->NewString((unsigned short *)title.characters(), title.length());
+
+ env->CallVoidMethod(mJavaFrame->mObj, mJavaFrame->mSetTitle,
+ jTitleStr);
+ checkException(env);
+ env->DeleteLocalRef(jTitleStr);
+}
+
+void
+WebCoreFrameBridge::windowObjectCleared(WebCore::FrameAndroid* frame)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterFB counter;
+#endif
+ LOGV("::WebCore:: windowObjectCleared");
+ JNIEnv* env = javavm_to_jnienv(mJavaFrame->mJVM);
+
+ env->CallVoidMethod(mJavaFrame->mObj, mJavaFrame->mWindowObjectCleared, (int)frame);
+ checkException(env);
+}
+
+void
+WebCoreFrameBridge::setProgress(float newProgress)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterFB counter;
+#endif
+ JNIEnv* env = javavm_to_jnienv(mJavaFrame->mJVM);
+ int progress = (int) (100 * newProgress);
+ env->CallVoidMethod(mJavaFrame->mObj, mJavaFrame->mSetProgress, progress);
+ checkException(env);
+}
+
+const WebCore::String
+WebCoreFrameBridge::userAgentForURL(const WebCore::KURL* url)
+{
+ return mUserAgent;
+}
+
+void
+WebCoreFrameBridge::didReceiveIcon(WebCore::Image* icon)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterFB counter;
+#endif
+ LOG_ASSERT(icon, "DidReceiveIcon called without an image!");
+ JNIEnv* env = javavm_to_jnienv(mJavaFrame->mJVM);
+ jobject bitmap = webcoreImageToJavaBitmap(env, icon);
+ if (!bitmap)
+ return;
+
+ env->CallVoidMethod(mJavaFrame->mObj, mJavaFrame->mDidReceiveIcon, bitmap);
+ env->DeleteLocalRef(bitmap);
+ checkException(env);
+}
+
+void
+WebCoreFrameBridge::updateVisitedHistory(const WebCore::KURL& url, bool reload)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterFB counter;
+#endif
+ WebCore::String urlStr(url.string());
+ JNIEnv* env = javavm_to_jnienv(mJavaFrame->mJVM);
+ jstring jUrlStr = env->NewString((unsigned short*)urlStr.characters(), urlStr.length());
+
+ env->CallVoidMethod(mJavaFrame->mObj, mJavaFrame->mUpdateVisitedHistory, jUrlStr, reload);
+ checkException(env);
+}
+
+bool
+WebCoreFrameBridge::canHandleRequest(const WebCore::ResourceRequest& request)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterFB counter;
+#endif
+ // Internal loads are ok but any request that is due to a user hitting a key
+ // should be checked.
+ bool userGesture = false;
+#ifdef ANDROID_USER_GESTURE
+ userGesture = request.userGesture();
+#endif
+ WebCore::KURL requestUrl = request.url();
+ if (!mInKeyHandler && !userGesture &&
+ (requestUrl.protocolIs("http") || requestUrl.protocolIs("https") ||
+ requestUrl.protocolIs("file") || requestUrl.protocolIs("about") ||
+ requestUrl.protocolIs("javascript")))
+ return true;
+ WebCore::String url(request.url().string());
+ // Empty urls should not be sent to java
+ if (url.isEmpty())
+ return true;
+ JNIEnv* env = javavm_to_jnienv(mJavaFrame->mJVM);
+ jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length());
+
+ // check to see whether browser app wants to hijack url loading.
+ // if browser app handles the url, we will return false to bail out WebCore loading
+ jboolean ret = env->CallBooleanMethod(mJavaFrame->mObj, mJavaFrame->mHandleUrl, jUrlStr);
+ checkException(env);
+ return (ret == 0);
+}
+
+WebCore::Frame*
+WebCoreFrameBridge::createWindow(bool dialog, bool userGesture)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterFB counter;
+#endif
+ JNIEnv* env = javavm_to_jnienv(mJavaFrame->mJVM);
+ jobject obj = env->CallObjectMethod(mJavaFrame->mObj,
+ mJavaFrame->mCreateWindow, dialog, userGesture);
+ if (obj) {
+ WebCore::FrameAndroid* frame = GET_NATIVE_FRAME(env, obj);
+ return frame;
+ }
+ return NULL;
+}
+
+void
+WebCoreFrameBridge::requestFocus() const
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterFB counter;
+#endif
+ JNIEnv* env = javavm_to_jnienv(mJavaFrame->mJVM);
+ env->CallVoidMethod(mJavaFrame->mObj, mJavaFrame->mRequestFocus);
+ checkException(env);
+}
+
+void
+WebCoreFrameBridge::closeWindow(WebCoreViewBridge* viewBridge)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterFB counter;
+#endif
+ assert(viewBridge);
+ JNIEnv* env = javavm_to_jnienv(mJavaFrame->mJVM);
+ // TODO: This is a hack until WebCoreViewBridge is no longer an interface.
+ env->CallVoidMethod(mJavaFrame->mObj, mJavaFrame->mCloseWindow,
+ ((WebViewCore*)viewBridge)->getJavaObject());
+}
+
+struct PolicyFunctionWrapper {
+ WebCore::FramePolicyFunction func;
+};
+
+void
+WebCoreFrameBridge::decidePolicyForFormResubmission(WebCore::FramePolicyFunction func)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterFB counter;
+#endif
+ JNIEnv* env = javavm_to_jnienv(mJavaFrame->mJVM);
+ PolicyFunctionWrapper* p = new PolicyFunctionWrapper;
+ p->func = func;
+ env->CallVoidMethod(mJavaFrame->mObj, mJavaFrame->mDecidePolicyForFormResubmission, p);
+}
+
+// ----------------------------------------------------------------------------
+static void CallPolicyFunction(JNIEnv* env, jobject obj, jint func, jint decision)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterFB counter(true);
+#endif
+ WebCore::FrameAndroid* pFrame = GET_NATIVE_FRAME(env, obj);
+ LOG_ASSERT(pFrame, "nativeCallPolicyFunction must take a valid frame pointer!");
+ PolicyFunctionWrapper* pFunc = (PolicyFunctionWrapper*)func;
+ LOG_ASSERT(pFunc, "nativeCallPolicyFunction must take a valid function pointer!");
+
+ (pFrame->loader()->*(pFunc->func))((WebCore::PolicyAction)decision);
+}
+
+static void CreateFrame(JNIEnv* env, jobject obj, jobject jAssetManager, jobject historyList)
+{
+ // Register this thread as the main thread.
+ KJS::Collector::registerAsMainThread();
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterFB counter(true);
+#endif
+ WebCore::ChromeClientAndroid* chromeC = new WebCore::ChromeClientAndroid;
+ WebCore::EditorClientAndroid* editorC = new WebCore::EditorClientAndroid;
+ WebCore::ContextMenuClient* contextMenuC = new WebCore::ContextMenuClientAndroid;
+ WebCore::DragClient* dragC = new WebCore::DragClientAndroid;
+ WebCore::FrameLoaderClientAndroid* loaderC = new WebCore::FrameLoaderClientAndroid;
+ WebCore::InspectorClientAndroid* inspectorC = new WebCore::InspectorClientAndroid;
+ // Create a new page
+ WebCore::Page* page = new WebCore::Page(chromeC, contextMenuC, editorC, dragC, inspectorC);
+ /* TODO: Don't turn on PageCache until we can restore the ScrollView State.
+ * This caused bug http://b/issue?id=1202983
+ page->settings()->setUsesPageCache(true);
+ // 10 is a random number chosen because it is small enough to give the user
+ // a good back/forward page cache without allowing the page cache to get too
+ // big.
+ WebCore::pageCache()->setCapacity(10);
+ */
+ editorC->setPage(page);
+ page->setGroupName("com.android.browser");
+ // Frames are automatically refed to 1, keep this ref because BrowserFrame will
+ // maintain a native frame pointer.
+ WebCore::FrameAndroid* frame = new WebCore::FrameAndroid(page, NULL, loaderC);
+ chromeC->setFrame(frame);
+ loaderC->setFrame(frame);
+
+ // Create one instance of WebCoreFrameBridge for calling into Java from WebCore
+ WebCoreFrameBridge* frameBridge = new WebCoreFrameBridge(env, obj, historyList);
+
+ // Pass the bridge to the frame and release our ownership.
+ frame->setBridge(frameBridge);
+ Release(frameBridge);
+
+ LOGV("::WebCore:: createFrame %p", frame);
+
+ // Set the mNativeFrame field in Frame
+ SET_NATIVE_FRAME(env, obj, (int)frame);
+
+ // Setup the asset manager.
+ AssetManager* am = assetManagerForJavaObject(env, jAssetManager);
+ // Initialize our skinning classes
+ WebCore::RenderSkinAndroid::Init(am);
+}
+
+static void DestroyFrame(JNIEnv* env, jobject obj)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterFB counter(true);
+#endif
+ WebCore::FrameAndroid* pFrame = GET_NATIVE_FRAME(env, obj);
+ LOG_ASSERT(pFrame, "nativeDestroyFrame must take a valid frame pointer!");
+
+ LOGV("::WebCore:: deleting frame %p", pFrame);
+
+ WebCore::FrameView* view = pFrame->view();
+ // detachFromParent will cause the page to be closed.
+ WebCore::FrameLoader* fl = pFrame->loader();
+ // retain a pointer because detachFromParent will set the page to null.
+ WebCore::Page* page = pFrame->page();
+ if (fl)
+ fl->detachFromParent();
+ delete page;
+ view->deref();
+
+ SET_NATIVE_FRAME(env, obj, 0);
+}
+
+static void CreateView(JNIEnv *env, jobject obj, jobject widget)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterFB counter(true);
+#endif
+ WebCore::FrameAndroid* pFrame = GET_NATIVE_FRAME(env, obj);
+ LOG_ASSERT(pFrame, "nativeCreateView must take a valid frame pointer!");
+
+ // Create a new FrameView and attach an initial WebViewCore. FrameView begins with an initial ref
+ // of 1 and that ref is in WebViewCore.
+ WebCore::FrameView* view = new WebCore::FrameView(pFrame);
+ // The viewBridge will make a java call to maintain a pointer to the view.
+ WebViewCore* viewBridge = new WebViewCore(env, widget, view);
+ view->setWebCoreViewBridge(viewBridge);
+ view->deref();
+ Release(viewBridge);
+
+ // Attach the view to the frame.
+ pFrame->setView(view);
+
+ // Set the frame to active to turn on keyboard focus.
+ pFrame->init();
+ pFrame->selectionController()->setFocused(true);
+
+ LOGV("::WebCore:: created view %p with bridge %p", view, viewBridge);
+}
+
+static void DetachView(JNIEnv *env, jobject obj)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterFB counter(true);
+#endif
+ WebCore::FrameAndroid* pFrame = GET_NATIVE_FRAME(env, obj);
+ LOG_ASSERT(pFrame, "nativeDetachView must take a valid frame pointer!");
+ LOGV("::WebCore:: detaching view from frame %p", pFrame);
+
+ WebCore::FrameView* view = pFrame->view();
+ LOG_ASSERT(view, "cannot detach a null view!");
+
+ // Remove keyboard focus
+ pFrame->selectionController()->setFocused(false);
+
+ // Remove the FrameView from the frame.
+ pFrame->setView(NULL);
+
+}
+
+static jboolean LoadUrl(JNIEnv *env, jobject obj, jstring url)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterFB counter(true);
+#endif
+ WebCore::FrameAndroid* pFrame = GET_NATIVE_FRAME(env, obj);
+ LOG_ASSERT(pFrame, "nativeLoadUrl must take a valid frame pointer!");
+
+ const char* urlStr = env->GetStringUTFChars(url, NULL);
+ WebCore::String webcoreUrl(urlStr);
+ WebCore::ResourceRequest request(webcoreUrl);
+ WebCore::DeprecatedString protocol = request.url().protocol();
+ // If the url is http(s) and doesn't have a host, it is a bad url.
+ if ((WebCore::equalIgnoringCase(protocol, "http") ||
+ WebCore::equalIgnoringCase(protocol, "https")) &&
+ request.url().host().isEmpty()) {
+ env->ReleaseStringUTFChars(url, urlStr);
+ return false;
+ }
+
+ pFrame->loader()->load(request);
+ env->ReleaseStringUTFChars(url, urlStr);
+ return true;
+}
+
+
+static void LoadData(JNIEnv *env, jobject obj, jstring baseUrl, jstring data,
+ jstring mimeType, jstring encoding, jstring failUrl)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterFB counter(true);
+#endif
+ WebCore::FrameAndroid* pFrame = GET_NATIVE_FRAME(env, obj);
+ LOG_ASSERT(pFrame, "nativeLoadData must take a valid frame pointer!");
+
+ // Setup the resource request
+ const char* baseUrlStr = env->GetStringUTFChars(baseUrl, NULL);
+ WebCore::String baseUrlString(baseUrlStr);
+ WebCore::ResourceRequest request(baseUrlString);
+
+ // Setup the substituteData
+ const char* dataStr = env->GetStringUTFChars(data, NULL);
+ WTF::RefPtr<WebCore::SharedBuffer> sharedBuffer =
+ new WebCore::SharedBuffer();
+ LOG_ASSERT(dataStr, "nativeLoadData has a null data string.");
+ sharedBuffer->append(dataStr, strlen(dataStr));
+ const char* mimeTypeStr = env->GetStringUTFChars(mimeType, NULL);
+ WebCore::String mimeTypeString(mimeTypeStr);
+ const char* encodingStr = env->GetStringUTFChars(encoding, NULL);
+ WebCore::String encodingString(encodingStr);
+ const char* failUrlStr = env->GetStringUTFChars(failUrl, NULL);
+ WebCore::KURL failURL(failUrlStr);
+ WebCore::SubstituteData substituteData(sharedBuffer, mimeTypeString,
+ encodingString, failURL);
+
+ // Perform the load
+ pFrame->loader()->load(request, substituteData);
+
+ // Release the Java strings
+ env->ReleaseStringUTFChars(baseUrl, baseUrlStr);
+ env->ReleaseStringUTFChars(data, dataStr);
+ env->ReleaseStringUTFChars(mimeType, mimeTypeStr);
+ env->ReleaseStringUTFChars(encoding, encodingStr);
+ env->ReleaseStringUTFChars(failUrl, failUrlStr);
+}
+
+static void StopLoading(JNIEnv *env, jobject obj)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterFB counter(true);
+#endif
+ WebCore::FrameAndroid* pFrame = GET_NATIVE_FRAME(env, obj);
+ LOG_ASSERT(pFrame, "nativeStopLoading must take a valid frame pointer!");
+ LOGV("::WebCore:: stopLoading %p", pFrame);
+
+ // Stop loading the page and do not send an unload event
+ pFrame->loader()->stopForUserCancel();
+}
+
+static jstring ExternalRepresentation(JNIEnv *env, jobject obj)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterFB counter(true);
+#endif
+ WebCore::FrameAndroid* pFrame = GET_NATIVE_FRAME(env, obj);
+ LOG_ASSERT(pFrame, "android_webcore_nativeExternalRepresentation must take a valid frame pointer!");
+
+ // Request external representation of the render tree
+ WebCore::DeprecatedString renderDump = externalRepresentation(pFrame->renderer());
+ unsigned len = renderDump.length();
+ if (!len)
+ return NULL;
+ return env->NewString((unsigned short*)renderDump.unicode(), len);
+}
+
+static jstring DocumentAsText(JNIEnv *env, jobject obj)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterFB counter(true);
+#endif
+ WebCore::FrameAndroid* pFrame = GET_NATIVE_FRAME(env, obj);
+ LOG_ASSERT(pFrame, "android_webcore_nativeDocumentAsText must take a valid frame pointer!");
+
+ WebCore::Element *documentElement = pFrame->document()->documentElement();
+ WebCore::String renderDump = ((WebCore::HTMLElement*)documentElement)->innerText();
+ renderDump.append("\n");
+ unsigned len = renderDump.length();
+ if (!len)
+ return NULL;
+ return env->NewString((unsigned short*)renderDump.characters(), len);
+}
+
+static void Reload(JNIEnv *env, jobject obj, jboolean allowStale)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterFB counter(true);
+#endif
+ WebCore::FrameAndroid* pFrame = GET_NATIVE_FRAME(env, obj);
+ LOG_ASSERT(pFrame, "nativeReload must take a valid frame pointer!");
+
+ WebCore::FrameLoader* loader = pFrame->loader();
+ if (allowStale)
+ loader->reloadAllowingStaleData(loader->documentLoader()->overrideEncoding());
+ else
+ loader->reload();
+}
+
+static void GoBackOrForward(JNIEnv *env, jobject obj, jint pos)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterFB counter(true);
+#endif
+ WebCore::FrameAndroid* pFrame = GET_NATIVE_FRAME(env, obj);
+ LOG_ASSERT(pFrame, "nativeGoBackOrForward must take a valid frame pointer!");
+
+ if (pos == 1)
+ pFrame->page()->goForward();
+ else if (pos == -1)
+ pFrame->page()->goBack();
+ else
+ pFrame->loader()->goBackOrForward(pos);
+}
+
+static jobject StringByEvaluatingJavaScriptFromString(JNIEnv *env, jobject obj, jstring script)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterFB counter(true);
+#endif
+ WebCore::FrameAndroid* pFrame = GET_NATIVE_FRAME(env, obj);
+ LOG_ASSERT(pFrame, "stringByEvaluatingJavaScriptFromString must take a valid frame pointer!");
+
+ const char* scriptStr = env->GetStringUTFChars(script, NULL);
+ WebCore::String result = pFrame->stringByEvaluatingJavaScriptFromString(scriptStr);
+ env->ReleaseStringUTFChars(script, scriptStr);
+
+ unsigned len = result.length();
+ if (len == 0)
+ return NULL;
+ return env->NewString((unsigned short*)result.characters(), len);
+}
+
+static void AddJavascriptInterface(JNIEnv *env, jobject obj, jint nativeFramePointer,
+ jobject javascriptObj, jstring interfaceName)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterFB counter(true);
+#endif
+ WebCore::FrameAndroid* pFrame = (WebCore::FrameAndroid*)nativeFramePointer;
+ LOG_ASSERT(pFrame, "nativeAddJavascriptInterface must take a valid frame pointer!");
+
+ const char* interfaceNameStr = env->GetStringUTFChars(interfaceName, NULL);
+ JavaVM* vm;
+ env->GetJavaVM(&vm);
+ LOGV("::WebCore:: addJSInterface: %p", pFrame);
+ pFrame->addJavascriptInterface((void*)(vm), javascriptObj, interfaceNameStr);
+
+ env->ReleaseStringUTFChars(interfaceName, interfaceNameStr);
+}
+
+static void SetCacheDisabled(JNIEnv *env, jobject obj, jboolean disabled)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterFB counter(true);
+#endif
+ WebCore::cache()->setDisabled(disabled);
+}
+
+static jboolean CacheDisabled(JNIEnv *env, jobject obj)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterFB counter(true);
+#endif
+ return WebCore::cache()->disabled();
+}
+
+static void ClearCache(JNIEnv *env, jobject obj)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterFB counter(true);
+#endif
+ if (!WebCore::cache()->disabled()) {
+ // Disabling the cache will remove all resources from the cache. They may
+ // still live on if they are referenced by some Web page though.
+ WebCore::cache()->setDisabled(true);
+ WebCore::cache()->setDisabled(false);
+ }
+ // force JavaScript to GC when clear cache
+ WebCore::gcController().garbageCollectSoon();
+ // clear image cache
+ SkImageRef_GlobalPool::SetRAMUsed(0);
+}
+
+static jboolean DocumentHasImages(JNIEnv *env, jobject obj)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterFB counter(true);
+#endif
+ WebCore::FrameAndroid* pFrame = GET_NATIVE_FRAME(env, obj);
+ LOG_ASSERT(pFrame, "DocumentHasImages must take a valid frame pointer!");
+
+ return pFrame->document()->images()->length() > 0;
+}
+
+static jboolean HasPasswordField(JNIEnv *env, jobject obj)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterFB counter(true);
+#endif
+ WebCore::FrameAndroid* pFrame = GET_NATIVE_FRAME(env, obj);
+ LOG_ASSERT(pFrame, "HasPasswordField must take a valid frame pointer!");
+
+ bool found = false;
+ WTF::PassRefPtr<WebCore::HTMLCollection> form = pFrame->document()->forms();
+ WebCore::Node* node = form->firstItem();
+ while (node && !found) {
+ WTF::Vector<WebCore::HTMLGenericFormElement*> elements =
+ ((WebCore::HTMLFormElement*)node)->formElements;
+ size_t size = elements.size();
+ for (size_t i = 0; i< size && !found; i++) {
+ WebCore::HTMLGenericFormElement* e = elements[i];
+ if (e->hasLocalName(WebCore::HTMLNames::inputTag)) {
+ if (((WebCore::HTMLInputElement*)e)->inputType() ==
+ WebCore::HTMLInputElement::PASSWORD)
+ found = true;
+ }
+ }
+ node = form->nextItem();
+ }
+ return found;
+}
+
+static jobjectArray GetUsernamePassword(JNIEnv *env, jobject obj)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterFB counter(true);
+#endif
+ WebCore::FrameAndroid* pFrame = GET_NATIVE_FRAME(env, obj);
+ LOG_ASSERT(pFrame, "GetUsernamePassword must take a valid frame pointer!");
+ jobjectArray strArray = NULL;
+
+ WebCore::String username, password;
+ bool found = false;
+ WTF::PassRefPtr<WebCore::HTMLCollection> form = pFrame->document()->forms();
+ WebCore::Node* node = form->firstItem();
+ while (node && !found) {
+ WTF::Vector<WebCore::HTMLGenericFormElement*> elements =
+ ((WebCore::HTMLFormElement*)node)->formElements;
+ size_t size = elements.size();
+ for (size_t i = 0; i< size && !found; i++) {
+ WebCore::HTMLGenericFormElement* e = elements[i];
+ if (e->hasLocalName(WebCore::HTMLNames::inputTag)) {
+ WebCore::HTMLInputElement* input = (WebCore::HTMLInputElement*)e;
+ if (input->autoComplete() == false)
+ continue;
+ if (input->inputType() == WebCore::HTMLInputElement::PASSWORD)
+ password = input->value();
+ else if (input->inputType() == WebCore::HTMLInputElement::TEXT)
+ username = input->value();
+ if (!username.isNull() && !password.isNull())
+ found = true;
+ }
+ }
+ node = form->nextItem();
+ }
+ if (found) {
+ jclass stringClass = env->FindClass("java/lang/String");
+ strArray = env->NewObjectArray(2, stringClass, NULL);
+ env->SetObjectArrayElement(strArray, 0, env->NewString((unsigned short *)
+ username.characters(), username.length()));
+ env->SetObjectArrayElement(strArray, 1, env->NewString((unsigned short *)
+ password.characters(), password.length()));
+ }
+ return strArray;
+}
+
+static void SetUsernamePassword(JNIEnv *env, jobject obj,
+ jstring username, jstring password)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterFB counter(true);
+#endif
+ WebCore::FrameAndroid* pFrame = GET_NATIVE_FRAME(env, obj);
+ LOG_ASSERT(pFrame, "SetUsernamePassword must take a valid frame pointer!");
+
+ WebCore::HTMLInputElement* usernameEle = NULL;
+ WebCore::HTMLInputElement* passwordEle = NULL;
+ bool found = false;
+ WTF::PassRefPtr<WebCore::HTMLCollection> form = pFrame->document()->forms();
+ WebCore::Node* node = form->firstItem();
+ while (node && !found) {
+ WTF::Vector<WebCore::HTMLGenericFormElement*> elements =
+ ((WebCore::HTMLFormElement*)node)->formElements;
+ size_t size = elements.size();
+ for (size_t i = 0; i< size && !found; i++) {
+ WebCore::HTMLGenericFormElement* e = elements[i];
+ if (e->hasLocalName(WebCore::HTMLNames::inputTag)) {
+ WebCore::HTMLInputElement* input = (WebCore::HTMLInputElement*)e;
+ if (input->autoComplete() == false)
+ continue;
+ if (input->inputType() == WebCore::HTMLInputElement::PASSWORD)
+ passwordEle = input;
+ else if (input->inputType() == WebCore::HTMLInputElement::TEXT)
+ usernameEle = input;
+ if (usernameEle != NULL && passwordEle != NULL)
+ found = true;
+ }
+ }
+ node = form->nextItem();
+ }
+ if (found) {
+ const char* usernameStr = env->GetStringUTFChars(username, NULL);
+ const char* passwordStr = env->GetStringUTFChars(password, NULL);
+ usernameEle->setValue(usernameStr);
+ passwordEle->setValue(passwordStr);
+ env->ReleaseStringUTFChars(username, usernameStr);
+ env->ReleaseStringUTFChars(password, passwordStr);
+ }
+}
+
+static jobject GetFormTextData(JNIEnv *env, jobject obj)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterFB counter(true);
+#endif
+ WebCore::FrameAndroid* pFrame = GET_NATIVE_FRAME(env, obj);
+ LOG_ASSERT(pFrame, "GetFormTextData must take a valid frame pointer!");
+ jobject hashMap = NULL;
+
+ WTF::PassRefPtr<WebCore::HTMLCollection> collection = pFrame->document()->forms();
+ if (collection->length() > 0) {
+ jclass mapClass = env->FindClass("java/util/HashMap");
+ LOG_ASSERT(mapClass, "Could not find HashMap class!");
+ jmethodID init = env->GetMethodID(mapClass, "<init>", "(I)V");
+ LOG_ASSERT(init, "Could not find constructor for HashMap");
+ hashMap = env->NewObject(mapClass, init, 1);
+ LOG_ASSERT(hashMap, "Could not create a new HashMap");
+ jmethodID put = env->GetMethodID(mapClass, "put",
+ "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
+ LOG_ASSERT(put, "Could not find put method on HashMap");
+
+ static const WebCore::AtomicString text("text");
+ static const WebCore::AtomicString off("off");
+
+ WebCore::HTMLFormElement* form;
+ WebCore::HTMLInputElement* input;
+ for (WebCore::Node* node = collection->firstItem(); node; node = collection->nextItem()) {
+ form = static_cast<WebCore::HTMLFormElement*>(node);
+ if (form->autoComplete()) {
+ WTF::Vector<WebCore::HTMLGenericFormElement*> elements = form->formElements;
+ size_t size = elements.size();
+ for (size_t i = 0; i < size; i++) {
+ WebCore::HTMLGenericFormElement* e = elements[i];
+ if (e->type() == text) {
+ if (e->hasAttribute(WebCore::HTMLNames::autocompleteAttr)) {
+ const WebCore::AtomicString& attr = e->getAttribute(WebCore::HTMLNames::autocompleteAttr);
+ if (attr == off)
+ continue;
+ }
+ input = (WebCore::HTMLInputElement*) e;
+ WebCore::String value = input->value();
+ int len = value.length();
+ if (len) {
+ const WebCore::AtomicString& name = input->name();
+ jstring key = env->NewString((jchar *)name.characters(), name.length());
+ jstring val = env->NewString((jchar *)value.characters(), len);
+ LOG_ASSERT(key && val, "name or value not set");
+ env->CallObjectMethod(hashMap, put, key, val);
+ env->DeleteLocalRef(key);
+ env->DeleteLocalRef(val);
+ }
+ }
+ }
+ }
+ }
+ env->DeleteLocalRef(mapClass);
+
+ }
+ return hashMap;
+}
+
+// ----------------------------------------------------------------------------
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gBrowserFrameNativeMethods[] = {
+ /* name, signature, funcPtr */
+ { "nativeCallPolicyFunction", "(II)V",
+ (void*) CallPolicyFunction },
+ { "nativeCreateFrame", "(Landroid/content/res/AssetManager;Landroid/webkit/WebBackForwardList;)V",
+ (void*) CreateFrame },
+ { "nativeCreateView", "(Landroid/webkit/WebViewCore;)V",
+ (void*) CreateView },
+ { "nativeDestroyFrame", "()V",
+ (void*) DestroyFrame },
+ { "nativeDetachView", "()V",
+ (void*) DetachView },
+ { "stopLoading", "()V",
+ (void*) StopLoading },
+ { "nativeLoadUrl", "(Ljava/lang/String;)Z",
+ (void*) LoadUrl },
+ { "nativeLoadData", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
+ (void*) LoadData },
+ { "externalRepresentation", "()Ljava/lang/String;",
+ (void*) ExternalRepresentation },
+ { "documentAsText", "()Ljava/lang/String;",
+ (void*) DocumentAsText },
+ { "reload", "(Z)V",
+ (void*) Reload },
+ { "goBackOrForward", "(I)V",
+ (void*) GoBackOrForward },
+ { "nativeAddJavascriptInterface", "(ILjava/lang/Object;Ljava/lang/String;)V",
+ (void*) AddJavascriptInterface },
+ { "stringByEvaluatingJavaScriptFromString",
+ "(Ljava/lang/String;)Ljava/lang/String;",
+ (void*) StringByEvaluatingJavaScriptFromString },
+ { "setCacheDisabled", "(Z)V",
+ (void*) SetCacheDisabled },
+ { "cacheDisabled", "()Z",
+ (void*) CacheDisabled },
+ { "clearCache", "()V",
+ (void*) ClearCache },
+ { "documentHasImages", "()Z",
+ (void*) DocumentHasImages },
+ { "hasPasswordField", "()Z",
+ (void*) HasPasswordField },
+ { "getUsernamePassword", "()[Ljava/lang/String;",
+ (void*) GetUsernamePassword },
+ { "setUsernamePassword", "(Ljava/lang/String;Ljava/lang/String;)V",
+ (void*) SetUsernamePassword },
+ { "getFormTextData", "()Ljava/util/HashMap;",
+ (void*) GetFormTextData }
+};
+
+int register_webcoreframebridge(JNIEnv* env)
+{
+ jclass clazz = env->FindClass("android/webkit/BrowserFrame");
+ LOG_ASSERT(clazz, "Cannot find BrowserFrame");
+ gFrameAndroidField = env->GetFieldID(clazz, "mNativeFrame", "I");
+ LOG_ASSERT(gFrameAndroidField, "Cannot find mNativeFrame on BrowserFrame");
+
+ return jniRegisterNativeMethods(env, "android/webkit/BrowserFrame",
+ gBrowserFrameNativeMethods, NELEM(gBrowserFrameNativeMethods));
+}
+
+} /* namespace android */
+
diff --git a/WebCore/platform/android/jni/WebCoreFrameBridge.h b/WebCore/platform/android/jni/WebCoreFrameBridge.h
new file mode 100644
index 0000000..ba89f19
--- /dev/null
+++ b/WebCore/platform/android/jni/WebCoreFrameBridge.h
@@ -0,0 +1,106 @@
+/*
+** Copyright 2006-2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef WEBCOREFRAMEBRIDGE_H
+#define WEBCOREFRAMEBRIDGE_H
+
+#include "FrameLoaderClient.h"
+#include "PlatformString.h"
+#include "WebCoreRefObject.h"
+#include <jni.h>
+
+namespace WebCore {
+ class FrameAndroid;
+ class HistoryItem;
+ class Image;
+ class RenderPart;
+ class ResourceHandle;
+ class ResourceRequest;
+}
+
+class WebCoreViewBridge;
+
+namespace android {
+
+class WebCoreResourceLoader;
+
+class WebCoreFrameBridge : public WebCoreRefObject {
+ public:
+ WebCoreFrameBridge(JNIEnv* env, jobject obj, jobject historyList);
+ ~WebCoreFrameBridge();
+
+ WebCoreResourceLoader* startLoadingResource(WebCore::ResourceHandle*,
+ const WebCore::ResourceRequest& request,
+ bool isHighPriority,
+ bool synchronous);
+
+ void reportError(int errorCode, const WebCore::String& description,
+ const WebCore::String& failingUrl);
+
+ void loadStarted(WebCore::FrameAndroid* frame);
+
+ void transitionToCommitted(WebCore::Frame* frame);
+
+ void didFinishLoad(WebCore::Frame* frame);
+
+ void addHistoryItem(WebCore::HistoryItem* item);
+
+ void removeHistoryItem(int index);
+
+ void updateHistoryIndex(int newIndex);
+
+ void setTitle(const WebCore::String& title);
+
+ void windowObjectCleared(WebCore::FrameAndroid* frame);
+
+ void setProgress(float newProgress);
+
+ const WebCore::String userAgentForURL(const WebCore::KURL* url);
+
+ void didReceiveIcon(WebCore::Image* icon);
+
+ void updateVisitedHistory(const WebCore::KURL& url, bool reload);
+
+ bool canHandleRequest(const WebCore::ResourceRequest& request);
+
+ WebCore::Frame* createWindow(bool dialog, bool userGesture);
+
+ void requestFocus() const;
+
+ void closeWindow(WebCoreViewBridge* viewBridge);
+
+ void decidePolicyForFormResubmission(WebCore::FramePolicyFunction func);
+
+ void setUserAgent(WebCore::String userAgent) { mUserAgent = userAgent; }
+
+ /**
+ * This function is called during a key event so that canHandleRequest can
+ * avoid asking the application to override the url loading. If a load is
+ * due to a key event, then we ask the application if it wants to override
+ * the load. Otherwise, we attempt to load the resource internally.
+ */
+ void setInKeyHandler(bool inKeyHandler) { mInKeyHandler = inKeyHandler; }
+
+ private:
+ struct JavaBrowserFrame;
+ JavaBrowserFrame* mJavaFrame;
+ WebCore::String mUserAgent;
+ bool mInKeyHandler;
+};
+
+} // namespace android
+
+#endif // WEBCOREFRAMEBRIDGE_H
diff --git a/WebCore/platform/android/jni/WebCoreJni.cpp b/WebCore/platform/android/jni/WebCoreJni.cpp
new file mode 100644
index 0000000..8ba3d0b
--- /dev/null
+++ b/WebCore/platform/android/jni/WebCoreJni.cpp
@@ -0,0 +1,83 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "WebCoreJni.h"
+#include <jni.h>
+
+#ifdef LOG
+#undef LOG
+#endif
+#define LOG_TAG "webcoreglue"
+#include <utils/Log.h>
+
+namespace android {
+
+JavaVM* WebCoreJni::mJavaVM;
+
+extern int register_webcoreframebridge(JNIEnv*);
+extern int register_javabridge(JNIEnv*);
+extern int register_resource_loader(JNIEnv*);
+extern int register_webviewcore(JNIEnv*);
+extern int register_webhistory(JNIEnv*);
+extern int register_webicondatabase(JNIEnv*);
+extern int register_websettings(JNIEnv*);
+extern int register_webview(JNIEnv*);
+
+}
+
+struct RegistrationMethod {
+ const char* name;
+ int (*func)(JNIEnv*);
+};
+
+static RegistrationMethod gWebCoreRegMethods[] = {
+ { "JavaBridge", android::register_javabridge },
+ { "WebCoreFrameBridge", android::register_webcoreframebridge },
+ { "WebCoreResourceLoader", android::register_resource_loader },
+ { "WebViewCore", android::register_webviewcore },
+ { "WebHistory", android::register_webhistory },
+ { "WebIconDatabase", android::register_webicondatabase },
+ { "WebSettings", android::register_websettings },
+ { "WebView", android::register_webview }
+};
+
+EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved)
+{
+ // Save the JavaVM pointer for use globally.
+ android::WebCoreJni::setJavaVM(vm);
+
+ JNIEnv* env = NULL;
+ jint result = -1;
+
+ if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
+ LOGE("GetEnv failed!");
+ return result;
+ }
+ LOG_ASSERT(env, "Could not retrieve the env!");
+
+ const RegistrationMethod* method = gWebCoreRegMethods;
+ const RegistrationMethod* end = method + sizeof(gWebCoreRegMethods)/sizeof(RegistrationMethod);
+ while (method != end) {
+ if (method->func(env) < 0) {
+ LOGE("%s registration failed!", method->name);
+ return result;
+ }
+ method++;
+ }
+
+ return JNI_VERSION_1_4;
+}
diff --git a/WebCore/platform/android/jni/WebCoreJni.h b/WebCore/platform/android/jni/WebCoreJni.h
new file mode 100644
index 0000000..4031d43
--- /dev/null
+++ b/WebCore/platform/android/jni/WebCoreJni.h
@@ -0,0 +1,32 @@
+/* Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef WEBCOREJNI_H
+#define WEBCOREJNI_H
+
+#include <jni.h>
+
+namespace android {
+
+class WebCoreJni {
+ static JavaVM *mJavaVM;
+ public:
+ static void setJavaVM(JavaVM *vm) { mJavaVM = vm; }
+ static JavaVM *getJavaVM() { return mJavaVM; }
+};
+
+} // namespace android
+
+#endif // WEBCOREJNI_H
diff --git a/WebCore/platform/android/jni/WebCoreRefObject.h b/WebCore/platform/android/jni/WebCoreRefObject.h
new file mode 100644
index 0000000..7e96191
--- /dev/null
+++ b/WebCore/platform/android/jni/WebCoreRefObject.h
@@ -0,0 +1,38 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef WEBCORE_FOUNDATION_h
+#define WEBCORE_FOUNDATION_h
+
+#include "SkRefCnt.h"
+
+typedef SkRefCnt WebCoreRefObject;
+
+static inline WebCoreRefObject* Retain(WebCoreRefObject* obj)
+{
+ if (obj)
+ obj->ref();
+ return obj;
+}
+
+static inline void Release(WebCoreRefObject* obj)
+{
+ if (obj)
+ obj->unref();
+}
+
+#endif // WEBCORE_FOUNDATION_h
diff --git a/WebCore/platform/android/jni/WebCoreResourceLoader.cpp b/WebCore/platform/android/jni/WebCoreResourceLoader.cpp
new file mode 100644
index 0000000..3807a2a
--- /dev/null
+++ b/WebCore/platform/android/jni/WebCoreResourceLoader.cpp
@@ -0,0 +1,395 @@
+/*
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#define LOG_TAG "webcoreglue"
+
+#include <config.h>
+#include <wtf/Platform.h>
+
+#include "WebCoreResourceLoader.h"
+#include "SkUtils.h"
+#include "WebCoreJni.h"
+
+#include "ResourceError.h"
+#include "ResourceHandle.h"
+#include "ResourceHandleClient.h"
+#include "ResourceHandleInternal.h"
+#include "ResourceResponse.h"
+
+#ifdef ANDROID_INSTRUMENT
+#include "Frame.h"
+#include "SystemTime.h"
+#endif
+
+#undef LOG
+#include <utils/Log.h>
+#include <utils/misc.h>
+#include <JNIHelp.h>
+#include <SkTypes.h>
+#include <stdlib.h>
+
+#ifdef ANDROID_INSTRUMENT
+static uint32_t sTotalTimeUsed = 0;
+
+namespace WebCore {
+void Frame::resetResourceLoadTimeCounter()
+{
+ sTotalTimeUsed = 0;
+}
+
+void Frame::reportResourceLoadTimeCounter()
+{
+ LOG(LOG_DEBUG, "WebCore", "*-* Total native 3 (resource load) time: %d ms\n",
+ sTotalTimeUsed);
+}
+}
+#endif
+
+namespace android {
+
+#ifdef ANDROID_INSTRUMENT
+class TimeCounterRC {
+public:
+ TimeCounterRC() {
+ mStartTime = WebCore::get_thread_msec();
+ }
+
+ ~TimeCounterRC() {
+ sTotalTimeUsed += WebCore::get_thread_msec() - mStartTime;
+ }
+
+private:
+ uint32_t mStartTime;
+};
+#endif
+
+// ----------------------------------------------------------------------------
+
+static struct resourceloader_t {
+ jfieldID mObject;
+ jmethodID mCancelMethodID;
+ jmethodID mDownloadFileMethodID;
+ jmethodID mWillLoadFromCacheMethodID;
+} gResourceLoader;
+
+// ----------------------------------------------------------------------------
+
+/**
+ * Helper method for checking java exceptions
+ * @return true if an exception occurred.
+ */
+static bool checkException(JNIEnv* env)
+{
+ if (env->ExceptionCheck() != 0)
+ {
+ LOGE("*** Uncaught exception returned from Java call!\n");
+ env->ExceptionDescribe();
+ return true;
+ }
+ return false;
+}
+
+// ----------------------------------------------------------------------------
+
+extern JavaVM* jnienv_to_javavm(JNIEnv* env);
+extern JNIEnv* javavm_to_jnienv(JavaVM* vm);
+
+//-----------------------------------------------------------------------------
+
+#define GET_NATIVE_HANDLE(env, obj) ((WebCore::ResourceHandle*)env->GetIntField(obj, gResourceLoader.mObject))
+#define SET_NATIVE_HANDLE(env, obj, handle) (env->SetIntField(obj, gResourceLoader.mObject, handle))
+
+//-----------------------------------------------------------------------------
+// ResourceLoadHandler
+
+WebCoreResourceLoader::WebCoreResourceLoader(JNIEnv *env, jobject jLoadListener)
+{
+ mJvm = jnienv_to_javavm(env);
+ mJLoader = env->NewGlobalRef(jLoadListener);
+}
+
+WebCoreResourceLoader::~WebCoreResourceLoader()
+{
+ JNIEnv* env = javavm_to_jnienv(mJvm);
+ SET_NATIVE_HANDLE(env, mJLoader, 0);
+ env->DeleteGlobalRef(mJLoader);
+ mJLoader = 0;
+}
+
+void WebCoreResourceLoader::cancel()
+{
+ JNIEnv* env = javavm_to_jnienv(mJvm);
+ env->CallVoidMethod(mJLoader, gResourceLoader.mCancelMethodID);
+ SET_NATIVE_HANDLE(env, mJLoader, 0);
+ checkException(env);
+}
+
+void WebCoreResourceLoader::downloadFile()
+{
+ JNIEnv* env = javavm_to_jnienv(mJvm);
+ env->CallVoidMethod(mJLoader, gResourceLoader.mDownloadFileMethodID);
+ checkException(env);
+}
+
+/*
+* This static method is called to check to see if a POST response is in
+* the cache. This may be slow, but is only used during a navigation to
+* a POST response.
+*/
+bool WebCoreResourceLoader::willLoadFromCache(const WebCore::KURL& url)
+{
+ JNIEnv* env = javavm_to_jnienv(android::WebCoreJni::getJavaVM());
+ WebCore::DeprecatedString urlStr = url.deprecatedString();
+ jstring jUrlStr = env->NewString((unsigned short *)urlStr.unicode(), urlStr.length());
+ jclass resourceLoader = env->FindClass("android/webkit/LoadListener");
+ bool val = env->CallStaticBooleanMethod(resourceLoader,
+ gResourceLoader.mWillLoadFromCacheMethodID, jUrlStr);
+ checkException(env);
+ env->DeleteLocalRef(jUrlStr);
+
+ return val;
+}
+
+// ----------------------------------------------------------------------------
+void WebCoreResourceLoader::SetResponseHeader(JNIEnv* env, jobject obj, jint nativeResponse, jstring key, jstring val)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterRC counter;
+#endif
+
+ WebCore::ResourceResponse* response = (WebCore::ResourceResponse*)nativeResponse;
+ LOG_ASSERT(response, "nativeSetResponseHeader must take a valid response pointer!");
+
+ LOG_ASSERT(key, "How did a null value become a key?");
+ if (val) {
+ const char* keyStr = env->GetStringUTFChars(key, NULL);
+ const char* valStr = env->GetStringUTFChars(val, NULL);
+ if (valStr)
+ response->setHTTPHeaderField(keyStr, valStr);
+
+ env->ReleaseStringUTFChars(key, keyStr);
+ env->ReleaseStringUTFChars(val, valStr);
+ }
+}
+
+jint WebCoreResourceLoader::CreateResponse(JNIEnv* env, jobject obj, jstring url, jint statusCode,
+ jstring statusText, jstring mimeType, jlong expectedLength,
+ jstring encoding, jlong expireTime)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterRC counter;
+#endif
+ LOG_ASSERT(url, "Must have a url in the response!");
+ const char* urlStr = env->GetStringUTFChars(url, NULL);
+ const char* encodingStr = NULL;
+ const char* mimeTypeStr = NULL;
+ if (mimeType) {
+ mimeTypeStr = env->GetStringUTFChars(mimeType, NULL);
+ LOGV("Response setMIMEType: %s", mimeTypeStr);
+ }
+ if (encoding) {
+ encodingStr = env->GetStringUTFChars(encoding, NULL);
+ LOGV("Response setTextEncodingName: %s", encodingStr);
+ }
+ WebCore::ResourceResponse* response = new WebCore::ResourceResponse(WebCore::KURL(urlStr),
+ mimeTypeStr, (long long)expectedLength, encodingStr, WebCore::String());
+ response->setHTTPStatusCode(statusCode);
+ if (statusText) {
+ const char* statusStr = env->GetStringUTFChars(statusText, NULL);
+ response->setHTTPStatusText(statusStr);
+ LOGV("Response setStatusText: %s", statusStr);
+ env->ReleaseStringUTFChars(statusText, statusStr);
+ }
+ // FIXME: This assumes that time_t is a long and that long is the same size as int.
+ if ((unsigned long)expireTime > INT_MAX)
+ expireTime = INT_MAX;
+ response->setExpirationDate((time_t)expireTime);
+ if (encoding)
+ env->ReleaseStringUTFChars(encoding, encodingStr);
+ if (mimeType)
+ env->ReleaseStringUTFChars(mimeType, mimeTypeStr);
+ env->ReleaseStringUTFChars(url, urlStr);
+ return (int)response;
+}
+
+void WebCoreResourceLoader::ReceivedResponse(JNIEnv* env, jobject obj, jint nativeResponse)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterRC counter;
+#endif
+ WebCore::ResourceHandle* handle = GET_NATIVE_HANDLE(env, obj);
+ LOG_ASSERT(handle, "nativeReceivedResponse must take a valid handle!");
+ // ResourceLoader::didFail() can set handle to be NULL, we need to check
+ if (!handle)
+ return;
+
+ WebCore::ResourceResponse* response = (WebCore::ResourceResponse*)nativeResponse;
+ LOG_ASSERT(response, "nativeReceivedResponse must take a valid resource pointer!");
+ handle->client()->didReceiveResponse(handle, *response);
+ // As the client makes a copy of the response, delete it here.
+ delete response;
+}
+
+void WebCoreResourceLoader::AddData(JNIEnv* env, jobject obj, jbyteArray dataArray, jint length)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterRC counter;
+#endif
+ LOGV("webcore_resourceloader data(%d)", length);
+
+ WebCore::ResourceHandle* handle = GET_NATIVE_HANDLE(env, obj);
+ LOG_ASSERT(handle, "nativeAddData must take a valid handle!");
+ // ResourceLoader::didFail() can set handle to be NULL, we need to check
+ if (!handle)
+ return;
+
+ SkAutoMemoryUsageProbe mup("android_webcore_resourceloader_nativeAddData");
+
+ bool result = false;
+ jbyte * data = env->GetByteArrayElements(dataArray, NULL);
+
+ LOG_ASSERT(handle->client(), "Why do we not have a client?");
+ handle->client()->didReceiveData(handle, (const char *)data, length, length);
+ env->ReleaseByteArrayElements(dataArray, data, JNI_ABORT);
+}
+
+void WebCoreResourceLoader::Finished(JNIEnv* env, jobject obj)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterRC counter;
+#endif
+ LOGV("webcore_resourceloader finished");
+ WebCore::ResourceHandle* handle = GET_NATIVE_HANDLE(env, obj);
+ LOG_ASSERT(handle, "nativeFinished must take a valid handle!");
+ // ResourceLoader::didFail() can set handle to be NULL, we need to check
+ if (!handle)
+ return;
+
+ LOG_ASSERT(handle->client(), "Why do we not have a client?");
+ handle->client()->didFinishLoading(handle);
+}
+
+jstring WebCoreResourceLoader::RedirectedToUrl(JNIEnv* env, jobject obj,
+ jstring baseUrl, jstring redirectTo, jint nativeResponse)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterRC counter;
+#endif
+ LOGV("webcore_resourceloader redirectedToUrl");
+ WebCore::ResourceHandle* handle = GET_NATIVE_HANDLE(env, obj);
+ LOG_ASSERT(handle, "nativeRedirectedToUrl must take a valid handle!");
+ // ResourceLoader::didFail() can set handle to be NULL, we need to check
+ if (!handle)
+ return NULL;
+
+ const char* baseStr = env->GetStringUTFChars(baseUrl, NULL);
+ const char* redirectStr = env->GetStringUTFChars(redirectTo, NULL);
+ LOG_ASSERT(handle->client(), "Why do we not have a client?");
+ WebCore::ResourceRequest r = handle->request();
+ WebCore::KURL url(baseStr, redirectStr);
+ r.setURL(url);
+ if (r.httpMethod() == "POST")
+ r.setHTTPMethod("GET");
+ env->ReleaseStringUTFChars(baseUrl, baseStr);
+ env->ReleaseStringUTFChars(redirectTo, redirectStr);
+ WebCore::ResourceResponse* response = (WebCore::ResourceResponse*)nativeResponse;
+ // If the url fails to resolve the relative path, return null.
+ if (url.protocol().isEmpty()) {
+ delete response;
+ return NULL;
+ }
+ handle->client()->willSendRequest(handle, r, *response);
+ delete response;
+ WebCore::String s = url.string();
+ return env->NewString((unsigned short*)s.characters(), s.length());
+}
+
+void WebCoreResourceLoader::Error(JNIEnv* env, jobject obj, jint id, jstring description,
+ jstring failingUrl)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterRC counter;
+#endif
+ LOGV("webcore_resourceloader error");
+ WebCore::ResourceHandle* handle = GET_NATIVE_HANDLE(env, obj);
+ LOG_ASSERT(handle, "nativeError must take a valid handle!");
+ // ResourceLoader::didFail() can set handle to be NULL, we need to check
+ if (!handle)
+ return;
+
+ const char* descStr = env->GetStringUTFChars(description, NULL);
+ const char* failUrl = env->GetStringUTFChars(failingUrl, NULL);
+ handle->client()->didFail(handle, WebCore::ResourceError("", id,
+ WebCore::String(failUrl), WebCore::String(descStr)));
+ env->ReleaseStringUTFChars(failingUrl, failUrl);
+ env->ReleaseStringUTFChars(description, descStr);
+}
+
+// ----------------------------------------------------------------------------
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gResourceloaderMethods[] = {
+ /* name, signature, funcPtr */
+ { "nativeSetResponseHeader", "(ILjava/lang/String;Ljava/lang/String;)V",
+ (void*) WebCoreResourceLoader::SetResponseHeader },
+ { "nativeCreateResponse", "(Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;JLjava/lang/String;J)I",
+ (void*) WebCoreResourceLoader::CreateResponse },
+ { "nativeReceivedResponse", "(I)V",
+ (void*) WebCoreResourceLoader::ReceivedResponse },
+ { "nativeAddData", "([BI)V",
+ (void*) WebCoreResourceLoader::AddData },
+ { "nativeFinished", "()V",
+ (void*) WebCoreResourceLoader::Finished },
+ { "nativeRedirectedToUrl", "(Ljava/lang/String;Ljava/lang/String;I)Ljava/lang/String;",
+ (void*) WebCoreResourceLoader::RedirectedToUrl },
+ { "nativeError", "(ILjava/lang/String;Ljava/lang/String;)V",
+ (void*) WebCoreResourceLoader::Error }
+};
+
+int register_resource_loader(JNIEnv* env)
+{
+ jclass resourceLoader = env->FindClass("android/webkit/LoadListener");
+ LOG_FATAL_IF(resourceLoader == NULL,
+ "Unable to find class android/webkit/LoadListener");
+
+ gResourceLoader.mObject =
+ env->GetFieldID(resourceLoader, "mNativeLoader", "I");
+ LOG_FATAL_IF(gResourceLoader.mObject == NULL,
+ "Unable to find android/webkit/LoadListener.mNativeLoader");
+
+ gResourceLoader.mCancelMethodID =
+ env->GetMethodID(resourceLoader, "cancel", "()V");
+ LOG_FATAL_IF(gResourceLoader.mCancelMethodID == NULL,
+ "Could not find method cancel on LoadListener");
+
+ gResourceLoader.mDownloadFileMethodID =
+ env->GetMethodID(resourceLoader, "downloadFile", "()V");
+ LOG_FATAL_IF(gResourceLoader.mDownloadFileMethodID == NULL,
+ "Could not find method downloadFile on LoadListener");
+
+ gResourceLoader.mWillLoadFromCacheMethodID =
+ env->GetStaticMethodID(resourceLoader, "willLoadFromCache", "(Ljava/lang/String;)Z");
+ LOG_FATAL_IF(gResourceLoader.mWillLoadFromCacheMethodID == NULL,
+ "Could not find static method willLoadFromCache on LoadListener");
+
+ return jniRegisterNativeMethods(env, "android/webkit/LoadListener",
+ gResourceloaderMethods, NELEM(gResourceloaderMethods));
+}
+
+} /* namespace android */
+
diff --git a/WebCore/platform/android/jni/WebCoreResourceLoader.h b/WebCore/platform/android/jni/WebCoreResourceLoader.h
new file mode 100644
index 0000000..e3b3cc7
--- /dev/null
+++ b/WebCore/platform/android/jni/WebCoreResourceLoader.h
@@ -0,0 +1,67 @@
+/* //device/libs/android_runtime/android_webcore_resource_loader.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef ANDROID_WEBKIT_RESOURCELOADLISTENER_H
+#define ANDROID_WEBKIT_RESOURCELOADLISTENER_H
+
+#include "KURL.h"
+
+#include "WebCoreRefObject.h"
+#include <jni.h>
+
+namespace android {
+
+class WebCoreResourceLoader : public WebCoreRefObject
+{
+public:
+ WebCoreResourceLoader(JNIEnv *env, jobject jLoadListener);
+ virtual ~WebCoreResourceLoader();
+
+ /**
+ * Call to java to cancel the current load.
+ */
+ void cancel();
+
+ /**
+ * Call to java to download the current load rather than feed it
+ * back to WebCore
+ */
+ void downloadFile();
+
+ /**
+ * Call to java to find out if this URL is in the cache
+ */
+ static bool willLoadFromCache(const WebCore::KURL& url);
+
+ // Native jni functions
+ static void SetResponseHeader(JNIEnv*, jobject, jint, jstring, jstring);
+ static jint CreateResponse(JNIEnv*, jobject, jstring, jint, jstring,
+ jstring, jlong, jstring, jlong);
+ static void ReceivedResponse(JNIEnv*, jobject, jint);
+ static void AddData(JNIEnv*, jobject, jbyteArray, jint);
+ static void Finished(JNIEnv*, jobject);
+ static jstring RedirectedToUrl(JNIEnv*, jobject, jstring, jstring, jint);
+ static void Error(JNIEnv*, jobject, jint, jstring, jstring);
+
+private:
+ JavaVM* mJvm;
+ jobject mJLoader;
+};
+
+} // end namespace android
+
+#endif
diff --git a/WebCore/platform/android/jni/WebCoreViewBridge.h b/WebCore/platform/android/jni/WebCoreViewBridge.h
new file mode 100644
index 0000000..58aa953
--- /dev/null
+++ b/WebCore/platform/android/jni/WebCoreViewBridge.h
@@ -0,0 +1,191 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef WEBCORE_VIEW_BRIDGE_H
+#define WEBCORE_VIEW_BRIDGE_H
+
+#include "IntRect.h"
+#include "SkTDArray.h"
+#include "WebCoreRefObject.h"
+#include "Widget.h"
+#include <ui/KeycodeLabels.h>
+#include <stdlib.h>
+namespace WebCore
+{
+ class GraphicsContext;
+ class Node;
+ class StringImpl;
+ class String;
+ class RenderText;
+ class Frame;
+ class FrameView;
+}
+
+class WebCoreReply : public WebCoreRefObject {
+public:
+ virtual ~WebCoreReply() {}
+
+ virtual void replyInt(int value) {
+ SkDEBUGF(("WebCoreReply::replyInt(%d) not handled\n", value));
+ }
+
+ virtual void replyIntArray(SkTDArray<int> array) {
+ SkDEBUGF(("WebCoreReply::replyIntArray() not handled\n"));
+ }
+ // add more replyFoo signatures as needed
+};
+
+class WebCoreViewBridge : public WebCoreRefObject {
+public:
+ WebCoreViewBridge(): mBounds(0,0,0,0), mScreenWidth(0), mScale(100),
+ mWidget(NULL), mParent(NULL) {}
+ virtual ~WebCoreViewBridge() { Release(mParent); }
+
+ virtual void setParent(WebCoreViewBridge* parent) {Release(mParent); mParent = parent; Retain(mParent); }
+ virtual WebCoreViewBridge* getParent() { return mParent; }
+
+ // these are needed for WidgetAndroid.cpp
+ virtual void draw(WebCore::GraphicsContext* ctx,
+ const WebCore::IntRect& rect, bool invalCache) = 0;
+ virtual void layout() {}
+ virtual bool isEnabled() const { return true; }
+ virtual void setEnabled(bool) {}
+ virtual bool hasFocus() const { return true; }
+ virtual void setFocus(bool) {}
+ virtual void didFirstLayout() {}
+ virtual void restoreScale(int) {}
+
+ // Used by the page cache
+ virtual void setView(WebCore::FrameView* view) {}
+
+ const WebCore::IntRect& getBounds() const
+ {
+ return mBounds;
+ }
+ virtual void setBounds(int left, int top, int right, int bottom)
+ {
+ this->setLocation(left, top);
+ this->setSize(right - left, bottom - top);
+ }
+ virtual int getMaxXScroll() const { return width() >> 2; }
+ virtual int getMaxYScroll() const { return height() >> 2; }
+ virtual void notifyFocusSet() {}
+ virtual void notifyProgressFinished() {}
+ // Subclasses should implement this if they want to do something after being resized
+ virtual void onResize() {}
+
+ // These are referenced by Scrollview (and others)
+ virtual bool scrollIntoView(WebCore::IntRect rect, bool force) { return false; }
+ virtual void scrollTo(int x, int y, bool animate=false) {}
+ virtual void scrollBy(int x, int y) {}
+ virtual void contentInvalidate(const WebCore::IntRect &rect)
+ {
+ if (mParent)
+ mParent->contentInvalidate(rect);
+ }
+ virtual void contentInvalidate()
+ {
+ if (mParent)
+ mParent->contentInvalidate();
+ }
+ // invalidate the view/display, NOT the content/DOM
+ virtual void viewInvalidate()
+ {
+ if (mParent)
+ mParent->viewInvalidate();
+ }
+
+ // these need not be virtual
+ //
+ void setSize(int w, int h)
+ {
+ int ow = width();
+ int oh = height();
+ mBounds.setWidth(w);
+ mBounds.setHeight(h);
+ // Only call onResize if the new size is different.
+ if (w != ow || h != oh)
+ onResize();
+ }
+
+ // used by layout when it needs to wrap content column around screen
+ void setSizeScreenWidthAndScale(int w, int h, int screenWidth, int scale)
+ {
+ int ow = width();
+ int oh = height();
+ int osw = mScreenWidth;
+ mBounds.setWidth(w);
+ mBounds.setHeight(h);
+ mScreenWidth = screenWidth;
+ mScale = scale;
+ // Only call onResize if the new size is different.
+ if (w != ow || h != oh || screenWidth != osw)
+ onResize();
+ }
+
+ void setLocation(int x, int y)
+ {
+ mBounds.setX(x);
+ mBounds.setY(y);
+ }
+
+ int width() const { return mBounds.width(); }
+ int height() const { return mBounds.height(); }
+ int locX() const { return mBounds.x(); }
+ int locY() const { return mBounds.y(); }
+ int screenWidth() const { return mParent ? mParent->screenWidth() : mScreenWidth; }
+ int scale() const { return mParent ? mParent->scale() : mScale; }
+
+ // called by RenderPopupMenuAndroid
+ virtual void popupRequest(WebCoreReply* reply,
+ int currIndex,
+ const uint16_t** labels, // the first short is the length (number of following shorts)
+ size_t labelCount, // the number of label strings
+ const int enabled[], // bools telling which corresponding labels are selectable
+ size_t enabledCount) // length of the enabled array, which should equal labelCount
+ {
+ if (mParent)
+ mParent->popupRequest(reply, currIndex, labels, labelCount, enabled, enabledCount);
+ }
+
+ //implemented in android_widget_htmlwidget
+ virtual void removeFrameGeneration(WebCore::Frame* ) {}
+ virtual void updateFrameGeneration(WebCore::Frame* ) {}
+ virtual void jsAlert(const WebCore::String& url, const WebCore::String& text) { }
+ virtual bool jsConfirm(const WebCore::String& url, const WebCore::String& text) { return false; }
+ virtual bool jsPrompt(const WebCore::String& url, const WebCore::String& message, const WebCore::String& defaultValue, WebCore::String& result) { return false;}
+ virtual bool jsUnload(const WebCore::String& url, const WebCore::String& message) { return false; }
+
+ virtual void updateTextfield(WebCore::Node* pointer, bool changeToPassword, const WebCore::String& text)
+ {
+ if (mParent)
+ mParent->updateTextfield(pointer, changeToPassword, text);
+ }
+
+ void setWidget(WebCore::Widget* w) { mWidget = w; }
+ WebCore::Widget* widget() { return mWidget; }
+
+private:
+ WebCore::IntRect mBounds;
+ int mScreenWidth;
+ int mScale;
+ WebCore::Widget* mWidget;
+protected:
+ WebCoreViewBridge* mParent;
+};
+
+#endif // WEBCORE_VIEW_BRIDGE_H
diff --git a/WebCore/platform/android/jni/WebHistory.cpp b/WebCore/platform/android/jni/WebHistory.cpp
new file mode 100644
index 0000000..4248c68
--- /dev/null
+++ b/WebCore/platform/android/jni/WebHistory.cpp
@@ -0,0 +1,969 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#define LOG_TAG "webhistory"
+
+#include <config.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/Platform.h>
+
+#include "WebHistory.h"
+
+#include "BackForwardList.h"
+#include "CString.h"
+#include "DocumentLoader.h"
+#include "Frame.h"
+#include "FrameLoader.h"
+#include "FrameLoaderClientAndroid.h"
+#include "FrameTree.h"
+#include "HistoryItem.h"
+#include "Page.h"
+#include "TextEncoding.h"
+#include "WebCoreFrameBridge.h"
+
+#undef LOG
+#include <JNIHelp.h>
+#include <SkUtils.h>
+#include <utils/Log.h>
+#include <utils/misc.h>
+
+namespace android {
+
+// Forward declarations
+static void write_item(WTF::Vector<char>& v, WebCore::HistoryItem* item);
+static void write_children_recursive(WTF::Vector<char>& v, WebCore::HistoryItem* parent);
+static bool read_item_recursive(WebCore::HistoryItem* child, const char** pData, int length);
+
+// Field ids for WebHistoryItems
+struct WebHistoryItemFields {
+ jmethodID mInit;
+ jmethodID mUpdate;
+ jfieldID mTitle;
+ jfieldID mUrl;
+} gWebHistoryItem;
+
+struct WebBackForwardListFields {
+ jmethodID mAddHistoryItem;
+ jmethodID mRemoveHistoryItem;
+ jfieldID mCurrentIndex;
+} gWebBackForwardList;
+
+//--------------------------------------------------------------------------
+// WebBackForwardList native methods.
+//--------------------------------------------------------------------------
+
+static void WebHistoryClose(JNIEnv* env, jobject obj, jint frame)
+{
+ LOG_ASSERT(frame, "Close needs a valid Frame pointer!");
+ WebCore::Frame* pFrame = (WebCore::Frame*)frame;
+
+ WebCore::BackForwardList* list = pFrame->page()->backForwardList();
+ RefPtr<WebCore::HistoryItem> current = list->currentItem();
+ // Remove each item instead of using close(). close() is intended to be used
+ // right before the list is deleted.
+ WebCore::HistoryItemVector& entries = list->entries();
+ int size = entries.size();
+ for (int i = size - 1; i >= 0; --i)
+ list->removeItem(entries[i].get());
+ // Add the current item back to the list.
+ if (current) {
+ current->setBridge(NULL);
+ // addItem will update the children to match the newly created bridge
+ list->addItem(current);
+
+ /*
+ * The Grand Prix site uses anchor navigations to change the display.
+ * WebKit tries to be smart and not load child frames that have the
+ * same history urls during an anchor navigation. This means that the
+ * current history item stored in the child frame's loader does not
+ * match the item found in the history tree. If we remove all the
+ * entries in the back/foward list, we have to restore the entire tree
+ * or else a HistoryItem might have a deleted parent.
+ *
+ * In order to restore the history tree correctly, we have to look up
+ * all the frames first and then look up the history item. We do this
+ * because the history item in the tree may be null at this point.
+ * Unfortunately, a HistoryItem can only search its immediately
+ * children so we do a breadth-first rebuild of the tree.
+ */
+
+ // Keep a small list of child frames to traverse.
+ WTF::Vector<WebCore::Frame*> frameQueue;
+ // Fix the top-level item.
+ pFrame->loader()->setCurrentHistoryItem(current);
+ WebCore::Frame* child = pFrame->tree()->firstChild();
+ // Remember the parent history item so we can search for a child item.
+ RefPtr<WebCore::HistoryItem> parent = current;
+ while (child) {
+ // Use the old history item since the current one may have a
+ // deleted parent.
+ WebCore::HistoryItem* item = parent->childItemWithName(child->tree()->name());
+ child->loader()->setCurrentHistoryItem(item);
+ // Append the first child to the queue if it exists.
+ if (WebCore::Frame* f = child->tree()->firstChild())
+ frameQueue.append(f);
+ child = child->tree()->nextSibling();
+ // If we don't have a sibling for this frame and the queue isn't
+ // empty, use the next entry in the queue.
+ if (!child && !frameQueue.isEmpty()) {
+ child = frameQueue.at(0);
+ frameQueue.remove(0);
+ // Figure out the parent history item used when searching for
+ // the history item to use.
+ parent = child->tree()->parent()->loader()->currentHistoryItem();
+ }
+ }
+ }
+}
+
+static void WebHistoryRestoreIndex(JNIEnv* env, jobject obj, jint frame, jint index)
+{
+ LOG_ASSERT(frame, "RestoreState needs a valid Frame pointer!");
+ WebCore::Frame* pFrame = (WebCore::Frame*)frame;
+
+ // Set the current index in the list.
+ WebCore::BackForwardList* list = pFrame->page()->backForwardList();
+ WebCore::HistoryItem* currentItem = list->entries()[index].get();
+ list->goToItem(currentItem);
+
+ // Update the current and previous history item.
+ WebCore::FrameLoader* loader = pFrame->loader();
+ loader->setCurrentHistoryItem(currentItem);
+ loader->setPreviousHistoryItem(list->backItem());
+
+ // Update the request with the current item's info.
+ WebCore::ResourceRequest& request = loader->documentLoader()->request();
+ request.setURL(currentItem->url());
+ request.setMainDocumentURL(currentItem->url());
+ if (currentItem->originalFormData()) {
+ request.setHTTPMethod("POST");
+ request.setHTTPContentType(currentItem->formContentType());
+ request.setHTTPReferrer(currentItem->formReferrer());
+ request.setHTTPBody(currentItem->formData());
+ }
+
+ // Reload the current page
+ loader->reloadAllowingStaleData(loader->documentLoader()->overrideEncoding());
+}
+
+static void WebHistoryInflate(JNIEnv* env, jobject obj, jint frame, jbyteArray data)
+{
+ LOG_ASSERT(frame, "Inflate needs a valid frame pointer!");
+ LOG_ASSERT(data, "Inflate needs a valid data pointer!");
+
+ // Get the actual bytes and the length from the java array.
+ jbyte* bytes = env->GetByteArrayElements(data, NULL);
+ jsize size = env->GetArrayLength(data);
+
+ // Inflate the history tree into one HistoryItem or null if the inflation
+ // failed.
+ WebCore::HistoryItem* newItem = new WebCore::HistoryItem();
+#ifdef ANDROID_HISTORY_CLIENT
+ RefPtr<WebHistoryItem> bridge = new WebHistoryItem(env, obj, newItem);
+ newItem->setBridge(bridge.get());
+#endif
+ // Inflate the item recursively. If it fails, that is ok. We'll have an
+ // incomplete HistoryItem but that is better than crashing due to a null
+ // item.
+ read_item_recursive(newItem, (const char**)&bytes, (int)size);
+#ifdef ANDROID_HISTORY_CLIENT
+ bridge->setActive();
+#endif
+
+ // Add the new item to the back/forward list.
+ WebCore::Frame* pFrame = (WebCore::Frame*)frame;
+ pFrame->page()->backForwardList()->addItem(newItem);
+
+#ifdef ANDROID_HISTORY_CLIENT
+ // Update the item.
+ bridge->updateHistoryItem(newItem);
+#endif
+}
+
+// 7 empty strings + no document state + children count = 9 unsigned values
+// 1 char for isTargetItem
+// ANDROID_HISTORY_CLIENT adds 2 ints for scale and traversals.
+#ifdef ANDROID_HISTORY_CLIENT
+#ifdef ANDROID_FIX
+#define HISTORY_MIN_SIZE ((int)(sizeof(unsigned) * 14 + sizeof(char)))
+#else
+#define HISTORY_MIN_SIZE ((int)(sizeof(unsigned) * 11 + sizeof(char)))
+#endif
+#else
+#ifdef ANDROID_FIX
+#define HISTORY_MIN_SIZE ((int)(sizeof(unsigned) * 12 + sizeof(char)))
+#else
+#define HISTORY_MIN_SIZE ((int)(sizeof(unsigned) * 9 + sizeof(char)))
+#endif
+#endif
+
+jbyteArray WebHistory::Flatten(JNIEnv* env, WTF::Vector<char>& v, WebCore::HistoryItem* item)
+{
+ if (!item)
+ return NULL;
+
+ // Reserve a vector of chars with an initial size of HISTORY_MIN_SIZE.
+ v.reserveCapacity(HISTORY_MIN_SIZE);
+
+ // Write the top-level history item and then write all the children
+ // recursively.
+#ifdef ANDROID_HISTORY_CLIENT
+ LOG_ASSERT(item->bridge(), "Why don't we have a bridge object here?");
+#endif
+ write_item(v, item);
+ write_children_recursive(v, item);
+
+ // Try to create a new java byte array.
+ jbyteArray b = env->NewByteArray(v.size());
+ if (!b)
+ return NULL;
+
+ // Write our flattened data to the java array.
+ jbyte* bytes = env->GetByteArrayElements(b, NULL);
+ memcpy(bytes, v.data(), v.size());
+ env->ReleaseByteArrayElements(b, bytes, 0);
+ return b;
+}
+
+WebHistoryItem::WebHistoryItem(JNIEnv* env, jobject obj,
+ WebCore::HistoryItem* item) {
+ JavaVM* vm;
+ mJVM = env->GetJavaVM(&vm) >= 0 ? vm : NULL;
+ mObject = env->NewGlobalRef(obj);
+ mScale = 100;
+ mTraversals = -1;
+ mActive = false;
+ mParent = NULL;
+ mHistoryItem = item;
+}
+
+WebHistoryItem::~WebHistoryItem() {
+ if (mObject) {
+ JNIEnv* env;
+ env = mJVM->GetEnv((void **)&env, JNI_VERSION_1_4) >= 0 ? env : NULL;
+ if (!env)
+ return;
+ env->DeleteGlobalRef(mObject);
+ }
+}
+
+void WebHistoryItem::updateHistoryItem(WebCore::HistoryItem* item) {
+#ifdef ANDROID_HISTORY_CLIENT
+ // Do not want to update during inflation.
+ if (!mActive)
+ return;
+ WebHistoryItem* webItem = this;
+ // Now we need to update the top-most WebHistoryItem based on the top-most
+ // HistoryItem.
+ if (mParent) {
+ webItem = mParent.get();
+ if (webItem->hasOneRef()) {
+ // if the parent only has one ref, it is from this WebHistoryItem.
+ // This means that the matching WebCore::HistoryItem has been freed.
+ // This can happen during clear().
+ LOGW("Can't updateHistoryItem as the top HistoryItem is gone");
+ return;
+ }
+ while (webItem->parent())
+ webItem = webItem->parent();
+ item = webItem->historyItem();
+ }
+ JNIEnv* env;
+ env = webItem->mJVM->GetEnv((void **)&env, JNI_VERSION_1_4) >= 0 ? env : NULL;
+ if (!env)
+ return;
+ const WebCore::String& urlString = item->urlString();
+ jstring urlStr = NULL;
+ if (!urlString.isNull())
+ urlStr = env->NewString((unsigned short*)urlString.characters(), urlString.length());
+ const WebCore::String& titleString = item->title();
+ jstring titleStr = NULL;
+ if (!titleString.isNull())
+ titleStr = env->NewString((unsigned short*)titleString.characters(), titleString.length());
+
+ // Try to get the favicon from the history item. For some pages like Grand
+ // Prix, there are history items with anchors. If the icon fails for the
+ // item, try to get the icon using the url without the ref.
+ jobject favicon = NULL;
+ WebCore::String url = item->urlString();
+ if (item->url().hasRef()) {
+ int refIndex = url.reverseFind('#');
+ url = url.substring(0, refIndex);
+ }
+ WebCore::Image* icon = WebCore::iconDatabase()->iconForPageURL(url,
+ WebCore::IntSize(16, 16));
+
+ if (icon)
+ favicon = webcoreImageToJavaBitmap(env, icon);
+
+ WTF::Vector<char> data;
+ jbyteArray array = WebHistory::Flatten(env, data, item);
+ env->CallVoidMethod(webItem->mObject, gWebHistoryItem.mUpdate, urlStr, titleStr, favicon, array);
+ env->DeleteLocalRef(urlStr);
+ env->DeleteLocalRef(titleStr);
+ if (favicon)
+ env->DeleteLocalRef(favicon);
+ env->DeleteLocalRef(array);
+#endif
+}
+
+static void historyItemChanged(WebCore::HistoryItem* item) {
+#ifdef ANDROID_HISTORY_CLIENT
+ LOG_ASSERT(item,
+ "historyItemChanged called with a null item");
+ if (item->bridge())
+ item->bridge()->updateHistoryItem(item);
+#endif
+}
+
+void WebHistory::AddItem(JNIEnv* env, jobject list, WebCore::HistoryItem* item)
+{
+#ifdef ANDROID_HISTORY_CLIENT
+ LOG_ASSERT(item, "newItem must take a valid HistoryItem!");
+ // Item already added. Should only happen when we are inflating the list.
+ if (item->bridge())
+ return;
+
+ // Allocate a blank WebHistoryItem
+ jclass clazz = env->FindClass("android/webkit/WebHistoryItem");
+ jobject newItem = env->NewObject(clazz, gWebHistoryItem.mInit);
+
+ // Create the bridge, make it active, and attach it to the item.
+ WebHistoryItem* bridge = new WebHistoryItem(env, newItem, item);
+ bridge->setActive();
+ item->setBridge(bridge);
+
+ // Update the history item which will flatten the data and call update on
+ // the java item.
+ bridge->updateHistoryItem(item);
+
+ // Add it to the list.
+ env->CallVoidMethod(list, gWebBackForwardList.mAddHistoryItem, newItem);
+
+ // Delete our local reference.
+ env->DeleteLocalRef(newItem);
+#endif
+}
+
+void WebHistory::RemoveItem(JNIEnv* env, jobject list, int index)
+{
+ env->CallVoidMethod(list, gWebBackForwardList.mRemoveHistoryItem, index);
+}
+
+void WebHistory::UpdateHistoryIndex(JNIEnv* env, jobject list, int newIndex)
+{
+ env->SetIntField(list, gWebBackForwardList.mCurrentIndex, newIndex);
+}
+
+static void write_string(WTF::Vector<char>& v, const WebCore::String& str)
+{
+ unsigned strLen = str.length();
+ // Only do work if the string has data.
+ if (strLen) {
+ // Determine how much to grow the vector. Use the worst case for utf8 to
+ // avoid reading the string twice. Add sizeof(unsigned) to hold the
+ // string length in utf8.
+ unsigned vectorLen = v.size() + sizeof(unsigned);
+ unsigned length = (strLen << 2) + vectorLen;
+ // Grow the vector. This will change the value of v.size() but we
+ // remember the original size above.
+ v.grow(length);
+ // Grab the position to write to.
+ char* data = v.begin() + vectorLen;
+ // Write the actual string
+ int l = SkUTF16_ToUTF8(str.characters(), strLen, data);
+ LOGV("Writing string %d %.*s", l, l, data);
+ // Go back and write the utf8 length. Subtract sizeof(unsigned) from
+ // data to get the position to write the length.
+ memcpy(data - sizeof(unsigned), (char*)&l, sizeof(unsigned));
+ // Shrink the internal state of the vector so we match what was
+ // actually written.
+ v.shrink(vectorLen + l);
+ } else
+ v.append((char*)&strLen, sizeof(unsigned));
+}
+
+static void write_item(WTF::Vector<char>& v, WebCore::HistoryItem* item)
+{
+ // Original url
+ write_string(v, item->originalURLString());
+
+ // Url
+ write_string(v, item->urlString());
+
+ // Title
+ write_string(v, item->title());
+
+ // Form content type
+ write_string(v, item->formContentType());
+
+ // Form referrer
+ write_string(v, item->formReferrer());
+
+ // Form data
+ const WebCore::FormData* formData = item->formData();
+ if (formData)
+ write_string(v, formData->flattenToString());
+ else
+ write_string(v, WebCore::String()); // Empty constructor does not allocate a buffer.
+
+#ifdef ANDROID_FIX
+ // original form content type
+ write_string(v, item->originalFormContentType());
+
+ // original form referrer
+ write_string(v, item->originalFormReferrer());
+
+ // original form data
+ const WebCore::FormData* origformData = item->originalFormData();
+ if (origformData)
+ write_string(v, origformData->flattenToString());
+ else
+ write_string(v, WebCore::String()); // Empty constructor does not allocate a buffer.
+#endif
+
+ // Target
+ write_string(v, item->target());
+
+#ifdef ANDROID_HISTORY_CLIENT
+ WebHistoryItem* bridge = item->bridge();
+ LOG_ASSERT(bridge, "We should have a bridge here!");
+ // Screen scale
+ int scale = bridge->scale();
+ LOGV("Writing scale %d", scale);
+ v.append((char*)&scale, sizeof(int));
+
+ // Focus position
+ int traversals = bridge->traversals();
+ LOGV("Writing traversals %d", traversals);
+ v.append((char*)&traversals, sizeof(int));
+#endif
+
+ // Document state
+ const WTF::Vector<WebCore::String>& docState = item->documentState();
+ WTF::Vector<WebCore::String>::const_iterator end = docState.end();
+ unsigned stateSize = docState.size();
+ LOGV("Writing docState %d", stateSize);
+ v.append((char*)&stateSize, sizeof(unsigned));
+ for (WTF::Vector<WebCore::String>::const_iterator i = docState.begin(); i != end; ++i) {
+ write_string(v, *i);
+ }
+
+ // Is target item
+ LOGV("Writing isTargetItem %d", item->isTargetItem());
+ v.append((char)item->isTargetItem());
+
+ // Children count
+ unsigned childCount = item->children().size();
+ LOGV("Writing childCount %d", childCount);
+ v.append((char*)&childCount, sizeof(unsigned));
+}
+
+static void write_children_recursive(WTF::Vector<char>& v, WebCore::HistoryItem* parent)
+{
+ const WebCore::HistoryItemVector& children = parent->children();
+ WebCore::HistoryItemVector::const_iterator end = children.end();
+ for (WebCore::HistoryItemVector::const_iterator i = children.begin(); i != end; ++i) {
+ WebCore::HistoryItem* item = (*i).get();
+#ifdef ANDROID_HISTORY_CLIENT
+ LOG_ASSERT(parent->bridge(),
+ "The parent item should have a bridge object!");
+ if (!item->bridge()) {
+ WebHistoryItem* bridge = new WebHistoryItem(parent->bridge());
+ item->setBridge(bridge);
+ bridge->setActive();
+ } else {
+ // The only time this item's parent may not be the same as the
+ // parent's bridge is during history close. In that case, the
+ // parent must not have a parent bridge.
+ LOG_ASSERT(parent->bridge()->parent() == NULL ||
+ item->bridge()->parent() == parent->bridge(),
+ "Somehow this item has an incorrect parent");
+ item->bridge()->setParent(parent->bridge());
+ }
+#endif
+ write_item(v, item);
+ write_children_recursive(v, item);
+ }
+}
+
+static bool read_item_recursive(WebCore::HistoryItem* newItem,
+ const char** pData, int length)
+{
+ if (!pData || length < HISTORY_MIN_SIZE)
+ return false;
+
+ const WebCore::TextEncoding& e = WebCore::UTF8Encoding();
+ const char* data = *pData;
+ const char* end = data + length;
+ int sizeofUnsigned = (int)sizeof(unsigned);
+
+ // Read the original url
+ // Read the expected length of the string.
+ int l;
+ memcpy(&l, data, sizeofUnsigned);
+ // Increment data pointer by the size of an unsigned int.
+ data += sizeofUnsigned;
+ if (l) {
+ LOGV("Original url %d %.*s", l, l, data);
+ // If we have a length, check if that length exceeds the data length
+ // and return null if there is not enough data.
+ if (data + l < end)
+ newItem->setOriginalURLString(e.decode(data, l));
+ else
+ return false;
+ // Increment the data pointer by the length of the string.
+ data += l;
+ }
+ // Check if we have enough data left to continue.
+ if (end - data < sizeofUnsigned)
+ return false;
+
+ // Read the url
+ memcpy(&l, data, sizeofUnsigned);
+ data += sizeofUnsigned;
+ if (l) {
+ LOGV("Url %d %.*s", l, l, data);
+ if (data + l < end)
+ newItem->setURLString(e.decode(data, l));
+ else
+ return false;
+ data += l;
+ }
+ if (end - data < sizeofUnsigned)
+ return false;
+
+ // Read the title
+ memcpy(&l, data, sizeofUnsigned);
+ data += sizeofUnsigned;
+ if (l) {
+ LOGV("Title %d %.*s", l, l, data);
+ if (data + l < end)
+ newItem->setTitle(e.decode(data, l));
+ else
+ return false;
+ data += l;
+ }
+ if (end - data < sizeofUnsigned)
+ return false;
+
+ // Generate a new ResourceRequest object for populating form information.
+ WebCore::String formContentType;
+ WebCore::String formReferrer;
+ WebCore::FormData* formData = NULL;
+
+ // Read the form content type
+ memcpy(&l, data, sizeofUnsigned);
+ data += sizeofUnsigned;
+ if (l) {
+ LOGV("Content type %d %.*s", l, l, data);
+ if (data + l < end)
+ formContentType = e.decode(data, l);
+ else
+ return false;
+ data += l;
+ }
+ if (end - data < sizeofUnsigned)
+ return false;
+
+ // Read the form referrer
+ memcpy(&l, data, sizeofUnsigned);
+ data += sizeofUnsigned;
+ if (l) {
+ LOGV("Referrer %d %.*s", l, l, data);
+ if (data + l < end)
+ formReferrer = e.decode(data, l);
+ else
+ return false;
+ data += l;
+ }
+ if (end - data < sizeofUnsigned)
+ return false;
+
+ // Read the form data
+ memcpy(&l, data, sizeofUnsigned);
+ data += sizeofUnsigned;
+ if (l) {
+ LOGV("Form data %d %.*s", l, l, data);
+ if (data + l < end)
+ formData = new WebCore::FormData(data, l);
+ else
+ return false;
+ data += l;
+ }
+ if (end - data < sizeofUnsigned)
+ return false;
+
+ // Set up the form info
+ if (formData != NULL) {
+ WebCore::ResourceRequest r;
+ r.setHTTPMethod("POST");
+ r.setHTTPContentType(formContentType);
+ r.setHTTPReferrer(formReferrer);
+ r.setHTTPBody(formData);
+ newItem->setFormInfoFromRequest(r);
+ }
+
+#ifdef ANDROID_FIX
+ WebCore::String origformContentType;
+ WebCore::String origformReferrer;
+ WebCore::FormData* origformData = NULL;
+
+ // Read the original form content type
+ memcpy(&l, data, sizeofUnsigned);
+ data += sizeofUnsigned;
+ if (l) {
+ LOGV("Original content type %d %.*s", l, l, data);
+ if (data + l < end)
+ origformContentType = e.decode(data, l);
+ else
+ return false;
+ data += l;
+ }
+ if (end - data < sizeofUnsigned)
+ return false;
+
+ // Read the original form referrer
+ memcpy(&l, data, sizeofUnsigned);
+ data += sizeofUnsigned;
+ if (l) {
+ LOGV("Original referrer %d %.*s", l, l, data);
+ if (data + l < end)
+ origformReferrer = e.decode(data, l);
+ else
+ return false;
+ data += l;
+ }
+ if (end - data < sizeofUnsigned)
+ return false;
+
+ // Read the original form data
+ memcpy(&l, data, sizeofUnsigned);
+ data += sizeofUnsigned;
+ if (l) {
+ LOGV("Original form data %d %.*s", l, l, data);
+ if (data + l < end)
+ origformData = new WebCore::FormData(data, l);
+ else
+ return false;
+ data += l;
+ }
+ if (end - data < sizeofUnsigned)
+ return false;
+
+ if (origformData)
+ newItem->setOriginalFormInfo(origformData, origformContentType, origformReferrer);
+#endif
+
+ // Read the target
+ memcpy(&l, data, sizeofUnsigned);
+ data += sizeofUnsigned;
+ if (l) {
+ LOGV("Target %d %.*s", l, l, data);
+ if (data + l < end)
+ newItem->setTarget(e.decode(data, l));
+ else
+ return false;
+ data += l;
+ }
+ if (end - data < sizeofUnsigned)
+ return false;
+
+#ifdef ANDROID_HISTORY_CLIENT
+ WebHistoryItem* bridge = newItem->bridge();
+ LOG_ASSERT(bridge, "There should be a bridge object during inflate");
+ // Read the screen scale
+ memcpy(&l, data, sizeofUnsigned);
+ LOGV("Screen scale %d", l);
+ bridge->setScale(l);
+ data += sizeofUnsigned;
+ if (end - data < (int)sizeof(int))
+ return false;
+
+ // Read the focus index
+ memcpy(&l, data, sizeof(int));
+ LOGV("Traversals %d", l);
+ bridge->setTraversals(l);
+ data += sizeof(int);
+ if (end - data < sizeofUnsigned)
+ return false;
+#endif
+
+ // Read the document state
+ memcpy(&l, data, sizeofUnsigned);
+ LOGV("Document state %d", l);
+ data += sizeofUnsigned;
+ if (l) {
+ // Check if we have enough data to at least parse the sizes of each
+ // document state string.
+ if (data + l * sizeofUnsigned >= end)
+ return false;
+ // Create a new vector and reserve enough space for the document state.
+ WTF::Vector<WebCore::String> docState;
+ docState.reserveCapacity(l);
+ while (l--) {
+ // Check each time if we have enough to parse the length of the next
+ // string.
+ if (end - data < sizeofUnsigned)
+ return false;
+ int strLen;
+ memcpy(&strLen, data, sizeofUnsigned);
+ data += sizeofUnsigned;
+ if (data + strLen < end)
+ docState.append(e.decode(data, strLen));
+ else
+ return false;
+ LOGV("\t\t%d %.*s", strLen, strLen, data);
+ data += strLen;
+ }
+ newItem->setDocumentState(docState);
+ }
+ // Check if we have enough to read the next byte
+ if (data >= end)
+ return false;
+
+ // Read is target item
+ // Cast the value to unsigned char in order to make a negative value larger
+ // than 1. A value that is not 0 or 1 is a failure.
+ unsigned char c = (unsigned char)data[0];
+ if (c > 1)
+ return false;
+ LOGV("Target item %d", c);
+ newItem->setIsTargetItem((bool)c);
+ data++;
+ if (end - data < sizeofUnsigned)
+ return false;
+
+ // Read the child count
+ memcpy(&l, data, sizeofUnsigned);
+ LOGV("Child count %d", l);
+ data += sizeofUnsigned;
+ *pData = data;
+ if (l) {
+ // Check if we have the minimum amount need to parse l children.
+ if (data + l * HISTORY_MIN_SIZE >= end)
+ return false;
+ while (l--) {
+ // No need to check the length each time because read_item_recursive
+ // will return null if there isn't enough data left to parse.
+ WebCore::HistoryItem* child = new WebCore::HistoryItem();
+#ifdef ANDROID_HISTORY_CLIENT
+ // Set a bridge that will not call into java.
+ child->setBridge(new WebHistoryItem(bridge));
+#endif
+ // Read the child item.
+ if (!read_item_recursive(child, pData, end - data)) {
+ delete child;
+ return false;
+ }
+#ifdef ANDROID_HISTORY_CLIENT
+ child->bridge()->setActive();
+#endif
+ newItem->addChildItem(child);
+ }
+ }
+ return true;
+}
+
+#ifndef NDEBUG
+static void unit_test()
+{
+ LOGD("Entering history unit test!");
+ const char* test1 = new char[0];
+ WebCore::HistoryItem* testItem = new WebCore::HistoryItem();
+#ifdef ANDROID_HISTORY_CLIENT
+ testItem->setBridge(new WebHistoryItem(NULL));
+#endif
+ LOG_ASSERT(!read_item_recursive(testItem, &test1, 0), "0 length array should fail!");
+ delete[] test1;
+ const char* test2 = new char[2];
+ LOG_ASSERT(!read_item_recursive(testItem, &test2, 2), "Small array should fail!");
+ delete[] test2;
+ LOG_ASSERT(!read_item_recursive(testItem, NULL, HISTORY_MIN_SIZE), "Null data should fail!");
+ // Original Url
+ char* test3 = new char[HISTORY_MIN_SIZE];
+ const char* ptr = (const char*)test3;
+ memset(test3, 0, HISTORY_MIN_SIZE);
+ *(int*)test3 = 4000;
+ LOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length originalUrl should fail!");
+ // Url
+ int offset = 4;
+ memset(test3, 0, HISTORY_MIN_SIZE);
+ ptr = (const char*)test3;
+ *(int*)(test3 + offset) = 4000;
+ LOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length url should fail!");
+ // Title
+ offset += 4;
+ memset(test3, 0, HISTORY_MIN_SIZE);
+ ptr = (const char*)test3;
+ *(int*)(test3 + offset) = 4000;
+ LOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length title should fail!");
+ // Form content type
+ offset += 4;
+ memset(test3, 0, HISTORY_MIN_SIZE);
+ ptr = (const char*)test3;
+ *(int*)(test3 + offset) = 4000;
+ LOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length contentType should fail!");
+ // Form referrer
+ offset += 4;
+ memset(test3, 0, HISTORY_MIN_SIZE);
+ ptr = (const char*)test3;
+ *(int*)(test3 + offset) = 4000;
+ LOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length referrer should fail!");
+ // Form data
+ offset += 4;
+ memset(test3, 0, HISTORY_MIN_SIZE);
+ ptr = (const char*)test3;
+ *(int*)(test3 + offset) = 4000;
+ LOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length form data should fail!");
+#ifdef ANDROID_FIX
+ // Original form content type
+ offset += 4;
+ memset(test3, 0, HISTORY_MIN_SIZE);
+ ptr = (const char*)test3;
+ *(int*)(test3 + offset) = 4000;
+ LOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length contentType should fail!");
+ // Original form referrer
+ offset += 4;
+ memset(test3, 0, HISTORY_MIN_SIZE);
+ ptr = (const char*)test3;
+ *(int*)(test3 + offset) = 4000;
+ LOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length referrer should fail!");
+ // Original form data
+ offset += 4;
+ memset(test3, 0, HISTORY_MIN_SIZE);
+ ptr = (const char*)test3;
+ *(int*)(test3 + offset) = 4000;
+ LOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length form data should fail!");
+#endif
+ // Target
+ offset += 4;
+ memset(test3, 0, HISTORY_MIN_SIZE);
+ ptr = (const char*)test3;
+ *(int*)(test3 + offset) = 4000;
+ LOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length target should fail!");
+#ifdef ANDROID_HISTORY_CLIENT
+ offset += 4; // Scale
+ offset += 4; // traversals
+#endif
+ // Document state
+ offset += 4;
+ memset(test3, 0, HISTORY_MIN_SIZE);
+ ptr = (const char*)test3;
+ *(int*)(test3 + offset) = 4000;
+ LOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 length document state should fail!");
+ // Is target item
+ offset += 1;
+ memset(test3, 0, HISTORY_MIN_SIZE);
+ ptr = (const char*)test3;
+ *(char*)(test3 + offset) = '!';
+ LOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE), "IsTargetItem should fail with ! as the value!");
+ // Child count
+ offset += 4;
+ memset(test3, 0, HISTORY_MIN_SIZE);
+ ptr = (const char*)test3;
+ *(int*)(test3 + offset) = 4000;
+ LOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE), "4000 kids should fail!");
+
+#ifdef ANDROID_HISTORY_CLIENT
+ offset = 36;
+#else
+ offset = 28;
+#endif
+#ifdef ANDROID_FIX
+ offset += 12;
+#endif
+ // Test document state
+ delete[] test3;
+ test3 = new char[HISTORY_MIN_SIZE + sizeof(unsigned)];
+ memset(test3, 0, HISTORY_MIN_SIZE + sizeof(unsigned));
+ ptr = (const char*)test3;
+ *(int*)(test3 + offset) = 1;
+ *(int*)(test3 + offset + 4) = 20;
+ LOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE + sizeof(unsigned)), "1 20 length document state string should fail!");
+ delete[] test3;
+ test3 = new char[HISTORY_MIN_SIZE + 2 * sizeof(unsigned)];
+ memset(test3, 0, HISTORY_MIN_SIZE + 2 * sizeof(unsigned));
+ ptr = (const char*)test3;
+ *(int*)(test3 + offset) = 2;
+ *(int*)(test3 + offset + 4) = 0;
+ *(int*)(test3 + offset + 8) = 20;
+ LOG_ASSERT(!read_item_recursive(testItem, &ptr, HISTORY_MIN_SIZE + 2 * sizeof(unsigned) ), "2 20 length document state string should fail!");
+ delete[] test3;
+ delete testItem;
+}
+#endif
+
+//---------------------------------------------------------
+// JNI registration
+//---------------------------------------------------------
+static JNINativeMethod gWebBackForwardListMethods[] = {
+ { "nativeClose", "(I)V",
+ (void*) WebHistoryClose },
+ { "restoreIndex", "(II)V",
+ (void*) WebHistoryRestoreIndex }
+};
+
+static JNINativeMethod gWebHistoryItemMethods[] = {
+ { "inflate", "(I[B)V",
+ (void*) WebHistoryInflate }
+};
+
+int register_webhistory(JNIEnv* env)
+{
+#ifdef ANDROID_HISTORY_CLIENT
+ // Get notified of all changes to history items.
+ WebCore::notifyHistoryItemChanged = historyItemChanged;
+#endif
+#ifndef NDEBUG
+ unit_test();
+#endif
+ // Find WebHistoryItem, its constructor, and the update method.
+ jclass clazz = env->FindClass("android/webkit/WebHistoryItem");
+ LOG_ASSERT(clazz, "Unable to find class android/webkit/WebHistoryItem");
+ gWebHistoryItem.mInit = env->GetMethodID(clazz, "<init>", "()V");
+ LOG_ASSERT(gWebHistoryItem.mInit, "Could not find WebHistoryItem constructor");
+ gWebHistoryItem.mUpdate = env->GetMethodID(clazz, "update",
+ "(Ljava/lang/String;Ljava/lang/String;Landroid/graphics/Bitmap;[B)V");
+ LOG_ASSERT(gWebHistoryItem.mUpdate, "Could not find method update in WebHistoryItem");
+
+ // Find the field ids for mTitle and mUrl.
+ gWebHistoryItem.mTitle = env->GetFieldID(clazz, "mTitle", "Ljava/lang/String;");
+ LOG_ASSERT(gWebHistoryItem.mTitle, "Could not find field mTitle in WebHistoryItem");
+ gWebHistoryItem.mUrl = env->GetFieldID(clazz, "mUrl", "Ljava/lang/String;");
+ LOG_ASSERT(gWebHistoryItem.mUrl, "Could not find field mUrl in WebHistoryItem");
+
+ // Find the WebBackForwardList object, the addHistoryItem and
+ // removeHistoryItem methods and the mCurrentIndex field.
+ clazz = env->FindClass("android/webkit/WebBackForwardList");
+ LOG_ASSERT(clazz, "Unable to find class android/webkit/WebBackForwardList");
+ gWebBackForwardList.mAddHistoryItem = env->GetMethodID(clazz, "addHistoryItem",
+ "(Landroid/webkit/WebHistoryItem;)V");
+ LOG_ASSERT(gWebBackForwardList.mAddHistoryItem, "Could not find method addHistoryItem");
+ gWebBackForwardList.mRemoveHistoryItem = env->GetMethodID(clazz, "removeHistoryItem",
+ "(I)V");
+ LOG_ASSERT(gWebBackForwardList.mRemoveHistoryItem, "Could not find method removeHistoryItem");
+ gWebBackForwardList.mCurrentIndex = env->GetFieldID(clazz, "mCurrentIndex", "I");
+ LOG_ASSERT(gWebBackForwardList.mCurrentIndex, "Could not find field mCurrentIndex");
+
+ int result = jniRegisterNativeMethods(env, "android/webkit/WebBackForwardList",
+ gWebBackForwardListMethods, NELEM(gWebBackForwardListMethods));
+ return (result < 0) ? result : jniRegisterNativeMethods(env, "android/webkit/WebHistoryItem",
+ gWebHistoryItemMethods, NELEM(gWebHistoryItemMethods));
+}
+
+} /* namespace android */
diff --git a/WebCore/platform/android/jni/WebHistory.h b/WebCore/platform/android/jni/WebHistory.h
new file mode 100644
index 0000000..62db099
--- /dev/null
+++ b/WebCore/platform/android/jni/WebHistory.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2006, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_WEBKIT_WEBHISTORY_H
+#define ANDROID_WEBKIT_WEBHISTORY_H
+
+#include <jni.h>
+#include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+ class HistoryItem;
+}
+
+namespace android {
+
+class WebHistory {
+public:
+ static jbyteArray Flatten(JNIEnv*, WTF::Vector<char>&, WebCore::HistoryItem*);
+ static void AddItem(JNIEnv*, jobject, WebCore::HistoryItem*);
+ static void RemoveItem(JNIEnv*, jobject, int);
+ static void UpdateHistoryIndex(JNIEnv*, jobject, int);
+};
+
+class WebHistoryItem : public WTF::RefCounted<WebHistoryItem> {
+public:
+ WebHistoryItem(WebHistoryItem* parent)
+ : mParent(parent)
+ , mObject(NULL)
+ , mJVM(NULL)
+ , mScale(100)
+ , mTraversals(-1)
+ , mActive(false)
+ , mHistoryItem(NULL) {}
+ WebHistoryItem(JNIEnv*, jobject, WebCore::HistoryItem*);
+ ~WebHistoryItem();
+ void updateHistoryItem(WebCore::HistoryItem* item);
+ void setScale(int s) { mScale = s; }
+ void setTraversals(int t) { mTraversals = t; }
+ void setActive() { mActive = true; }
+ void setParent(WebHistoryItem* parent) { mParent = parent; }
+ WebHistoryItem* parent() { return mParent.get(); }
+ int scale() { return mScale; }
+ int traversals() { return mTraversals; }
+ jobject object() { return mObject; }
+ WebCore::HistoryItem* historyItem() { return mHistoryItem; }
+private:
+ RefPtr<WebHistoryItem> mParent;
+ jobject mObject;
+ JavaVM* mJVM;
+ int mScale;
+ int mTraversals;
+ bool mActive;
+ WebCore::HistoryItem* mHistoryItem;
+};
+
+};
+
+#endif
diff --git a/WebCore/platform/android/jni/WebIconDatabase.cpp b/WebCore/platform/android/jni/WebIconDatabase.cpp
new file mode 100644
index 0000000..2d5c39c
--- /dev/null
+++ b/WebCore/platform/android/jni/WebIconDatabase.cpp
@@ -0,0 +1,232 @@
+/*
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#define LOG_TAG "favicons"
+
+#include <config.h>
+#include <wtf/Platform.h>
+
+#include "WebCoreJni.h"
+#include "WebIconDatabase.h"
+
+#include "IconDatabase.h"
+#include "Image.h"
+#include "IntRect.h"
+#include "JavaSharedClient.h"
+#include "KURL.h"
+
+#include <pthread.h>
+#include "GraphicsJNI.h"
+#include <SkBitmap.h>
+#include <SkImageDecoder.h>
+#include <SkTemplates.h>
+#undef LOG
+#include <utils/Log.h>
+#include <utils/misc.h>
+#include <JNIHelp.h>
+
+namespace android {
+
+jobject webcoreImageToJavaBitmap(JNIEnv* env, WebCore::Image* icon)
+{
+ if (!icon)
+ return NULL;
+ SkBitmap bm;
+ WebCore::SharedBuffer* buffer = icon->data();
+ if (!buffer || !SkImageDecoder::DecodeMemory(buffer->data(), buffer->size(),
+ &bm, SkBitmap::kNo_Config,
+ SkImageDecoder::kDecodePixels_Mode))
+ return NULL;
+
+ return GraphicsJNI::createBitmap(env, new SkBitmap(bm), false, NULL);
+}
+
+static WebIconDatabase* gIconDatabaseClient = new WebIconDatabase();
+
+// XXX: Called by the IconDatabase thread
+void WebIconDatabase::dispatchDidAddIconForPageURL(const WebCore::String& pageURL)
+{
+ // Attempt to attach to the current vm.
+ JavaVM* vm = WebCoreJni::getJavaVM();
+ JavaVMAttachArgs args;
+
+ args.version = JNI_VERSION_1_4;
+ args.name = "IconDatabase";
+ args.group = NULL;
+
+ JNIEnv* env;
+ bool threadIsAttached = true;
+ if (vm->AttachCurrentThread(&env, (void*) &args) != JNI_OK) {
+ LOGE("Could not attach IconDatabase thread to the VM");
+ threadIsAttached = false;
+ }
+
+ mNotificationsMutex.lock();
+ mNotifications.append(pageURL);
+ if (!mDeliveryRequested) {
+ if (threadIsAttached) {
+ mDeliveryRequested = true;
+ WebCore::JavaSharedClient::EnqueueFunctionPtr(DeliverNotifications, this);
+ }
+ }
+ mNotificationsMutex.unlock();
+}
+
+// Called in the WebCore thread
+void WebIconDatabase::RegisterForIconNotification(WebIconDatabaseClient* client)
+{
+ gIconDatabaseClient->mClientsMutex.lock();
+ gIconDatabaseClient->mClients.append(client);
+ gIconDatabaseClient->mClientsMutex.unlock();
+}
+
+// Called in the WebCore thread
+void WebIconDatabase::UnregisterForIconNotification(WebIconDatabaseClient* client)
+{
+ WebIconDatabase* db = gIconDatabaseClient;
+ db->mClientsMutex.lock();
+ for (unsigned i = 0; i < db->mClients.size(); ++i) {
+ if (db->mClients[i] == client) {
+ db->mClients.remove(i);
+ break;
+ }
+ }
+ db->mClientsMutex.unlock();
+}
+
+// Called in the WebCore thread
+void WebIconDatabase::DeliverNotifications(void* v)
+{
+ ASSERT(v);
+ ((WebIconDatabase*)v)->deliverNotifications();
+}
+
+// Called in the WebCore thread
+void WebIconDatabase::deliverNotifications()
+{
+ ASSERT(mDeliveryRequested);
+
+ // Swap the notifications queue
+ Vector<WebCore::String> queue;
+ mNotificationsMutex.lock();
+ queue.swap(mNotifications);
+ mDeliveryRequested = false;
+ mNotificationsMutex.unlock();
+
+ // Swap the clients queue
+ Vector<WebIconDatabaseClient*> clients;
+ mClientsMutex.lock();
+ clients.swap(mClients);
+ mClientsMutex.unlock();
+
+ for (unsigned i = 0; i < queue.size(); ++i) {
+ for (unsigned j = 0; j < clients.size(); ++j) {
+ clients[j]->didAddIconForPageUrl(queue[i]);
+ }
+ }
+}
+
+static void Open(JNIEnv* env, jobject obj, jstring path)
+{
+ WebCore::IconDatabase* iconDb = WebCore::iconDatabase();
+ if (iconDb->isOpen())
+ return;
+ iconDb->setEnabled(true);
+ iconDb->setClient(gIconDatabaseClient);
+ LOG_ASSERT(path, "No path given to nativeOpen");
+ const char* pathStr = env->GetStringUTFChars(path, NULL);
+ LOG_ASSERT(pathStr, "GetStringUTFChars failed for the path");
+ LOGV("Opening WebIconDatabase file '%s'", pathStr);
+ bool res = iconDb->open(pathStr);
+ if (!res)
+ LOGE("Open failed!");
+ env->ReleaseStringUTFChars(path, pathStr);
+}
+
+static void Close(JNIEnv* env, jobject obj)
+{
+ WebCore::iconDatabase()->close();
+}
+
+static void RemoveAllIcons(JNIEnv* env, jobject obj)
+{
+ LOGV("Removing all icons");
+ WebCore::iconDatabase()->removeAllIcons();
+}
+
+static jobject IconForPageUrl(JNIEnv* env, jobject obj, jstring url)
+{
+ LOG_ASSERT(url, "No url given to iconForPageUrl");
+ const char* urlStr = env->GetStringUTFChars(url, NULL);
+ LOG_ASSERT(urlStr, "GetStringUTFChars failed for url");
+
+ WebCore::Image* icon = WebCore::iconDatabase()->iconForPageURL(urlStr,
+ WebCore::IntSize(16, 16));
+ LOGV("Retrieving icon for '%s' %p", urlStr, icon);
+ env->ReleaseStringUTFChars(url, urlStr);
+ return webcoreImageToJavaBitmap(env, icon);
+}
+
+static void RetainIconForPageUrl(JNIEnv* env, jobject obj, jstring url)
+{
+ LOG_ASSERT(url, "No url given to retainIconForPageUrl");
+ const char* urlStr = env->GetStringUTFChars(url, NULL);
+ LOG_ASSERT(urlStr, "GetStringUTFChars failed for url");
+
+ LOGV("Retaining icon for '%s'", urlStr);
+ WebCore::iconDatabase()->retainIconForPageURL(urlStr);
+ env->ReleaseStringUTFChars(url, urlStr);
+}
+
+static void ReleaseIconForPageUrl(JNIEnv* env, jobject obj, jstring url)
+{
+ LOG_ASSERT(url, "No url given to releaseIconForPageUrl");
+ const char* urlStr = env->GetStringUTFChars(url, NULL);
+ LOG_ASSERT(urlStr, "GetStringUTFChars failed for url");
+
+ LOGV("Releasing icon for '%s'", urlStr);
+ WebCore::iconDatabase()->releaseIconForPageURL(urlStr);
+ env->ReleaseStringUTFChars(url, urlStr);
+}
+
+/*
+ * JNI registration
+ */
+static JNINativeMethod gWebIconDatabaseMethods[] = {
+ { "nativeOpen", "(Ljava/lang/String;)V",
+ (void*) Open },
+ { "nativeClose", "()V",
+ (void*) Close },
+ { "nativeRemoveAllIcons", "()V",
+ (void*) RemoveAllIcons },
+ { "nativeIconForPageUrl", "(Ljava/lang/String;)Landroid/graphics/Bitmap;",
+ (void*) IconForPageUrl },
+ { "nativeRetainIconForPageUrl", "(Ljava/lang/String;)V",
+ (void*) RetainIconForPageUrl },
+ { "nativeReleaseIconForPageUrl", "(Ljava/lang/String;)V",
+ (void*) ReleaseIconForPageUrl }
+};
+
+int register_webicondatabase(JNIEnv* env)
+{
+ jclass webIconDB = env->FindClass("android/webkit/WebIconDatabase");
+ LOG_ASSERT(webIconDB, "Unable to find class android.webkit.WebIconDatabase");
+
+ return jniRegisterNativeMethods(env, "android/webkit/WebIconDatabase",
+ gWebIconDatabaseMethods, NELEM(gWebIconDatabaseMethods));
+}
+
+}
diff --git a/WebCore/platform/android/jni/WebIconDatabase.h b/WebCore/platform/android/jni/WebIconDatabase.h
new file mode 100644
index 0000000..eefe1f6
--- /dev/null
+++ b/WebCore/platform/android/jni/WebIconDatabase.h
@@ -0,0 +1,69 @@
+/* //device/libs/WebKitLib/WebKit/WebCore/platform/android/jni/android_webkit_webicondatabase.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef ANDROID_WEBKIT_WEBICONDATABASE_H
+#define ANDROID_WEBKIT_WEBICONDATABASE_H
+
+#include "IconDatabaseClient.h"
+#include "utils/threads.h"
+#include "wtf/Vector.h"
+
+#include <jni.h>
+
+namespace WebCore {
+ class Image;
+ class String;
+}
+
+namespace android {
+
+ class WebIconDatabaseClient {
+ public:
+ virtual ~WebIconDatabaseClient() {}
+ virtual void didAddIconForPageUrl(const WebCore::String& pageUrl) = 0;
+ };
+
+ class WebIconDatabase : public WebCore::IconDatabaseClient {
+ public:
+ WebIconDatabase() : mDeliveryRequested(false) {}
+ // IconDatabaseClient method
+ virtual void dispatchDidAddIconForPageURL(const WebCore::String& pageURL);
+
+ static void RegisterForIconNotification(WebIconDatabaseClient* client);
+ static void UnregisterForIconNotification(WebIconDatabaseClient* client);
+ static void DeliverNotifications(void*);
+
+ private:
+ // Deliver all the icon notifications
+ void deliverNotifications();
+
+ // List of clients and a mutex to protect it.
+ Vector<WebIconDatabaseClient*> mClients;
+ android::Mutex mClientsMutex;
+
+ // Queue of page urls that have received an icon.
+ Vector<WebCore::String> mNotifications;
+ android::Mutex mNotificationsMutex;
+ // Flag to indicate that we have requested a delivery of notifications.
+ bool mDeliveryRequested;
+ };
+
+ jobject webcoreImageToJavaBitmap(JNIEnv* env, WebCore::Image* icon);
+
+};
+
+#endif
diff --git a/WebCore/platform/android/jni/WebSettings.cpp b/WebCore/platform/android/jni/WebSettings.cpp
new file mode 100644
index 0000000..8d9efc0
--- /dev/null
+++ b/WebCore/platform/android/jni/WebSettings.cpp
@@ -0,0 +1,309 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#define LOG_TAG "websettings"
+
+#include <config.h>
+#include <wtf/Platform.h>
+
+#include "Document.h"
+#include "Frame.h"
+#include "FrameAndroid.h"
+#include "FrameLoader.h"
+#include "FrameView.h"
+#include "DocLoader.h"
+#include "Page.h"
+#ifdef ANDROID_PLUGINS
+#include "PluginDatabaseAndroid.h"
+#endif
+#include "Settings.h"
+#include "WebCoreFrameBridge.h"
+
+#undef LOG
+#include <JNIHelp.h>
+#include <utils/Log.h>
+#include <utils/misc.h>
+
+namespace android {
+
+struct FieldIds {
+ FieldIds(JNIEnv* env, jclass clazz) {
+ mLayoutAlgorithm = env->GetFieldID(clazz, "mLayoutAlgorithm",
+ "Landroid/webkit/WebSettings$LayoutAlgorithm;");
+ mTextSize = env->GetFieldID(clazz, "mTextSize",
+ "Landroid/webkit/WebSettings$TextSize;");
+ mStandardFontFamily = env->GetFieldID(clazz, "mStandardFontFamily",
+ "Ljava/lang/String;");
+ mFixedFontFamily = env->GetFieldID(clazz, "mFixedFontFamily",
+ "Ljava/lang/String;");
+ mSansSerifFontFamily = env->GetFieldID(clazz, "mSansSerifFontFamily",
+ "Ljava/lang/String;");
+ mSerifFontFamily = env->GetFieldID(clazz, "mSerifFontFamily",
+ "Ljava/lang/String;");
+ mCursiveFontFamily = env->GetFieldID(clazz, "mCursiveFontFamily",
+ "Ljava/lang/String;");
+ mFantasyFontFamily = env->GetFieldID(clazz, "mFantasyFontFamily",
+ "Ljava/lang/String;");
+ mDefaultTextEncoding = env->GetFieldID(clazz, "mDefaultTextEncoding",
+ "Ljava/lang/String;");
+ mUserAgent = env->GetFieldID(clazz, "mUserAgent",
+ "Ljava/lang/String;");
+ mMinimumFontSize = env->GetFieldID(clazz, "mMinimumFontSize", "I");
+ mMinimumLogicalFontSize = env->GetFieldID(clazz, "mMinimumLogicalFontSize", "I");
+ mDefaultFontSize = env->GetFieldID(clazz, "mDefaultFontSize", "I");
+ mDefaultFixedFontSize = env->GetFieldID(clazz, "mDefaultFixedFontSize", "I");
+ mLoadsImagesAutomatically = env->GetFieldID(clazz, "mLoadsImagesAutomatically", "Z");
+#ifdef ANDROID_BLOCK_NETWORK_IMAGE
+ mBlockNetworkImage = env->GetFieldID(clazz, "mBlockNetworkImage", "Z");
+#endif
+ mJavaScriptEnabled = env->GetFieldID(clazz, "mJavaScriptEnabled", "Z");
+ mPluginsEnabled = env->GetFieldID(clazz, "mPluginsEnabled", "Z");
+#ifdef ANDROID_PLUGINS
+ mPluginsPath = env->GetFieldID(clazz, "mPluginsPath", "Ljava/lang/String;");
+#endif
+ mJavaScriptCanOpenWindowsAutomatically = env->GetFieldID(clazz,
+ "mJavaScriptCanOpenWindowsAutomatically", "Z");
+ mUseWideViewport = env->GetFieldID(clazz, "mUseWideViewport", "Z");
+ mSupportMultipleWindows = env->GetFieldID(clazz, "mSupportMultipleWindows", "Z");
+ mUseDoubleTree = env->GetFieldID(clazz, "mUseDoubleTree", "Z");
+
+ LOG_ASSERT(mLayoutAlgorithm, "Could not find field mLayoutAlgorithm");
+ LOG_ASSERT(mTextSize, "Could not find field mTextSize");
+ LOG_ASSERT(mStandardFontFamily, "Could not find field mStandardFontFamily");
+ LOG_ASSERT(mFixedFontFamily, "Could not find field mFixedFontFamily");
+ LOG_ASSERT(mSansSerifFontFamily, "Could not find field mSansSerifFontFamily");
+ LOG_ASSERT(mSerifFontFamily, "Could not find field mSerifFontFamily");
+ LOG_ASSERT(mCursiveFontFamily, "Could not find field mCursiveFontFamily");
+ LOG_ASSERT(mFantasyFontFamily, "Could not find field mFantasyFontFamily");
+ LOG_ASSERT(mDefaultTextEncoding, "Could not find field mDefaultTextEncoding");
+ LOG_ASSERT(mUserAgent, "Could not find field mUserAgent");
+ LOG_ASSERT(mMinimumFontSize, "Could not find field mMinimumFontSize");
+ LOG_ASSERT(mMinimumLogicalFontSize, "Could not find field mMinimumLogicalFontSize");
+ LOG_ASSERT(mDefaultFontSize, "Could not find field mDefaultFontSize");
+ LOG_ASSERT(mDefaultFixedFontSize, "Could not find field mDefaultFixedFontSize");
+ LOG_ASSERT(mLoadsImagesAutomatically, "Could not find field mLoadsImagesAutomatically");
+#ifdef ANDROID_BLOCK_NETWORK_IMAGE
+ LOG_ASSERT(mBlockNetworkImage, "Could not find field mBlockNetworkImage");
+#endif
+ LOG_ASSERT(mJavaScriptEnabled, "Could not find field mJavaScriptEnabled");
+ LOG_ASSERT(mPluginsEnabled, "Could not find field mPluginsEnabled");
+#ifdef ANDROID_PLUGINS
+ LOG_ASSERT(mPluginsPath, "Could not find field mPluginsPath");
+#endif
+ LOG_ASSERT(mJavaScriptCanOpenWindowsAutomatically,
+ "Could not find field mJavaScriptCanOpenWindowsAutomatically");
+ LOG_ASSERT(mUseWideViewport, "Could not find field mUseWideViewport");
+ LOG_ASSERT(mSupportMultipleWindows, "Could not find field mSupportMultipleWindows");
+ LOG_ASSERT(mUseDoubleTree, "Could not find field mUseDoubleTree");
+
+ jclass c = env->FindClass("java/lang/Enum");
+ LOG_ASSERT(c, "Could not find Enum class!");
+ mOrdinal = env->GetMethodID(c, "ordinal", "()I");
+ LOG_ASSERT(mOrdinal, "Could not find method ordinal");
+ c = env->FindClass("android/webkit/WebSettings$TextSize");
+ LOG_ASSERT(c, "Could not find TextSize enum");
+ mTextSizeValue = env->GetFieldID(c, "value", "I");
+ }
+
+ // Field ids
+ jfieldID mLayoutAlgorithm;
+ jfieldID mTextSize;
+ jfieldID mStandardFontFamily;
+ jfieldID mFixedFontFamily;
+ jfieldID mSansSerifFontFamily;
+ jfieldID mSerifFontFamily;
+ jfieldID mCursiveFontFamily;
+ jfieldID mFantasyFontFamily;
+ jfieldID mDefaultTextEncoding;
+ jfieldID mUserAgent;
+ jfieldID mMinimumFontSize;
+ jfieldID mMinimumLogicalFontSize;
+ jfieldID mDefaultFontSize;
+ jfieldID mDefaultFixedFontSize;
+ jfieldID mLoadsImagesAutomatically;
+#ifdef ANDROID_BLOCK_NETWORK_IMAGE
+ jfieldID mBlockNetworkImage;
+#endif
+ jfieldID mJavaScriptEnabled;
+ jfieldID mPluginsEnabled;
+#ifdef ANDROID_PLUGINS
+ jfieldID mPluginsPath;
+#endif
+ jfieldID mJavaScriptCanOpenWindowsAutomatically;
+ jfieldID mUseWideViewport;
+ jfieldID mSupportMultipleWindows;
+ jfieldID mUseDoubleTree;
+
+ // Ordinal() method and value field for enums
+ jmethodID mOrdinal;
+ jfieldID mTextSizeValue;
+};
+
+static struct FieldIds* gFieldIds;
+
+class WebSettings {
+public:
+ static void Sync(JNIEnv* env, jobject obj, jint frame)
+ {
+ WebCore::FrameAndroid* pFrame = (WebCore::FrameAndroid*)frame;
+ LOG_ASSERT(pFrame, "%s must take a valid frame pointer!", __FUNCTION__);
+ WebCore::Settings* s = pFrame->page()->settings();
+ WebCore::DocLoader* docLoader = pFrame->document()->docLoader();
+
+#ifdef ANDROID_LAYOUT
+ jobject layout = env->GetObjectField(obj, gFieldIds->mLayoutAlgorithm);
+ WebCore::Settings::LayoutAlgorithm l = (WebCore::Settings::LayoutAlgorithm)
+ env->CallIntMethod(layout, gFieldIds->mOrdinal);
+ if (s->layoutAlgorithm() != l) {
+ s->setLayoutAlgorithm(l);
+ if (pFrame->document()) {
+ pFrame->document()->updateStyleSelector();
+ if (pFrame->document()->renderer()) {
+ pFrame->cleanupForFullLayout(pFrame->document()->renderer());
+ LOG_ASSERT(pFrame->view(), "No view for this frame when trying to relayout");
+ pFrame->view()->layout();
+ // FIXME: This call used to scroll the page to put the focus into view.
+ // It worked on the WebViewCore, but now scrolling is done outside of the
+ // WebViewCore, on the UI side, so there needs to be a new way to do this.
+ //pFrame->makeFocusVisible();
+ }
+ }
+ }
+#endif
+ jobject textSize = env->GetObjectField(obj, gFieldIds->mTextSize);
+ jint zoomFactor = env->GetIntField(textSize, gFieldIds->mTextSizeValue);
+ if (pFrame->zoomFactor() != zoomFactor)
+ pFrame->setZoomFactor(zoomFactor);
+
+ jstring str = (jstring)env->GetObjectField(obj, gFieldIds->mStandardFontFamily);
+ const char* font = env->GetStringUTFChars(str, NULL);
+ s->setStandardFontFamily(font);
+ env->ReleaseStringUTFChars(str, font);
+
+ str = (jstring)env->GetObjectField(obj, gFieldIds->mFixedFontFamily);
+ font = env->GetStringUTFChars(str, NULL);
+ s->setFixedFontFamily(font);
+ env->ReleaseStringUTFChars(str, font);
+
+ str = (jstring)env->GetObjectField(obj, gFieldIds->mSansSerifFontFamily);
+ font = env->GetStringUTFChars(str, NULL);
+ s->setSansSerifFontFamily(font);
+ env->ReleaseStringUTFChars(str, font);
+
+ str = (jstring)env->GetObjectField(obj, gFieldIds->mSerifFontFamily);
+ font = env->GetStringUTFChars(str, NULL);
+ s->setSerifFontFamily(font);
+ env->ReleaseStringUTFChars(str, font);
+
+ str = (jstring)env->GetObjectField(obj, gFieldIds->mCursiveFontFamily);
+ font = env->GetStringUTFChars(str, NULL);
+ s->setCursiveFontFamily(font);
+ env->ReleaseStringUTFChars(str, font);
+
+ str = (jstring)env->GetObjectField(obj, gFieldIds->mFantasyFontFamily);
+ font = env->GetStringUTFChars(str, NULL);
+ s->setFantasyFontFamily(font);
+ env->ReleaseStringUTFChars(str, font);
+
+ str = (jstring)env->GetObjectField(obj, gFieldIds->mDefaultTextEncoding);
+ const char* encoding = env->GetStringUTFChars(str, NULL);
+ s->setDefaultTextEncodingName(encoding);
+ env->ReleaseStringUTFChars(str, encoding);
+
+ str = (jstring)env->GetObjectField(obj, gFieldIds->mUserAgent);
+ const char* userAgentStr = env->GetStringUTFChars(str, NULL);
+ pFrame->bridge()->setUserAgent(userAgentStr);
+ env->ReleaseStringUTFChars(str, userAgentStr);
+
+ jint size = env->GetIntField(obj, gFieldIds->mMinimumFontSize);
+ s->setMinimumFontSize(size);
+
+ size = env->GetIntField(obj, gFieldIds->mMinimumLogicalFontSize);
+ s->setMinimumLogicalFontSize(size);
+
+ size = env->GetIntField(obj, gFieldIds->mDefaultFontSize);
+ s->setDefaultFontSize(size);
+
+ size = env->GetIntField(obj, gFieldIds->mDefaultFixedFontSize);
+ s->setDefaultFixedFontSize(size);
+
+ jboolean flag = env->GetBooleanField(obj, gFieldIds->mLoadsImagesAutomatically);
+ s->setLoadsImagesAutomatically(flag);
+ if (flag)
+ docLoader->setAutoLoadImages(true);
+
+#ifdef ANDROID_BLOCK_NETWORK_IMAGE
+ flag = env->GetBooleanField(obj, gFieldIds->mBlockNetworkImage);
+ s->setBlockNetworkImage(flag);
+ if(!flag)
+ docLoader->setBlockNetworkImage(false);
+#endif
+
+ flag = env->GetBooleanField(obj, gFieldIds->mJavaScriptEnabled);
+ s->setJavaScriptEnabled(flag);
+
+ flag = env->GetBooleanField(obj, gFieldIds->mPluginsEnabled);
+ s->setPluginsEnabled(flag);
+
+#ifdef ANDROID_PLUGINS
+ str = (jstring)env->GetObjectField(obj, gFieldIds->mPluginsPath);
+ if (str) {
+ const char* pluginsPathStr = env->GetStringUTFChars(str, NULL);
+ s->setPluginsPath(pluginsPathStr);
+ // Also sync PluginDatabaseAndroid with the new default path.
+ ::WebCore::PluginDatabaseAndroid::setDefaultPluginsPath(pluginsPathStr);
+ env->ReleaseStringUTFChars(str, pluginsPathStr);
+ }
+#endif
+
+ flag = env->GetBooleanField(obj, gFieldIds->mJavaScriptCanOpenWindowsAutomatically);
+ s->setJavaScriptCanOpenWindowsAutomatically(flag);
+
+ flag = env->GetBooleanField(obj, gFieldIds->mUseWideViewport);
+ s->setUseWideViewport(flag);
+
+#ifdef ANDROID_MULTIPLE_WINDOWS
+ flag = env->GetBooleanField(obj, gFieldIds->mSupportMultipleWindows);
+ s->setSupportMultipleWindows(flag);
+#endif
+
+#if USE(LOW_BANDWIDTH_DISPLAY)
+ flag = env->GetBooleanField(obj, gFieldIds->mUseDoubleTree);
+ pFrame->loader()->setUseLowBandwidthDisplay(flag);
+#endif
+ }
+};
+
+//-------------------------------------------------------------
+// JNI registration
+//-------------------------------------------------------------
+
+static JNINativeMethod gWebSettingsMethods[] = {
+ { "nativeSync", "(I)V",
+ (void*) WebSettings::Sync }
+};
+
+int register_websettings(JNIEnv* env)
+{
+ jclass clazz = env->FindClass("android/webkit/WebSettings");
+ LOG_ASSERT(clazz, "Unable to find class WebSettings!");
+ gFieldIds = new FieldIds(env, clazz);
+ return jniRegisterNativeMethods(env, "android/webkit/WebSettings",
+ gWebSettingsMethods, NELEM(gWebSettingsMethods));
+}
+
+}
diff --git a/WebCore/platform/android/jni/WebViewCore.cpp b/WebCore/platform/android/jni/WebViewCore.cpp
new file mode 100644
index 0000000..dc2cd48
--- /dev/null
+++ b/WebCore/platform/android/jni/WebViewCore.cpp
@@ -0,0 +1,2211 @@
+/*
+ * Copyright 2006, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "webcoreglue"
+
+#include <config.h>
+#include <wtf/Platform.h>
+
+#include "android_graphics.h"
+#include "GraphicsJNI.h"
+#include "SkPicture.h"
+
+#include "AtomicString.h"
+#include "CacheBuilder.h"
+#include "CachedNode.h"
+#include "CachedRoot.h"
+#include "Color.h"
+#include "Document.h"
+#include "Element.h"
+#include "Editor.h"
+#include "EditorClientAndroid.h"
+#include "EventHandler.h"
+#include "EventNames.h"
+#include "Font.h"
+#include "FrameAndroid.h"
+#include "FrameLoader.h"
+#include "FrameTree.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "HitTestResult.h"
+#include "HTMLAnchorElement.h"
+#include "HTMLAreaElement.h"
+#include "HTMLElement.h"
+#include "HTMLImageElement.h"
+#include "HTMLInputElement.h"
+#include "HTMLMapElement.h"
+#include "HTMLNames.h"
+#include "HTMLOptGroupElement.h"
+#include "HTMLOptionElement.h"
+#include "HTMLSelectElement.h"
+#include "HTMLTextAreaElement.h"
+#include "HTMLTextFieldInnerElement.h"
+#include "InlineTextBox.h"
+#include "KeyboardCodes.h"
+#include "Node.h"
+#include "Page.h"
+#include "PlatformGraphicsContext.h"
+#include "PlatformKeyboardEvent.h"
+#include "PlatformString.h"
+#include "PluginInfoStore.h"
+#include "Position.h"
+#include "RenderLayer.h"
+#include "RenderText.h"
+#include "RenderTextControl.h"
+#include "RenderThemeAndroid.h"
+#include "RenderView.h"
+#include "ResourceRequest.h"
+#include "SelectionController.h"
+#include "Settings.h"
+#include "StringImpl.h"
+#include "Text.h"
+#include "TypingCommand.h"
+#include "WebCoreFrameBridge.h"
+#include "WebViewCore.h"
+#include "HistoryItem.h"
+
+#ifdef LOG
+#undef LOG
+#endif
+
+#include <ui/KeycodeLabels.h>
+#include <utils/Log.h>
+#include "SkTDArray.h"
+#include "SkTime.h"
+#include <SkTypes.h>
+#include <SkCanvas.h>
+#include <SkUtils.h>
+#include <JNIHelp.h>
+
+#include "SystemTime.h"
+
+#ifdef ANDROID_INSTRUMENT
+static uint32_t sTotalTimeUsed = 0;
+static uint32_t sTotalPaintTimeUsed = 0;
+static uint32_t sCounter = 0;
+
+namespace WebCore {
+void Frame::resetWebViewCoreTimeCounter()
+{
+ sTotalTimeUsed = 0;
+}
+
+void Frame::reportWebViewCoreTimeCounter()
+{
+ LOG(LOG_DEBUG, "WebCore", "*-* Total native 4 (webview core) time: %d ms\n",
+ sTotalTimeUsed);
+}
+// This should be in Frame.cpp, but android LOG is conflict with webcore LOG
+void Frame::resetPaintTimeCounter()
+{
+ sTotalPaintTimeUsed = 0;
+ sCounter = 0;
+}
+
+void Frame::reportPaintTimeCounter()
+{
+ LOG(LOG_DEBUG, "WebCore", "*-* Total draw time: %d ms called %d times\n",
+ sTotalPaintTimeUsed, sCounter);
+}
+}
+#endif
+
+////////////////////////////////////////////////////////////////////////////////////////////////
+
+namespace android {
+
+#ifdef ANDROID_INSTRUMENT
+class TimeCounterWV {
+public:
+ TimeCounterWV() {
+ mStartTime = WebCore::get_thread_msec();
+ }
+
+ ~TimeCounterWV() {
+ sTotalTimeUsed += WebCore::get_thread_msec() - mStartTime;
+ }
+
+private:
+ uint32_t mStartTime;
+};
+#endif
+
+// ----------------------------------------------------------------------------
+
+#define GET_NATIVE_VIEW(env, obj) ((WebViewCore*)env->GetIntField(obj, gWebViewCoreFields.mNativeClass))
+
+// Field ids for WebViewCore
+struct WebViewCoreFields {
+ jfieldID mNativeClass;
+ jfieldID mViewportWidth;
+ jfieldID mViewportHeight;
+ jfieldID mViewportInitialScale;
+ jfieldID mViewportMinimumScale;
+ jfieldID mViewportMaximumScale;
+ jfieldID mViewportUserScalable;
+ jfieldID mWebView;
+} gWebViewCoreFields;
+
+// ----------------------------------------------------------------------------
+
+extern JavaVM* jnienv_to_javavm(JNIEnv* env);
+extern JNIEnv* javavm_to_jnienv(JavaVM* vm);
+
+// ----------------------------------------------------------------------------
+
+/**
+ * Helper method for checking java exceptions
+ * @return true if an exception occurred.
+ */
+static bool checkException(JNIEnv *env)
+{
+ if (env->ExceptionCheck() != 0)
+ {
+ LOGE("*** Uncaught exception returned from Java call!\n");
+ env->ExceptionDescribe();
+ return true;
+ }
+ return false;
+}
+
+// ----------------------------------------------------------------------------
+
+struct WebViewCore::JavaGlue
+{
+ JavaVM* mJVM;
+ jobject mObj;
+ jmethodID mSpawnScrollTo;
+ jmethodID mScrollTo;
+ jmethodID mScrollBy;
+ jmethodID mContentInvalidate;
+ jmethodID mRequestListBox;
+ jmethodID mRequestSingleListBox;
+ jmethodID mJsAlert;
+ jmethodID mJsConfirm;
+ jmethodID mJsPrompt;
+ jmethodID mJsUnload;
+ jmethodID mDidFirstLayout;
+ jmethodID mSendMarkNodeInvalid;
+ jmethodID mSendNotifyFocusSet;
+ jmethodID mSendNotifyProgressFinished;
+ jmethodID mSendRecomputeFocus;
+ jmethodID mSendViewInvalidate;
+ jmethodID mUpdateTextfield;
+ jmethodID mRestoreScale;
+};
+
+/*
+ * WebViewCore Implementation
+ */
+
+static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], const char signature[])
+{
+ jmethodID m = env->GetMethodID(clazz, name, signature);
+ LOG_ASSERT(m, "Could not find method %s", name);
+ return m;
+}
+
+Mutex WebViewCore::gFrameCacheMutex;
+Mutex WebViewCore::gFrameGenerationMutex;
+Mutex WebViewCore::gRecomputeFocusMutex;
+Mutex WebViewCore::gButtonMutex;
+
+WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::FrameView* view)
+ : mView(view)
+{
+ mFrame = (WebCore::FrameAndroid*)mView->frame();
+ // This will be derefed in WebCoreFrameBridge during destroy.
+ mView->ref();
+
+ mPopupReply = NULL;
+ mBuildGeneration = 0;
+ mMoveGeneration = 0;
+ mGeneration = 0;
+ mLastGeneration = 0;
+ mTouchGeneration = 0;
+ mBlockTextfieldUpdates = false;
+ // just initial values. These should be set by client
+ mMaxXScroll = 320/4;
+ mMaxYScroll = 240/4;
+ mButtons = NULL;
+ mTextGeneration = 0;
+
+ LOG_ASSERT(mFrame, "Uh oh, somehow a frameview was made without an initial frame!");
+
+ jclass clazz = env->GetObjectClass(javaWebViewCore);
+ mJavaGlue = new JavaGlue;
+ mJavaGlue->mJVM = jnienv_to_javavm(env);
+ mJavaGlue->mObj = env->NewGlobalRef(javaWebViewCore);
+ mJavaGlue->mSpawnScrollTo = GetJMethod(env, clazz, "contentSpawnScrollTo", "(II)V");
+ mJavaGlue->mScrollTo = GetJMethod(env, clazz, "contentScrollTo", "(II)V");
+ mJavaGlue->mScrollBy = GetJMethod(env, clazz, "contentScrollBy", "(II)V");
+ mJavaGlue->mContentInvalidate = GetJMethod(env, clazz, "contentInvalidate", "()V");
+ mJavaGlue->mRequestListBox = GetJMethod(env, clazz, "requestListBox", "([Ljava/lang/String;[Z[I)V");
+ mJavaGlue->mRequestSingleListBox = GetJMethod(env, clazz, "requestListBox", "([Ljava/lang/String;[ZI)V");
+ mJavaGlue->mJsAlert = GetJMethod(env, clazz, "jsAlert", "(Ljava/lang/String;Ljava/lang/String;)V");
+ mJavaGlue->mJsConfirm = GetJMethod(env, clazz, "jsConfirm", "(Ljava/lang/String;Ljava/lang/String;)Z");
+ mJavaGlue->mJsPrompt = GetJMethod(env, clazz, "jsPrompt", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
+ mJavaGlue->mJsUnload = GetJMethod(env, clazz, "jsUnload", "(Ljava/lang/String;Ljava/lang/String;)Z");
+ mJavaGlue->mDidFirstLayout = GetJMethod(env, clazz, "didFirstLayout", "(Ljava/lang/String;)V");
+ mJavaGlue->mSendMarkNodeInvalid = GetJMethod(env, clazz, "sendMarkNodeInvalid", "(I)V");
+ mJavaGlue->mSendNotifyFocusSet = GetJMethod(env, clazz, "sendNotifyFocusSet", "()V");
+ mJavaGlue->mSendNotifyProgressFinished = GetJMethod(env, clazz, "sendNotifyProgressFinished", "()V");
+ mJavaGlue->mSendRecomputeFocus = GetJMethod(env, clazz, "sendRecomputeFocus", "()V");
+ mJavaGlue->mSendViewInvalidate = GetJMethod(env, clazz, "sendViewInvalidate", "()V");
+ mJavaGlue->mUpdateTextfield = GetJMethod(env, clazz, "updateTextfield", "(IZLjava/lang/String;I)V");
+ mJavaGlue->mRestoreScale = GetJMethod(env, clazz, "restoreScale", "(I)V");
+
+ env->SetIntField(javaWebViewCore, gWebViewCoreFields.mNativeClass, (jint)this);
+
+ mVisibleRect.setWidth(0);
+ mVisibleRect.setHeight(0);
+
+ reset(true);
+}
+
+WebViewCore::~WebViewCore()
+{
+ // Release the focused view
+ Release(mPopupReply);
+
+ if (mJavaGlue->mObj) {
+ JNIEnv* env = javavm_to_jnienv(mJavaGlue->mJVM);
+ env->DeleteGlobalRef(mJavaGlue->mObj);
+ mJavaGlue->mObj = 0;
+ }
+ delete mJavaGlue;
+ delete mFrameCacheKit;
+ delete mNavPictureKit;
+ if (mButtons != NULL) {
+ mButtons->deleteAll();
+ delete mButtons;
+ }
+}
+
+void WebViewCore::reset(bool fromConstructor)
+{
+ if (fromConstructor) {
+ mFrameCacheKit = NULL;
+ mNavPictureKit = NULL;
+ } else {
+ gFrameCacheMutex.lock();
+ delete mFrameCacheKit;
+ delete mNavPictureKit;
+ mFrameCacheKit = NULL;
+ mNavPictureKit = NULL;
+ gFrameCacheMutex.unlock();
+ }
+
+ mLastFocused = NULL;
+ mLastFocusedBounds = WebCore::IntRect(0,0,0,0);
+ mUpdatedFrameCache = true;
+ mFrameCacheOutOfDate = true;
+ mBlockFocusChange = false;
+ mSnapAnchorNode = NULL;
+ mUseReplay = false;
+}
+
+void WebViewCore::draw(WebCore::GraphicsContext* ctx,
+ const WebCore::IntRect& r, bool invalCache)
+{
+ LOG_ASSERT(mFrame, "%s has no frame for this view!", __FUNCTION__);
+ LOG_ASSERT(mFrame == mView->frame(), "Our frames do not match!");
+#ifdef ANDROID_INSTRUMENT
+ uint32_t startTime = WebCore::get_thread_msec();
+#endif
+ if (NULL == mFrame->renderer()) {
+ // We only do this if there is nothing else to draw.
+ // If there is a renderer, it will fill the bg itself, so we don't want to
+ // double-draw (slow)
+ SkCanvas* canvas = ctx->platformContext()->mCanvas;
+ canvas->drawColor(SK_ColorWHITE);
+ }
+ else {
+ mFrame->paint(ctx, r);
+ }
+ if (invalCache) {
+ WebCore::CacheBuilder& builder = mFrame->getCacheBuilder();
+ WebCore::Node* oldFocusNode = builder.currentFocus();
+ mFrameCacheOutOfDate = true;
+ WebCore::IntRect oldBounds = oldFocusNode ?
+ oldFocusNode->getRect() : WebCore::IntRect(0,0,0,0);
+ DBG_NAV_LOGD_ONCE("mLastFocused=%p oldFocusNode=%p"
+ " mLastFocusedBounds={%d,%d,%d,%d} oldBounds={%d,%d,%d,%d}",
+ mLastFocused, oldFocusNode,
+ mLastFocusedBounds.x(), mLastFocusedBounds.y(), mLastFocusedBounds.width(), mLastFocusedBounds.height(),
+ oldBounds.x(), oldBounds.y(), oldBounds.width(), oldBounds.height());
+ if (mLastFocused != oldFocusNode || mLastFocusedBounds != oldBounds) {
+ mLastFocused = oldFocusNode;
+ mLastFocusedBounds = oldBounds;
+ DBG_NAV_LOG("call updateFrameCache");
+ updateFrameCache();
+ }
+ }
+#ifdef ANDROID_INSTRUMENT
+ sTotalPaintTimeUsed += WebCore::get_thread_msec() - startTime;
+ sCounter++;
+#endif
+}
+
+void WebViewCore::recordPicture(SkPicture* picture, bool invalCache)
+{
+ // if there is no document yet, just return
+ if (!mFrame->document())
+ return;
+
+ // Call layout to ensure that the contentWidth and contentHeight are correct
+ WebCore::ScrollView* view = mFrame->view();
+ view->ignoreUpdateContents(true);
+ layout();
+ view->ignoreUpdateContents(false);
+
+#if USE(DOUBLE_TREE)
+ // if haveStylesheetsLoaded() is false, render is not created, so don't call draw.
+ // It can happen when we switch from fast display mode, new style sheets are requested,
+ // if we call draw, we will have blank screen.
+ if (mFrame->document() && !mFrame->loader()->isComplete() &&
+ !mFrame->document()->haveStylesheetsLoaded()) {
+ LOGV("skip %s", __FUNCTION__);
+ return;
+ }
+#endif
+
+ // draw into the picture's recording canvas
+ SkAutoPictureRecord arp(picture, contentWidth(), contentHeight());
+ SkAutoMemoryUsageProbe mup(__FUNCTION__);
+
+ WebCore::PlatformGraphicsContext pgc(arp.getRecordingCanvas());
+ WebCore::GraphicsContext gc(&pgc);
+ WebCore::IntRect r = WebCore::IntRect(0, 0, INT_MAX, INT_MAX);
+ draw(&gc, r, invalCache);
+
+ // If this was done for the Java Picture that is being displayed, grab the
+ // info for the buttons, so the UI thread can grab them and update them
+ // according to their state.
+ if (invalCache) {
+ gButtonMutex.lock();
+ if (mButtons != NULL) {
+ mButtons->deleteAll();
+ delete mButtons;
+ }
+ mButtons = pgc.getAndClearButtonInfo();
+ gButtonMutex.unlock();
+ }
+}
+
+void WebViewCore::onResize()
+{
+ LOGV("view is resized, notifying the frame to relayout...");
+ LOG_ASSERT(mFrame == mView->frame(), "Our frames do not match!");
+ // r could be NULL because our frame has not processed any data. This happens
+ // when an HTMLWidget is first created, attached and sizeChanged is called.
+ WebCore::RenderObject *r = mFrame->renderer();
+ if (r) {
+ r->setNeedsLayoutAndPrefWidthsRecalc();
+ mFrame->forceLayout(true);
+ }
+}
+
+WebCore::RenderLayer* WebViewCore::getRenderLayer()
+{
+ LOG_ASSERT(mView, "A view was not associated with this view bridge!");
+ LOG_ASSERT(mFrame, "A frame was not associated with our frame view!");
+ LOG_ASSERT(mFrame == mView->frame(), "Our frames do not match!");
+ WebCore::Document* doc = mFrame->document();
+ if (doc == NULL)
+ return NULL;
+ WebCore::RenderObject* renderer = doc->renderer();
+ return renderer->enclosingLayer();
+}
+
+bool WebViewCore::pinXToDocument(int* xPtr)
+{
+ WebCore::RenderLayer* layer = getRenderLayer();
+ if (layer == NULL)
+ return false;
+ int docWidth = layer->width();
+ int x = *xPtr;
+ if (x < 0 || docWidth <= this->width())
+ x = 0;
+ else if (x + this->width() > docWidth)
+ x = docWidth - this->width();
+ *xPtr = x;
+ return true;
+}
+
+bool WebViewCore::pinYToDocument(int* yPtr)
+{
+ WebCore::RenderLayer* layer = getRenderLayer();
+ if (layer == NULL)
+ return false;
+ int docHeight = layer->height();
+ int y = *yPtr;
+ if (y < 0 || docHeight <= this->height())
+ y = 0;
+ else if (y + this->height() > docHeight)
+ y = docHeight - this->height();
+ *yPtr = y;
+ return true;
+}
+
+void WebViewCore::scrollTo(int x, int y, bool animate)
+{
+ LOG_ASSERT(mParent == NULL, "Why do we have a parent");
+ LOG_ASSERT(mJavaGlue->mObj, "A Java widget was not associated with this view bridge!");
+
+// LOGD("WebViewCore::scrollTo(%d %d)\n", x, y);
+
+ JNIEnv* env = javavm_to_jnienv(mJavaGlue->mJVM);
+ env->CallVoidMethod(mJavaGlue->mObj, animate ? mJavaGlue->mSpawnScrollTo : mJavaGlue->mScrollTo, x, y);
+ checkException(env);
+}
+
+void WebViewCore::sendMarkNodeInvalid(WebCore::Node* node)
+{
+ LOG_ASSERT(mJavaGlue->mObj, "A Java widget was not associated with this view bridge!");
+ JNIEnv* env = javavm_to_jnienv(mJavaGlue->mJVM);
+ env->CallVoidMethod(mJavaGlue->mObj, mJavaGlue->mSendMarkNodeInvalid, (int) node);
+ checkException(env);
+}
+
+void WebViewCore::sendNotifyFocusSet()
+{
+ LOG_ASSERT(mJavaGlue->mObj, "A Java widget was not associated with this view bridge!");
+ JNIEnv* env = javavm_to_jnienv(mJavaGlue->mJVM);
+ env->CallVoidMethod(mJavaGlue->mObj, mJavaGlue->mSendNotifyFocusSet);
+ checkException(env);
+}
+
+void WebViewCore::sendNotifyProgressFinished()
+{
+ LOG_ASSERT(mJavaGlue->mObj, "A Java widget was not associated with this view bridge!");
+ JNIEnv* env = javavm_to_jnienv(mJavaGlue->mJVM);
+ env->CallVoidMethod(mJavaGlue->mObj, mJavaGlue->mSendNotifyProgressFinished);
+ checkException(env);
+}
+
+void WebViewCore::sendRecomputeFocus()
+{
+ LOG_ASSERT(mJavaGlue->mObj, "A Java widget was not associated with this view bridge!");
+ JNIEnv* env = javavm_to_jnienv(mJavaGlue->mJVM);
+ env->CallVoidMethod(mJavaGlue->mObj, mJavaGlue->mSendRecomputeFocus);
+ checkException(env);
+}
+
+void WebViewCore::sendViewInvalidate()
+{
+ LOG_ASSERT(mJavaGlue->mObj, "A Java widget was not associated with this view bridge!");
+ JNIEnv* env = javavm_to_jnienv(mJavaGlue->mJVM);
+ env->CallVoidMethod(mJavaGlue->mObj, mJavaGlue->mSendViewInvalidate);
+ checkException(env);
+}
+
+void WebViewCore::scrollBy(int dx, int dy)
+{
+ LOG_ASSERT(mParent == NULL, "Why do we have a parent");
+ if ((dx | dy) == 0)
+ return;
+ JNIEnv* env = javavm_to_jnienv(mJavaGlue->mJVM);
+ env->CallVoidMethod(mJavaGlue->mObj, mJavaGlue->mScrollBy, dx, dy);
+ checkException(env);
+}
+
+void WebViewCore::contentInvalidate(const WebCore::IntRect &rect)
+{
+// DBG_NAV_LOGD("rect={%d,%d,%d,%d}", rect.x(), rect.y(), rect.width(), rect.height());
+ JNIEnv* env = javavm_to_jnienv(mJavaGlue->mJVM);
+ env->CallVoidMethod(mJavaGlue->mObj, mJavaGlue->mContentInvalidate);
+ checkException(env);
+}
+
+void WebViewCore::contentInvalidate()
+{
+// DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
+ JNIEnv* env = javavm_to_jnienv(mJavaGlue->mJVM);
+ env->CallVoidMethod(mJavaGlue->mObj, mJavaGlue->mContentInvalidate);
+ checkException(env);
+}
+
+static int pin_pos(int x, int width, int targetWidth)
+{
+ if (x + width > targetWidth)
+ x = targetWidth - width;
+ if (x < 0)
+ x = 0;
+ return x;
+}
+
+void WebViewCore::didFirstLayout()
+{
+ LOG_ASSERT(mParent == NULL, "Why do we have a parent");
+
+ DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
+ LOG_ASSERT(mJavaGlue->mObj, "A Java widget was not associated with this view bridge!");
+
+ const WebCore::KURL& url = mFrame->loader()->url();
+ if (url.isEmpty())
+ return;
+ LOGV("::WebCore:: didFirstLayout %s", url.string().ascii().data());
+
+ JNIEnv* env = javavm_to_jnienv(mJavaGlue->mJVM);
+ WebCore::String urlString(url.string());
+ jstring urlStr = env->NewString((unsigned short*)urlString.characters(), urlString.length());
+ env->CallVoidMethod(mJavaGlue->mObj, mJavaGlue->mDidFirstLayout, urlStr);
+ checkException(env);
+ env->DeleteLocalRef(urlStr);
+
+ DBG_NAV_LOG("call updateFrameCache");
+ updateFrameCache();
+ mHistory.setDidFirstLayout(true);
+}
+
+void WebViewCore::restoreScale(int scale)
+{
+ LOG_ASSERT(mParent == NULL, "Why do we have a parent");
+
+ DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
+ LOG_ASSERT(mJavaGlue->mObj, "A Java widget was not associated with this view bridge!");
+
+ JNIEnv* env = javavm_to_jnienv(mJavaGlue->mJVM);
+ env->CallVoidMethod(mJavaGlue->mObj, mJavaGlue->mRestoreScale, scale);
+ checkException(env);
+}
+
+static void layoutIfNeededRecursive(WebCore::Frame* f)
+{
+ if (!f)
+ return;
+
+ WebCore::FrameView* v = f->view();
+ if (!v)
+ return;
+
+ if (v->needsLayout())
+ v->layout();
+
+ if (!f->tree())
+ return;
+
+ WebCore::Frame* child = f->tree()->firstChild();
+ while (child) {
+ WebCore::FrameView* childView = child->view();
+ if (childView)
+ layoutIfNeededRecursive(child);
+ if (!child->tree())
+ break;
+ child = child->tree()->nextSibling();
+ }
+}
+
+void WebViewCore::layout()
+{
+ LOG_ASSERT(mParent == NULL, "Why do we have a parent");
+
+ SkASSERT(mView);
+ layoutIfNeededRecursive(mFrame);
+}
+
+void WebViewCore::notifyFocusSet()
+{
+ sendNotifyFocusSet();
+}
+
+void WebViewCore::notifyProgressFinished()
+{
+ DBG_NAV_LOG("call updateFrameCache");
+ updateFrameCache();
+ sendNotifyProgressFinished();
+}
+
+void WebViewCore::doMaxScroll(WebCore::CacheBuilder::Direction dir)
+{
+ int dx = 0, dy = 0;
+
+ switch (dir) {
+ case WebCore::CacheBuilder::LEFT:
+ dx = -this->getMaxXScroll();
+ break;
+ case WebCore::CacheBuilder::UP:
+ dy = -this->getMaxXScroll();
+ break;
+ case WebCore::CacheBuilder::RIGHT:
+ dx = this->getMaxYScroll();
+ break;
+ case WebCore::CacheBuilder::DOWN:
+ dy = this->getMaxYScroll();
+ break;
+ case WebCore::CacheBuilder::UNINITIALIZED:
+ default:
+ LOG_ASSERT(0, "unexpected focus selector");
+ }
+ this->scrollBy(dx, dy);
+}
+
+void WebViewCore::getVisibleRect(WebCore::IntRect* rect) const
+{
+ SkASSERT(rect);
+ *rect = mVisibleRect;
+}
+
+void WebViewCore::setVisibleRect(const WebCore::IntRect& r)
+{
+ DBG_NAV_LOGD("{%d,%d,%d,%d}", r.x(), r.y(), r.width(), r.height());
+ if (mVisibleRect != r) {
+ if (mVisibleRect.x() != r.x() || mVisibleRect.y() != r.y())
+ mFrame->sendScrollEvent();
+ mVisibleRect = r;
+ // The visible rect is located within our coordinate space so it
+ // contains the actual scroll position. Setting the location makes hit
+ // testing work correctly.
+ setLocation(r.x(), r.y());
+ }
+}
+
+void WebViewCore::dump()
+{
+#if DUMP_NAV_CACHE
+ if (mFrame != NULL)
+ mFrame->getCacheBuilder().mDebug.print();
+#endif
+}
+
+WebCore::String WebViewCore::retrieveHref(WebCore::Frame* frame, WebCore::Node* node)
+{
+ WebCore::CacheBuilder& builder = mFrame->getCacheBuilder();
+ if (builder.validNode(frame, node) == false)
+ return WebCore::String();
+ if (node->hasTagName(WebCore::HTMLNames::aTag) == false)
+ return WebCore::String();
+ WebCore::HTMLAnchorElement* anchor = static_cast<WebCore::HTMLAnchorElement*>(node);
+ return anchor->href();
+}
+
+WebCore::String WebViewCore::retrieveImageRef(int x, int y)
+{
+ WebCore::IntPoint point(x,y);
+ WebCore::HitTestResult result = mFrame->eventHandler()->hitTestResultAtPoint(point, false);
+ WebCore::Node* node = result.innerNode();
+ if (node == NULL || node->hasTagName(WebCore::HTMLNames::imgTag) == false)
+ return WebCore::String();
+ WebCore::HTMLImageElement* img = static_cast<WebCore::HTMLImageElement*>(node);
+ return img->src();
+}
+
+bool WebViewCore::prepareFrameCache()
+{
+ if (mFrameCacheOutOfDate == false) {
+ DBG_NAV_LOG("mFrameCacheOutOfDate == false");
+ return false;
+ }
+ mFrameCacheOutOfDate = false;
+#if DEBUG_NAV_UI
+ DBG_NAV_LOG("mFrameCacheOutOfDate was true");
+ mNow = SkTime::GetMSecs();
+#endif
+ mTemp = new CachedRoot();
+ mTemp->init(mFrame, &mHistory);
+ mTemp->setGeneration(++mBuildGeneration);
+ WebCore::CacheBuilder& builder = mFrame->getCacheBuilder();
+ WebCore::Settings* settings = frame()->page()->settings();
+ builder.allowAllTextDetection();
+ if (settings->formatDetectionAddress() == false)
+ builder.disallowAddressDetection();
+ if (settings->formatDetectionEmail() == false)
+ builder.disallowEmailDetection();
+ if (settings->formatDetectionTelephone() == false)
+ builder.disallowPhoneDetection();
+ builder.buildCache(mTemp);
+ mTempPict = new SkPicture();
+ recordPicture(mTempPict, false);
+ mTemp->setPicture(mTempPict);
+ mTemp->setTextGeneration(mTextGeneration);
+ return true;
+}
+
+void WebViewCore::releaseFrameCache(bool newCache)
+{
+ if (newCache == false) {
+ DBG_NAV_LOG("newCache == false");
+ return;
+ }
+ gFrameCacheMutex.lock();
+ delete mFrameCacheKit;
+ delete mNavPictureKit;
+ mFrameCacheKit = mTemp;
+ mNavPictureKit = mTempPict;
+ mUpdatedFrameCache = true;
+#if DEBUG_NAV_UI
+ const CachedNode* cachedFocusNode = mFrameCacheKit->currentFocus();
+ DBG_NAV_LOGD("cachedFocusNode=%d (nodePointer=%p)",
+ cachedFocusNode ? cachedFocusNode->index() : 0,
+ cachedFocusNode ? cachedFocusNode->nodePointer() : NULL);
+#endif
+ gFrameCacheMutex.unlock();
+ notifyFocusSet();
+ // it's tempting to send an invalidate here, but it's a bad idea
+ // the cache is now up to date, but the focus is not -- the event
+ // may need to be recomputed from the prior history. An invalidate
+ // will draw the stale location causing the ring to flash at the wrong place.
+}
+
+void WebViewCore::updateFrameCache()
+{
+ mUseReplay = false;
+ releaseFrameCache(prepareFrameCache());
+}
+
+void WebViewCore::removeFrameGeneration(WebCore::Frame* frame)
+{
+ DBG_NAV_LOGD("frame=%p mGeneration=%d", frame, mGeneration);
+ gFrameGenerationMutex.lock();
+ int last = mFrameGenerations.size() - 1;
+ for (int index = 0; index <= last; index++) {
+ if (mFrameGenerations[index].mFrame == frame) {
+ DBG_NAV_LOGD("index=%d last=%d", index, last);
+ if (index != last)
+ mFrameGenerations[index] = mFrameGenerations[last];
+ mFrameGenerations.removeLast();
+ break;
+ }
+ }
+ gFrameGenerationMutex.unlock();
+}
+
+void WebViewCore::updateFrameGeneration(WebCore::Frame* frame)
+{
+ DBG_NAV_LOGD("frame=%p mGeneration=%d", frame, mGeneration);
+ gFrameGenerationMutex.lock();
+ ++mBuildGeneration;
+ for (size_t index = 0; index < mFrameGenerations.size(); index++) {
+ if (mFrameGenerations[index].mFrame == frame) {
+ DBG_NAV_LOG("replace");
+ mFrameGenerations[index].mGeneration = mBuildGeneration;
+ goto done;
+ }
+ }
+ {
+ FrameGen frameGen = {frame, mBuildGeneration};
+ mFrameGenerations.append(frameGen);
+ DBG_NAV_LOG("append");
+ }
+done:
+ gFrameGenerationMutex.unlock();
+}
+
+int WebViewCore::retrieveFrameGeneration(WebCore::Frame* frame)
+{
+ int result = INT_MAX;
+ gFrameGenerationMutex.lock();
+ for (size_t index = 0; index < mFrameGenerations.size(); index++) {
+ if (mFrameGenerations[index].mFrame == frame) {
+ result = mFrameGenerations[index].mGeneration;
+ break;
+ }
+ }
+ gFrameGenerationMutex.unlock();
+ DBG_NAV_LOGD("frame=%p mGeneration=%d result=%d", frame, mGeneration, result);
+ return result;
+}
+
+void WebViewCore::setFinalFocus(WebCore::Frame* frame, WebCore::Node* node,
+ int x, int y, bool block)
+{
+ DBG_NAV_LOGD("frame=%p node=%p x=%d y=%d", frame, node, x, y);
+ bool result = finalKitFocus(frame, node, x, y);
+ if (block) {
+ mBlockFocusChange = true;
+ if (result == false && node != NULL)
+ touchUp(mTouchGeneration, 0, NULL, NULL, x, y, 0, true, true);
+ }
+}
+
+void WebViewCore::setKitFocus(int moveGeneration, int buildGeneration,
+ WebCore::Frame* frame, WebCore::Node* node, int x, int y,
+ bool ignoreNullFocus)
+{
+ DBG_NAV_LOGD("mMoveGeneration=%d moveGeneration=%d"
+ " buildGeneration=%d frame=%p node=%p x=%d y=%d",
+ mMoveGeneration, moveGeneration, buildGeneration, frame, node, x, y);
+ if (mBlockFocusChange) {
+ DBG_NAV_LOG("mBlockFocusChange");
+ return;
+ }
+ if (mMoveGeneration > moveGeneration) {
+ DBG_NAV_LOGD("mMoveGeneration=%d > moveGeneration=%d",
+ mMoveGeneration, moveGeneration);
+ return; // short-circuit if a newer move has already been generated
+ }
+ if (commonKitFocus(moveGeneration, buildGeneration, frame, node, x, y,
+ ignoreNullFocus) == false)
+ return;
+ mLastGeneration = moveGeneration;
+}
+
+bool WebViewCore::commonKitFocus(int generation, int buildGeneration,
+ WebCore::Frame* frame, WebCore::Node* node, int x, int y,
+ bool ignoreNullFocus)
+{
+ DBG_NAV_LOGD("generation=%d buildGeneration=%d frame=%p"
+ " node=%p x=%d y=%d", generation, buildGeneration, frame, node, x, y);
+ mUseReplay = true;
+ bool newCache = prepareFrameCache(); // must wait for possible recompute before using
+ if (mMoveGeneration > generation) {
+ DBG_NAV_LOGD("mMoveGeneration=%d > generation=%d",
+ mMoveGeneration, generation);
+ releaseFrameCache(newCache);
+ return false; // short-circuit if a newer move has already been generated
+ }
+ // if the nav cache has been rebuilt since this focus request was generated,
+ // send a request back to the UI side to recompute the kit-side focus
+ if (mBuildGeneration > buildGeneration || (node != NULL && mFrame->getCacheBuilder().validNode(frame, node) == false)) {
+ DBG_NAV_LOGD("mBuildGeneration=%d > buildGeneration=%d",
+ mBuildGeneration, buildGeneration);
+ gRecomputeFocusMutex.lock();
+ bool first = mRecomputeEvents.size() == 0;
+ mRecomputeEvents.append(generation);
+ gRecomputeFocusMutex.unlock();
+ releaseFrameCache(newCache);
+ if (first)
+ sendRecomputeFocus();
+ return false;
+ }
+ releaseFrameCache(newCache);
+ if (node == NULL && ignoreNullFocus)
+ return true;
+ finalKitFocus(frame, node, x, y);
+ return true;
+}
+
+bool WebViewCore::finalKitFocus(WebCore::Frame* frame, WebCore::Node* node,
+ int x, int y)
+{
+ if (NULL == frame)
+ frame = mFrame;
+ WebCore::CacheBuilder& builder = mFrame->getCacheBuilder();
+ WebCore::Node* oldFocusNode = builder.currentFocus();
+ mMousePos = WebCore::IntPoint(x, y);
+ // validNode will still return true if the node is null, as long as we have
+ // a valid frame. Do not want to make a call on frame unless it is valid.
+ bool valid = builder.validNode(frame, node);
+ if (valid) {
+ WebCore::PlatformMouseEvent mouseEvent(mMousePos, mMousePos, WebCore::NoButton,
+ WebCore::MouseEventMoved, 1, false, false, false, false, WebCore::currentTime());
+ frame->eventHandler()->handleMouseMoveEvent(mouseEvent);
+ }
+ WebCore::Document* oldDoc = oldFocusNode ? oldFocusNode->document() : NULL;
+ if (node == NULL) {
+ if (oldFocusNode != NULL)
+ oldDoc->setFocusedNode(NULL);
+ return false;
+ } else if (valid == false) {
+ DBG_NAV_LOGD("sendMarkNodeInvalid node=%p", node);
+ sendMarkNodeInvalid(node);
+ if (oldFocusNode != NULL)
+ oldDoc->setFocusedNode(NULL);
+ return false;
+ }
+ // If we jump frames (docs), kill the focus on the old doc
+ builder.setLastFocus(node);
+ if (oldFocusNode != NULL && node->document() != oldDoc) {
+ oldDoc->setFocusedNode(NULL);
+ }
+ WebCore::RenderObject* renderer = node->renderer();
+ /* <area> element doesn't have a renderer, but it can accept focus */
+ LOG_ASSERT(!(renderer && renderer->isWidget()), "widgets unsupported");
+ if (node->isTextNode() == false)
+ static_cast<WebCore::Element*>(node)->focus(false);
+ //setFocus on things that WebCore doesn't recognize as supporting focus
+ //for instance, if there is an onclick element that does not support focus
+ DBG_NAV_LOGD("setFocusedNode node=%p", node);
+ node->document()->setFocusedNode(node);
+ mLastFocused = node;
+ mLastFocusedBounds = node->getRect();
+ return true;
+}
+
+// helper function to find the frame that has focus
+static WebCore::Frame* FocusedFrame(WebCore::FrameAndroid* frame)
+{
+ if (!frame)
+ return NULL;
+ WebCore::Node* focusNode = frame->getCacheBuilder().currentFocus();
+ if (!focusNode)
+ return NULL;
+ WebCore::Document* doc = focusNode->document();
+ if (!doc)
+ return NULL;
+ return doc->frame();
+}
+
+static WebCore::RenderTextControl* FocusedTextControl(WebCore::FrameAndroid* frame)
+{
+ WebCore::Node* focusNode = frame->getCacheBuilder().currentFocus();
+ WebCore::RenderObject* renderer = focusNode->renderer();
+ if (renderer && (renderer->isTextField() || renderer->isTextArea())) {
+ return static_cast<WebCore::RenderTextControl*>(renderer);
+ }
+ return NULL;
+}
+
+WebCore::Frame* WebViewCore::changedKitFocus(WebCore::Frame* frame,
+ WebCore::Node* node, int x, int y)
+{
+ if (frame == NULL || node == NULL)
+ return mFrame;
+ WebCore::Node* current = mFrame->getCacheBuilder().currentFocus();
+ if (current == node)
+ return frame;
+ return finalKitFocus(frame, node, x, y) ? frame : mFrame;
+}
+
+static int findTextBoxIndex(WebCore::Node* node, const WebCore::IntPoint& pt)
+{
+ if (node->isTextNode() == false) {
+ DBG_NAV_LOGD("node=%p pt=(%d,%d) isText=false", node, pt.x(), pt.y());
+ return -2; // error
+ }
+ WebCore::RenderText* renderText = (WebCore::RenderText*) node->renderer();
+ if (renderText == NULL) {
+ DBG_NAV_LOGD("node=%p pt=(%d,%d) renderText=NULL", node, pt.x(), pt.y());
+ return -3; // error
+ }
+ int renderX, renderY;
+ renderText->absolutePosition(renderX, renderY);
+ WebCore::InlineTextBox *textBox = renderText->firstTextBox();
+ int globalX, globalY;
+ WebCore::CacheBuilder::GetGlobalOffset(node, &globalX, &globalY);
+ int x = pt.x() - globalX;
+ int y = pt.y() - globalY;
+ do {
+ int textBoxStart = textBox->start();
+ int textBoxEnd = textBoxStart + textBox->len();
+ if (textBoxEnd <= textBoxStart)
+ continue;
+ WebCore::IntRect bounds = textBox->selectionRect(renderX, renderY,
+ textBoxStart, textBoxEnd);
+ if (bounds.contains(x, y) == false)
+ continue;
+ int offset = textBox->offsetForPosition(x - renderX);
+#if DEBUG_NAV_UI
+ int prior = offset > 0 ? textBox->positionForOffset(offset - 1) : -1;
+ int current = textBox->positionForOffset(offset);
+ int next = textBox->positionForOffset(offset + 1);
+ DBG_NAV_LOGD(
+ "offset=%d pt.x=%d globalX=%d renderX=%d x=%d "
+ "textBox->x()=%d textBox->start()=%d prior=%d current=%d next=%d",
+ offset, pt.x(), globalX, renderX, x,
+ textBox->xPos(), textBox->start(), prior, current, next
+ );
+#endif
+ return textBox->start() + offset;
+ } while ((textBox = textBox->nextTextBox()) != NULL);
+ return -1; // couldn't find point, may have walked off end
+}
+
+static inline bool isSpace(UChar c)
+{
+ return c <= ' ' || WTF::Unicode::direction(c) == WTF::Unicode::WhiteSpaceNeutral;
+}
+
+static int centerX(const SkIRect& rect) { return (rect.fLeft + rect.fRight) >> 1; }
+static int centerY(const SkIRect& rect) { return (rect.fTop + rect.fBottom) >> 1; }
+
+WebCore::String WebViewCore::getSelection(SkRegion* selRgn)
+{
+ SkRegion::Iterator iter(*selRgn);
+ WebCore::String result;
+ for (; iter.done() == false; iter.next()) {
+ const SkIRect& rect = iter.rect();
+ DBG_NAV_LOGD("rect=(%d, %d, %d, %d)", rect.fLeft, rect.fTop,
+ rect.fRight, rect.fBottom);
+ int cy = centerY(rect);
+ WebCore::IntPoint startPt = WebCore::IntPoint(rect.fLeft + 1, cy);
+ WebCore::HitTestResult hitTestResult = mFrame->eventHandler()->
+ hitTestResultAtPoint(startPt, false);
+ WebCore::Node* node = hitTestResult.innerNode();
+ if (node == NULL) {
+ DBG_NAV_LOG("node == NULL");
+ return result;
+ }
+ WebCore::IntPoint endPt = WebCore::IntPoint(rect.fRight - 1, cy);
+ hitTestResult = mFrame->eventHandler()->hitTestResultAtPoint(endPt, false);
+ WebCore::Node* endNode = hitTestResult.innerNode();
+ if (endNode == NULL) {
+ DBG_NAV_LOG("endNode == NULL");
+ return result;
+ }
+ int start = findTextBoxIndex(node, startPt);
+ if (start < 0)
+ continue;
+ int end = findTextBoxIndex(endNode, endPt);
+ if (end < -1) // use node if endNode is not valid
+ endNode = node;
+ if (end <= 0)
+ end = static_cast<WebCore::Text*>(endNode)->string()->length();
+ DBG_NAV_LOGD("node=%p start=%d endNode=%p end=%d", node, start, endNode, end);
+ do {
+ if (node->isTextNode() == false)
+ continue;
+ if (node->getRect().isEmpty())
+ continue;
+ WebCore::Text* textNode = static_cast<WebCore::Text*>(node);
+ WebCore::StringImpl* string = textNode->string();
+ if (string->length() == 0)
+ continue;
+ const UChar* chars = string->characters();
+ int newLen = node == endNode ? end : string->length();
+ int oldLen = result.length();
+ if (oldLen == 0) {
+ if (newLen < start) {
+ DBG_NAV_LOGD("newLen=%d < start=%d", newLen, start);
+ return result;
+ }
+ result.append(chars + start, newLen - start);
+ continue;
+ }
+ if (isSpace(result.characters()[oldLen - 1]) == false &&
+ isSpace(chars[0]) == false) {
+ result.append(" ");
+ }
+ result.append(chars, newLen);
+ } while (node != endNode && (node = node->traverseNextNode()) != NULL);
+ }
+#if DUMP_NAV_CACHE
+ {
+ char buffer[256];
+ WebCore::CacheBuilder::Debug debug;
+ debug.init(buffer, sizeof(buffer));
+ debug.print("copy: ");
+ debug.wideString(result);
+ DUMP_NAV_LOGD("%s", buffer);
+ }
+#endif
+ return result;
+}
+
+WebCore::Frame* WebViewCore::setSelection(WebCore::Frame* frame, WebCore::Node* node,
+ int x, int y, int start, int end)
+{
+ // FIXME: Consider using a generation number to avoid doing this many more times than necessary.
+ frame = changedKitFocus(frame, node, x, y);
+ ((WebCore::FrameAndroid*) frame)->select(start, end);
+ return frame;
+}
+
+WebCore::Frame* WebViewCore::deleteSelection(WebCore::Frame* frame, WebCore::Node* node,
+ int x, int y, int start, int end)
+{
+ frame = setSelection(frame, node, x, y, start, end);
+ if (start != end) {
+ WebCore::PlatformKeyboardEvent downEvent(kKeyCodeDel, WebCore::VK_BACK, true, false, false, false, false);
+ frame->eventHandler()->keyEvent(downEvent);
+ WebCore::PlatformKeyboardEvent upEvent(kKeyCodeDel, WebCore::VK_BACK, false, false, false, false, false);
+ frame->eventHandler()->keyEvent(upEvent);
+ }
+ return frame;
+}
+
+void WebViewCore::replaceTextfieldText(WebCore::Frame* frame, WebCore::Node* node, int x, int y,
+ int oldStart, int oldEnd, jstring replace, int start, int end)
+{
+ JNIEnv* env = javavm_to_jnienv(mJavaGlue->mJVM);
+ const jchar* outputChars = NULL == replace ? NULL : env->GetStringChars(replace, NULL);
+
+ WebCore::String webcoreString;
+ if (outputChars == NULL) {
+ webcoreString = WebCore::String();
+ }
+ else {
+ webcoreString = WebCore::String((const UChar*) outputChars, env->GetStringLength(replace));
+ }
+ frame = setSelection(frame, node, x, y, oldStart, oldEnd);
+ WebCore::TypingCommand::insertText(frame->document(), webcoreString, false);
+ ((WebCore::FrameAndroid*) frame)->select(start, end);
+ if (replace && outputChars)
+ env->ReleaseStringChars(replace, outputChars);
+ checkException(env);
+}
+
+void WebViewCore::passToJs(WebCore::Frame* frame, WebCore::Node* node, int x, int y, int generation,
+ jstring currentText, int keyCode, int keyValue, bool down, bool cap, bool fn, bool sym)
+{
+ frame = changedKitFocus(frame, node, x, y);
+ WebCore::PlatformKeyboardEvent event(keyCode, keyValue, down, false, cap, fn, sym);
+ // Block text field updates during a key press.
+ mBlockTextfieldUpdates = true;
+ frame->eventHandler()->keyEvent(event);
+ mBlockTextfieldUpdates = false;
+ mTextGeneration = generation;
+
+ WebCore::Node* currentFocus = mFrame->getCacheBuilder().currentFocus();
+ // Make sure we have the same focus and it is a text field.
+ if (node == currentFocus && currentFocus) {
+ WebCore::RenderObject* renderer = currentFocus->renderer();
+ if (renderer != NULL && (renderer->isTextField() || renderer->isTextArea())) {
+ WebCore::RenderTextControl* renderText = static_cast<WebCore::RenderTextControl*>(renderer);
+ JNIEnv* env = javavm_to_jnienv(mJavaGlue->mJVM);
+ const jchar* str = env->GetStringChars(currentText, NULL);
+ WebCore::String current = WebCore::String(str, env->GetStringLength(currentText));
+ env->ReleaseStringChars(currentText, str);
+ WebCore::String test = renderText->text();
+ // If the text changed during the key event, update the UI text field.
+ if (test != current)
+ updateTextfield(currentFocus, false, test);
+ }
+ }
+}
+
+void WebViewCore::saveDocumentState(WebCore::Frame* frame, WebCore::Node* node, int x, int y)
+{
+ frame = changedKitFocus(frame, node, x, y);
+ WebCore::HistoryItem *item = frame->loader()->currentHistoryItem();
+
+ // item can be null when there is no offical URL for the current page. This happens
+ // when the content is loaded using with WebCoreFrameBridge::LoadData() and there
+ // is no failing URL (common case is when content is loaded using data: scheme)
+ if (item != 0) {
+ item->setDocumentState(frame->document()->formElementsState());
+ }
+}
+
+// Convert a WebCore::String into an array of characters where the first
+// character represents the length, for easy conversion to java.
+static uint16_t* stringConverter(const WebCore::String& text)
+{
+ size_t length = text.length();
+ uint16_t* itemName = new uint16_t[length+1];
+ itemName[0] = (uint16_t)length;
+ uint16_t* firstChar = &(itemName[1]);
+ memcpy((void*)firstChar, text.characters(), sizeof(UChar)*length);
+ return itemName;
+}
+
+// Response to dropdown created for a listbox.
+class ListBoxReply : public WebCoreReply {
+public:
+ ListBoxReply(WebCore::HTMLSelectElement* select, WebCore::Frame* frame, WebViewCore* view)
+ : m_select(select)
+ , m_frame(frame)
+ , m_viewImpl(view)
+ {}
+
+ // Response used if the listbox only allows single selection.
+ // index is listIndex of the selected item, or -1 if nothing is selected.
+ virtual void replyInt(int index) {
+ // If the select element no longer exists, do to a page change, etc, silently return.
+ if (!m_select || m_viewImpl->mFrame->getCacheBuilder().validNode(m_frame, m_select) == false)
+ return;
+ if (-1 == index) {
+ if (m_select->selectedIndex() != -1) {
+ m_select->deselectItems();
+ m_select->onChange();
+ m_viewImpl->contentInvalidate();
+ }
+ return;
+ }
+ WebCore::HTMLOptionElement* option = static_cast<WebCore::HTMLOptionElement*>(
+ m_select->item(m_select->listToOptionIndex(index)));
+ if (!option->selected()) {
+ option->setSelected(true);
+ m_select->onChange();
+ m_viewImpl->contentInvalidate();
+ }
+ }
+
+ // Response if the listbox allows multiple selection. array stores the listIndices
+ // of selected positions.
+ virtual void replyIntArray(SkTDArray<int> array) {
+ // If the select element no longer exists, do to a page change, etc, silently return.
+ if (!m_select || m_viewImpl->mFrame->getCacheBuilder().validNode(m_frame, m_select) == false)
+ return;
+ m_select->deselectItems();
+ int count = array.count();
+ WebCore::HTMLOptionElement* option;
+ for (int i = 0; i < count; i++) {
+ option = static_cast<WebCore::HTMLOptionElement*>(
+ m_select->item(array[m_select->listToOptionIndex(i)]));
+ option->setSelected(true);
+ }
+ m_viewImpl->contentInvalidate();
+ }
+private:
+ // The select element associated with this listbox.
+ WebCore::HTMLSelectElement* m_select;
+ // The frame of this select element, to verify that it is valid.
+ WebCore::Frame* m_frame;
+ // For calling invalidate.
+ WebViewCore* m_viewImpl;
+};
+
+// Create an array of java Strings.
+static jobjectArray makeLabelArray(JNIEnv* env, const uint16_t** labels, size_t count)
+{
+ jclass stringClass = env->FindClass("java/lang/String");
+ LOG_ASSERT(stringClass, "Could not find java/lang/String");
+ jobjectArray array = env->NewObjectArray(count, stringClass, NULL);
+ LOG_ASSERT(array, "Could not create new string array");
+
+ for (size_t i = 0; i < count; i++) {
+ jobject newString = env->NewString(&labels[i][1], labels[i][0]);
+ env->SetObjectArrayElement(array, i, newString);
+ env->DeleteLocalRef(newString);
+ checkException(env);
+ }
+ env->DeleteLocalRef(stringClass);
+ return array;
+}
+
+void WebViewCore::listBoxRequest(WebCoreReply* reply, const uint16_t** labels, size_t count, const int enabled[], size_t enabledCount,
+ bool multiple, const int selected[], size_t selectedCountOrSelection) {
+ // Reuse mPopupReply
+ Release(mPopupReply);
+ mPopupReply = NULL;
+
+ LOG_ASSERT(mJavaGlue->mObj, "No java widget associated with this view!");
+
+ // Create an array of java Strings for the drop down.
+ JNIEnv* env = javavm_to_jnienv(mJavaGlue->mJVM);
+ jobjectArray labelArray = makeLabelArray(env, labels, count);
+
+ // Create an array determining whether each item is enabled.
+ jbooleanArray enabledArray = env->NewBooleanArray(enabledCount);
+ checkException(env);
+ jboolean* ptrArray = env->GetBooleanArrayElements(enabledArray, NULL);
+ checkException(env);
+ for (size_t i = 0; i < enabledCount; i++) {
+ ptrArray[i] = enabled[i];
+ }
+ env->ReleaseBooleanArrayElements(enabledArray, NULL, enabledCount);
+ checkException(env);
+
+ if (multiple) {
+ // Pass up an array representing which items are selected.
+ jintArray selectedArray = env->NewIntArray(selectedCountOrSelection);
+ checkException(env);
+ jint* selArray = env->GetIntArrayElements(selectedArray, NULL);
+ checkException(env);
+ for (size_t i = 0; i < selectedCountOrSelection; i++) {
+ selArray[i] = selected[i];
+ }
+ env->ReleaseIntArrayElements(selectedArray, NULL, selectedCountOrSelection);
+
+ env->CallVoidMethod(mJavaGlue->mObj, mJavaGlue->mRequestListBox, labelArray, enabledArray, selectedArray);
+ env->DeleteLocalRef(selectedArray);
+ } else {
+ // Pass up the single selection.
+ env->CallVoidMethod(mJavaGlue->mObj, mJavaGlue->mRequestSingleListBox, labelArray, enabledArray, selectedCountOrSelection);
+ }
+
+ env->DeleteLocalRef(labelArray);
+ env->DeleteLocalRef(enabledArray);
+ checkException(env);
+
+ Retain(reply);
+ mPopupReply = reply;
+}
+
+bool WebViewCore::keyUp(KeyCode keyCode, int keyVal)
+{
+ DBG_NAV_LOGD("keyCode=%d", keyCode);
+ bool keyHandled = false;
+ WebCore::Node* focusNode = mFrame->getCacheBuilder().currentFocus();
+ if (focusNode != NULL) {
+ WebCore::FrameAndroid* focusFrame = Android(focusNode->document()->frame());
+
+ WebCoreFrameBridge* bridge = mFrame->bridge();
+ switch (keyCode) {
+ case kKeyCodeNewline:
+ case kKeyCodeDpadCenter: {
+ focusFrame->loader()->resetMultipleFormSubmissionProtection();
+ bridge->setInKeyHandler(true);
+ if ((focusNode->hasTagName(WebCore::HTMLNames::inputTag) &&
+ ((WebCore::HTMLInputElement*)focusNode)->isTextField()) ||
+ focusNode->hasTagName(WebCore::HTMLNames::textareaTag)) {
+ // Create the key down event.
+ WebCore::PlatformKeyboardEvent keydown(keyCode, keyVal, true, false, false, false, false);
+ // Create the key up event.
+ WebCore::PlatformKeyboardEvent keyup(keyCode, keyVal, false, false, false, false, false);
+ // Send both events.
+ keyHandled = focusFrame->eventHandler()->keyEvent(keydown);
+ keyHandled |= focusFrame->eventHandler()->keyEvent(keyup);
+ } else {
+ keyHandled = handleMouseClick(focusFrame, focusNode);
+ }
+ bridge->setInKeyHandler(false);
+ break;
+ }
+ default:
+ keyHandled = false;
+ }
+ }
+ mBlockFocusChange = false;
+ return keyHandled;
+}
+
+void WebViewCore::touchUp(int touchGeneration, int buildGeneration,
+ WebCore::Frame* frame, WebCore::Node* node, int x, int y, int size,
+ bool isClick, bool retry)
+{
+ if (mTouchGeneration > touchGeneration) {
+ DBG_NAV_LOGD("mTouchGeneration=%d > touchGeneration=%d"
+ " x=%d y=%d", mTouchGeneration, touchGeneration, x, y);
+ return; // short circuit if a newer touch has been generated
+ }
+ if (retry)
+ finalKitFocus(frame, node, x, y);
+ else if (commonKitFocus(touchGeneration, buildGeneration,
+ frame, node, x, y, false) == false) {
+ return;
+ }
+ mLastGeneration = touchGeneration;
+ // If this is just a touch and not a click, we have already done the change in focus,
+ // so just leave the function now.
+ if (!isClick)
+ return;
+ WebCore::EditorClientAndroid* client = static_cast<WebCore::EditorClientAndroid*>(mFrame->editor()->client());
+ client->setFromClick(true);
+ DBG_NAV_LOGD("touchGeneration=%d handleMouseClick frame=%p node=%p"
+ " x=%d y=%d", touchGeneration, frame, node, x, y);
+ handleMouseClick(frame, node);
+ client->setFromClick(false);
+}
+
+bool WebViewCore::handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* nodePtr) {
+ if (framePtr != NULL && mFrame->getCacheBuilder().validNode(framePtr, nodePtr) == false)
+ return false;
+ WebCoreFrameBridge* bridge = mFrame->bridge();
+ // Need to special case area tags because an image map could have an area element in the middle
+ // so when attempting to get the default, the point chosen would be follow the wrong link.
+ if (nodePtr != NULL && nodePtr->hasTagName(WebCore::HTMLNames::areaTag)) {
+ bridge->setInKeyHandler(true);
+ WebCore::EventTargetNodeCast(nodePtr)->dispatchSimulatedClick(0, true, true);
+ bridge->setInKeyHandler(false);
+ return true;
+ }
+ WebCore::RenderObject* renderer = nodePtr != NULL ? nodePtr->renderer() : NULL;
+ if (renderer) {
+ if (renderer->isMenuList()) {
+ WebCore::HTMLSelectElement* select = static_cast<WebCore::HTMLSelectElement*>(nodePtr);
+ const WTF::Vector<WebCore::HTMLElement*>& listItems = select->listItems();
+ SkTDArray<const uint16_t*> names;
+ SkTDArray<int> enabledArray;
+ SkTDArray<int> selectedArray;
+ int size = listItems.size();
+ bool multiple = select->multiple();
+ for (int i = 0; i < size; i++) {
+ if (listItems[i]->hasTagName(WebCore::HTMLNames::optionTag)) {
+ WebCore::HTMLOptionElement* option = static_cast<WebCore::HTMLOptionElement*>(listItems[i]);
+ *names.append() = stringConverter(option->optionText());
+ *enabledArray.append() = option->disabled() ? 0 : 1;
+ if (multiple && option->selected())
+ *selectedArray.append() = i;
+ } else if (listItems[i]->hasTagName(WebCore::HTMLNames::optgroupTag)) {
+ WebCore::HTMLOptGroupElement* optGroup = static_cast<WebCore::HTMLOptGroupElement*>(listItems[i]);
+ *names.append() = stringConverter(optGroup->groupLabelText());
+ *enabledArray.append() = 0;
+ if (multiple)
+ *selectedArray.append() = 0;
+ }
+ }
+ WebCoreReply* reply = new ListBoxReply(select, select->document()->frame(), this);
+ listBoxRequest(reply, names.begin(), size, enabledArray.begin(), enabledArray.count(),
+ multiple, selectedArray.begin(), multiple ? selectedArray.count() :
+ select->optionToListIndex(select->selectedIndex()));
+ return true;
+ }
+ }
+ if (NULL == framePtr)
+ framePtr = mFrame;
+ bridge->setInKeyHandler(true);
+ DBG_NAV_LOGD("mMousePos={%d,%d}", mMousePos.x(), mMousePos.y());
+ WebCore::PlatformMouseEvent mouseDown(mMousePos, mMousePos, WebCore::LeftButton,
+ WebCore::MouseEventPressed, 1, false, false, false, false,
+ WebCore::currentTime());
+ // ignore the return from as it will return true if the hit point can trigger selection change
+ framePtr->eventHandler()->handleMousePressEvent(mouseDown);
+ WebCore::PlatformMouseEvent mouseUp(mMousePos, mMousePos, WebCore::LeftButton,
+ WebCore::MouseEventReleased, 1, false, false, false, false,
+ WebCore::currentTime());
+ bool handled = framePtr->eventHandler()->handleMouseReleaseEvent(mouseUp);
+ bridge->setInKeyHandler(false);
+ return handled;
+}
+
+void WebViewCore::popupReply(int index)
+{
+ if (mPopupReply) {
+ mPopupReply->replyInt(index);
+ Release(mPopupReply);
+ mPopupReply = NULL;
+ }
+}
+
+void WebViewCore::popupReply(SkTDArray<int> array) {
+ if (mPopupReply) {
+ mPopupReply->replyIntArray(array);
+ Release(mPopupReply);
+ mPopupReply = NULL;
+ }
+}
+
+void WebViewCore::jsAlert(const WebCore::String& url, const WebCore::String& text)
+{
+ JNIEnv* env = javavm_to_jnienv(mJavaGlue->mJVM);
+ jstring jInputStr = env->NewString((unsigned short *)text.characters(), text.length());
+ jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length());
+ env->CallVoidMethod(mJavaGlue->mObj, mJavaGlue->mJsAlert, jUrlStr, jInputStr);
+ env->DeleteLocalRef(jInputStr);
+ env->DeleteLocalRef(jUrlStr);
+ checkException(env);
+}
+
+bool WebViewCore::jsConfirm(const WebCore::String& url, const WebCore::String& text)
+{
+ JNIEnv* env = javavm_to_jnienv(mJavaGlue->mJVM);
+ jstring jInputStr = env->NewString((unsigned short *)text.characters(), text.length());
+ jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length());
+ jboolean result = env->CallBooleanMethod(mJavaGlue->mObj, mJavaGlue->mJsConfirm, jUrlStr, jInputStr);
+ env->DeleteLocalRef(jInputStr);
+ env->DeleteLocalRef(jUrlStr);
+ checkException(env);
+ return result;
+}
+
+bool WebViewCore::jsPrompt(const WebCore::String& url, const WebCore::String& text, const WebCore::String& defaultValue, WebCore::String& result)
+{
+ JNIEnv* env = javavm_to_jnienv(mJavaGlue->mJVM);
+ jstring jInputStr = env->NewString((unsigned short *)text.characters(), text.length());
+ jstring jDefaultStr = env->NewString((unsigned short *)defaultValue.characters(), defaultValue.length());
+ jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length());
+ jstring returnVal = (jstring) env->CallObjectMethod(mJavaGlue->mObj, mJavaGlue->mJsPrompt, jUrlStr, jInputStr, jDefaultStr);
+ // If returnVal is null, it means that the user cancelled the dialog.
+ if (!returnVal)
+ return false;
+
+ const jchar* outputChars = env->GetStringChars(returnVal, NULL);
+ if (outputChars == NULL) {
+ result = WebCore::String();
+ } else {
+ result = WebCore::String((const UChar*) outputChars, env->GetStringLength(returnVal));
+ }
+ env->ReleaseStringChars(returnVal, outputChars);
+ env->DeleteLocalRef(jInputStr);
+ env->DeleteLocalRef(jDefaultStr);
+ env->DeleteLocalRef(jUrlStr);
+ checkException(env);
+ return true;
+}
+
+bool WebViewCore::jsUnload(const WebCore::String& url, const WebCore::String& message)
+{
+ JNIEnv* env = javavm_to_jnienv(mJavaGlue->mJVM);
+ jstring jInputStr = env->NewString((unsigned short *)message.characters(), message.length());
+ jstring jUrlStr = env->NewString((unsigned short *)url.characters(), url.length());
+ jboolean result = env->CallBooleanMethod(mJavaGlue->mObj, mJavaGlue->mJsUnload, jUrlStr, jInputStr);
+ env->DeleteLocalRef(jInputStr);
+ env->DeleteLocalRef(jUrlStr);
+ checkException(env);
+ return result;
+}
+
+WebCoreViewBridge*
+WebViewCore::createBridgeForView(WebCore::FrameView* view)
+{
+ SkASSERT(view);
+ WebViewCore* viewBridge = new WebViewCore(javavm_to_jnienv(mJavaGlue->mJVM), mJavaGlue->mObj, view);
+ WebCore::IntRect r = getBounds();
+ viewBridge->setBounds(r.x(), r.y(), r.right(), r.bottom());
+ return viewBridge;
+}
+
+jobject
+WebViewCore::getJavaObject()
+{
+ return mJavaGlue->mObj;
+}
+
+jobject
+WebViewCore::getWebViewJavaObject()
+{
+ JNIEnv* env = javavm_to_jnienv(mJavaGlue->mJVM);
+ return env->GetObjectField(mJavaGlue->mObj, gWebViewCoreFields.mWebView);
+}
+
+void WebViewCore::updateTextfield(WebCore::Node* ptr, bool changeToPassword,
+ const WebCore::String& text)
+{
+ if (mBlockTextfieldUpdates)
+ return;
+ JNIEnv* env = javavm_to_jnienv(mJavaGlue->mJVM);
+ if (changeToPassword) {
+ env->CallVoidMethod(mJavaGlue->mObj, mJavaGlue->mUpdateTextfield,
+ (int) ptr, true, NULL, mTextGeneration);
+ checkException(env);
+ return;
+ }
+ int length = text.length();
+ jstring string = env->NewString((unsigned short *) text.characters(), length);
+ env->CallVoidMethod(mJavaGlue->mObj, mJavaGlue->mUpdateTextfield,
+ (int) ptr, false, string, mTextGeneration);
+ env->DeleteLocalRef(string);
+ checkException(env);
+}
+
+void WebViewCore::setSnapAnchor(int x, int y)
+{
+ mSnapAnchorNode = NULL;
+ if (x == 0 && y == 0) {
+ return;
+ }
+
+ WebCore::IntPoint point = WebCore::IntPoint(x, y);
+ WebCore::Node* node = mFrame->eventHandler()->hitTestResultAtPoint(point, false).innerNode();
+ if (node) {
+// LOGD("found focus node name: %s, type %d\n", node->nodeName().utf8().data(), node->nodeType());
+ while (node) {
+ if (node->hasTagName(WebCore::HTMLNames::divTag) ||
+ node->hasTagName(WebCore::HTMLNames::tableTag)) {
+ mSnapAnchorNode = node;
+ return;
+ }
+// LOGD("parent node name: %s, type %d\n", node->nodeName().utf8().data(), node->nodeType());
+ node = node->parentNode();
+ }
+ }
+}
+
+void WebViewCore::snapToAnchor()
+{
+ if (mSnapAnchorNode) {
+ if (mSnapAnchorNode->inDocument()) {
+ int rx, ry;
+ mSnapAnchorNode->renderer()->absolutePosition(rx, ry);
+ scrollTo(rx, ry);
+ } else {
+ mSnapAnchorNode = NULL;
+ }
+ }
+}
+
+void WebViewCore::setBackgroundColor(SkColor c)
+{
+ WebCore::FrameView* view = mFrame->view();
+ if (view == NULL)
+ return;
+ WebCore::Color bcolor(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c),
+ SkColorGetA(c));
+ view->setBaseBackgroundColor(bcolor);
+}
+
+//----------------------------------------------------------------------
+// Native JNI methods
+//----------------------------------------------------------------------
+static jstring WebCoreStringToJString(JNIEnv *env, WebCore::String string)
+{
+ int length = string.length();
+ if (0 == length)
+ return 0;
+ jstring ret = env->NewString((jchar *)string.characters(), length);
+ env->DeleteLocalRef(ret);
+ return ret;
+}
+
+void WebViewCore::SetSize(JNIEnv *env, jobject obj, jint width, jint height,
+ jint screenWidth, jfloat scale)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterWV counter;
+#endif
+ WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+ LOGV("webviewcore::nativeSetSize(%u %u)\n viewImpl: %p", (unsigned)width, (unsigned)height, viewImpl);
+ LOG_ASSERT(viewImpl, "viewImpl not set in nativeSetSize");
+ // convert the scale to an int
+ int s = (int) (scale * 100);
+ // a negative value indicates that we should not change the scale
+ if (scale < 0)
+ s = viewImpl->scale();
+
+ viewImpl->setSizeScreenWidthAndScale(width, height, screenWidth, s);
+}
+
+void WebViewCore::SetVisibleRect(JNIEnv *env, jobject obj,
+ jint x, jint y, jint width, jint height)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterWV counter;
+#endif
+ WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(viewImpl, "need viewImpl");
+
+ viewImpl->setVisibleRect(WebCore::IntRect(x, y, width, height));
+}
+
+jboolean WebViewCore::KeyUp(JNIEnv *env, jobject obj, jint key, jint val)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterWV counter;
+#endif
+// LOGV("webviewcore::nativeKeyUp(%u)\n", (unsigned)key);
+ WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(viewImpl, "viewImpl not set in nativeKeyUp");
+ return viewImpl->keyUp((KeyCode)key, val);
+}
+
+void WebViewCore::DeleteSelection(JNIEnv *env, jobject obj,
+ jint frame, jint node, jint x, jint y, jint start, jint end)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterWV counter;
+#endif
+ LOGV("webviewcore::nativeDeleteSelection()\n");
+ WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(viewImpl, "viewImpl not set in nativeDeleteSelection");
+ viewImpl->deleteSelection((WebCore::Frame*) frame, (WebCore::Node*) node,
+ x, y, start, end);
+}
+
+void WebViewCore::SetSelection(JNIEnv *env, jobject obj,
+ jint frame, jint node, jint x, jint y, jint start, jint end)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterWV counter;
+#endif
+ LOGV("webviewcore::nativeSetSelection()\n");
+ WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(viewImpl, "viewImpl not set in nativeDeleteSelection");
+ viewImpl->setSelection((WebCore::Frame*) frame, (WebCore::Node*) node,
+ x, y, start, end);
+}
+
+
+void WebViewCore::ReplaceTextfieldText(JNIEnv *env, jobject obj,
+ jint framePtr, jint nodePtr, jint x, jint y, jint oldStart, jint oldEnd,
+ jstring replace, jint start, jint end)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterWV counter;
+#endif
+ LOGV("webviewcore::nativeReplaceTextfieldText()\n");
+ WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(viewImpl, "viewImpl not set in nativeReplaceTextfieldText");
+ viewImpl->replaceTextfieldText((WebCore::Frame*) framePtr, (WebCore::Node*) nodePtr, x, y, oldStart,
+ oldEnd, replace, start, end);
+}
+
+void WebViewCore::PassToJs(JNIEnv *env, jobject obj, jint frame, jint node,
+ jint x, jint y, jint generation, jstring currentText, jint keyCode,
+ jint keyValue, jboolean down, jboolean cap, jboolean fn, jboolean sym)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterWV counter;
+#endif
+ LOGV("webviewcore::nativePassToJs()\n");
+ WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(viewImpl, "viewImpl not set in nativePassToJs");
+ viewImpl->passToJs((WebCore::Frame*) frame, (WebCore::Node*) node,
+ x, y, generation, currentText, keyCode, keyValue, down, cap, fn, sym);
+}
+
+void WebViewCore::SaveDocumentState(JNIEnv *env, jobject obj, jint frame, jint node, jint x, jint y)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterWV counter;
+#endif
+ LOGV("webviewcore::nativeSaveDocumentState()\n");
+ WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(viewImpl, "viewImpl not set in nativeSaveDocumentState");
+ viewImpl->saveDocumentState((WebCore::Frame*) frame, (WebCore::Node*) node, x, y);
+}
+
+void WebViewCore::Draw(JNIEnv *env, jobject obj, jobject contentPict)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterWV counter;
+#endif
+ WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(viewImpl, "viewImpl not set in nativeDraw");
+ LOG_ASSERT(contentPict, "need a valid java picture for nativeDraw");
+ SkPicture* picture = GraphicsJNI::getNativePicture(env, contentPict);
+ LOG_ASSERT(picture, "need native picture in nativeDraw");
+ viewImpl->recordPicture(picture, true);
+}
+
+void WebViewCore::SendListBoxChoice(JNIEnv* env, jobject obj, jint choice)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterWV counter;
+#endif
+ WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoice");
+ viewImpl->popupReply(choice);
+}
+
+void WebViewCore::SendListBoxChoices(JNIEnv* env, jobject obj, jbooleanArray jArray, jint size)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterWV counter;
+#endif
+ WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(viewImpl, "viewImpl not set in nativeSendListBoxChoices");
+ jboolean* ptrArray = env->GetBooleanArrayElements(jArray, NULL);
+ SkTDArray<int> array;
+ for (int i = 0; i < size; i++) {
+ if (ptrArray[i]) {
+ *array.append() = i;
+ }
+ }
+ viewImpl->popupReply(array);
+}
+
+void WebViewCore::ClearMatches(JNIEnv *env, jobject obj)
+{
+ WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(viewImpl, "viewImpl not set in nativeClearMatches");
+
+ WebCore::Frame* frame = viewImpl->frame();
+ while (frame) {
+ if (frame->document())
+ frame->document()->removeMarkers();
+ WebCore::SelectionController* controller = frame->selectionController();
+ if (controller->isRange()) {
+ WebCore::Position pos = controller->start();
+ WebCore::Position end = controller->end();
+ do {
+ if (pos.inRenderedText()) {
+ WebCore::RenderObject* renderer = pos.node()->renderer();
+ if (renderer != NULL) {
+ renderer->setSelectionState(WebCore::RenderObject::SelectionNone);
+ }
+ }
+ pos = pos.next();
+ } while (pos != end);
+ controller->clear();
+ }
+ frame = frame->tree()->traverseNext();
+ }
+}
+
+jboolean WebViewCore::Find(JNIEnv *env, jobject obj, jstring find,
+ jboolean forward, jboolean fromSelection) {
+ WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(viewImpl, "viewImpl not set in nativeFind");
+
+ if (NULL == find)
+ return false;
+ int length = env->GetStringLength(find);
+ if (0 == length)
+ return false; // perhaps we want to return true, in order to show the correct dialog
+ const jchar* findChars = env->GetStringChars(find, NULL);
+ // Will this ever return NULL if find is not NULL and its length is not zero?
+ if (NULL == findChars)
+ return false;
+ WebCore::String findString = WebCore::String((const UChar*) findChars, length);
+ env->ReleaseStringChars(find, findChars);
+ WebCore::Frame* mainFrame = viewImpl->frame();
+ WebCore::Frame* frame = mainFrame;
+ bool found = false;
+ if (fromSelection) {
+ // Need to figure out which frame has a selection, then start from there
+ while (frame && frame->selectionController()->isNone()) {
+ frame = frame->tree()->traverseNext();
+ }
+ if (!frame) {
+ // No selection, so start from the beginning.
+ frame = mainFrame;
+ }
+ // Now we have the frame with the selection.
+ WebCore::Frame* starterFrame = frame;
+ bool firstTimeThroughLoop = true;
+ if (forward) {
+ while (!(found = frame->findString(findString, true, false, false, true))) {
+ if (firstTimeThroughLoop) {
+ firstTimeThroughLoop = false;
+ // FIXME: Clearing the selection is necessary for the search to
+ // work properly. However, the invalidation does not remove
+ // the drawn rectangle from old frames.
+ frame->selectionController()->clear();
+ }
+ frame = frame->tree()->traverseNextWithWrap(true);
+ if (frame == starterFrame)
+ break;
+ }
+ } else {
+ // Search backwards, searching the frames in reverse order as well.
+ while (!(found = frame->findString(findString, false, false, false, true))) {
+ if (firstTimeThroughLoop) {
+ firstTimeThroughLoop = false;
+ frame->selectionController()->clear();
+ }
+ frame = frame->tree()->traversePreviousWithWrap(true);
+ if (frame == starterFrame)
+ break;
+ }
+ }
+ // In order to wrap to the beginning of the initial frame.
+ if (!found) {
+ found = frame->findString(findString, forward, false, false, true);
+ }
+ } else {
+ // Clear any old selections so find will work properly.
+ while (frame) {
+ frame->selectionController()->clear();
+ frame->invalidateSelection();
+ frame = frame->tree()->traverseNext();
+ }
+ frame = mainFrame;
+ do {
+ found = frame->findString(findString, forward, false, false, false);
+ } while (!found && (frame = frame->tree()->traverseNext()) != NULL);
+ }
+ if (found) {
+ frame->view()->scrollRectIntoViewRecursively(frame->selectionController()->caretRect());
+ return true;
+ }
+ return false;
+}
+
+jstring WebViewCore::FindAddress(JNIEnv *env, jobject obj, jstring addr)
+{
+ if (NULL == addr)
+ return NULL;
+ int length = env->GetStringLength(addr);
+ if (0 == length)
+ return NULL;
+ const jchar* addrChars = env->GetStringChars(addr, NULL);
+ int start, end;
+ bool success = WebCore::CacheBuilder::FindAddress(addrChars, length,
+ &start, &end) == WebCore::CacheBuilder::FOUND_COMPLETE;
+ jstring ret = NULL;
+ if (success) {
+ ret = env->NewString((jchar*) addrChars + start, end - start);
+ env->DeleteLocalRef(ret);
+ }
+ env->ReleaseStringChars(addr, addrChars);
+ return ret;
+}
+
+jint WebViewCore::FindAll(JNIEnv *env, jobject obj, jstring find) {
+ WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(viewImpl, "viewImpl not set in nativeFindAll");
+ if (NULL == find)
+ return 0;
+ int length = env->GetStringLength(find);
+ if (0 == length)
+ return 0;
+ const jchar* findChars = env->GetStringChars(find, NULL);
+ // Will this ever return NULL if find is not NULL and its length is not zero?
+ if (NULL == findChars)
+ return 0;
+ WebCore::String findString = WebCore::String((const UChar*) findChars, length);
+ env->ReleaseStringChars(find, findChars);
+ WebCore::Frame* frame = viewImpl->frame();
+ int numFound = 0;
+ ClearMatches(env, obj);
+ while (frame) {
+ frame->selectionController()->clear();
+ frame->invalidateSelection();
+ if (frame->document())
+ frame->document()->removeMarkers();
+ frame->setMarkedTextMatchesAreHighlighted(true);
+ numFound += frame->markAllMatchesForText(findString, false, 0);
+ frame = frame->tree()->traverseNext();
+ }
+ if (numFound > 0)
+ Find(env, obj, find, true, false);
+ return numFound;
+}
+
+void WebViewCore::TouchUp(JNIEnv *env, jobject obj, jint touchGeneration,
+ jint buildGeneration, jint frame, jint node, jint x, jint y, jint size,
+ jboolean isClick, jboolean retry)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterWV counter;
+#endif
+ WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
+ viewImpl->touchUp(touchGeneration, buildGeneration,
+ (WebCore::Frame*) frame, (WebCore::Node*) node, x, y, size, isClick, retry);
+}
+
+jstring WebViewCore::RetrieveHref(JNIEnv *env, jobject obj, jint frame,
+ jint node)
+{
+ WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
+ WebCore::String result = viewImpl->retrieveHref((WebCore::Frame*) frame,
+ (WebCore::Node*) node);
+ if (!result.isEmpty())
+ return WebCoreStringToJString(env, result);
+ return NULL;
+}
+
+jstring WebViewCore::RetrieveImageRef(JNIEnv *env, jobject obj, jint x, jint y)
+{
+ WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
+ WebCore::String result = viewImpl->retrieveImageRef(x, y);
+ if (!result.isEmpty())
+ return WebCoreStringToJString(env, result);
+ return NULL;
+}
+
+void WebViewCore::SetFinalFocus(JNIEnv *env, jobject obj, jint frame, jint node,
+ jint x, jint y, jboolean block)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterWV counter;
+#endif
+ WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
+ viewImpl->setFinalFocus((WebCore::Frame*) frame, (WebCore::Node*) node, x,
+ y, block);
+}
+
+void WebViewCore::SetKitFocus(JNIEnv *env, jobject obj, jint moveGeneration,
+ jint buildGeneration, jint frame, jint node, jint x, jint y,
+ jboolean ignoreNullFocus)
+{
+#ifdef ANDROID_INSTRUMENT
+ TimeCounterWV counter;
+#endif
+ WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
+ viewImpl->setKitFocus(moveGeneration, buildGeneration,
+ (WebCore::Frame*) frame, (WebCore::Node*) node, x, y,
+ ignoreNullFocus);
+}
+
+void WebViewCore::UnblockFocus(JNIEnv *env, jobject obj)
+{
+ WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
+ viewImpl->unblockFocus();
+}
+
+void WebViewCore::UpdateFrameCache(JNIEnv *env, jobject obj)
+{
+ WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
+ viewImpl->updateFrameCache();
+}
+
+jint WebViewCore::GetContentMinPrefWidth(JNIEnv *env, jobject obj)
+{
+ WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
+
+ WebCore::Frame* frame = viewImpl->frame();
+ if (frame) {
+ WebCore::Document* document = frame->document();
+ if (document) {
+ WebCore::RenderObject* renderer = document->renderer();
+ if (renderer && renderer->isRenderView()) {
+ return renderer->minPrefWidth();
+ }
+ }
+ }
+ return 0;
+}
+
+void WebViewCore::SetViewportSettingsFromNative(JNIEnv *env, jobject obj)
+{
+ WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
+
+ WebCore::Settings* s = viewImpl->frame()->page()->settings();
+ if (s == NULL)
+ return;
+
+ env->SetIntField(obj, gWebViewCoreFields.mViewportWidth, s->viewportWidth());
+ env->SetIntField(obj, gWebViewCoreFields.mViewportHeight, s->viewportHeight());
+ env->SetIntField(obj, gWebViewCoreFields.mViewportInitialScale, s->viewportInitialScale());
+ env->SetIntField(obj, gWebViewCoreFields.mViewportMinimumScale, s->viewportMinimumScale());
+ env->SetIntField(obj, gWebViewCoreFields.mViewportMaximumScale, s->viewportMaximumScale());
+ env->SetBooleanField(obj, gWebViewCoreFields.mViewportUserScalable, s->viewportUserScalable());
+}
+
+void WebViewCore::SetSnapAnchor(JNIEnv *env, jobject obj, jint x, jint y)
+{
+ WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
+
+ viewImpl->setSnapAnchor(x, y);
+}
+
+void WebViewCore::SnapToAnchor(JNIEnv *env, jobject obj)
+{
+ WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
+
+ viewImpl->snapToAnchor();
+}
+
+void WebViewCore::SetBackgroundColor(JNIEnv *env, jobject obj, jint color)
+{
+ WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
+
+ viewImpl->setBackgroundColor((SkColor) color);
+}
+
+static void jrect_to_skirect(JNIEnv* env, jobject obj, SkIRect* result)
+{
+ int L, T, R, B;
+ GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B);
+ result->set(L, T, R, B);
+}
+
+jstring WebViewCore::GetSelection(JNIEnv *env, jobject obj, jobject selRgn)
+{
+ WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
+ SkRegion* selectionRegion = GraphicsJNI::getNativeRegion(env, selRgn);
+ WebCore::String result = viewImpl->getSelection(selectionRegion);
+ if (!result.isEmpty())
+ return WebCoreStringToJString(env, result);
+ return NULL;
+}
+
+void WebViewCore::Dump(JNIEnv *env, jobject obj)
+{
+ WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
+
+ viewImpl->dump();
+}
+
+void WebViewCore::RefreshPlugins(JNIEnv *env,
+ jobject obj,
+ jboolean reloadOpenPages)
+{
+ // Refresh the list of plugins, optionally reloading all open
+ // pages.
+ WebCore::refreshPlugins(reloadOpenPages);
+}
+
+// ----------------------------------------------------------------------------
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gJavaWebViewCoreMethods[] = {
+ { "nativeClearMatches", "()V",
+ (void*) WebViewCore::ClearMatches } ,
+ { "nativeDraw", "(Landroid/graphics/Picture;)V",
+ (void*) WebViewCore::Draw },
+ { "nativeKeyUp", "(II)Z",
+ (void*) WebViewCore::KeyUp },
+ { "nativeSendListBoxChoices", "([ZI)V",
+ (void*) WebViewCore::SendListBoxChoices },
+ { "nativeSendListBoxChoice", "(I)V",
+ (void*) WebViewCore::SendListBoxChoice },
+ { "nativeSetSize", "(IIIF)V",
+ (void*) WebViewCore::SetSize },
+ { "nativeSetVisibleRect", "(IIII)V",
+ (void*) WebViewCore::SetVisibleRect },
+ { "nativeSetSelection", "(IIIIII)V",
+ (void*) WebViewCore::SetSelection } ,
+ { "nativeDeleteSelection", "(IIIIII)V",
+ (void*) WebViewCore::DeleteSelection } ,
+ { "nativeReplaceTextfieldText", "(IIIIIILjava/lang/String;II)V",
+ (void*) WebViewCore::ReplaceTextfieldText } ,
+ { "passToJs", "(IIIIILjava/lang/String;IIZZZZ)V",
+ (void*) WebViewCore::PassToJs } ,
+ { "nativeSaveDocumentState", "(IIII)V",
+ (void*) WebViewCore::SaveDocumentState },
+ { "nativeFind", "(Ljava/lang/String;ZZ)Z",
+ (void*) WebViewCore::Find } ,
+ { "nativeFindAddress", "(Ljava/lang/String;)Ljava/lang/String;",
+ (void*) WebViewCore::FindAddress },
+ { "nativeFindAll", "(Ljava/lang/String;)I",
+ (void*) WebViewCore::FindAll } ,
+ { "nativeTouchUp", "(IIIIIIIZZ)V",
+ (void*) WebViewCore::TouchUp },
+ { "nativeRetrieveImageRef", "(II)Ljava/lang/String;",
+ (void*) WebViewCore::RetrieveImageRef },
+ { "nativeRetrieveHref", "(II)Ljava/lang/String;",
+ (void*) WebViewCore::RetrieveHref },
+ { "nativeSetFinalFocus", "(IIIIZ)V",
+ (void*) WebViewCore::SetFinalFocus },
+ { "nativeSetKitFocus", "(IIIIIIZ)V",
+ (void*) WebViewCore::SetKitFocus },
+ { "nativeUnblockFocus", "()V",
+ (void*) WebViewCore::UnblockFocus },
+ { "nativeUpdateFrameCache", "()V",
+ (void*) WebViewCore::UpdateFrameCache },
+ { "nativeGetContentMinPrefWidth", "()I",
+ (void*) WebViewCore::GetContentMinPrefWidth },
+ { "setViewportSettingsFromNative", "()V",
+ (void*) WebViewCore::SetViewportSettingsFromNative },
+ { "nativeSetSnapAnchor", "(II)V",
+ (void*) WebViewCore::SetSnapAnchor },
+ { "nativeSnapToAnchor", "()V",
+ (void*) WebViewCore::SnapToAnchor },
+ { "nativeSetBackgroundColor", "(I)V",
+ (void*) WebViewCore::SetBackgroundColor },
+ { "nativeGetSelection",
+ "(Landroid/graphics/Region;)Ljava/lang/String;",
+ (void*) WebViewCore::GetSelection },
+ { "nativeRefreshPlugins", "(Z)V",
+ (void*) WebViewCore::RefreshPlugins },
+ { "nativeDump", "()V",
+ (void*) WebViewCore::Dump }
+};
+
+int register_webviewcore(JNIEnv* env)
+{
+ jclass widget = env->FindClass("android/webkit/WebViewCore");
+ LOG_ASSERT(widget != NULL,
+ "Unable to find class android/webkit/WebViewCore");
+ gWebViewCoreFields.mNativeClass = env->GetFieldID(widget, "mNativeClass",
+ "I");
+ LOG_ASSERT(gWebViewCoreFields.mNativeClass != NULL,
+ "Unable to find android/webkit/WebViewCore.mNativeClass");
+ gWebViewCoreFields.mViewportWidth = env->GetFieldID(widget,
+ "mViewportWidth", "I");
+ LOG_ASSERT(gWebViewCoreFields.mViewportWidth != NULL,
+ "Unable to find android/webkit/WebViewCore.mViewportWidth");
+ gWebViewCoreFields.mViewportHeight = env->GetFieldID(widget,
+ "mViewportHeight", "I");
+ LOG_ASSERT(gWebViewCoreFields.mViewportHeight != NULL,
+ "Unable to find android/webkit/WebViewCore.mViewportHeight");
+ gWebViewCoreFields.mViewportInitialScale = env->GetFieldID(widget,
+ "mViewportInitialScale", "I");
+ LOG_ASSERT(gWebViewCoreFields.mViewportInitialScale != NULL,
+ "Unable to find android/webkit/WebViewCore.mViewportInitialScale");
+ gWebViewCoreFields.mViewportMinimumScale = env->GetFieldID(widget,
+ "mViewportMinimumScale", "I");
+ LOG_ASSERT(gWebViewCoreFields.mViewportMinimumScale != NULL,
+ "Unable to find android/webkit/WebViewCore.mViewportMinimumScale");
+ gWebViewCoreFields.mViewportMaximumScale = env->GetFieldID(widget,
+ "mViewportMaximumScale", "I");
+ LOG_ASSERT(gWebViewCoreFields.mViewportMaximumScale != NULL,
+ "Unable to find android/webkit/WebViewCore.mViewportMaximumScale");
+ gWebViewCoreFields.mViewportUserScalable = env->GetFieldID(widget,
+ "mViewportUserScalable", "Z");
+ LOG_ASSERT(gWebViewCoreFields.mViewportUserScalable != NULL,
+ "Unable to find android/webkit/WebViewCore.mViewportUserScalable");
+ gWebViewCoreFields.mWebView = env->GetFieldID(widget,
+ "mWebView", "Landroid/webkit/WebView;");
+ LOG_ASSERT(gWebViewCoreFields.mWebView != NULL,
+ "Unable to find android/webkit/WebViewCore.mWebView");
+
+ return jniRegisterNativeMethods(env, "android/webkit/WebViewCore",
+ gJavaWebViewCoreMethods, NELEM(gJavaWebViewCoreMethods));
+}
+
+} /* namespace android */
diff --git a/WebCore/platform/android/jni/WebViewCore.h b/WebCore/platform/android/jni/WebViewCore.h
new file mode 100644
index 0000000..1cb51b2
--- /dev/null
+++ b/WebCore/platform/android/jni/WebViewCore.h
@@ -0,0 +1,400 @@
+/*
+ *
+ * Copyright 2006, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_WIDGET_HTMLWIDGET_H
+#define ANDROID_WIDGET_HTMLWIDGET_H
+
+#include "WebCoreViewBridge.h"
+#include "CacheBuilder.h"
+#include "CachedHistory.h"
+#include "FrameView.h"
+#include "SkColor.h"
+#include "SkScalar.h"
+#include "SkRegion.h"
+#include <ui/Rect.h>
+#include <jni.h>
+
+namespace WebCore {
+ class AtomicString;
+ class Color;
+ class GraphicsContext;
+ class HTMLSelectElement;
+ class RenderPart;
+ class RenderText;
+ class FrameAndroid;
+ class Node;
+ class RenderTextControl;
+}
+
+class SkPicture;
+
+namespace android {
+
+ class CachedRoot;
+
+ class ListBoxReply;
+
+ class WebViewCore : public WebCoreViewBridge
+ {
+ public:
+ /**
+ * Initialize the ViewBridge with a JNI environment, a native HTMLWidget object
+ * and an associated frame to perform actions on.
+ */
+ WebViewCore(JNIEnv* env, jobject javaView, WebCore::FrameView* view);
+ virtual ~WebViewCore();
+
+ /**
+ * Set the scroll offset.
+ * @param x The x position of the new scroll offset.
+ * @param y The y position of the new scroll offset.
+ */
+// void setScrollOffset(int x, int y);
+
+ // Inherited from WebCoreViewBridge
+ virtual void draw(WebCore::GraphicsContext* ctx,
+ const WebCore::IntRect& rect, bool invalCache);
+
+ /**
+ * Layout our Frame if needed and recursively layout all child frames.
+ */
+ virtual void layout();
+
+ /**
+ * Scroll to an absolute position.
+ * @param x The x coordinate.
+ * @param y The y coordinate.
+ * @param animate If it is true, animate to the new scroll position
+ *
+ * This method calls Java to trigger a gradual scroll event.
+ */
+ virtual void scrollTo(int x, int y, bool animate = false);
+
+ /**
+ * Scroll to the point x,y relative to the current position.
+ * @param x The relative x position.
+ * @param y The relative y position.
+ */
+ virtual void scrollBy(int x, int y);
+
+ /**
+ * Mark the display list as invalid, and post an event (once) to
+ * rebuild the display list by calling webcore to draw the dom
+ */
+ virtual void contentInvalidate();
+ virtual void contentInvalidate(const WebCore::IntRect &rect);
+
+ // invalidate the view/display, NOT the content/DOM
+ virtual void viewInvalidate() { sendViewInvalidate(); }
+
+ /**
+ * Called by webcore when the focus was set after returning to prior page
+ * used to rebuild and display any changes in focus
+ */
+ virtual void notifyFocusSet();
+ /**
+ * Called by webcore when the progress indicator is done
+ * used to rebuild and display any changes in focus
+ */
+ virtual void notifyProgressFinished();
+
+ /**
+ * On resize is called after a setSize event on WebCoreViewBridge. onResize
+ * then tells the frame to relayout the contents due to the size change
+ */
+ virtual void onResize();
+
+ /**
+ * Notify the view that WebCore did its first layout.
+ */
+ virtual void didFirstLayout();
+
+ /**
+ * Notify the view to restore the screen width, which in turn restores
+ * the scale.
+ */
+ virtual void restoreScale(int);
+
+ /* Set the view and frame */
+ virtual void setView(WebCore::FrameView* view) {
+ if (mView)
+ mView->deref();
+ mView = view;
+ if (mView) {
+ mView->ref();
+ mFrame = (WebCore::FrameAndroid*)mView->frame();
+ reset(false);
+ } else
+ mFrame = NULL;
+ }
+
+ // new methods for this subclass
+
+ void reset(bool fromConstructor);
+
+ WebCore::FrameAndroid* frame() const { return mFrame; }
+ WebCore::String retrieveHref(WebCore::Frame* frame, WebCore::Node* node);
+
+ /**
+ * Return the url of the image located at (x,y) in content coordinates, or
+ * null if there is no image at that point.
+ *
+ * @param x x content ordinate
+ * @param y y content ordinate
+ * @return WebCore::String url of the image located at (x,y), or null if there is
+ * no image there.
+ */
+ WebCore::String retrieveImageRef(int x, int y);
+
+ WebCore::String getSelection(SkRegion* );
+ void recordPicture(SkPicture* picture, bool invalCache);
+ void setFrameCacheOutOfDate();
+ void setFinalFocus(WebCore::Frame* frame, WebCore::Node* node,
+ int x, int y, bool block);
+ void setKitFocus(int moveGeneration, int buildGeneration,
+ WebCore::Frame* frame, WebCore::Node* node, int x, int y,
+ bool ignoreNullFocus);
+ int getMaxXScroll() const { return mMaxXScroll; }
+ int getMaxYScroll() const { return mMaxYScroll; }
+ void setMaxXScroll(int maxx) { mMaxXScroll = maxx; }
+ void setMaxYScroll(int maxy) { mMaxYScroll = maxy; }
+
+ int contentWidth() const { return mView->contentsWidth(); }
+ int contentHeight() const { return mView->contentsHeight(); }
+
+ // the visible rect is in document coordinates, and describes the
+ // intersection of the document with the "window" in the UI.
+ void getVisibleRect(WebCore::IntRect* rect) const;
+ void setVisibleRect(const WebCore::IntRect& rect);
+
+ WebCore::FrameView* getFrameView() { return mView; }
+ void listBoxRequest(WebCoreReply* reply, const uint16_t** labels, size_t count, const int enabled[], size_t enabledCount,
+ bool multiple, const int selected[], size_t selectedCountOrSelection);
+
+ /**
+ * Handle keyDown events from Java.
+ * @param keyCode The key pressed.
+ * @return Whether keyCode was handled by this class.
+ */
+ bool keyUp(KeyCode keyCode, int keyValue);
+
+ /**
+ * Handle motionUp event from the UI thread (called touchUp in the
+ * WebCore thread).
+ */
+ void touchUp(int touchGeneration, int buildGeneration,
+ WebCore::Frame* frame, WebCore::Node* node, int x, int y,
+ int size, bool isClick, bool retry);
+
+ /**
+ * Return a new WebCoreViewBridge to interface with the passed in view.
+ */
+ virtual WebCoreViewBridge* createBridgeForView(WebCore::FrameView* view);
+
+ /**
+ * Sets the index of the label from a popup
+ */
+ void popupReply(int index);
+ void popupReply(SkTDArray<int>array);
+
+ virtual void jsAlert(const WebCore::String& url, const WebCore::String& text);
+ virtual bool jsConfirm(const WebCore::String& url, const WebCore::String& text);
+ virtual bool jsPrompt(const WebCore::String& url, const WebCore::String& message, const WebCore::String& defaultValue, WebCore::String& result);
+ virtual bool jsUnload(const WebCore::String& url, const WebCore::String& message);
+
+ /**
+ * Delete text from start to end in the focused textfield. If there is no
+ * focus, or if start == end, silently fail, but set selection to that value.
+ * If start and end are out of order, swap them.
+ * Use the frame, node, x, and y to ensure that the correct node is focused.
+ * Return a frame. Convenience so replaceTextfieldText can use this function.
+ */
+ WebCore::Frame* deleteSelection(WebCore::Frame* frame, WebCore::Node* node, int x,
+ int y,int start, int end);
+
+ /**
+ * Set the selection of the currently focused textfield to (start, end).
+ * If start and end are out of order, swap them.
+ * Use the frame, node, x, and y to ensure that the correct node is focused.
+ * Return a frame. Convenience so deleteSelection can use this function.
+ */
+ WebCore::Frame* setSelection(WebCore::Frame* frame, WebCore::Node* node, int x,
+ int y,int start, int end);
+ /**
+ * In the currenlty focused textfield, represented by frame, node, x, and y (which
+ * are used to ensure it has focus), replace the characters from oldStart to oldEnd
+ * (if oldStart == oldEnd, this will be an insert at that position) with replace,
+ * and set the selection to (start, end).
+ */
+ void replaceTextfieldText(WebCore::Frame* frame, WebCore::Node* node, int x, int y,
+ int oldStart, int oldEnd, jstring replace, int start, int end);
+ void passToJs(WebCore::Frame* frame, WebCore::Node* node, int x, int y, int generation,
+ jstring currentText, int jKeyCode, int keyVal, bool down, bool cap, bool fn, bool sym);
+
+ void saveDocumentState(WebCore::Frame* frame, WebCore::Node* node, int x, int y);
+
+ // TODO: I don't like this hack but I need to access the java object in
+ // order to send it as a parameter to java
+ jobject getJavaObject();
+
+ // Return the parent WebView Java object associated with this
+ // WebViewCore.
+ jobject getWebViewJavaObject();
+
+ bool pinXToDocument(int* yPtr);
+ bool pinYToDocument(int* yPtr);
+
+ WebCore::RenderLayer* getRenderLayer();
+
+ /**
+ * Tell the java side to update the focused textfield
+ * @param pointer Pointer to the node for the input field.
+ * @param changeToPassword If true, we are changing the textfield to
+ * a password field, and ignore the String
+ * @param text If changeToPassword is false, this is the new text that
+ * should go into the textfield.
+ */
+ virtual void updateTextfield(WebCore::Node* pointer,
+ bool changeToPassword, const WebCore::String& text);
+
+ virtual void removeFrameGeneration(WebCore::Frame* );
+ virtual void updateFrameGeneration(WebCore::Frame* );
+
+ void setBackgroundColor(SkColor c);
+ void setSnapAnchor(int x, int y);
+ void snapToAnchor();
+ void unblockFocus() { mBlockFocusChange = false; }
+ void updateFrameCache();
+ void dump();
+
+ // jni methods
+ static void Destroy(JNIEnv*, jobject);
+ static void Dump(JNIEnv*, jobject);
+ static void RefreshPlugins(JNIEnv*, jobject, jboolean);
+ static void SetSize(JNIEnv*, jobject, jint, jint, jint, jfloat);
+ static void SetVisibleRect(JNIEnv*, jobject, jint, jint, jint, jint);
+ static jboolean KeyUp(JNIEnv*, jobject, jint, jint);
+ static void DeleteSelection(JNIEnv*, jobject, jint, jint, jint, jint,
+ jint, jint);
+ static void SetSelection(JNIEnv*, jobject, jint, jint, jint, jint,
+ jint, jint);
+ static void ReplaceTextfieldText(JNIEnv*, jobject, jint, jint, jint,
+ jint, jint, jint, jstring, jint, jint);
+ static void PassToJs(JNIEnv*, jobject, jint, jint, jint, jint, jint,
+ jstring, jint, jint, jboolean, jboolean, jboolean, jboolean);
+ static void SaveDocumentState(JNIEnv*, jobject, jint, jint, jint, jint);
+ static void Draw(JNIEnv*, jobject, jobject);
+ static void SendListBoxChoices(JNIEnv*, jobject, jbooleanArray, jint);
+ static void SendListBoxChoice(JNIEnv* env, jobject obj, jint choice);
+ static void ClearMatches(JNIEnv*, jobject);
+ static jboolean Find(JNIEnv*, jobject, jstring, jboolean, jboolean);
+ static jstring FindAddress(JNIEnv*, jobject, jstring);
+ static jint FindAll(JNIEnv*, jobject, jstring);
+ static void TouchUp(JNIEnv*, jobject, jint, jint, jint, jint, jint,
+ jint, jint, jboolean, jboolean);
+ static jstring RetrieveHref(JNIEnv*, jobject, jint, jint);
+ static jstring RetrieveImageRef(JNIEnv*, jobject, jint, jint);
+ static void SetFinalFocus(JNIEnv*, jobject, jint, jint, jint, jint,
+ jboolean);
+ static void SetKitFocus(JNIEnv*, jobject, jint, jint, jint, jint, jint,
+ jint, jboolean);
+ static void UnblockFocus(JNIEnv*, jobject);
+ static void UpdateFrameCache(JNIEnv*, jobject);
+ static jint GetContentMinPrefWidth(JNIEnv*, jobject);
+ static void SetViewportSettingsFromNative(JNIEnv*, jobject);
+ static void SetBackgroundColor(JNIEnv *env, jobject obj, jint color);
+ static void SetSnapAnchor(JNIEnv*, jobject, jint, jint);
+ static void SnapToAnchor(JNIEnv*, jobject);
+ static jstring GetSelection(JNIEnv*, jobject, jobject);
+ // end jni methods
+
+ // these members are shared with webview.cpp
+ int retrieveFrameGeneration(WebCore::Frame* );
+ static Mutex gFrameCacheMutex;
+ CachedRoot* mFrameCacheKit; // nav data being built by webcore
+ SkPicture* mNavPictureKit;
+ int mGeneration; // copy of the number bumped by WebViewNative
+ int mMoveGeneration; // copy of state in WebViewNative triggered by move
+ int mTouchGeneration; // copy of state in WebViewNative triggered by touch
+ int mLastGeneration; // last action using up to date cache
+ bool mUpdatedFrameCache;
+ bool mUseReplay;
+ static Mutex gRecomputeFocusMutex;
+ WTF::Vector<int> mRecomputeEvents;
+ // These two fields go together: we use the mutex to protect access to
+ // mButtons, so that we, and webview.cpp can look/modify the mButtons
+ // field safely from our respective threads
+ static Mutex gButtonMutex;
+ SkTDArray<Container*>* mButtons;
+ // end of shared members
+ private:
+ friend class ListBoxReply;
+ struct FrameGen {
+ const WebCore::Frame* mFrame;
+ int mGeneration;
+ };
+ WTF::Vector<FrameGen> mFrameGenerations;
+ static Mutex gFrameGenerationMutex;
+ struct JavaGlue;
+ struct JavaGlue* mJavaGlue;
+ WebCore::FrameView* mView;
+ WebCore::FrameAndroid* mFrame;
+ WebCoreReply* mPopupReply;
+ WebCore::Node* mLastFocused;
+ WebCore::IntRect mLastFocusedBounds;
+ // Used in passToJS to avoid updating the UI text field until after the
+ // key event has been processed.
+ bool mBlockTextfieldUpdates;
+ // Passed in with key events to know when they were generated. Store it
+ // with the cache so that we can ignore stale text changes.
+ int mTextGeneration;
+ CachedRoot* mTemp;
+ SkPicture* mTempPict;
+ int mBuildGeneration;
+ int mMaxXScroll;
+ int mMaxYScroll;
+ WebCore::IntRect mVisibleRect;
+ WebCore::IntPoint mMousePos;
+ bool mFrameCacheOutOfDate;
+ bool mBlockFocusChange;
+ int mLastPassed;
+ int mLastVelocity;
+ CachedHistory mHistory;
+ WebCore::Node* mSnapAnchorNode;
+ WebCore::Frame* changedKitFocus(WebCore::Frame* frame,
+ WebCore::Node* node, int x, int y);
+ bool commonKitFocus(int generation, int buildGeneration,
+ WebCore::Frame* frame, WebCore::Node* node, int x, int y,
+ bool ignoreNullFocus);
+ bool finalKitFocus(WebCore::Frame* frame, WebCore::Node* node, int x, int y);
+ void doMaxScroll(WebCore::CacheBuilder::Direction dir);
+ void sendMarkNodeInvalid(WebCore::Node* );
+ void sendNotifyFocusSet();
+ void sendNotifyProgressFinished();
+ void sendRecomputeFocus();
+ void sendViewInvalidate();
+ bool handleMouseClick(WebCore::Frame* framePtr, WebCore::Node* nodePtr);
+ bool prepareFrameCache();
+ void releaseFrameCache(bool newCache);
+#if DEBUG_NAV_UI
+ uint32_t mNow;
+#endif
+ };
+
+} // namespace android
+
+#endif // ANDROID_WIDGET_HTMLWIDGET_H
diff --git a/WebCore/platform/android/nav/CacheBuilder.cpp b/WebCore/platform/android/nav/CacheBuilder.cpp
new file mode 100644
index 0000000..cee6ca7
--- /dev/null
+++ b/WebCore/platform/android/nav/CacheBuilder.cpp
@@ -0,0 +1,2974 @@
+/*
+ * Copyright 2006, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.max
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CachedPrefix.h"
+#include "CachedNode.h"
+#include "CachedRoot.h"
+#include "Document.h"
+#include "EventNames.h"
+#include "EventTargetNode.h"
+#include "Frame.h"
+#include "FrameAndroid.h"
+#include "FrameTree.h"
+#include "FrameView.h"
+//#include "GraphicsContext.h"
+#include "HTMLAreaElement.h"
+#include "HTMLImageElement.h"
+#include "HTMLInputElement.h"
+#include "HTMLNames.h"
+#include "HTMLOptionElement.h"
+#include "HTMLSelectElement.h"
+#include "InlineTextBox.h"
+#include "KURL.h"
+#include "RenderImage.h"
+#include "RenderInline.h"
+#include "RenderListBox.h"
+#include "RenderSkinCombo.h"
+#include "RenderTextControl.h"
+#include "RenderWidget.h"
+#include "SkCanvas.h"
+#include "SkPoint.h"
+#include "Text.h"
+#include "WebCoreFrameBridge.h"
+#include "WebCoreViewBridge.h"
+#include "Widget.h"
+#include <wtf/unicode/Unicode.h>
+
+#ifdef DUMP_NAV_CACHE_USING_PRINTF
+ FILE* gNavCacheLogFile = NULL;
+ android::Mutex gWriteLogMutex;
+#endif
+
+#include "CacheBuilder.h"
+
+#define MINIMUM_FOCUSABLE_WIDTH 3
+#define MINIMUM_FOCUSABLE_HEIGHT 3
+#define MAXIMUM_FOCUS_RING_COUNT 32
+
+namespace WebCore {
+
+CacheBuilder* CacheBuilder::Builder(Frame* frame) {
+ return &Android(frame)->m_cacheBuilder;
+}
+
+FrameAndroid* CacheBuilder::FrameAnd(CacheBuilder* cacheBuilder) {
+ return (FrameAndroid*) ((char*) cacheBuilder - OFFSETOF(FrameAndroid, m_cacheBuilder));
+}
+
+FrameAndroid* CacheBuilder::FrameAnd(const CacheBuilder* cacheBuilder) {
+ return (FrameAndroid*) ((char*) cacheBuilder - OFFSETOF(FrameAndroid, m_cacheBuilder));
+}
+
+#if DUMP_NAV_CACHE
+
+#define DEBUG_BUFFER_SIZE 256
+#define DEBUG_WRAP_SIZE 150
+#define DEBUG_WRAP_MAX 170
+
+FrameAndroid* CacheBuilder::Debug::frameAnd() const {
+ CacheBuilder* nav = (CacheBuilder*) ((char*) this - OFFSETOF(CacheBuilder, mDebug));
+ return CacheBuilder::FrameAnd(nav);
+}
+
+void CacheBuilder::Debug::attr(const AtomicString& name, const AtomicString& value) {
+ if (name.isNull() || name.isEmpty() || value.isNull() || value.isEmpty())
+ return;
+ uChar(name.characters(), name.length(), false);
+ print("=");
+ wideString(value.characters(), value.length(), false);
+ print(" ");
+}
+
+void CacheBuilder::Debug::comma(const char* str) {
+ print(str);
+ print(", ");
+}
+
+int CacheBuilder::Debug::flowBoxes(RenderFlow* flow, int ifIndex, int indent) {
+ char scratch[256];
+ const InlineFlowBox* box = flow->firstLineBox();
+ if (box == NULL)
+ return ifIndex;
+ do {
+ newLine();
+ int i = snprintf(scratch, sizeof(scratch), "// render flow:%p"
+ " box:%p%.*s", flow, box, indent, " ");
+ for (; box; box = box->nextFlowBox()) {
+ i += snprintf(&scratch[i], sizeof(scratch) - i,
+ " [%d]:{%d, %d, %d, %d}", ++ifIndex,
+ box->xPos(), box->yPos(), box->width(), box->height());
+ if (ifIndex % 4 == 0)
+ break;
+ }
+ print(scratch);
+ } while (box);
+ RenderObject const * const end = flow->lastChild();
+ if (end == NULL)
+ return ifIndex;
+ indent += 2;
+ if (indent > 8)
+ indent = 8;
+ for (const RenderObject* renderer = flow->firstChild(); renderer != end;
+ renderer = renderer->nextSibling())
+ {
+ if (renderer->isInlineFlow())
+ ifIndex = flowBoxes((RenderFlow*) renderer, ifIndex, indent);
+ }
+ return ifIndex;
+}
+
+void CacheBuilder::Debug::flush() {
+ int len;
+ do {
+ int limit = mIndex;
+ if (limit < DEBUG_WRAP_SIZE)
+ return;
+ if (limit < DEBUG_WRAP_MAX)
+ len = limit;
+ else {
+ limit = DEBUG_WRAP_MAX;
+ len = DEBUG_WRAP_SIZE;
+ while (len < limit) {
+ char test = mBuffer[len];
+ if (test < '/' || (test > '9' && test < 'A') || (test > 'Z' && test < 'a') || test > 'z')
+ break;
+ len++;
+ }
+ while (mBuffer[len] == '\\' || mBuffer[len] == '"')
+ len++;
+ }
+ const char* prefix = mPrefix;
+ if (prefix[0] == '\"') {
+ // see if we're inside a quote
+ int quoteCount = 0;
+ for (int index = 0; index < len; index++) {
+ if (mBuffer[index] == '\\') {
+ index++;
+ continue;
+ }
+ if (mBuffer[index] == '\n') {
+ quoteCount = 0;
+ continue;
+ }
+ if (mBuffer[index] == '"')
+ quoteCount++;
+ }
+ if ((quoteCount & 1) == 0)
+ prefix = "\n";
+ }
+ DUMP_NAV_LOGD("%.*s", len, mBuffer);
+ int copy = mIndex - len;
+ strcpy(mBuffer, prefix);
+ memcpy(&mBuffer[strlen(prefix)], &mBuffer[len], copy);
+ mIndex = strlen(prefix) + copy;
+ } while (true);
+}
+
+void CacheBuilder::Debug::frameName(char*& namePtr, const char* max) const {
+ if (namePtr >= max)
+ return;
+ Frame* frame = frameAnd();
+ Frame* parent = frame->tree()->parent();
+ if (parent)
+ Builder(parent)->mDebug.frameName(namePtr, max);
+ const AtomicString& name = frame->tree()->name();
+ if (name.length() == 0)
+ return;
+ unsigned index = 0;
+ if (name.startsWith(AtomicString("opener")))
+ index = 6;
+ for (; index < name.length(); index++) {
+ char ch = name[index];
+ if (ch <= ' ')
+ ch = '_';
+ if (WTF::isASCIIAlphanumeric(ch) || ch == '_')
+ *namePtr++ = ch;
+ }
+}
+
+void CacheBuilder::Debug::frames() {
+ FrameAndroid* frame = frameAnd();
+ Document* doc = frame->document();
+ if (doc == NULL)
+ return;
+ bool top = frame->tree()->parent() == NULL;
+ if (top) {
+#ifdef DUMP_NAV_CACHE_USING_PRINTF
+ gWriteLogMutex.lock();
+ ASSERT(gNavCacheLogFile == NULL);
+ gNavCacheLogFile = fopen(NAV_CACHE_LOG_FILE, "a");
+#endif
+ groups();
+ }
+ Frame* child = frame->tree()->firstChild();
+ bool hasChild = child != NULL;
+ if (top && hasChild)
+ DUMP_NAV_LOGD("\nnamespace TEST_SPACE {\n\n");
+ while (child) {
+ Builder(child)->mDebug.frames();
+ child = child->tree()->nextSibling();
+ }
+ if (hasChild) {
+ child = frame->tree()->firstChild();
+ while (child) {
+ char childName[256];
+ char* childNamePtr = childName;
+ Builder(child)->mDebug.frameName(childNamePtr, childNamePtr + sizeof(childName) - 1);
+ *childNamePtr = '\0';
+ if (child == frame->tree()->firstChild())
+ DUMP_NAV_LOGD("DebugTestFrameGroup TEST%s_GROUP[] = {\n", childName);
+ Frame* next = child->tree()->nextSibling();
+ Document* doc = child->document();
+ if (doc != NULL) {
+ RenderObject* renderer = doc->renderer();
+ if (renderer != NULL) {
+ RenderLayer* layer = renderer->enclosingLayer();
+ if (layer != NULL) {
+ DUMP_NAV_LOGD("{ ");
+ DUMP_NAV_LOGD("TEST%s_RECTS, ", childName);
+ DUMP_NAV_LOGD("TEST%s_RECT_COUNT, ", childName);
+ DUMP_NAV_LOGD("TEST%s_RECTPARTS, ", childName);
+ DUMP_NAV_LOGD("TEST%s_BOUNDS,\n", childName);
+ DUMP_NAV_LOGD("TEST%s_WIDTH, ", childName);
+ DUMP_NAV_LOGD("TEST%s_HEIGHT,\n", childName);
+ DUMP_NAV_LOGD("0, 0, 0, 0,\n");
+ DUMP_NAV_LOGD("TEST%s_FOCUS, ", childName);
+ Frame* grandChild = child->tree()->firstChild();
+ if (grandChild) {
+ char grandChildName[256];
+ char* grandChildNamePtr = grandChildName;
+ Builder(grandChild)->mDebug.frameName(grandChildNamePtr,
+ grandChildNamePtr + sizeof(grandChildName) - 1);
+ *grandChildNamePtr = '\0';
+ DUMP_NAV_LOGD("TEST%s_GROUP, ", grandChildName);
+ DUMP_NAV_LOGD("sizeof(TEST%s_GROUP) / sizeof(DebugTestFrameGroup), ", grandChildName);
+ } else
+ DUMP_NAV_LOGD("NULL, 0, ");
+ DUMP_NAV_LOGD("\"%s\"\n", childName);
+ DUMP_NAV_LOGD("}%c\n", next ? ',' : ' ');
+ }
+ }
+ }
+ child = next;
+ }
+ DUMP_NAV_LOGD("};\n");
+ }
+ if (top) {
+ if (hasChild)
+ DUMP_NAV_LOGD("\n} // end of namespace\n\n");
+ char name[256];
+ char* frameNamePtr = name;
+ frameName(frameNamePtr, frameNamePtr + sizeof(name) - 1);
+ *frameNamePtr = '\0';
+ DUMP_NAV_LOGD("DebugTestFrameGroup TEST%s_GROUP = {\n", name);
+ DUMP_NAV_LOGD("TEST%s_RECTS, ", name);
+ DUMP_NAV_LOGD("TEST%s_RECT_COUNT, ", name);
+ DUMP_NAV_LOGD("TEST%s_RECTPARTS, ", name);
+ DUMP_NAV_LOGD("TEST%s_BOUNDS,\n", name);
+ DUMP_NAV_LOGD("TEST%s_WIDTH, ", name);
+ DUMP_NAV_LOGD("TEST%s_HEIGHT,\n", name);
+ DUMP_NAV_LOGD("TEST%s_MAX_H, ", name);
+ DUMP_NAV_LOGD("TEST%s_MIN_H, ", name);
+ DUMP_NAV_LOGD("TEST%s_MAX_V, ", name);
+ DUMP_NAV_LOGD("TEST%s_MIN_V,\n", name);
+ DUMP_NAV_LOGD("TEST%s_FOCUS, ", name);
+ if (hasChild) {
+ child = frame->tree()->firstChild();
+ char childName[256];
+ char* childNamePtr = childName;
+ Builder(child)->mDebug.frameName(childNamePtr, childNamePtr + sizeof(childName) - 1);
+ *childNamePtr = '\0';
+ DUMP_NAV_LOGD("TEST_SPACE::TEST%s_GROUP, ", childName);
+ DUMP_NAV_LOGD("sizeof(TEST_SPACE::TEST%s_GROUP) / sizeof(DebugTestFrameGroup), \n" ,childName);
+ } else
+ DUMP_NAV_LOGD("NULL, 0, ");
+ DUMP_NAV_LOGD("\"%s\"\n", name);
+ DUMP_NAV_LOGD("};\n");
+#ifdef DUMP_NAV_CACHE_USING_PRINTF
+ if (gNavCacheLogFile)
+ fclose(gNavCacheLogFile);
+ gNavCacheLogFile = NULL;
+ gWriteLogMutex.unlock();
+#endif
+ }
+}
+
+void CacheBuilder::Debug::init(char* buffer, size_t size) {
+ mBuffer = buffer;
+ mBufferSize = size;
+ mIndex = 0;
+ mPrefix = "";
+}
+
+void CacheBuilder::Debug::groups() {
+ FrameAndroid* frame = frameAnd();
+ Frame* child = frame->tree()->firstChild();
+ bool hasChild = child != NULL;
+ if (frame->tree()->parent() == NULL && hasChild)
+ DUMP_NAV_LOGD("namespace TEST_SPACE {\n\n");
+ while (child) {
+ Builder(child)->mDebug.groups();
+ child = child->tree()->nextSibling();
+ }
+ if (frame->tree()->parent() == NULL && hasChild)
+ DUMP_NAV_LOGD("\n} // end of namespace\n\n");
+ Document* doc = frame->document();
+ char name[256];
+ char* frameNamePtr = name;
+ frameName(frameNamePtr, frameNamePtr + sizeof(name) - 1);
+ *frameNamePtr = '\0';
+ if (doc == NULL) {
+ DUMP_NAV_LOGD("// %s has no document\n", name);
+ return;
+ }
+ RenderObject* renderer = doc->renderer();
+ if (renderer == NULL) {
+ DUMP_NAV_LOGD("// %s has no renderer\n", name);
+ return;
+ }
+ RenderLayer* layer = renderer->enclosingLayer();
+ if (layer == NULL) {
+ DUMP_NAV_LOGD("// %s has no enclosingLayer\n", name);
+ return;
+ }
+ Node* node = doc;
+ Node* focus = doc->focusedNode();
+ bool atLeastOne = false;
+ do {
+ if ((atLeastOne |= isFocusable(node)) != false)
+ break;
+ } while ((node = node->traverseNextNode()) != NULL);
+ int focusIndex = -1;
+ if (atLeastOne == false) {
+ DUMP_NAV_LOGD("#define TEST%s_RECTS NULL\n", name);
+ DUMP_NAV_LOGD("static int TEST%s_RECT_COUNT = 0; // no focusable nodes\n", name);
+ DUMP_NAV_LOGD("#define TEST%s_RECTPARTS NULL\n", name);
+ } else {
+ node = doc;
+ int count = 1;
+ DUMP_NAV_LOGD("static DebugTestNode TEST%s_RECTS[] = {\n", name);
+ do {
+ String properties;
+ EventTargetNode* elementTarget = node->isEventTargetNode() ?
+ (EventTargetNode*) node : NULL;
+ if (elementTarget) {
+ if (elementTarget->getEventListener(EventNames::clickEvent))
+ properties.append("ONCLICK | ");
+ if (elementTarget->getEventListener(EventNames::mousedownEvent))
+ properties.append("MOUSEDOWN | ");
+ if (elementTarget->getEventListener(EventNames::mouseupEvent))
+ properties.append("MOUSEUP | ");
+ if (elementTarget->getEventListener(EventNames::mouseoverEvent))
+ properties.append("MOUSEOVER | ");
+ if (elementTarget->getEventListener(EventNames::mouseoutEvent))
+ properties.append("MOUSEOUT | ");
+ if (elementTarget->getEventListener(EventNames::keydownEvent))
+ properties.append("KEYDOWN | ");
+ if (elementTarget->getEventListener(EventNames::keyupEvent))
+ properties.append("KEYUP | ");
+ }
+ if (CacheBuilder::HasFrame(node))
+ properties.append("FRAME | ");
+ if (focus == node) {
+ properties.append("FOCUS | ");
+ focusIndex = count;
+ }
+ if (node->isKeyboardFocusable(NULL))
+ properties.append("KEYBOARD_FOCUSABLE | ");
+ if (node->isMouseFocusable())
+ properties.append("MOUSE_FOCUSABLE | ");
+ if (node->isFocusable())
+ properties.append("SIMPLE_FOCUSABLE | ");
+ if (properties.isEmpty())
+ properties.append("0");
+ else
+ properties.truncate(properties.length() - 3);
+ IntRect rect = node->getRect();
+ if (node->hasTagName(HTMLNames::areaTag))
+ rect = static_cast<HTMLAreaElement*>(node)->getAreaRect();
+ char buffer[DEBUG_BUFFER_SIZE];
+ memset(buffer, 0, sizeof(buffer));
+ mBuffer = buffer;
+ mBufferSize = sizeof(buffer);
+ mPrefix = "\"\n\"";
+ mIndex = snprintf(buffer, sizeof(buffer), "{{%d, %d, %d, %d}, ", rect.x(), rect.y(),
+ rect.width(), rect.height());
+ localName(node);
+ uChar(properties.characters(), properties.length(), false);
+ print(", ");
+ int parentIndex = ParentIndex(node, count, node->parentNode());
+ char scratch[256];
+ snprintf(scratch, sizeof(scratch), "%d", parentIndex);
+ comma(scratch);
+ Element* element = static_cast<Element*>(node);
+ if (node->isElementNode() && element->hasID())
+ wideString(element->getIDAttribute());
+ else if (node->isTextNode()) {
+ #if 01 // set to one to abbreviate text that can be omitted from the address detection code
+ if (rect.isEmpty() && node->textContent().length() > 100) {
+ wideString(node->textContent().characters(), 100, false);
+ snprintf(scratch, sizeof(scratch), "/* + %d bytes */",
+ node->textContent().length() - 100);
+ print(scratch);
+ } else
+ #endif
+ wideString(node->textContent().characters(), node->textContent().length(), true);
+ } else if (node->hasTagName(HTMLNames::aTag) ||
+ node->hasTagName(HTMLNames::areaTag))
+ {
+ HTMLAnchorElement* anchor = static_cast<HTMLAnchorElement*>(node);
+ wideString(anchor->href());
+ } else if (node->hasTagName(HTMLNames::imgTag)) {
+ HTMLImageElement* image = static_cast<HTMLImageElement*>(node);
+ wideString(image->src());
+ } else
+ print("\"\"");
+ RenderObject* renderer = node->renderer();
+ if (renderer) {
+ const IntRect& absB = renderer->absoluteBoundingBoxRect();
+ snprintf(scratch, sizeof(scratch), ", {%d, %d, %d, %d}, %s},",
+ absB.x(), absB.y(), absB.width(), absB.height(),
+ renderer->hasOverflowClip() ? "true" : "false");
+ print(scratch);
+ } else
+ print(", {0, 0, 0, 0}, false},");
+ flush();
+ snprintf(scratch, sizeof(scratch), "// %d: ", count);
+ mPrefix = "\n// ";
+ print(scratch);
+ //print(renderer ? renderer->information().ascii() : "NO_RENDER_INFO");
+ if (node->isElementNode()) {
+ Element* element = static_cast<Element*>(node);
+ NamedAttrMap* attrs = element->attributes();
+ unsigned length = attrs->length();
+ if (length > 0) {
+ newLine();
+ print("// attr: ");
+ for (unsigned i = 0; i < length; i++) {
+ Attribute* a = attrs->attributeItem(i);
+ attr(a->localName(), a->value());
+ }
+ }
+ }
+ if (renderer)
+ renderTree(renderer, 0, node, count);
+ count++;
+ newLine();
+ } while ((node = node->traverseNextNode()) != NULL);
+ DUMP_NAV_LOGD("}; // focusables = %d\n", count - 1);
+ DUMP_NAV_LOGD("\n");
+ DUMP_NAV_LOGD("static int TEST%s_RECT_COUNT = %d;\n\n", name, count - 1);
+ // look for rects with multiple parts
+ node = doc;
+ count = 1;
+ bool hasRectParts = false;
+ int globalOffsetX, globalOffsetY;
+ GetGlobalOffset(frame, &globalOffsetX, &globalOffsetY);
+ do {
+ IntRect rect;
+ bool _isFocusable = isFocusable(node) || (node->isTextNode()
+ && node->getRect().isEmpty() == false
+ );
+ int nodeIndex = count++;
+ if (_isFocusable == false)
+ continue;
+ RenderObject* renderer = node->renderer();
+ if (renderer == NULL)
+ continue;
+ WTF::Vector<IntRect> rects;
+ IntRect clipBounds = IntRect(0, 0, INT_MAX, INT_MAX);
+ IntRect focusBounds = IntRect(0, 0, INT_MAX, INT_MAX);
+ IntRect* rectPtr = &focusBounds;
+ if (node->isTextNode()) {
+ Text* textNode = (Text*) node;
+ if (CacheBuilder::ConstructTextRects(textNode, 0, textNode,
+ INT_MAX, globalOffsetX, globalOffsetY, rectPtr,
+ clipBounds, &rects) == false)
+ continue;
+ } else {
+ IntRect nodeBounds = node->getRect();
+ if (CacheBuilder::ConstructPartRects(node, nodeBounds, rectPtr,
+ globalOffsetX, globalOffsetY, &rects) == false)
+ continue;
+ }
+ unsigned arraySize = rects.size();
+ if (arraySize > 1 || (arraySize == 1 && (rectPtr->width() != rect.width())) ||
+ rectPtr->height() != rect.height()) {
+ if (hasRectParts == false) {
+ DUMP_NAV_LOGD("static DebugTestRectPart TEST%s_RECTPARTS[] = {\n", name);
+ hasRectParts = true;
+ }
+ if (node->isTextNode() == false) {
+ unsigned rectIndex = 0;
+ for (; rectIndex < arraySize; rectIndex++) {
+ rectPtr = &rects.at(rectIndex);
+ DUMP_NAV_LOGD("{ %d, %d, %d, %d, %d }, // %d\n", nodeIndex,
+ rectPtr->x(), rectPtr->y(), rectPtr->width(),
+ rectPtr->height(), rectIndex + 1);
+ }
+ } else {
+ RenderText* renderText = (RenderText*) node->renderer();
+ InlineTextBox* textBox = renderText->firstTextBox();
+ unsigned rectIndex = 0;
+ while (textBox) {
+ int renderX, renderY;
+ renderText->absolutePosition(renderX, renderY);
+ IntRect rect = textBox->selectionRect(renderX, renderY, 0, INT_MAX);
+ mIndex = 0;
+ mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex, "{ %d, %d, %d, %d, %d",
+ nodeIndex, rect.x(), rect.y(), rect.width(), rect.height());
+ mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex, ", %d, %d, %d",
+ textBox->len(), textBox->selectionHeight(), textBox->selectionTop());
+ mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex, ", %d, %d, %d",
+ textBox->spaceAdd(), textBox->start(), textBox->textPos());
+ mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex, ", %d, %d, %d, %d",
+ textBox->xPos(), textBox->yPos(), textBox->width(), textBox->height());
+ mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex, ", %d }, // %d ",
+ textBox->baseline(), ++rectIndex);
+ wideString(node->textContent().characters() + textBox->start(), textBox->len(), true);
+ DUMP_NAV_LOGD("%.*s\n", mIndex, mBuffer);
+ textBox = textBox->nextTextBox();
+ }
+ }
+ }
+ } while ((node = node->traverseNextNode()) != NULL);
+ if (hasRectParts)
+ DUMP_NAV_LOGD("{0}\n};\n\n");
+ else
+ DUMP_NAV_LOGD("static DebugTestRectPart* TEST%s_RECTPARTS = NULL;\n", name);
+ }
+ int contentsWidth = layer->width();
+ int contentsHeight = layer->height();
+ DUMP_NAV_LOGD("static int TEST%s_FOCUS = %d;\n", name, focusIndex);
+ DUMP_NAV_LOGD("static int TEST%s_WIDTH = %d;\n", name, contentsWidth);
+ DUMP_NAV_LOGD("static int TEST%s_HEIGHT = %d;\n", name, contentsHeight);
+}
+
+bool CacheBuilder::Debug::isFocusable(Node* node) {
+ if (node->hasTagName(HTMLNames::areaTag))
+ return true;
+ if (node->renderer() == false)
+ return false;
+ if (node->isKeyboardFocusable(NULL))
+ return true;
+ if (node->isMouseFocusable())
+ return true;
+ if (node->isFocusable())
+ return true;
+ if (node->isEventTargetNode())
+ return true;
+ if (CacheBuilder::AnyIsClick(node))
+ return false;
+ if (CacheBuilder::HasTriggerEvent(node))
+ return true;
+ return false;
+}
+
+void CacheBuilder::Debug::localName(Node* node) {
+ const AtomicString& local = node->localName();
+ if (node->isTextNode())
+ print("\"#text\"");
+ else
+ wideString(local.characters(), local.length(), false);
+ print(", ");
+}
+
+void CacheBuilder::Debug::newLine(int indent) {
+ if (mPrefix[0] != '\n')
+ print(&mPrefix[0], 1);
+ flush();
+ int lastnewline = mIndex - 1;
+ while (lastnewline >= 0 && mBuffer[lastnewline] != '\n')
+ lastnewline--;
+ lastnewline++;
+ char* buffer = mBuffer;
+ if (lastnewline > 0) {
+ DUMP_NAV_LOGD("%.*s", lastnewline, buffer);
+ mIndex -= lastnewline;
+ buffer += lastnewline;
+ }
+ size_t prefixLen = strlen(mPrefix);
+ int minPrefix = prefixLen - 1;
+ while (minPrefix >= 0 && mPrefix[minPrefix] != '\n')
+ minPrefix--;
+ minPrefix = prefixLen - minPrefix - 1;
+ if (mIndex > minPrefix)
+ DUMP_NAV_LOGD("%.*s\n", mIndex, buffer);
+ mIndex = 0;
+ setIndent(indent);
+}
+
+int CacheBuilder::Debug::ParentIndex(Node* node, int count, Node* parent)
+{
+ if (parent == NULL)
+ return -1;
+ ASSERT(node != parent);
+ int result = count;
+ Node* previous = node;
+ do {
+ result--;
+ previous = previous->traversePreviousNode();
+ } while (previous && previous != parent);
+ if (previous != NULL)
+ return result;
+ result = count;
+ do {
+ result++;
+ } while ((node = node->traverseNextNode()) != NULL && node != parent);
+ if (node != NULL)
+ return result;
+ ASSERT(0);
+ return -1;
+}
+
+void CacheBuilder::Debug::print(const char* name) {
+ print(name, strlen(name));
+}
+
+void CacheBuilder::Debug::print(const char* name, unsigned len) {
+ do {
+ if (mIndex + len >= DEBUG_BUFFER_SIZE)
+ flush();
+ int copyLen = mIndex + len < DEBUG_BUFFER_SIZE ?
+ len : DEBUG_BUFFER_SIZE - mIndex;
+ memcpy(&mBuffer[mIndex], name, copyLen);
+ mIndex += copyLen;
+ name += copyLen;
+ len -= copyLen;
+ } while (len > 0);
+ mBuffer[mIndex] = '\0';
+}
+
+void CacheBuilder::Debug::setIndent(int indent)
+{
+ char scratch[64];
+ snprintf(scratch, sizeof(scratch), "%.*s", indent,
+ " ");
+ print(scratch);
+}
+
+void CacheBuilder::Debug::renderTree(RenderObject* renderer, int indent,
+ Node* child, int count)
+{
+ char scratch[256];
+ Node* node = renderer->node();
+ if (node != child) {
+ count = ParentIndex(child, count, node);
+ if (renderer->isRenderBlock() == false)
+ goto tryParent;
+ RenderBlock* renderBlock = (RenderBlock*) renderer;
+ if (renderBlock->hasColumns() == false)
+ goto tryParent;
+ Vector<IntRect>* rects = renderBlock->columnRects();
+ newLine(indent);
+ snprintf(scratch, sizeof(scratch), "// render parent=%d", count);
+ print(scratch);
+ for (size_t x = 0; x < rects->size(); x++) {
+ const IntRect& rect = rects->at(x);
+ snprintf(scratch, sizeof(scratch), "(%d,%d,%d,%d) ", rect.x(),
+ rect.y(), rect.width(), rect.height());
+ print(scratch);
+ }
+ }
+ {
+ newLine(indent);
+ RenderStyle* style = renderer->style();
+ EVisibility vis = style->visibility();
+ ASSERT(vis == VISIBLE || vis == HIDDEN || vis == COLLAPSE);
+ snprintf(scratch, sizeof(scratch),
+ "// render style visible:%s opacity:%g width:%d height:%d"
+ " hasBackground:%s isInlineFlow:%s isBlockFlow:%s"
+ " textOverflow:%s",
+ vis == VISIBLE ? "visible" : vis == HIDDEN ? "hidden" : "collapse",
+ style->opacity(), renderer->width(), renderer->height(),
+ style->hasBackground() ? "true" : "false",
+ renderer->isInlineFlow() ? "true" : "false",
+ renderer->isBlockFlow() ? "true" : "false",
+ style->textOverflow() ? "true" : "false"
+ );
+ print(scratch);
+ newLine(indent);
+ const IntRect& oRect = renderer->overflowRect(true);
+ const IntRect& cRect = renderer->getOverflowClipRect(0,0);
+ snprintf(scratch, sizeof(scratch),
+ "// render xPos:%d yPos:%d overflowRect:{%d, %d, %d, %d} "
+ " getOverflowClipRect:{%d, %d, %d, %d} ",
+ renderer->xPos(), renderer->yPos(),
+ oRect.x(), oRect.y(), oRect.width(), oRect.height(),
+ cRect.x(), cRect.y(), cRect.width(), cRect.height()
+ );
+ print(scratch);
+ if (renderer->isInlineFlow()) {
+ RenderFlow* renderFlow = (RenderFlow*) renderer;
+ int ifIndex = 0;
+ flowBoxes(renderFlow, ifIndex, 0);
+ }
+ }
+tryParent:
+ RenderObject* parent = renderer->parent();
+ if (parent)
+ renderTree(parent, indent + 2, node, count);
+}
+
+void CacheBuilder::Debug::uChar(const UChar* name, unsigned len, bool hex) {
+ const UChar* end = name + len;
+ bool wroteHex = false;
+ while (name < end) {
+ unsigned ch = *name++;
+ if (ch == '\t' || ch == '\n' || ch == '\r' || ch == 0xa0)
+ ch = ' ';
+ if (ch < ' ' || ch == 0x7f) {
+ if (hex) {
+ mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex, "\\x%02x", ch);
+ wroteHex = true;
+ } else
+ mBuffer[mIndex++] = '?';
+ } else if (ch >= 0x80) {
+ if (hex) {
+ if (ch < 0x800)
+ mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex,
+ "\\x%02x\\x%02x", ch >> 6 | 0xc0, (ch & 0x3f) | 0x80);
+ else
+ mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex,
+ "\\x%02x\\x%02x\\x%02x", ch >> 12 | 0xe0,
+ (ch >> 6 & 0x3f) | 0x80, (ch & 0x3f) | 0x80);
+ wroteHex = true;
+ } else
+ mBuffer[mIndex++] = '?';
+ } else {
+ if (wroteHex && WTF::isASCIIHexDigit((UChar) ch))
+ mIndex += snprintf(&mBuffer[mIndex], mBufferSize - mIndex,
+ "\" \"");
+ else if (ch == '"' || ch == '\\')
+ mBuffer[mIndex++] = '\\';
+ mBuffer[mIndex++] = ch;
+ wroteHex = false;
+ }
+ if (mIndex + 1 >= DEBUG_BUFFER_SIZE)
+ flush();
+ }
+ flush();
+}
+
+void CacheBuilder::Debug::validateFrame() {
+ FrameAndroid* frame = frameAnd();
+ android::WebCoreFrameBridge* bridge = frame->bridge();
+ ASSERT(bridge);
+ WebCoreViewBridge* vbridge = frame->view()->getWebCoreViewBridge();
+ ASSERT(vbridge);
+ Page* page = frame->page();
+ ASSERT(page);
+ ASSERT((int) page > 0x10000);
+ Frame* child = frame->tree()->firstChild();
+ while (child) {
+ Builder(child)->mDebug.validateFrame();
+ child = child->tree()->nextSibling();
+ }
+}
+
+void CacheBuilder::Debug::wideString(const UChar* chars, int length, bool hex) {
+ if (length == 0)
+ print("\"\"");
+ else {
+ print("\"");
+ uChar(chars, length, hex);
+ print("\"");
+ }
+}
+
+void CacheBuilder::Debug::wideString(const String& str) {
+ wideString(str.characters(), str.length(), false);
+}
+
+#endif // DUMP_NAV_CACHE
+
+CacheBuilder::CacheBuilder()
+{
+ mLastKnownFocus = NULL;
+ mAllowableTypes = android::ALL_CACHEDNODETYPES;
+#ifdef DUMP_NAV_CACHE_USING_PRINTF
+ gNavCacheLogFile = NULL;
+#endif
+}
+
+void CacheBuilder::adjustForColumns(const ClipColumnTracker& track,
+ android::CachedNode* node, IntRect* bounds)
+{
+ int x = 0;
+ int y = 0;
+ int tx = track.mBounds.x();
+ int ty = track.mBounds.y();
+ int columnGap = track.mColumnGap;
+ size_t limit = track.mColumns->size();
+ for (size_t index = 0; index < limit; index++) {
+ IntRect column = track.mColumns->at(index);
+ column.move(tx, ty);
+ IntRect test = *bounds;
+ test.move(x, y);
+ if (column.contains(test)) {
+ if ((x | y) == 0)
+ return;
+ *bounds = test;
+ node->move(x, y);
+ return;
+ }
+ int xOffset = column.width() + columnGap;
+ x += track.mDirection == LTR ? xOffset : -xOffset;
+ y -= column.height();
+ }
+}
+
+bool CacheBuilder::AnyChildIsClick(Node* node)
+{
+ Node* child = node->firstChild();
+ while (child != NULL) {
+ if (child->isEventTargetNode()) {
+ EventTargetNode* target = (EventTargetNode*) child;
+ if (target->isFocusable() ||
+ target->getEventListener(EventNames::clickEvent) ||
+ target->getEventListener(EventNames::mousedownEvent) ||
+ target->getEventListener(EventNames::mouseupEvent) ||
+ target->getEventListener(EventNames::keydownEvent) ||
+ target->getEventListener(EventNames::keyupEvent))
+ return true;
+ }
+ if (AnyChildIsClick(child))
+ return true;
+ child = child->nextSibling();
+ }
+ return false;
+}
+
+bool CacheBuilder::AnyIsClick(Node* node)
+{
+ if (node->hasTagName(HTMLNames::bodyTag))
+ return AnyChildIsClick(node);
+ EventTargetNode* target = (EventTargetNode*) node;
+ if (target->getEventListener(EventNames::mouseoverEvent) == NULL &&
+ target->getEventListener(EventNames::mouseoutEvent) == NULL &&
+ target->getEventListener(EventNames::keydownEvent) == NULL &&
+ target->getEventListener(EventNames::keyupEvent) == NULL)
+ return false;
+ if (target->getEventListener(EventNames::clickEvent))
+ return false;
+ if (target->getEventListener(EventNames::mousedownEvent))
+ return false;
+ if (target->getEventListener(EventNames::mouseupEvent))
+ return false;
+ return AnyChildIsClick(node);
+}
+
+void CacheBuilder::buildCache(android::CachedRoot* root)
+{
+ FrameAndroid* frame = FrameAnd(this);
+ mLastKnownFocus = NULL;
+ BuildFrame(frame, frame, root, (android::CachedFrame*) root);
+ root->finishInit(); // set up frame parent pointers, child pointers
+ setData((android::CachedFrame*) root);
+}
+
+static Node* OneAfter(Node* node)
+{
+ Node* parent = node;
+ Node* sibling = NULL;
+ while ((parent = parent->parentNode()) != NULL) {
+ sibling = parent->nextSibling();
+ if (sibling != NULL)
+ break;
+ }
+ return sibling;
+}
+
+// when new focus is found, push it's parent on a stack
+ // as long as more focii are found with the same (grand) parent, note it
+ // (which only requires retrieving the last parent on the stack)
+// when the parent's last child is found, pop the stack
+// different from Tracker in that Tracker only pushes focii with children
+
+// making this work with focus - child focus - grandchild focus is tricky
+// if I keep the generation number, I may be able to more quickly determine that
+// a node is a grandchild of the focus's parent
+// this additionally requires being able to find the grandchild's parent
+
+// keep nodes that are focusable
+void CacheBuilder::BuildFrame(FrameAndroid* root, FrameAndroid* frame,
+ android::CachedRoot* cachedRoot, android::CachedFrame* cachedFrame)
+{
+ WTF::Vector<Tracker> tracker(1);
+ {
+ Tracker* baseTracker = tracker.data(); // sentinel
+ bzero(baseTracker, sizeof(Tracker));
+ baseTracker->mCachedNodeIndex = -1;
+ }
+ WTF::Vector<ClipColumnTracker> clipTracker(1);
+ {
+ ClipColumnTracker* baseTracker = clipTracker.data(); // sentinel
+ bzero(baseTracker, sizeof(ClipColumnTracker));
+ }
+#if DUMP_NAV_CACHE
+ char* frameNamePtr = cachedFrame->mDebug.mFrameName;
+ Builder(frame)->mDebug.frameName(frameNamePtr, frameNamePtr +
+ sizeof(cachedFrame->mDebug.mFrameName) - 1);
+ *frameNamePtr = '\0';
+ int nodeIndex = 1;
+#endif
+ NodeWalk walk;
+ Document* doc = frame->document();
+ Node* parent = doc;
+ android::CachedNode cachedParentNode;
+ cachedParentNode.init(cachedFrame, parent);
+#if DUMP_NAV_CACHE
+ cachedParentNode.mDebug.mNodeIndex = nodeIndex;
+#endif
+ cachedFrame->add(cachedParentNode);
+ Node* node = parent;
+ int cacheIndex = 1;
+ Node* focused = doc->focusedNode();
+ if (focused)
+ setLastFocus(focused);
+ int globalOffsetX, globalOffsetY;
+ GetGlobalOffset(frame, &globalOffsetX, &globalOffsetY);
+ while (walk.mMore || (node = node->traverseNextNode()) != NULL) {
+#if DUMP_NAV_CACHE
+ nodeIndex++;
+#endif
+ Tracker* last = &tracker.last();
+ int lastChildIndex = cachedFrame->size() - 1;
+ while (node == last->mLastChild) {
+ if (CleanUpContainedNodes(cachedFrame, last, lastChildIndex))
+ cacheIndex--;
+ tracker.removeLast();
+ lastChildIndex = last->mCachedNodeIndex;
+ last = &tracker.last();
+ }
+ if (node == last->mParentLastChild)
+ last->mParentLastChild = NULL;
+ do {
+ const ClipColumnTracker* lastClip = &clipTracker.last();
+ if (node != lastClip->mLastChild)
+ break;
+ clipTracker.removeLast();
+ } while (true);
+ Frame* child = HasFrame(node);
+ android::CachedNode cachedNode;
+ if (child != NULL) {
+ if (child->document() == NULL)
+ continue;
+ RenderObject* nodeRenderer = node->renderer();
+ if (nodeRenderer != NULL && nodeRenderer->style()->visibility() == HIDDEN)
+ continue;
+ android::CachedFrame cachedChild;
+ cachedChild.init(cachedRoot, cacheIndex, Android(child));
+ int childFrameIndex = cachedFrame->childCount();
+ cachedFrame->addFrame(cachedChild);
+ cachedNode.init(cachedFrame, node);
+ cachedNode.setIndex(cacheIndex++);
+ cachedNode.setChildFrameIndex(childFrameIndex);
+#if DUMP_NAV_CACHE
+ cachedNode.mDebug.mNodeIndex = nodeIndex;
+ cachedNode.mDebug.mParentGroupIndex = Debug::ParentIndex(
+ node, nodeIndex, NULL);
+#endif
+ cachedFrame->add(cachedNode);
+ android::CachedFrame* childPtr = cachedFrame->lastChild();
+ BuildFrame(root, Android(child), cachedRoot, childPtr);
+ continue;
+ }
+ RenderObject* nodeRenderer = node->renderer();
+ bool isTransparent = false;
+ bool hasFocusRing = true;
+ if (nodeRenderer != NULL) {
+ RenderStyle* style = nodeRenderer->style();
+ if (style->visibility() == HIDDEN)
+ continue;
+ if (nodeRenderer->isImage()) { // set all the area elements to have a link to their images
+ RenderImage* image = static_cast<RenderImage*>(nodeRenderer);
+ image->setImageForAreaElements();
+ }
+ isTransparent = style->hasBackground() == false;
+ hasFocusRing = style->tapHighlightColor().alpha() > 0;
+ }
+ bool more = walk.mMore;
+ walk.reset();
+ // GetGlobalBounds(node, &bounds, false);
+ bool anchorHasSrcUrl = false;
+ bool computeFocusRings = false;
+ bool hasClip = false;
+ bool hasMouseOver = false;
+ bool isAnchor = false;
+ bool isArea = node->hasTagName(HTMLNames::areaTag);
+ bool isInput = false;
+ bool isPassword = false;
+ bool isTextArea = false;
+ bool isTextField = false;
+ bool isRtlText = false;
+ bool isUnclipped = false;
+ bool isFocus = node == focused;
+ bool takesFocus = false;
+ int maxLength = -1;
+ int textSize = 12;
+ int columnGap = 0;
+ TextDirection direction = LTR;
+ String name;
+ String exported;
+ android::CachedNodeType type = android::NORMAL_CACHEDNODETYPE;
+ IntRect bounds;
+ IntRect absBounds;
+ Node* lastChild = node->lastChild();
+ WTF::Vector<IntRect>* columns = NULL;
+ if (isArea) {
+ HTMLAreaElement* area = static_cast<HTMLAreaElement*>(node);
+ bounds = area->getAreaRect();
+ bounds.move(globalOffsetX, globalOffsetY);
+ absBounds = bounds;
+ isUnclipped = true; // FIXME: areamaps require more effort to detect
+ // assume areamaps are always visible for now
+ takesFocus = true;
+ goto keepNode;
+ }
+ if (nodeRenderer == NULL)
+ continue;
+ absBounds = nodeRenderer->absoluteBoundingBoxRect();
+ absBounds.move(globalOffsetX, globalOffsetY);
+ hasClip = nodeRenderer->hasOverflowClip();
+ if (nodeRenderer->isRenderBlock()) {
+ RenderBlock* renderBlock = (RenderBlock*) nodeRenderer;
+ if (renderBlock->hasColumns()) {
+ columns = renderBlock->columnRects();
+ columnGap = renderBlock->columnGap();
+ direction = renderBlock->style()->direction();
+ }
+ }
+ if ((hasClip != false || columns != NULL) && lastChild) {
+ clipTracker.grow(clipTracker.size() + 1);
+ ClipColumnTracker& clip = clipTracker.last();
+ clip.mBounds = absBounds;
+ clip.mLastChild = OneAfter(lastChild);
+ clip.mNode = node;
+ clip.mColumns = columns;
+ clip.mColumnGap = columnGap;
+ clip.mHasClip = hasClip;
+ clip.mDirection = direction;
+ if (columns != NULL) {
+ const IntRect& oRect = nodeRenderer->overflowRect(true);
+ clip.mBounds.move(oRect.x(), oRect.y());
+ }
+ }
+ if (node->isTextNode() && mAllowableTypes != android::NORMAL_CACHEDNODETYPE) {
+ if (last->mSomeParentTakesFocus) // don't look at text inside focusable node
+ continue;
+ android::CachedNodeType checkType;
+ if (isFocusableText(&walk, more, node, &checkType,
+ &exported) == false)
+ continue;
+ #if DUMP_NAV_CACHE
+ {
+ char buffer[DEBUG_BUFFER_SIZE];
+ mDebug.init(buffer, sizeof(buffer));
+ mDebug.print("text link found: ");
+ mDebug.wideString(exported);
+ DUMP_NAV_LOGD("%s\n", buffer);
+ }
+ #endif
+ type = (android::CachedNodeType) checkType;
+ // !!! test ! is the following line correctly needed for frames to work?
+ cachedNode.init(cachedFrame, node);
+ const ClipColumnTracker& clipTrack = clipTracker.last();
+ const IntRect& clip = clipTrack.mHasClip ? clipTrack.mBounds :
+ IntRect(0, 0, INT_MAX, INT_MAX);
+ if (ConstructTextRects((WebCore::Text*) node, walk.mStart,
+ (WebCore::Text*) walk.mFinalNode, walk.mEnd, globalOffsetX,
+ globalOffsetY, &bounds, clip, &cachedNode.focusRings()) == false)
+ continue;
+ cachedNode.setBounds(bounds);
+ if (bounds.width() < MINIMUM_FOCUSABLE_WIDTH)
+ continue;
+ if (bounds.height() < MINIMUM_FOCUSABLE_HEIGHT)
+ continue;
+ computeFocusRings = true;
+ isUnclipped = true; // FIXME: to hide or partially occlude synthesized links, each
+ // focus ring will also need the offset and length of characters
+ // used to produce it
+ goto keepTextNode;
+ }
+ if (node->hasTagName(WebCore::HTMLNames::inputTag)) {
+ HTMLInputElement* input = (HTMLInputElement*) node;
+ if (input->inputType() == HTMLInputElement::FILE)
+ continue;
+ isInput = true;
+ isTextField = input->isTextField();
+ isPassword = input->inputType() == HTMLInputElement::PASSWORD;
+ maxLength = input->maxLength();
+ name = String(input->name().domString());
+ isUnclipped = isTransparent; // can't detect if this is drawn on top (example: deviant.com login parts)
+ } else if (node->hasTagName(HTMLNames::textareaTag))
+ isTextArea = true;
+ else if (node->hasTagName(HTMLNames::aTag)) {
+ EventTargetNode* target = (EventTargetNode*) node;
+ hasMouseOver = target->getEventListener(EventNames::mouseoverEvent);
+ isAnchor = true;
+ String href = ((HTMLAnchorElement*) node)->href();
+#ifdef ANDROID_JAVASCRIPT_SECURITY
+ anchorHasSrcUrl = !href.isEmpty() && !WebCore::protocolIs(href, "javascript");
+ // Set the exported string for protocols that we know will not be
+ // handled by WebCore.
+ if (WebCore::protocolIs(href, "mailto") ||
+ WebCore::protocolIs(href, "tel") ||
+ WebCore::protocolIs(href, "geo"))
+ exported = String(KURL::decode_string(href.deprecatedString()));
+#endif
+ }
+ if (isTextField || isTextArea) {
+ RenderTextControl* renderText =
+ static_cast<RenderTextControl*>(nodeRenderer);
+ if (isFocus)
+ cachedRoot->setSelection(renderText->selectionStart(), renderText->selectionEnd());
+ exported = String(renderText->text());
+ // FIXME: Would it be better to use (float) size()?
+ // FIXME: Are we sure there will always be a style and font, and it's correct?
+ RenderStyle* style = nodeRenderer->style();
+ if (style) {
+ textSize = style->fontSize();
+ isRtlText = style->direction() == RTL;
+ }
+ }
+ takesFocus = true;
+ if (isAnchor) {
+ bounds = absBounds;
+ } else {
+ bool isFocusable = node->isKeyboardFocusable(NULL) ||
+ node->isMouseFocusable() || node->isFocusable();
+ if (isFocusable == false) {
+ if (node->isEventTargetNode() == false)
+ continue;
+ bool overOrOut = HasOverOrOut(node);
+ bool hasTrigger = HasTriggerEvent(node);
+ if (overOrOut == false && hasTrigger == false)
+ continue;
+ takesFocus = hasTrigger;
+ }
+ bounds = node->getRect();
+ // For Bank of America site
+ if (isTextField && nodeRenderer->paddingLeft() > 100) {
+ int paddingLeft = nodeRenderer->paddingLeft();
+ int paddingTop = nodeRenderer->paddingTop();
+ int x = bounds.x() + paddingLeft;
+ int y = bounds.y() + paddingTop;
+ int width = bounds.width() - paddingLeft - nodeRenderer->paddingRight();
+ int height = bounds.height() - paddingTop - nodeRenderer->paddingBottom();
+ bounds.setLocation(IntPoint(x, y));
+ bounds.setSize(IntSize(width, height));
+ }
+ if (bounds.width() < MINIMUM_FOCUSABLE_WIDTH)
+ continue;
+ if (bounds.height() < MINIMUM_FOCUSABLE_HEIGHT)
+ continue;
+ bounds.move(globalOffsetX, globalOffsetY);
+ }
+ computeFocusRings = true;
+ keepNode:
+ cachedNode.init(cachedFrame, node);
+ if (computeFocusRings == false) {
+ cachedNode.setBounds(bounds);
+ cachedNode.focusRings().append(bounds);
+ } else if (ConstructPartRects(node, bounds, cachedNode.boundsPtr(),
+ globalOffsetX, globalOffsetY, &cachedNode.focusRings()) == false)
+ continue;
+ keepTextNode:
+ IntRect clip = hasClip ? bounds : absBounds;
+ size_t clipIndex = clipTracker.size();
+ if (clipTracker.last().mNode == node)
+ clipIndex -= 1;
+ while (--clipIndex > 0) {
+ const ClipColumnTracker& clipTrack = clipTracker.at(clipIndex);
+ if (clipTrack.mHasClip == false) {
+ adjustForColumns(clipTrack, &cachedNode, &absBounds);
+ continue;
+ }
+ const IntRect& parentClip = clipTrack.mBounds;
+ if (hasClip == false && isAnchor)
+ clip = parentClip;
+ else
+ clip.intersect(parentClip);
+ hasClip = true;
+ DBG_NAV_LOGD("absBounds={%d,%d,%d,%d} parentClip={%d,%d,%d,%d}\n",
+ absBounds.x(), absBounds.y(), absBounds.width(), absBounds.height(),
+ parentClip.x(), parentClip.y(), parentClip.width(), parentClip.height());
+ }
+ if (hasClip && cachedNode.clip(clip) == false) {
+ cachedNode.setBounds(clip);
+ cachedNode.focusRings().append(clip);
+ isUnclipped = true;
+ }
+ cachedNode.setNavableRects();
+ cachedNode.setAnchorHasSrcUrl(anchorHasSrcUrl);
+ cachedNode.setChildFrameIndex(-1);
+ cachedNode.setExport(exported);
+ cachedNode.setHasFocusRing(hasFocusRing);
+ cachedNode.setHasMouseOver(hasMouseOver);
+ cachedNode.setHitBounds(absBounds);
+ cachedNode.setIndex(cacheIndex);
+ cachedNode.setIsAnchor(isAnchor);
+ cachedNode.setIsArea(isArea);
+ cachedNode.setIsFocus(isFocus);
+ cachedNode.setIsInput(isInput);
+ cachedNode.setIsPassword(isPassword);
+ cachedNode.setIsRtlText(isRtlText);
+ cachedNode.setIsTextArea(isTextArea);
+ cachedNode.setIsTextField(isTextField);
+ cachedNode.setIsTransparent(isTransparent);
+ cachedNode.setIsUnclipped(isUnclipped);
+ cachedNode.setMaxLength(maxLength);
+ cachedNode.setName(name);
+ cachedNode.setParentIndex(last->mCachedNodeIndex);
+ if (last->mParentLastChild == NULL)
+ last->mParentLastChild = OneAfter(node->parentNode()->lastChild());
+ cachedNode.setParentGroup(last->mParentLastChild);
+ cachedNode.setTextSize(textSize);
+ cachedNode.setType(type);
+#if DUMP_NAV_CACHE
+ cachedNode.mDebug.mNodeIndex = nodeIndex;
+ cachedNode.mDebug.mParentGroupIndex = Debug::ParentIndex(
+ node, nodeIndex, (Node*) cachedNode.parentGroup());
+#endif
+ cachedFrame->add(cachedNode);
+ {
+ int lastIndex = cachedFrame->size() - 1;
+ if (node == focused) {
+ android::CachedNode* cachedNodePtr = cachedFrame->getIndex(lastIndex);
+ cachedRoot->setCachedFocus(cachedFrame, cachedNodePtr);
+ }
+ if (lastChild != NULL) {
+ tracker.grow(tracker.size() + 1);
+ Tracker& working = tracker.last();
+ working.mCachedNodeIndex = lastIndex;
+ working.mLastChild = OneAfter(lastChild);
+ working.mParentLastChild = OneAfter(node->parentNode()->lastChild());
+ last = &tracker.at(tracker.size() - 2);
+ working.mSomeParentTakesFocus = last->mSomeParentTakesFocus | takesFocus;
+ }
+ }
+ cacheIndex++;
+tryNextNode:
+ ;
+ }
+ while (tracker.size() > 1) {
+ Tracker* last = &tracker.last();
+ int lastChildIndex = cachedFrame->size() - 1;
+ if (CleanUpContainedNodes(cachedFrame, last, lastChildIndex))
+ cacheIndex--;
+ tracker.removeLast();
+ }
+}
+
+bool CacheBuilder::CleanUpContainedNodes(android::CachedFrame* cachedFrame,
+ const Tracker* last, int lastChildIndex)
+{
+ // if outer is body, disable outer
+ // or if there's more than one inner, disable outer
+ // or if inner is keyboard focusable, disable outer
+ // else disable inner by removing it
+ int childCount = lastChildIndex - last->mCachedNodeIndex;
+ if (childCount == 0)
+ return false;
+ android::CachedNode* lastCached = cachedFrame->getIndex(last->mCachedNodeIndex);
+ Node* lastNode = (Node*) lastCached->nodePointer();
+ if ((childCount > 1 && lastNode->hasTagName(HTMLNames::selectTag) == false) ||
+ lastNode->hasTagName(HTMLNames::bodyTag) ||
+ lastNode->hasTagName(HTMLNames::formTag)) {
+ lastCached->setBounds(IntRect(0, 0, 0, 0));
+ lastCached->focusRings().clear();
+ lastCached->setNavableRects();
+ return false;
+ }
+ android::CachedNode* onlyChildCached = cachedFrame->lastNode();
+ Node* onlyChild = (Node*) onlyChildCached->nodePointer();
+ bool outerIsMouseMoveOnly =
+ lastNode->isKeyboardFocusable(NULL) == false &&
+ lastNode->isMouseFocusable() == false &&
+ lastNode->isFocusable() == false &&
+ lastNode->isEventTargetNode() == true &&
+ HasOverOrOut(lastNode) == true &&
+ HasTriggerEvent(lastNode) == false;
+ if (cachedFrame->focusIndex() == lastChildIndex)
+ cachedFrame->setFocusIndex(last->mCachedNodeIndex);
+ if (onlyChildCached->parent() == lastCached)
+ onlyChildCached->setParentIndex(lastCached->parentIndex());
+ if (outerIsMouseMoveOnly || onlyChild->isKeyboardFocusable(NULL))
+ *lastCached = *onlyChildCached;
+ cachedFrame->removeLast();
+ return true;
+}
+
+Node* CacheBuilder::currentFocus() const
+{
+ Frame* frame = FrameAnd(this);
+ Document* doc = frame->document();
+ if (doc != NULL) {
+ Node* focus = doc->focusedNode();
+ if (focus != NULL)
+ return focus;
+ }
+ Frame* child = frame->tree()->firstChild();
+ while (child) {
+ CacheBuilder* cacheBuilder = Builder(child);
+ Node* focus = cacheBuilder->currentFocus();
+ if (focus)
+ return focus;
+ child = child->tree()->nextSibling();
+ }
+ return NULL;
+}
+
+static bool strCharCmp(const char* matches, const UChar* test, int wordLength,
+ int wordCount)
+{
+ for (int index = 0; index < wordCount; index++) {
+ for (int inner = 0; inner < wordLength; inner++) {
+ if (matches[inner] != test[inner]) {
+ matches += wordLength;
+ goto next;
+ }
+ }
+ return true;
+next:
+ ;
+ }
+ return false;
+}
+
+static const int stateTwoLetter[] = {
+ 0x02060c00, // A followed by: [KLRSZ]
+ 0x00000000, // B
+ 0x00084001, // C followed by: [AOT]
+ 0x00000014, // D followed by: [CE]
+ 0x00000000, // E
+ 0x00001800, // F followed by: [LM]
+ 0x00100001, // G followed by: [AU]
+ 0x00000100, // H followed by: [I]
+ 0x00002809, // I followed by: [ADLN]
+ 0x00000000, // J
+ 0x01040000, // K followed by: [SY]
+ 0x00000001, // L followed by: [A]
+ 0x000ce199, // M followed by: [ADEHINOPST]
+ 0x0120129c, // N followed by: [CDEHJMVY]
+ 0x00020480, // O followed by: [HKR]
+ 0x00420001, // P followed by: [ARW]
+ 0x00000000, // Q
+ 0x00000100, // R followed by: [I]
+ 0x0000000c, // S followed by: [CD]
+ 0x00802000, // T followed by: [NX]
+ 0x00080000, // U followed by: [T]
+ 0x00080101, // V followed by: [AIT]
+ 0x01200101 // W followed by: [AIVY]
+};
+
+static const char firstIndex[] = {
+ 0, 5, 5, 8, 10, 10, 12, 14,
+ 15, 19, 19, 21, 22, 32, 40, 43,
+ 46, 46, 47, 49, 51, 52, 55, 59
+};
+
+// from http://infolab.stanford.edu/~manku/bitcount/bitcount.html
+#define TWO(c) (0x1u << (c))
+#define MASK(c) (((unsigned int)(-1)) / (TWO(TWO(c)) + 1u))
+#define COUNT(x,c) ((x) & MASK(c)) + (((x) >> (TWO(c))) & MASK(c))
+
+int bitcount (unsigned int n)
+{
+ n = COUNT(n, 0);
+ n = COUNT(n, 1);
+ n = COUNT(n, 2);
+ n = COUNT(n, 3);
+ return COUNT(n, 4);
+}
+
+#undef TWO
+#undef MASK
+#undef COUNT
+
+static bool isUnicodeSpace(UChar ch)
+{
+ return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' || ch == 0xa0;
+}
+
+static bool validZip(int stateIndex, const UChar* zipPtr)
+{
+ static const struct {
+ char mLow;
+ char mHigh;
+ char mException1;
+ char mException2;
+ } zipRange[] = {
+ { 99, 99, -1, -1 }, // AK Alaska
+ { 35, 36, -1, -1 }, // AL Alabama
+ { 71, 72, -1, -1 }, // AR Arkansas
+ { 96, 96, -1, -1 }, // AS American Samoa
+ { 85, 86, -1, -1 }, // AZ Arizona
+ { 90, 96, -1, -1 }, // CA California
+ { 80, 81, -1, -1 }, // CO Colorado
+ { 6, 6, -1, -1 }, // CT Connecticut
+ { 20, 20, -1, -1 }, // DC District of Columbia
+ { 19, 19, -1, -1 }, // DE Delaware
+ { 32, 34, -1, -1 }, // FL Florida
+ { 96, 96, -1, -1 }, // FM Federated States of Micronesia
+ { 30, 31, -1, -1 }, // GA Georgia
+ { 96, 96, -1, -1 }, // GU Guam
+ { 96, 96, -1, -1 }, // HI Hawaii
+ { 50, 52, -1, -1 }, // IA Iowa
+ { 83, 83, -1, -1 }, // ID Idaho
+ { 60, 62, -1, -1 }, // IL Illinois
+ { 46, 47, -1, -1 }, // IN Indiana
+ { 66, 67, 73, -1 }, // KS Kansas
+ { 40, 42, -1, -1 }, // KY Kentucky
+ { 70, 71, -1, -1 }, // LA Louisiana
+ { 1, 2, -1, -1 }, // MA Massachusetts
+ { 20, 21, -1, -1 }, // MD Maryland
+ { 3, 4, -1, -1 }, // ME Maine
+ { 96, 96, -1, -1 }, // MH Marshall Islands
+ { 48, 49, -1, -1 }, // MI Michigan
+ { 55, 56, -1, -1 }, // MN Minnesota
+ { 63, 65, -1, -1 }, // MO Missouri
+ { 96, 96, -1, -1 }, // MP Northern Mariana Islands
+ { 38, 39, -1, -1 }, // MS Mississippi
+ { 55, 56, -1, -1 }, // MT Montana
+ { 27, 28, -1, -1 }, // NC North Carolina
+ { 58, 58, -1, -1 }, // ND North Dakota
+ { 68, 69, -1, -1 }, // NE Nebraska
+ { 3, 4, -1, -1 }, // NH New Hampshire
+ { 7, 8, -1, -1 }, // NJ New Jersey
+ { 87, 88, 86, -1 }, // NM New Mexico
+ { 88, 89, 96, -1 }, // NV Nevada
+ { 10, 14, 0, 6 }, // NY New York
+ { 43, 45, -1, -1 }, // OH Ohio
+ { 73, 74, -1, -1 }, // OK Oklahoma
+ { 97, 97, -1, -1 }, // OR Oregon
+ { 15, 19, -1, -1 }, // PA Pennsylvania
+ { 6, 6, 0, 9 }, // PR Puerto Rico
+ { 96, 96, -1, -1 }, // PW Palau
+ { 2, 2, -1, -1 }, // RI Rhode Island
+ { 29, 29, -1, -1 }, // SC South Carolina
+ { 57, 57, -1, -1 }, // SD South Dakota
+ { 37, 38, -1, -1 }, // TN Tennessee
+ { 75, 79, 87, 88 }, // TX Texas
+ { 84, 84, -1, -1 }, // UT Utah
+ { 22, 24, 20, -1 }, // VA Virginia
+ { 6, 9, -1, -1 }, // VI Virgin Islands
+ { 5, 5, -1, -1 }, // VT Vermont
+ { 98, 99, -1, -1 }, // WA Washington
+ { 53, 54, -1, -1 }, // WI Wisconsin
+ { 24, 26, -1, -1 }, // WV West Virginia
+ { 82, 83, -1, -1 } // WY Wyoming
+ };
+
+ int zip = zipPtr[0] - '0';
+ zip *= 10;
+ zip += zipPtr[1] - '0';
+ int low = zipRange[stateIndex].mLow;
+ int high = zipRange[stateIndex].mHigh;
+ if (zip >= low && zip <= high)
+ return true;
+ if (zip == zipRange[stateIndex].mException1)
+ return true;
+ if (zip == zipRange[stateIndex].mException2)
+ return true;
+ return false;
+}
+
+CacheBuilder::FoundState CacheBuilder::FindAddress(const UChar* chars, unsigned length, int* start, int* end)
+{
+ FindState addressState;
+ FindReset(&addressState);
+ addressState.mWords[0] = addressState.mStarts[0] = chars;
+ FoundState state = FindPartialAddress(chars, chars, length, &addressState);
+ if (state == FOUND_PARTIAL && addressState.mProgress == ZIP_CODE &&
+ addressState.mNumberCount == 0) {
+ addressState.mProgress = FIND_STREET;
+ state = FindPartialAddress(NULL, NULL, 0, &addressState);
+ }
+ *start = addressState.mStartResult;
+ *end = addressState.mEndResult;
+ return state;
+}
+
+CacheBuilder::FoundState CacheBuilder::FindPartialAddress(const UChar* baseChars,
+ const UChar* chars, unsigned length, FindState* s)
+{
+ // lower case letters are optional; trailing asterisk is optional 's'
+ static char const* const longStreetNames[] = {
+ "\x04" "LleY" "\x04" "NneX" "\x05" "RCade" "\x05" "VEnue" "\x06" "LAMEDA", // A
+ "\x04" "aYoU" "\x04" "eaCH" "\x03" "eND" "\x05" "LuFf*" "\x05" "oTtoM"
+ "\x08" "ouLeVarD" "\x05" "Ranch" "\x05" "RidGe" "\x05" "RooK*"
+ "\x04" "urG*" "\x05" "YPass" "\x07" "roadWAY", // B
+ "\x05" "AMINO"
+ "\x03" "amP" "\x05" "anYoN" "\x03" "aPE" "\x07" "auSeWaY" "\x06" "enTeR*"
+ "\x06" "IRcle*" "\x05" "LiFf*" "\x03" "LuB" "\x05" "oMmoN" "\x06" "ORner*"
+ "\x05" "ouRSE" "\x05" "ourT*" "\x04" "oVe*" "\x04" "ReeK" "\x07" "REScent"
+ "\x04" "ReST" "\x07" "ROSSING" "\x08" "ROSSROAD" "\x04" "URVe"
+ "\x05" "AMINO" "\x06" "IRCULO" "\x07" "REScent", // C
+ "\x03" "aLe" "\x02" "aM" "\x05" "iVide" "\x05" "Rive*", // D
+ "\x06" "STate*" "\x09" "XPresswaY" "\x09" "XTension*", // E
+ "\x04" "ALL*" "\x04" "eRrY" "\x05" "ieLD*" "\x04" "LaT*" "\x04" "oRD*"
+ "\x05" "oReST" "\x05" "oRGe*" "\x04" "oRK*" "\x03" "orT" "\x06" "reeWaY", // F
+ "\x06" "arDeN*" "\x06" "aTeWaY" "\x04" "LeN*" "\x05" "ReeN*" "\x05" "RoVe*", // G
+ "\x06" "arBoR*" "\x04" "aVeN" "\x06" "eighTS" "\x06" "ighWaY" "\x04" "iLl*"
+ "\x05" "OLloW", // H
+ "\x04" "NLeT" "\x06" "Sland*" "\x03" "SLE", // I
+ "\x08" "unCTion*", // J
+ "\x03" "eY*" "\x05" "NoLl*", // K
+ "\x04" "aKe*" "\x03" "AND" "\x06" "aNDinG" "\x03" "aNe" "\x05" "iGhT*"
+ "\x03" "oaF" "\x04" "oCK*" "\x04" "oDGe" "\x03" "OOP", // L
+ "\x03" "ALL" "\x05" "aNoR*" "\x06" "eaDoW*" "\x03" "EWS" "\x04" "iLl*"
+ "\x06" "iSsioN" "\x07" "oTorWaY" "\x04" "ounT" "\x08" "ounTaiN*", // M
+ "\x03" "eCK", // N
+ "\x06" "RCHard" "\x03" "VAL" "\x07" "verPASs", // O
+ "\x04" "ARK*" "\x07" "arKWaY*" "\x03" "ASS" "\x06" "aSsaGE" "\x03" "ATH"
+ "\x03" "IKE" "\x04" "iNE*" "\x04" "Lace" "\x05" "LaiN*" "\x04" "LaZa"
+ "\x05" "oinT*" "\x04" "oRT*" "\x06" "Rairie" "\x06" "RIVADA", // P
+ NULL,
+ "\x05" "ADiaL" "\x03" "AMP" "\x04" "aNCH" "\x05" "aPiD*"
+ "\x03" "eST"
+ "\x05" "iDGe*" "\x04" "IVer" "\x04" "oaD*" "\x04" "ouTE" "\x02" "OW"
+ "\x02" "UE" "\x02" "UN", // R
+ "\x05" "HoaL*" "\x05" "HoRe*" "\x05" "KyWaY" "\x06" "PrinG*" "\x04" "PUR*"
+ "\x06" "Quare*" "\x06" "TAtion" "\x08" "TRAvenue" "\x05" "TReaM"
+ "\x06" "Treet*" "\x05" "uMmiT" "\x07" "PeeDWaY", // S
+ "\x06" "ERrace" "\x09" "hRoughWaY" "\x04" "RaCE" "\x04" "RAcK" "\x09" "RaFficwaY"
+ "\x04" "RaiL" "\x05" "UNneL" "\x07" "urnPiKE", // T
+ "\x08" "nderPASs" "\x05" "Nion*", // U
+ "\x06" "aLleY*" "\x06" "IAduct" "\x04" "ieW*" "\x07" "iLlaGe*" "\x04" "iLle"
+ "\x04" "ISta", // V
+ "\x04" "ALK*" "\x03" "ALL" "\x03" "AY*" "\x04" "eLl*", // W
+ "\x03" "ING" "\x02" "RD", // X
+ };
+
+ static char const* const longStateNames[] = {
+ "\x8e" "la" "\x85" "bama" "\x02" "\x84" "ska" "\x01" "\x8f" "merican Samoa" "\x04"
+ "\x91" "r" "\x86" "izona" "\x05" "\x87" "kansas" "\x03",
+ NULL,
+ "\x8b" "alifornia" "\x06" "\x95" "o" "\x87" "lorado" "\x07" "\x8a" "nnecticut" "\x08",
+ "\x89" "elaware" "\x0a" "\x95" "istrict of Columbia" "\x09",
+ NULL,
+ "\x9f" "ederated States of Micronesia" "\x0c" "\x88" "lorida" "\x0b",
+ "\x85" "uam" "\x0e" "\x88" "eorgia" "\x0d",
+ "\x87" "awaii" "\x0f",
+ "\x86" "daho" "\x11" "\x89" "llinois" "\x12" "\x88" "ndiana" "\x13" "\x85"
+ "owa" "\x10",
+ NULL,
+ "\x87" "ansas" "\x14" "\x89" "entucky" "\x15",
+ "\x8a" "ouisiana" "\x16",
+ "\x86" "aine" "\x19" "\x99" "ar" "\x8e" "shall Islands" "\x1a" "\x86" "yland" "\x18"
+ "\x8e" "assachusetts" "\x17" "\x93" "i" "\x87" "chigan" "\x1b"
+ "\x88" "nnesota" "\x1c" "\x93" "iss" "\x88" "issippi" "\x1f" "\x85"
+ "ouri" "\x1d" "\x88" "ontana" "\x20",
+ "\x90" "e" "\x87" "braska" "\x23" "\x85" "vada" "\x27" "\xa5" "ew " "\x8a"
+ "Hampshire" "\x24" "\x87" "Jersey" "\x25" "\x87" "Mexico" "\x26"
+ "\x85" "York" "\x28" "\x98" "orth " "\x89" "Carolina" "\x21" "\x87"
+ "Dakota" "\x22" "\x99" "orthern Mariana Islands" "\x1e",
+ "\x85" "hio" "\x29" "\x89" "klahoma" "\x2a" "\x87" "regon" "\x2b",
+ "\x86" "alau" "\x2e" "\x8d" "ennsylvania" "\x2c" "\x8c" "uerto Rico" "\x2d",
+ NULL,
+ "\x8d" "hode Island" "\x2f",
+ "\x98" "outh " "\x89" "Carolina" "\x30" "\x87" "Dakota" "\x31",
+ "\x90" "e" "\x88" "nnessee" "\x32" "\x84" "xas" "\x33",
+ "\x85" "tah" "\x34",
+ "\x88" "ermont" "\x37" "\x94" "irgin" "\x89" " Islands" "\x36" "\x83" "ia" "\x35",
+ "\x8b" "ashington" "\x38" "\x8e" "est Virginia" "\x3a" "\x8a" "isconsin" "\x39"
+ "\x88" "yoming" "\x3b"
+ };
+
+#if 0 // DEBUG_NAV_UI
+ static char const* const progressNames[] = {
+ "NO_ADDRESS",
+ "SKIP_TO_SPACE",
+ "HOUSE_NUMBER",
+ "NUMBER_TRAILING_SPACE",
+ "ADDRESS_LINE",
+ "STATE_NAME",
+ "SECOND_HALF",
+ "ZIP_CODE",
+ "PLUS_4",
+ "FIND_STREET"
+ };
+#endif
+ // strategy: US only support at first
+ // look for a 1 - 5 digit number for a street number (no support for 'One Microsoft Way')
+ // ignore if preceded by '#', Suite, Ste, Rm
+ // look for two or more words (up to 5? North Frank Lloyd Wright Blvd)
+ // note: "The Circle at North Hills St." has six words, and a lower 'at' -- allow at, by, of, in, the, and, ... ?
+ // if a word starts with a lowercase letter, no match
+ // allow: , . - # / (for 1/2) ' "
+ // don't look for street name type yet
+ // look for one or two delimiters to represent possible 2nd addr line and city name
+ // look for either full state name, or state two letters, and/or zip code (5 or 9 digits)
+ // now look for street suffix, either in full or abbreviated form, with optional 's' if there's an asterisk
+
+ s->mCurrentStart = chars;
+ s->mEnd = chars + length;
+ int candIndex = 0;
+ bool mustBeAllUpper = false;
+ bool secondHalf = false;
+ chars -= 1;
+ UChar ch = s->mCurrent;
+ while (++chars <= s->mEnd) {
+ UChar prior = ch;
+ ch = chars < s->mEnd ? *chars : ' ';
+ switch (s->mProgress) {
+ case NO_ADDRESS:
+ if (WTF::isASCIIDigit(ch) == false) {
+ if (ch != 'O') // letter 'O', not zero
+ continue;
+ if (s->mEnd - chars < 3)
+ continue;
+ prior = *++chars;
+ ch = *++chars;
+ if ((prior != 'n' || ch != 'e') && (prior != 'N' || ch != 'E'))
+ continue;
+ if (isUnicodeSpace(*++chars) == false)
+ continue;
+ s->mProgress = ADDRESS_LINE;
+ s->mStartResult = chars - 3 - s->mCurrentStart;
+ continue;
+ }
+ if (isUnicodeSpace(prior) == false) {
+ s->mProgress = SKIP_TO_SPACE;
+ continue;
+ }
+ s->mNumberCount = 1;
+ s->mProgress = HOUSE_NUMBER;
+ s->mStartResult = chars - s->mCurrentStart;
+ continue;
+ case SKIP_TO_SPACE:
+ if (isUnicodeSpace(ch) == false)
+ continue;
+ break;
+ case HOUSE_NUMBER:
+ if (WTF::isASCIIDigit(ch)) {
+ if (++s->mNumberCount >= 6)
+ s->mProgress = SKIP_TO_SPACE;
+ continue;
+ }
+ if (WTF::isASCIIUpper(ch)) { // allow one letter after house number, e.g. 12A SKOLFIELD PL, HARPSWELL, ME 04079
+ if (WTF::isASCIIDigit(prior) == false)
+ s->mProgress = SKIP_TO_SPACE;
+ continue;
+ }
+ if (ch == '-') {
+ if (s->mNumberCount > 0) { // permit 21-23 ELM ST
+ ++s->mNumberCount;
+ continue;
+ }
+ }
+ s->mNumberCount = 0;
+ s->mProgress = NUMBER_TRAILING_SPACE;
+ case NUMBER_TRAILING_SPACE:
+ if (isUnicodeSpace(ch))
+ continue;
+ if (0 && WTF::isASCIIDigit(ch)) {
+ s->mNumberCount = 1;
+ s->mProgress = HOUSE_NUMBER;
+ s->mStartResult = chars - s->mCurrentStart;
+ continue;
+ }
+ if (WTF::isASCIIDigit(ch) == false && WTF::isASCIIUpper(ch) == false)
+ break;
+ s->mProgress = ADDRESS_LINE;
+ case ADDRESS_LINE:
+ if (WTF::isASCIIAlpha(ch) || ch == '\'' || ch == '-' || ch == '&' || ch == '(' || ch == ')') {
+ if (++s->mLetterCount > 1) {
+ s->mNumberWords &= ~(1 << s->mWordCount);
+ continue;
+ }
+ if (s->mNumberCount >= 5)
+ break;
+// FIXME: the test below was added to give up on a non-address, but it
+// incorrectly discards addresses where the house number is in one node
+// and the street name is in the next; I don't recall what the failing case
+// is that suggested this fix.
+// if (s->mWordCount == 0 && s->mContinuationNode)
+// return FOUND_NONE;
+ s->mBases[s->mWordCount] = baseChars;
+ s->mWords[s->mWordCount] = chars - s->mNumberCount;
+ s->mStarts[s->mWordCount] = s->mCurrentStart;
+ if (WTF::isASCIILower(ch) && s->mNumberCount == 0)
+ s->mFirstLower = chars;
+ s->mNumberCount = 0;
+ if (WTF::isASCIILower(ch) || (WTF::isASCIIAlpha(ch) == false && ch != '-'))
+ s->mNumberWords &= ~(1 << s->mWordCount);
+ s->mUnparsed = true;
+ continue;
+ } else if (s->mFirstLower != NULL) {
+ size_t length = chars - s->mFirstLower;
+ if (length > 3)
+ break;
+ if (length == 3 && strCharCmp("and" "the", s->mFirstLower, 3, 2) == false)
+ break;
+ if (length == 2 && strCharCmp("at" "by" "el" "in" "of", s->mFirstLower, 2, 5) == false)
+ break;
+ goto resetWord;
+ }
+ if (ch == ',' || ch == '*') { // delimits lines
+ // asterisk as delimiter: http://www.sa.sc.edu/wellness/members.html
+ if (++s->mLineCount > 5)
+ break;
+ goto lookForState;
+ }
+ if (isUnicodeSpace(ch) || prior == '-') {
+ lookForState:
+ if (s->mUnparsed == false)
+ continue;
+ const UChar* candidate = s->mWords[s->mWordCount];
+ UChar firstLetter = candidate[0];
+ if (WTF::isASCIIUpper(firstLetter) == false && WTF::isASCIIDigit(firstLetter) == false)
+ goto resetWord;
+ s->mWordCount++;
+ if ((s->mWordCount == 2 && s->mNumberWords == 3 && WTF::isASCIIDigit(s->mWords[1][1])) || // choose second of 8888 333 Main
+ (s->mWordCount >= sizeof(s->mWords) / sizeof(s->mWords[0]) - 1)) { // subtract 1 since state names may have two parts
+ // search for simple number already stored since first potential house # didn't pan out
+ if (s->mNumberWords == 0)
+ break;
+ int shift = 0;
+ while ((s->mNumberWords & (1 << shift)) == 0)
+ shift++;
+ s->mNumberWords >>= ++shift;
+ if (s->mBases[0] != s->mBases[shift]) // if we're past the original node, bail
+ break;
+ memmove(s->mBases, &s->mBases[shift], (sizeof(s->mBases) / sizeof(s->mBases[0]) - shift) * sizeof(s->mBases[0]));
+ memmove(s->mWords, &s->mWords[shift], (sizeof(s->mWords) / sizeof(s->mWords[0]) - shift) * sizeof(s->mWords[0]));
+ memmove(s->mStarts, &s->mStarts[shift], (sizeof(s->mStarts) / sizeof(s->mStarts[0]) - shift) * sizeof(s->mStarts[0]));
+ s->mStartResult = s->mWords[0] - s->mStarts[0];
+ s->mWordCount -= shift;
+ // FIXME: need to adjust lineCount to account for discarded delimiters
+ }
+ if (s->mWordCount < 4)
+ goto resetWord;
+ firstLetter -= 'A';
+ if (firstLetter > 'W' - 'A')
+ goto resetWord;
+ UChar secondLetter = candidate[1];
+ if (prior == '-')
+ s->mLetterCount--; // trim trailing dashes, to accept CA-94043
+ if (s->mLetterCount == 2) {
+ secondLetter -= 'A';
+ if (secondLetter > 'Z' - 'A')
+ goto resetWord;
+ if ((stateTwoLetter[firstLetter] & 1 << secondLetter) != 0) {
+ // special case to ignore 'et al'
+ if (strCharCmp("ET", s->mWords[s->mWordCount - 2], 2, 1) == false) {
+ s->mStateWord = s->mWordCount - 1;
+ s->mZipHint = firstIndex[firstLetter] +
+ bitcount(stateTwoLetter[firstLetter] & ((1 << secondLetter) - 1));
+ goto foundStateName;
+ }
+ }
+ goto resetWord;
+ }
+ s->mStates = longStateNames[firstLetter];
+ if (s->mStates == NULL)
+ goto resetWord;
+ mustBeAllUpper = false;
+ s->mProgress = STATE_NAME;
+ unsigned char section = s->mStates[0];
+ ASSERT(section > 0x80);
+ s->mSectionLength = section & 0x7f;
+ candIndex = 1;
+ secondHalf = false;
+ s->mStateWord = s->mWordCount - 1;
+ goto stateName;
+ }
+ if (WTF::isASCIIDigit(ch)) {
+ if (s->mLetterCount == 0) {
+ if (++s->mNumberCount > 1)
+ continue;
+ if (s->mWordCount == 0 && s->mContinuationNode)
+ return FOUND_NONE;
+ s->mBases[s->mWordCount] = baseChars;
+ s->mWords[s->mWordCount] = chars;
+ s->mStarts[s->mWordCount] = s->mCurrentStart;
+ s->mNumberWords |= 1 << s->mWordCount;
+ s->mUnparsed = true;
+ }
+ continue;
+ }
+ if (ch == '.') { // optionally can follow letters
+ if (s->mLetterCount == 0)
+ break;
+ if (s->mNumberCount > 0)
+ break;
+ continue;
+ }
+ if (ch == '/') // between numbers (1/2) between words (12 Main / Ste 4d)
+ goto resetWord;
+ if (ch == '#') // can precede numbers, allow it to appear randomly
+ goto resetWord;
+ if (ch == '"') // sometimes parts of addresses are quoted (FIXME: cite an example here)
+ continue;
+ break;
+ case SECOND_HALF:
+ if (WTF::isASCIIAlpha(ch)) {
+ if (s->mLetterCount == 0) {
+ s->mBases[s->mWordCount] = baseChars;
+ s->mWords[s->mWordCount] = chars;
+ s->mStarts[s->mWordCount] = s->mCurrentStart;
+ s->mWordCount++;
+ }
+ s->mLetterCount++;
+ continue;
+ }
+ if (WTF::isASCIIDigit(ch) == false) {
+ if (s->mLetterCount > 0) {
+ s->mProgress = STATE_NAME;
+ candIndex = 0;
+ secondHalf = true;
+ goto stateName;
+ }
+ continue;
+ }
+ s->mProgress = ADDRESS_LINE;
+ goto resetState;
+ case STATE_NAME:
+ stateName:
+ // pick up length of first section
+ do {
+ int stateIndex = 1;
+ int skip = 0;
+ int prefix = 0;
+ bool subStr = false;
+ do {
+ unsigned char match = s->mStates[stateIndex];
+ if (match >= 0x80) {
+ if (stateIndex == s->mSectionLength)
+ break;
+ subStr = true;
+ // if (skip > 0)
+ // goto foundStateName;
+ prefix = candIndex;
+ skip = match & 0x7f;
+ match = s->mStates[++stateIndex];
+ }
+ UChar candChar = s->mWords[s->mWordCount - 1][candIndex];
+ if (mustBeAllUpper && WTF::isASCIILower(candChar))
+ goto skipToNext;
+ if (match != candChar) {
+ if (match != WTF::toASCIILower(candChar)) {
+ skipToNext:
+ if (subStr == false)
+ break;
+ if (stateIndex == s->mSectionLength) {
+ if (secondHalf) {
+ s->mProgress = ADDRESS_LINE;
+ goto resetState;
+ }
+ break;
+ }
+ stateIndex += skip;
+ skip = 0;
+ candIndex = prefix;
+ continue; // try next substring
+ }
+ mustBeAllUpper = true;
+ }
+ int nextindex = stateIndex + 1;
+ if (++candIndex >= s->mLetterCount && s->mStates[nextindex] == ' ') {
+ s->mProgress = SECOND_HALF;
+ s->mStates += nextindex;
+ s->mSectionLength -= nextindex;
+ goto resetWord;
+ }
+ if (nextindex + 1 == s->mSectionLength || skip == 2) {
+ s->mZipHint = s->mStates[nextindex] - 1;
+ goto foundStateName;
+ }
+ stateIndex += 1;
+ skip -= 1;
+ } while (true);
+ s->mStates += s->mSectionLength;
+ ASSERT(s->mStates[0] == 0 || (unsigned) s->mStates[0] > 0x80);
+ s->mSectionLength = s->mStates[0] & 0x7f;
+ candIndex = 1;
+ subStr = false;
+ } while (s->mSectionLength != 0);
+ s->mProgress = ADDRESS_LINE;
+ goto resetState;
+ foundStateName:
+ s->mEndResult = chars - s->mCurrentStart;
+ s->mEndWord = s->mWordCount - 1;
+ s->mProgress = ZIP_CODE;
+ // a couple of delimiters is an indication that the state name is good
+ // or, a non-space / non-alpha-digit is also good
+ s->mZipDelimiter = s->mLineCount > 2 || isUnicodeSpace(ch) == false;
+ if (WTF::isASCIIDigit(ch))
+ s->mZipStart = chars;
+ goto resetState;
+ case ZIP_CODE:
+ if (WTF::isASCIIDigit(ch)) {
+ int count = ++s->mNumberCount;
+ if (count == 1) {
+ if (WTF::isASCIIDigit(prior))
+ ++s->mNumberCount;
+ else
+ s->mZipStart = chars;
+ }
+ if (count <= 9)
+ continue;
+ } else if (isUnicodeSpace(ch)) {
+ if (s->mNumberCount == 0) {
+ s->mZipDelimiter = true; // two spaces delimit state name
+ continue;
+ }
+ } else if (ch == '-') {
+ if (s->mNumberCount == 5 && validZip(s->mZipHint, s->mZipStart)) {
+ s->mNumberCount = 0;
+ s->mProgress = PLUS_4;
+ continue;
+ }
+ if (s->mNumberCount == 0)
+ s->mZipDelimiter = true;
+ } else if (WTF::isASCIIAlpha(ch) == false)
+ s->mZipDelimiter = true;
+ if (s->mNumberCount == 5 || s->mNumberCount == 9) {
+ if (validZip(s->mZipHint, s->mZipStart) == false)
+ goto noZipMatch;
+ s->mEndResult = chars - s->mCurrentStart;
+ s->mEndWord = s->mWordCount - 1;
+ } else if (s->mZipDelimiter == false) {
+ noZipMatch:
+ --chars;
+ s->mProgress = ADDRESS_LINE;
+ continue;
+ }
+ s->mProgress = FIND_STREET;
+ goto findStreet;
+ case PLUS_4:
+ if (WTF::isASCIIDigit(ch)) {
+ if (++s->mNumberCount <= 4)
+ continue;
+ }
+ if (isUnicodeSpace(ch)) {
+ if (s->mNumberCount == 0)
+ continue;
+ }
+ if (s->mNumberCount == 4) {
+ if (WTF::isASCIIAlpha(ch) == false) {
+ s->mEndResult = chars - s->mCurrentStart;
+ s->mEndWord = s->mWordCount - 1;
+ }
+ } else if (s->mNumberCount != 0)
+ break;
+ s->mProgress = FIND_STREET;
+ case FIND_STREET:
+ findStreet: // minus two below skips city before state
+ for (int wordsIndex = s->mStateWord - 2; wordsIndex >= 0; --wordsIndex) {
+ const UChar* test = s->mWords[wordsIndex];
+ UChar letter = test[0];
+ letter -= 'A';
+ if (letter > 'X' - 'A')
+ continue;
+ const char* names = longStreetNames[letter];
+ if (names == NULL)
+ continue;
+ int offset;
+ while ((offset = *names++) != 0) {
+ int testIndex = 1;
+ bool abbr = false;
+ for (int idx = 0; idx < offset; idx++) {
+ char nameLetter = names[idx];
+ char testUpper = WTF::toASCIIUpper(test[testIndex]);
+ if (nameLetter == '*') {
+ if (testUpper == 'S')
+ testIndex++;
+ break;
+ }
+ bool fullOnly = WTF::isASCIILower(nameLetter);
+ nameLetter = WTF::toASCIIUpper(nameLetter);
+ if (testUpper == nameLetter) {
+ if (abbr && fullOnly)
+ goto nextTest;
+ testIndex++;
+ continue;
+ }
+ if (fullOnly == false)
+ goto nextTest;
+ abbr = true;
+ }
+ letter = test[testIndex];
+ if (WTF::isASCIIAlpha(letter) == false && WTF::isASCIIDigit(letter) == false) {
+ if (s->mNumberWords != 0) {
+ int shift = 0;
+ int wordReduction = -1;
+ do {
+ while ((s->mNumberWords & (1 << shift)) == 0)
+ shift++;
+ if (shift > wordsIndex)
+ break;
+ wordReduction = shift;
+ } while (s->mNumberWords >> ++shift != 0);
+ if (wordReduction >= 0) {
+ if (s->mContinuationNode)
+ return FOUND_NONE;
+ s->mStartResult = s->mWords[wordReduction] - s->mStarts[wordReduction];
+ }
+ }
+ return FOUND_COMPLETE;
+ }
+ nextTest:
+ names += offset;
+ }
+ }
+ if (s->mNumberWords != 0) {
+ unsigned shift = 0;
+ while ((s->mNumberWords & (1 << shift)) == 0)
+ shift++;
+ s->mNumberWords >>= ++shift;
+ if (s->mBases[0] != s->mBases[shift])
+ return FOUND_NONE;
+ memmove(s->mBases, &s->mBases[shift], (sizeof(s->mBases) / sizeof(s->mBases[0]) - shift) * sizeof(s->mBases[0]));
+ memmove(s->mWords, &s->mWords[shift], (sizeof(s->mWords) / sizeof(s->mWords[0]) - shift) * sizeof(s->mWords[0]));
+ memmove(s->mStarts, &s->mStarts[shift], (sizeof(s->mStarts) / sizeof(s->mStarts[0]) - shift) * sizeof(s->mStarts[0]));
+ s->mStartResult = s->mWords[0] - s->mStarts[0];
+ s->mWordCount -= shift;
+ s->mProgress = ADDRESS_LINE;
+ --chars;
+ continue;
+ }
+ break;
+ }
+ if (s->mContinuationNode)
+ return FOUND_NONE;
+ s->mProgress = NO_ADDRESS;
+ s->mWordCount = s->mLineCount = 0;
+ s->mNumberWords = 0;
+ resetState:
+ s->mStates = NULL;
+ resetWord:
+ s->mNumberCount = s->mLetterCount = 0;
+ s->mFirstLower = NULL;
+ s->mUnparsed = false;
+ }
+ s->mCurrent = ch;
+ return s->mProgress == NO_ADDRESS ? FOUND_NONE : FOUND_PARTIAL;
+}
+
+// Recogize common email patterns only. Currently has lots of state, walks text forwards and backwards -- will be
+// a real challenge to adapt to walk text across multiple nodes, I imagine
+// FIXME: it's too hard for the caller to call these incrementally -- it's probably best for this to
+// either walk the node tree directly or make a callout to get the next or previous node, if there is one
+// walking directly will avoid adding logic in caller to track the multiple partial or full nodes that compose this
+// text pattern.
+CacheBuilder::FoundState CacheBuilder::FindPartialEMail(const UChar* chars, unsigned length,
+ FindState* s)
+{
+ // the following tables were generated by tests/browser/focusNavigation/BrowserDebug.cpp
+ // hand-edit at your own risk
+ static const int domainTwoLetter[] = {
+ 0x02df797c, // a followed by: [cdefgilmnoqrstuwxz]
+ 0x036e73fb, // b followed by: [abdefghijmnorstvwyz]
+ 0x03b67ded, // c followed by: [acdfghiklmnorsuvxyz]
+ 0x02005610, // d followed by: [ejkmoz]
+ 0x001e00d4, // e followed by: [ceghrstu]
+ 0x00025700, // f followed by: [ijkmor]
+ 0x015fb9fb, // g followed by: [abdefghilmnpqrstuwy]
+ 0x001a3400, // h followed by: [kmnrtu]
+ 0x000f7818, // i followed by: [delmnoqrst]
+ 0x0000d010, // j followed by: [emop]
+ 0x0342b1d0, // k followed by: [eghimnprwyz]
+ 0x013e0507, // l followed by: [abcikrstuvy]
+ 0x03fffccd, // m followed by: [acdghklmnopqrstuvwxyz]
+ 0x0212c975, // n followed by: [acefgilopruz]
+ 0x00001000, // o followed by: [m]
+ 0x014e3cf1, // p followed by: [aefghklmnrstwy]
+ 0x00000001, // q followed by: [a]
+ 0x00504010, // r followed by: [eouw]
+ 0x032a7fdf, // s followed by: [abcdeghijklmnortvyz]
+ 0x026afeec, // t followed by: [cdfghjklmnoprtvwz]
+ 0x03041441, // u followed by: [agkmsyz]
+ 0x00102155, // v followed by: [aceginu]
+ 0x00040020, // w followed by: [fs]
+ 0x00000000, // x
+ 0x00180010, // y followed by: [etu]
+ 0x00401001, // z followed by: [amw]
+ };
+
+ static char const* const longDomainNames[] = {
+ "\x03" "ero" "\x03" "rpa", // aero, arpa
+ "\x02" "iz", // biz
+ "\x02" "at" "\x02" "om" "\x03" "oop", // cat, com, coop
+ NULL, // d
+ "\x02" "du", // edu
+ NULL, // f
+ "\x02" "ov", // gov
+ NULL, // h
+ "\x03" "nfo" "\x02" "nt", // info, int
+ "\x03" "obs", // jobs
+ NULL, // k
+ NULL, // l
+ "\x02" "il" "\x03" "obi" "\x05" "useum", // mil, mobi, museum
+ "\x03" "ame" "\x02" "et", // name, net
+ "\x02" "rg", // , org
+ "\x02" "ro", // pro
+ NULL, // q
+ NULL, // r
+ NULL, // s
+ "\x05" "ravel", // travel
+ NULL, // u
+ NULL, // v
+ NULL, // w
+ NULL, // x
+ NULL, // y
+ NULL, // z
+ };
+
+ const UChar* start = chars;
+ const UChar* end = chars + length;
+ while (chars < end) {
+ UChar ch = *chars++;
+ if (ch != '@')
+ continue;
+ const UChar* atLocation = chars - 1;
+ // search for domain
+ ch = *chars++ | 0x20; // convert uppercase to lower
+ if (ch < 'a' || ch > 'z')
+ continue;
+ while (chars < end) {
+ ch = *chars++;
+ if (IsDomainChar(ch) == false)
+ goto nextAt;
+ if (ch != '.')
+ continue;
+ UChar firstLetter = *chars++ | 0x20; // first letter of the domain
+ if (chars >= end)
+ return FOUND_NONE; // only one letter; must be at least two
+ firstLetter -= 'a';
+ if (firstLetter > 'z' - 'a')
+ continue; // non-letter followed '.'
+ int secondLetterMask = domainTwoLetter[firstLetter];
+ ch = *chars | 0x20; // second letter of the domain
+ ch -= 'a';
+ if (ch >= 'z' - 'a')
+ continue;
+ bool secondMatch = (secondLetterMask & 1 << ch) != 0;
+ const char* wordMatch = longDomainNames[firstLetter];
+ int wordIndex = 0;
+ while (wordMatch != NULL) {
+ int len = *wordMatch++;
+ char match;
+ do {
+ match = wordMatch[wordIndex];
+ if (match < 0x20)
+ goto foundDomainStart;
+ if (chars[wordIndex] != match)
+ break;
+ wordIndex++;
+ } while (true);
+ wordMatch += len;
+ if (*wordMatch == '\0')
+ break;
+ wordIndex = 0;
+ }
+ if (secondMatch) {
+ wordIndex = 1;
+ foundDomainStart:
+ chars += wordIndex;
+ if (chars < end) {
+ ch = *chars;
+ if (ch != '.') {
+ if (IsDomainChar(ch))
+ goto nextDot;
+ } else if (chars + 1 < end && IsDomainChar(chars[1]))
+ goto nextDot;
+ }
+ // found domain. Search backwards from '@' for beginning of email address
+ s->mEndResult = chars - start;
+ chars = atLocation;
+ if (chars <= start)
+ goto nextAt;
+ ch = *--chars;
+ if (ch == '.')
+ goto nextAt; // mailbox can't end in period
+ do {
+ if (IsMailboxChar(ch) == false) {
+ chars++;
+ break;
+ }
+ if (chars == start)
+ break;
+ ch = *--chars;
+ } while (true);
+ UChar firstChar = *chars;
+ if (firstChar == '.' || firstChar == '@') // mailbox can't start with period or be empty
+ goto nextAt;
+ s->mStartResult = chars - start;
+ return FOUND_COMPLETE;
+ }
+ nextDot:
+ ;
+ }
+nextAt:
+ chars = atLocation + 1;
+ }
+ return FOUND_NONE;
+}
+
+#define PHONE_PATTERN "(200) /-.\\ 100 -. 0000" // poor man's regex: parens optional, any one of punct, digit smallest allowed
+
+CacheBuilder::FoundState CacheBuilder::FindPartialNumber(const UChar* chars, unsigned length,
+ FindState* s)
+{
+ char* pattern = s->mPattern;
+ UChar* store = s->mStorePtr;
+ const UChar* start = chars;
+ const UChar* end = chars + length;
+ const UChar* lastDigit = NULL;
+ do {
+ bool initialized = s->mInitialized;
+ while (chars < end) {
+ if (initialized == false) {
+ s->mBackTwo = s->mBackOne;
+ s->mBackOne = s->mCurrent;
+ }
+ UChar ch = s->mCurrent = *chars;
+ do {
+ char patternChar = *pattern;
+ switch (patternChar) {
+ case '2':
+ if (initialized == false) {
+ s->mStartResult = chars - start;
+ initialized = true;
+ }
+ case '0':
+ case '1':
+ if (ch < patternChar || ch > '9')
+ goto resetPattern;
+ *store++ = ch;
+ pattern++;
+ lastDigit = chars;
+ goto nextChar;
+ case '\0':
+ if (WTF::isASCIIDigit(ch) == false) {
+ *store = '\0';
+ goto checkMatch;
+ }
+ goto resetPattern;
+ case ' ':
+ if (ch == patternChar)
+ goto nextChar;
+ break;
+ case '(':
+ if (ch == patternChar) {
+ s->mStartResult = chars - start;
+ initialized = true;
+ s->mOpenParen = true;
+ }
+ goto commonPunctuation;
+ case ')':
+ if ((ch == patternChar) ^ s->mOpenParen)
+ goto resetPattern;
+ default:
+ commonPunctuation:
+ if (ch == patternChar) {
+ pattern++;
+ goto nextChar;
+ }
+ }
+ } while (++pattern); // never false
+ nextChar:
+ chars++;
+ }
+ break;
+resetPattern:
+ if (s->mContinuationNode)
+ return FOUND_NONE;
+ FindResetNumber(s);
+ pattern = s->mPattern;
+ store = s->mStorePtr;
+ } while (++chars < end);
+checkMatch:
+ if (WTF::isASCIIDigit(s->mBackOne != '1' ? s->mBackOne : s->mBackTwo))
+ return FOUND_NONE;
+ *store = '\0';
+ s->mStorePtr = store;
+ s->mPattern = pattern;
+ s->mEndResult = lastDigit - start + 1;
+ char pState = pattern[0];
+ return pState == '\0' ? FOUND_COMPLETE : pState == '(' || (WTF::isASCIIDigit(pState) && WTF::isASCIIDigit(pattern[-1])) ?
+ FOUND_NONE : FOUND_PARTIAL;
+}
+
+CacheBuilder::FoundState CacheBuilder::FindPhoneNumber(const UChar* chars, unsigned length,
+ int* start, int* end)
+{
+ FindState state;
+ FindReset(&state);
+ FoundState result = FindPartialNumber(chars, length, &state);
+ *start = state.mStartResult;
+ *end = state.mEndResult;
+ return result;
+}
+
+void CacheBuilder::FindReset(FindState* state)
+{
+ memset(state, 0, sizeof(FindState));
+ state->mCurrent = ' ';
+ FindResetNumber(state);
+}
+
+void CacheBuilder::FindResetNumber(FindState* state)
+{
+ state->mOpenParen = false;
+ state->mPattern = (char*) PHONE_PATTERN;
+ state->mStorePtr = state->mStore;
+}
+
+void CacheBuilder::GetGlobalOffset(Node* node, int* x, int * y)
+{
+ GetGlobalOffset(node->document()->frame(), x, y);
+}
+
+void CacheBuilder::GetGlobalOffset(Frame* frame, int* x, int* y)
+{
+// TIMER_PROBE(__FUNCTION__);
+ ASSERT(x);
+ ASSERT(y);
+ *x = 0;
+ *y = 0;
+ if (!frame->view())
+ return;
+ WebCoreViewBridge* bridge = frame->view()->getWebCoreViewBridge();
+ if (bridge == NULL)
+ return;
+ WebCoreViewBridge* parent;
+ while ((parent = bridge->getParent()) != NULL) {
+ const WebCore::IntRect& rect = bridge->getBounds();
+ *x += rect.x();
+ *y += rect.y();
+ bridge = parent;
+ }
+ // TIMER_PROBE_END();
+}
+
+Frame* CacheBuilder::HasFrame(Node* node)
+{
+ RenderObject* renderer = node->renderer();
+ if (renderer == NULL)
+ return NULL;
+ if (renderer->isWidget() == false)
+ return NULL;
+ Widget* widget = static_cast<RenderWidget*>(renderer)->widget();
+ if (widget == NULL)
+ return NULL;
+ if (widget->isFrameView() == false)
+ return NULL;
+ return static_cast<FrameView*>(widget)->frame();
+}
+
+bool CacheBuilder::HasOverOrOut(Node* node)
+{
+ EventTargetNode* target = (EventTargetNode*) node;
+ return target->getEventListener(EventNames::mouseoverEvent) ||
+ target->getEventListener(EventNames::mouseoutEvent);
+
+}
+
+bool CacheBuilder::HasTriggerEvent(Node* node)
+{
+ EventTargetNode* target = (EventTargetNode*) node;
+ return target->getEventListener(EventNames::clickEvent) ||
+ target->getEventListener(EventNames::mousedownEvent) ||
+ target->getEventListener(EventNames::mouseupEvent) ||
+ target->getEventListener(EventNames::keydownEvent) ||
+ target->getEventListener(EventNames::keyupEvent);
+}
+
+// #define EMAIL_PATTERN "x@y.d" // where 'x' is letters, numbers, and '-', '.', '_' ; 'y' is 'x' without the underscore, and 'd' is a valid domain
+// - 0x2D . 0x2E 0-9 0x30-39 A-Z 0x41-5A _ 0x5F a-z 0x61-7A
+
+bool CacheBuilder::IsDomainChar(UChar ch)
+{
+ static const unsigned body[] = {0x03ff6000, 0x07fffffe, 0x07fffffe}; // 0-9 . - A-Z a-z
+ ch -= 0x20;
+ if (ch > 'z' - 0x20)
+ return false;
+ return (body[ch >> 5] & 1 << (ch & 0x1f)) != 0;
+}
+
+// does not find text to keep it fast
+// (this assume text nodes are more rarely moved than other nodes)
+Node* CacheBuilder::findByCenter(int x, int y) const
+{
+ DBG_NAV_LOGD("x=%d y=%d\n", x, y);
+ Frame* frame = FrameAnd(this);
+ Node* node = frame->document();
+ ASSERT(node != NULL);
+ int globalOffsetX, globalOffsetY;
+ GetGlobalOffset(frame, &globalOffsetX, &globalOffsetY);
+ while ((node = node->traverseNextNode()) != NULL) {
+ Frame* child = HasFrame(node);
+ if (child != NULL) {
+ if (child->document() == NULL)
+ continue;
+ CacheBuilder* cacheBuilder = Builder(child);
+ // if (cacheBuilder->mViewBounds.isEmpty())
+ // continue;
+ Node* result = cacheBuilder->findByCenter(x, y);
+ if (result != NULL)
+ return result;
+ }
+ if (node->isTextNode())
+ continue;
+ IntRect bounds;
+ if (node->hasTagName(HTMLNames::areaTag)) {
+ HTMLAreaElement* area = static_cast<HTMLAreaElement*>(node);
+ bounds = area->getAreaRect();
+ bounds.move(globalOffsetX, globalOffsetY);
+ } else
+ bounds = node->getRect();
+ if (bounds.isEmpty())
+ continue;
+ bounds.move(globalOffsetX, globalOffsetY);
+ if (x != bounds.x() + (bounds.width() >> 1))
+ continue;
+ if (y != bounds.y() + (bounds.height() >> 1))
+ continue;
+ if (node->isKeyboardFocusable(NULL))
+ return node;
+ if (node->isMouseFocusable())
+ return node;
+ if (node->isFocusable())
+ return node;
+ if (node->isEventTargetNode() == false)
+ continue;
+ if (AnyIsClick(node))
+ continue;
+ if (HasTriggerEvent(node) == false)
+ continue;
+ return node;
+ }
+ return NULL;
+}
+
+bool CacheBuilder::isFocusableText(NodeWalk* walk, bool more, Node* node,
+ android::CachedNodeType* type, String* exported) const
+{
+ Text* textNode = static_cast<Text*>(node);
+ StringImpl* string = textNode->string();
+ const UChar* baseChars = string->characters();
+// const UChar* originalBase = baseChars;
+ int length = string->length();
+ int index = 0;
+ while (index < length && isUnicodeSpace(baseChars[index]))
+ index++;
+ if (index >= length)
+ return false;
+ if (more == false) {
+ walk->mStart = 0;
+ walk->mEnd = 0;
+ walk->mFinalNode = node;
+ walk->mLastInline = NULL;
+ }
+ // starting with this node, search forward for email, phone number, and address
+ // if any of the three is found, track it so that the remaining can be looked for later
+ FoundState state = FOUND_NONE;
+ RenderText* renderer = (RenderText*) node->renderer();
+ bool foundBetter = false;
+ InlineTextBox* baseInline = walk->mLastInline != NULL ? walk->mLastInline :
+ renderer->firstTextBox();
+ if (baseInline == NULL)
+ return false;
+ int start = walk->mEnd;
+ InlineTextBox* saveInline;
+ int baseStart, firstStart = start;
+ saveInline = baseInline;
+ baseStart = start;
+ for (android::CachedNodeType checkType = android::ADDRESS_CACHEDNODETYPE;
+ checkType <= android::PHONE_CACHEDNODETYPE;
+ checkType = (android::CachedNodeType) (checkType << 1))
+ {
+ if ((checkType & mAllowableTypes) == 0)
+ continue;
+ InlineTextBox* inlineTextBox = baseInline;
+ FindState findState;
+ FindReset(&findState);
+ start = baseStart;
+ if (checkType == android::ADDRESS_CACHEDNODETYPE) {
+ findState.mBases[0] = baseChars;
+ findState.mWords[0] = baseChars + start;
+ findState.mStarts[0] = baseChars + start;
+ }
+ Node* lastPartialNode = NULL;
+ int lastPartialEnd = -1;
+ bool lastPartialMore = false;
+ bool firstPartial = true;
+ InlineTextBox* lastPartialInline = NULL;
+ do {
+ do {
+ const UChar* chars = baseChars + start;
+ length = inlineTextBox == NULL ? 0 :
+ inlineTextBox->end() - start + 1;
+ bool wasInitialized = findState.mInitialized;
+ switch (checkType) {
+ case android::ADDRESS_CACHEDNODETYPE:
+ state = FindPartialAddress(baseChars, chars, length, &findState);
+ break;
+ case android::EMAIL_CACHEDNODETYPE:
+ state = FindPartialEMail(chars, length, &findState);
+ break;
+ case android::PHONE_CACHEDNODETYPE:
+ state = FindPartialNumber(chars, length, &findState);
+ break;
+ default:
+ ASSERT(0);
+ }
+ findState.mInitialized = state != FOUND_NONE;
+ if (wasInitialized != findState.mInitialized)
+ firstStart = start;
+ if (state == FOUND_PARTIAL) {
+ lastPartialNode = node;
+ lastPartialEnd = findState.mEndResult + start;
+ lastPartialMore = firstPartial &&
+ lastPartialEnd < (int) string->length();
+ firstPartial = false;
+ lastPartialInline = inlineTextBox;
+ findState.mContinuationNode = true;
+ } else if (state == FOUND_COMPLETE) {
+ if (foundBetter == false || walk->mStart > findState.mStartResult) {
+ walk->mStart = findState.mStartResult + firstStart;
+ if (findState.mEndResult > 0) {
+ walk->mFinalNode = node;
+ walk->mEnd = findState.mEndResult + start;
+ walk->mMore = walk->mEnd < (int) string->length();
+ walk->mLastInline = inlineTextBox;
+ } else {
+ walk->mFinalNode = lastPartialNode;
+ walk->mEnd = lastPartialEnd;
+ walk->mMore = lastPartialMore;
+ walk->mLastInline = lastPartialInline;
+ }
+ *type = checkType;
+ if (checkType == android::PHONE_CACHEDNODETYPE) {
+ const UChar* store = findState.mStore;
+ *exported = String(store);
+ } else {
+ Node* temp = textNode;
+ length = 1;
+ start = walk->mStart;
+ exported->truncate(0);
+ do {
+ Text* tempText = static_cast<Text*>(temp);
+ StringImpl* string = tempText->string();
+ int end = tempText == walk->mFinalNode ?
+ walk->mEnd : string->length();
+ exported->append(String(string->substring(
+ start, end - start)));
+ ASSERT(end > start);
+ length += end - start + 1;
+ if (temp == walk->mFinalNode)
+ break;
+ start = 0;
+ do {
+ temp = temp->traverseNextNode();
+ ASSERT(temp);
+ } while (temp->isTextNode() == false);
+ // add a space in between text nodes to avoid
+ // words collapsing together
+ exported->append(" ");
+ } while (true);
+ }
+ foundBetter = true;
+ }
+ goto tryNextCheckType;
+ } else if (findState.mContinuationNode)
+ break;
+ if (inlineTextBox == NULL)
+ break;
+ inlineTextBox = inlineTextBox->nextTextBox();
+ if (inlineTextBox == NULL)
+ break;
+ start = inlineTextBox->start();
+ } while (true);
+ if (state == FOUND_NONE)
+ break;
+ // search for next text node, if any
+ Text* nextNode;
+ do {
+ do {
+ do {
+ node = node->traverseNextNode();
+ if (node == NULL || node->hasTagName(HTMLNames::aTag)) {
+ if (state == FOUND_PARTIAL &&
+ checkType == android::ADDRESS_CACHEDNODETYPE &&
+ findState.mProgress == ZIP_CODE &&
+ findState.mNumberCount == 0) {
+ baseChars = NULL;
+ inlineTextBox = NULL;
+ start = 0;
+ findState.mProgress = FIND_STREET;
+ goto finalNode;
+ }
+ goto tryNextCheckType;
+ }
+ } while (node->isTextNode() == false);
+ nextNode = static_cast<Text*>(node);
+ renderer = (RenderText*) nextNode->renderer();
+ } while (renderer == NULL);
+ baseInline = renderer->firstTextBox();
+ } while (baseInline == NULL);
+ string = nextNode->string();
+ baseChars = string->characters();
+ inlineTextBox = baseInline;
+ start = inlineTextBox->start();
+ finalNode:
+ findState.mEndResult = 0;
+ } while (true);
+tryNextCheckType:
+ node = textNode;
+ baseInline = saveInline;
+ string = textNode->string();
+ baseChars = string->characters();
+ }
+ if (foundBetter) {
+ android::CachedNodeType temp = *type;
+ switch (temp) {
+ case android::ADDRESS_CACHEDNODETYPE: {
+ static const char geoString[] = "geo:0,0?q=";
+ exported->insert(String(geoString), 0);
+ int index = sizeof(geoString) - 1;
+ String escapedComma("%2C");
+ while ((index = exported->find(',', index)) >= 0)
+ exported->replace(index, 1, escapedComma);
+ } break;
+ case android::EMAIL_CACHEDNODETYPE:
+ exported->insert(WebCore::String("mailto:"), 0);
+ break;
+ case android::PHONE_CACHEDNODETYPE:
+ exported->insert(WebCore::String("tel:"), 0);
+ break;
+ default:
+ break;
+ }
+ return true;
+ }
+noTextMatch:
+ walk->reset();
+ return false;
+}
+
+bool CacheBuilder::IsMailboxChar(UChar ch)
+{
+ static const unsigned body[] = {0x03ff6000, 0x87fffffe, 0x07fffffe}; // 0-9 . - A-Z _ a-z
+ ch -= 0x20;
+ if (ch > 'z' - 0x20)
+ return false;
+ return (body[ch >> 5] & 1 << (ch & 0x1f)) != 0;
+}
+
+bool CacheBuilder::outOfDate()
+{
+ Node* kitFocusNode = currentFocus();
+ if (mLastKnownFocus != kitFocusNode) {
+ DBG_NAV_LOGD("%s\n", "mLastKnownFocus != kitFocusNode");
+ return true;
+ }
+ if (kitFocusNode == NULL)
+ return false;
+ IntRect kitBounds = kitFocusNode->getRect();
+ bool result = kitBounds != mLastKnownFocusBounds;
+ if (result == true)
+ DBG_NAV_LOGD("%s\n", "kitBounds != mLastKnownFocusBounds");
+ return result;
+}
+
+void CacheBuilder::setLastFocus(Node* node)
+{
+ ASSERT(node);
+ mLastKnownFocus = node;
+ mLastKnownFocusBounds = node->getRect();
+}
+
+bool CacheBuilder::setData(android::CachedFrame* cachedFrame)
+{
+ FrameAndroid* frameAndroid = FrameAnd(this);
+ Document* doc = frameAndroid->document();
+ if (doc == NULL)
+ return false;
+ RenderObject* renderer = doc->renderer();
+ if (renderer == NULL)
+ return false;
+ RenderLayer* layer = renderer->enclosingLayer();
+ if (layer == NULL)
+ return false;
+ if (layer->width() == 0 || layer->height() == 0)
+ return false;
+ if (!frameAndroid->view())
+ return false;
+ WebCoreViewBridge* view = frameAndroid->view()->getWebCoreViewBridge();
+ cachedFrame->setLocalViewBounds(view->getBounds());
+ cachedFrame->setContentsSize(layer->width(), layer->height());
+ if (cachedFrame->childCount() == 0)
+ return true;
+ android::CachedFrame* lastCachedFrame = cachedFrame->lastChild();
+ cachedFrame = cachedFrame->firstChild();
+ do {
+ CacheBuilder* cacheBuilder = Builder((Frame* )cachedFrame->framePointer());
+ cacheBuilder->setData(cachedFrame);
+ } while (cachedFrame++ != lastCachedFrame);
+ return true;
+}
+
+bool CacheBuilder::validNode(void* matchFrame, void* matchNode) const
+{
+ Frame* frame = FrameAnd(this);
+ if (matchFrame == frame) {
+ if (matchNode == NULL)
+ return true;
+ Node* node = frame->document();
+ while (node != NULL) {
+ if (node == matchNode) {
+ const IntRect& rect = node->hasTagName(HTMLNames::areaTag) ?
+ static_cast<HTMLAreaElement*>(node)->getAreaRect() : node->getRect();
+ // Consider nodes with empty rects that are not at the origin
+ // to be valid, since news.google.com has valid nodes like this
+ if (rect.x() == 0 && rect.y() == 0 && rect.isEmpty())
+ return false;
+ return true;
+ }
+ node = node->traverseNextNode();
+ }
+ DBG_NAV_LOGD("frame=%p valid node=%p invalid\n", matchFrame, matchNode);
+ return false;
+ }
+ Frame* child = frame->tree()->firstChild();
+ while (child) {
+ bool result = Builder(child)->validNode(matchFrame, matchNode);
+ if (result)
+ return result;
+ child = child->tree()->nextSibling();
+ }
+#if DEBUG_NAV_UI
+ if (frame->tree()->parent() == NULL)
+ DBG_NAV_LOGD("frame=%p node=%p false\n", matchFrame, matchNode);
+#endif
+ return false;
+}
+
+static int Area(const IntRect& rect)
+{
+ return rect.width() * rect.height();
+}
+
+bool CacheBuilder::AddPartRect(IntRect& bounds, int x, int y,
+ WTF::Vector<IntRect>* result, IntRect* focusBounds)
+{
+ if (bounds.isEmpty())
+ return true;
+ bounds.move(x, y);
+ if (bounds.right() <= 0 || bounds.bottom() <= 0)
+ return true;
+ IntRect* work = result->begin() - 1;
+ IntRect* end = result->end();
+ while (++work < end) {
+ if (work->contains(bounds))
+ return true;
+ if (bounds.contains(*work)) {
+ *work = bounds;
+ focusBounds->unite(bounds);
+ return true;
+ }
+ if ((bounds.x() != work->x() || bounds.width() != work->width()) &&
+ (bounds.y() != work->y() || bounds.height() != work->height()))
+ continue;
+ IntRect test = *work;
+ test.unite(bounds);
+ if (Area(test) > Area(*work) + Area(bounds))
+ continue;
+ *work = test;
+ focusBounds->unite(bounds);
+ return true;
+ }
+ if (result->size() >= MAXIMUM_FOCUS_RING_COUNT)
+ return false;
+ result->append(bounds);
+ if (focusBounds->isEmpty())
+ *focusBounds = bounds;
+ else
+ focusBounds->unite(bounds);
+ return true;
+}
+
+bool CacheBuilder::ConstructPartRects(Node* node, const IntRect& bounds,
+ IntRect* focusBounds, int x, int y, WTF::Vector<IntRect>* result)
+{
+ WTF::Vector<ClipColumnTracker> clipTracker(1);
+ ClipColumnTracker* baseTracker = clipTracker.data(); // sentinel
+ bzero(baseTracker, sizeof(ClipColumnTracker));
+ if (node->hasChildNodes() && node->hasTagName(HTMLNames::buttonTag) == false
+ && node->hasTagName(HTMLNames::selectTag) == false) {
+ // collect all text rects from first to last child
+ Node* test = node->firstChild();
+ Node* last = NULL;
+ Node* prior = node;
+ while ((prior = prior->lastChild()) != NULL)
+ last = prior;
+ ASSERT(last != NULL);
+ bool nodeIsAnchor = node->hasTagName(HTMLNames::aTag);
+ do {
+ do {
+ const ClipColumnTracker* lastClip = &clipTracker.last();
+ if (test != lastClip->mLastChild)
+ break;
+ clipTracker.removeLast();
+ } while (true);
+ RenderObject* renderer = test->renderer();
+ if (renderer == NULL)
+ continue;
+ EVisibility vis = renderer->style()->visibility();
+ if (vis == HIDDEN)
+ continue;
+ if (test->isTextNode()) {
+ RenderText* renderText = (RenderText*) renderer;
+ InlineTextBox *textBox = renderText->firstTextBox();
+ if (textBox == NULL)
+ continue;
+ bool hasClip = renderer->hasOverflowClip();
+ size_t clipIndex = clipTracker.size();
+ IntRect clipBounds = IntRect(0, 0, INT_MAX, INT_MAX);
+ if (hasClip || --clipIndex > 0) {
+ clipBounds = hasClip ? renderer->absoluteBoundingBoxRect() :
+ clipTracker.at(clipIndex).mBounds; // x, y fixup done by ConstructTextRect
+ }
+ if (ConstructTextRect((Text*) test, textBox, 0, INT_MAX,
+ x, y, focusBounds, clipBounds, result) == false) {
+ return false;
+ }
+ continue;
+ }
+ if (test->hasTagName(HTMLNames::imgTag)) {
+ IntRect bounds = test->getRect();
+ if (AddPartRect(bounds, x, y, result, focusBounds) == false)
+ return false;
+ continue;
+ }
+ if (renderer->hasOverflowClip() == false) {
+ if (nodeIsAnchor && test->hasTagName(HTMLNames::divTag)) {
+ IntRect bounds = renderer->absoluteBoundingBoxRect(); // x, y fixup done by AddPartRect
+ int left = bounds.x() + renderer->paddingLeft()
+ + renderer->borderLeft();
+ int top = bounds.y() + renderer->paddingTop()
+ + renderer->borderTop();
+ int right = bounds.right() - renderer->paddingRight()
+ - renderer->borderRight();
+ int bottom = bounds.bottom() - renderer->paddingBottom()
+ - renderer->borderBottom();
+ if (left >= right || top >= bottom)
+ continue;
+ bounds = IntRect(left, top, right - left, bottom - top);
+ if (AddPartRect(bounds, x, y, result, focusBounds) == false)
+ return false;
+ }
+ continue;
+ }
+ Node* lastChild = test->lastChild();
+ if (lastChild == NULL)
+ continue;
+ clipTracker.grow(clipTracker.size() + 1);
+ ClipColumnTracker& clip = clipTracker.last();
+ clip.mBounds = renderer->absoluteBoundingBoxRect(); // x, y fixup done by ConstructTextRect
+ clip.mLastChild = OneAfter(lastChild);
+ clip.mNode = test;
+ } while (test != last && (test = test->traverseNextNode()) != NULL);
+ }
+ if (result->size() == 0) {
+ if (bounds.width() < MINIMUM_FOCUSABLE_WIDTH)
+ return false;
+ if (bounds.height() < MINIMUM_FOCUSABLE_HEIGHT)
+ return false;
+ result->append(bounds);
+ *focusBounds = bounds;
+ }
+ return true;
+}
+
+static inline bool isNotSpace(UChar c)
+{
+ return c <= 0x7F ? isUnicodeSpace(c) == false :
+ WTF::Unicode::direction(c) != WTF::Unicode::WhiteSpaceNeutral;
+}
+
+bool CacheBuilder::ConstructTextRect(Text* textNode,
+ InlineTextBox* textBox, int start, int relEnd, int x, int y,
+ IntRect* focusBounds, const IntRect& clipBounds, WTF::Vector<IntRect>* result)
+{
+ RenderText* renderText = (RenderText*) textNode->renderer();
+ EVisibility vis = renderText->style()->visibility();
+ StringImpl* string = textNode->string();
+ const UChar* chars = string->characters();
+ int renderX, renderY;
+ renderText->absolutePosition(renderX, renderY);
+ do {
+ int textBoxStart = textBox->start();
+ int textBoxEnd = textBoxStart + textBox->len();
+ if (textBoxEnd <= start)
+ continue;
+ if (textBoxEnd > relEnd)
+ textBoxEnd = relEnd;
+ IntRect bounds = textBox->selectionRect(renderX, renderY,
+ start, textBoxEnd);
+ bounds.intersect(clipBounds);
+ if (bounds.isEmpty())
+ continue;
+ bool drawable = false;
+ for (int index = start; index < textBoxEnd; index++)
+ if ((drawable |= isNotSpace(chars[index])) != false)
+ break;
+ if (drawable && vis != HIDDEN) {
+ if (AddPartRect(bounds, x, y, result, focusBounds) == false)
+ return false;
+ }
+ if (textBoxEnd == relEnd)
+ break;
+ } while ((textBox = textBox->nextTextBox()) != NULL);
+ return true;
+}
+
+bool CacheBuilder::ConstructTextRects(Text* node, int start,
+ Text* last, int end, int x, int y, IntRect* focusBounds,
+ const IntRect& clipBounds, WTF::Vector<IntRect>* result)
+{
+ result->clear();
+ *focusBounds = IntRect(0, 0, 0, 0);
+ do {
+ RenderText* renderText = (RenderText*) node->renderer();
+ int relEnd = node == last ? end : renderText->textLength();
+ InlineTextBox *textBox = renderText->firstTextBox();
+ if (textBox != NULL) {
+ do {
+ if ((int) textBox->end() >= start)
+ break;
+ } while ((textBox = textBox->nextTextBox()) != NULL);
+ if (ConstructTextRect(node, textBox, start, relEnd,
+ x, y, focusBounds, clipBounds, result) == false)
+ return false;
+ }
+ start = 0;
+ do {
+ if (node == last)
+ return true;
+ node = (Text*) node->traverseNextNode();
+ ASSERT(node != NULL);
+ } while (node->isTextNode() == false || node->renderer() == NULL);
+ } while (true);
+}
+
+}
diff --git a/WebCore/platform/android/nav/CacheBuilder.h b/WebCore/platform/android/nav/CacheBuilder.h
new file mode 100644
index 0000000..de5d153
--- /dev/null
+++ b/WebCore/platform/android/nav/CacheBuilder.h
@@ -0,0 +1,251 @@
+/* libs/WebKitLib/WebKit/platform/bridge/android/CacheBuilder.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef CacheBuilder_H
+#define CacheBuilder_H
+
+#include "CachedDebug.h"
+#include "CachedNodeType.h"
+#include "IntRect.h"
+#include "PlatformString.h"
+#include "TextDirection.h"
+#include "wtf/Vector.h"
+
+#define NAVIGATION_MAX_PHONE_LENGTH 14
+
+namespace android {
+ class CachedFrame;
+ class CachedNode;
+ class CachedRoot;
+}
+
+namespace WebCore {
+
+class Document;
+class Frame;
+class FrameAndroid;
+class InlineTextBox;
+class Node;
+class PlatformGraphicsContext;
+class RenderFlow;
+class RenderObject;
+class RenderLayer;
+class Text;
+
+class CacheBuilder {
+public:
+ enum Direction {
+ UNINITIALIZED = -1,
+ LEFT,
+ RIGHT,
+ UP,
+ DOWN,
+ DIRECTION_COUNT,
+ UP_DOWN = UP & DOWN, // mask and result
+ RIGHT_DOWN = RIGHT & DOWN, // mask and result
+ };
+ enum FoundState {
+ FOUND_NONE,
+ FOUND_PARTIAL,
+ FOUND_COMPLETE
+ };
+ CacheBuilder();
+ void allowAllTextDetection() { mAllowableTypes = android::ALL_CACHEDNODETYPES; }
+ void buildCache(android::CachedRoot* root);
+ static bool ConstructPartRects(Node* node, const IntRect& bounds,
+ IntRect* focusBounds, int x, int y, WTF::Vector<IntRect>* result);
+ Node* currentFocus() const;
+ void disallowAddressDetection() { mAllowableTypes = (android::CachedNodeType) (
+ mAllowableTypes & ~android::ADDRESS_CACHEDNODETYPE); }
+ void disallowEmailDetection() { mAllowableTypes = (android::CachedNodeType) (
+ mAllowableTypes & ~android::EMAIL_CACHEDNODETYPE); }
+ void disallowPhoneDetection() { mAllowableTypes = (android::CachedNodeType) (
+ mAllowableTypes & ~android::PHONE_CACHEDNODETYPE); }
+ static FoundState FindAddress(const UChar* , unsigned length, int* start, int* end);
+ Node* findByCenter(int x, int y) const;
+ static void GetGlobalOffset(Frame* , int* x, int * y);
+ static void GetGlobalOffset(Node* , int* x, int * y);
+ bool outOfDate();
+ void setLastFocus(Node* );
+ bool validNode(void* framePtr, void* nodePtr) const;
+private:
+ enum AddressProgress {
+ NO_ADDRESS,
+ SKIP_TO_SPACE,
+ HOUSE_NUMBER,
+ NUMBER_TRAILING_SPACE,
+ ADDRESS_LINE,
+ STATE_NAME,
+ SECOND_HALF,
+ ZIP_CODE,
+ PLUS_4,
+ FIND_STREET
+ };
+ struct NodeWalk {
+ NodeWalk() { reset(); }
+ int mStart;
+ int mEnd;
+ Node* mFinalNode;
+ InlineTextBox* mLastInline;
+ bool mMore;
+ void reset() { mMore = false; }
+ };
+ struct BoundsPart {
+ IntRect mRect;
+ int mStart;
+ int mEnd;
+ };
+ struct Bounds {
+ typedef bool (*FindText)(BoundsPart* result, InlineTextBox* , const String& match);
+ IntRect mNodeBounds;
+ BoundsPart mPart;
+ WTF::Vector<BoundsPart> mParts;
+ char mStore[NAVIGATION_MAX_PHONE_LENGTH + 1];
+ android::CachedNodeType mStoreType;
+ int mPartIndex;
+ Node* mNode;
+ Node* mFinalNode;
+ void reset() { mNode = NULL; }
+ };
+ struct FindState {
+ int mStartResult;
+ int mEndResult;
+ const UChar* mCurrentStart;
+ const UChar* mEnd;
+ AddressProgress mProgress;
+ int mNumberCount;
+ int mLetterCount;
+ unsigned mWordCount;
+ int mLineCount;
+ const UChar* mFirstLower;
+ const UChar* mZipStart;
+ const UChar* mBases[16]; // FIXME: random guess, maybe too small, maybe too big
+ const UChar* mWords[16];
+ const UChar* mStarts[16]; // text is not necessarily contiguous
+ const char* mStates;
+ int mEndWord;
+ int mStateWord;
+ int mZipHint;
+ int mSectionLength;
+ unsigned mNumberWords; // must contain as many bits as mWords contains elements
+ char* mPattern;
+ UChar mStore[NAVIGATION_MAX_PHONE_LENGTH + 1];
+ UChar* mStorePtr;
+ UChar mBackOne;
+ UChar mBackTwo;
+ UChar mCurrent;
+ bool mUnparsed;
+ bool mZipDelimiter;
+ bool mOpenParen;
+ bool mInitialized;
+ bool mContinuationNode;
+ };
+ struct ClipColumnTracker {
+ IntRect mBounds;
+ Node* mLastChild;
+ Node* mNode;
+ WTF::Vector<IntRect>* mColumns;
+ int mColumnGap;
+ TextDirection mDirection;
+ bool mHasClip;
+ };
+ struct Tracker {
+ int mCachedNodeIndex;
+ Node* mLastChild;
+ Node* mParentLastChild;
+ bool mSomeParentTakesFocus;
+ };
+ void adjustForColumns(const ClipColumnTracker& track,
+ android::CachedNode* node, IntRect* bounds);
+ static bool AddPartRect(IntRect& bounds, int x, int y,
+ WTF::Vector<IntRect>* result, IntRect* focusBounds);
+ static bool AnyIsClick(Node* node);
+ static bool AnyChildIsClick(Node* node);
+ void BuildFrame(FrameAndroid* root, FrameAndroid* frame,
+ android::CachedRoot* cachedRoot, android::CachedFrame* cachedFrame);
+ bool CleanUpContainedNodes(android::CachedFrame* cachedFrame,
+ const Tracker* last, int lastChildIndex);
+ static bool ConstructTextRect(Text* textNode,
+ InlineTextBox* textBox, int start, int relEnd, int x, int y,
+ IntRect* focusBounds, const IntRect& clip, WTF::Vector<IntRect>* result);
+ static bool ConstructTextRects(Text* node, int start,
+ Text* last, int end, int x, int y, IntRect* focusBounds,
+ const IntRect& clip, WTF::Vector<IntRect>* result);
+ static FoundState FindPartialAddress(const UChar* , const UChar* , unsigned length, FindState* );
+ static FoundState FindPartialEMail(const UChar* , unsigned length, FindState* );
+ static FoundState FindPartialNumber(const UChar* , unsigned length, FindState* );
+ static FoundState FindPhoneNumber(const UChar* chars, unsigned length, int* start, int* end);
+ static void FindReset(FindState* );
+ static void FindResetNumber(FindState* );
+ static FrameAndroid* FrameAnd(CacheBuilder* focusNav);
+ static FrameAndroid* FrameAnd(const CacheBuilder* focusNav);
+ static CacheBuilder* Builder(Frame* );
+ static Frame* HasFrame(Node* );
+ static bool HasOverOrOut(Node* );
+ static bool HasTriggerEvent(Node* );
+ static bool IsDomainChar(UChar ch);
+ bool isFocusableText(NodeWalk* , bool oldMore, Node* , android::CachedNodeType* type,
+ String* exported) const; //returns true if it is focusable
+ static bool IsMailboxChar(UChar ch);
+ static bool IsRealNode(Frame* , Node* );
+ int overlap(int left, int right); // returns distance scale factor as 16.16 scalar
+ bool setData(android::CachedFrame* );
+ Node* tryFocus(Direction direction);
+ Node* trySegment(Direction direction, int mainStart, int mainEnd);
+ Node* mLastKnownFocus;
+ IntRect mLastKnownFocusBounds;
+ android::CachedNodeType mAllowableTypes;
+#if DUMP_NAV_CACHE
+public:
+ class Debug {
+public:
+ void frameName(char*& namePtr, const char* max) const;
+ void init(char* buffer, size_t size);
+ static int ParentIndex(Node* node, int count, Node* parent);
+ void print() { frames(); }
+ void print(const char* name);
+ void wideString(const String& str);
+private:
+ void attr(const AtomicString& name, const AtomicString& value);
+ void comma(const char* str);
+ int flowBoxes(RenderFlow* flow, int ifIndex, int indent);
+ void flush();
+ FrameAndroid* frameAnd() const;
+ void frames();
+ void groups();
+ bool isFocusable(Node* node);
+ void localName(Node* node);
+ void newLine(int indent = 0);
+ void print(const char* name, unsigned len);
+ void renderTree(RenderObject* , int indent, Node* , int count);
+ void setIndent(int );
+ void uChar(const UChar* name, unsigned len, bool hex);
+ void validateFrame();
+ void validateStringData();
+ void wideString(const UChar* chars, int length, bool hex);
+ char* mBuffer;
+ size_t mBufferSize;
+ int mIndex;
+ const char* mPrefix;
+ int mMinPrefix;
+ } mDebug;
+#endif
+};
+
+}
+
+#endif
diff --git a/WebCore/platform/android/nav/CachedDebug.h b/WebCore/platform/android/nav/CachedDebug.h
new file mode 100644
index 0000000..14b6fad
--- /dev/null
+++ b/WebCore/platform/android/nav/CachedDebug.h
@@ -0,0 +1,75 @@
+/*
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef CachedDebug_H
+#define CachedDebug_H
+
+#ifndef DUMP_NAV_CACHE
+#ifdef NDEBUG
+#define DUMP_NAV_CACHE 0
+#else
+#define DUMP_NAV_CACHE 1
+#endif
+#endif
+
+#ifndef DEBUG_NAV_UI
+#ifdef NDEBUG
+#define DEBUG_NAV_UI 0
+#else
+#define DEBUG_NAV_UI 1
+#endif
+#endif
+
+#if DEBUG_NAV_UI
+#define DBG_NAV_LOG(message) LOGD("%s %s", __FUNCTION__, message)
+#define DBG_NAV_LOGD(format, ...) LOGD("%s " format, __FUNCTION__, __VA_ARGS__)
+#define DBG_NAV_LOGD_ONCE(format, ...) \
+do { \
+ static uint32_t savedTime = 0; \
+ uint32_t curTime = SkTime::GetMSecs(); \
+ uint32_t tempSavedTime = savedTime; \
+ savedTime = curTime; \
+ if (curTime - tempSavedTime < 100) \
+ break; \
+ LOGD("%s " format, __FUNCTION__, __VA_ARGS__); \
+} while (false)
+#define DEBUG_NAV_UI_LOGD(...) LOGD(__VA_ARGS__)
+#else
+#define DBG_NAV_LOG(message) ((void)0)
+#define DBG_NAV_LOGD(format, ...) ((void)0)
+#define DBG_NAV_LOGD_ONCE(format, ...) ((void)0)
+#define DEBUG_NAV_UI_LOGD(...) ((void)0)
+#endif
+
+#if DUMP_NAV_CACHE != 0 && !defined DUMP_NAV_CACHE_USING_PRINTF && defined NDEBUG
+#define DUMP_NAV_CACHE_USING_PRINTF
+#endif
+
+#if DUMP_NAV_CACHE
+#ifdef DUMP_NAV_CACHE_USING_PRINTF
+#include <stdio.h>
+extern FILE* gNavCacheLogFile;
+#define NAV_CACHE_LOG_FILE "/data/data/com.android.browser/navlog"
+#define DUMP_NAV_LOGD(...) do { if (gNavCacheLogFile) \
+ fprintf(gNavCacheLogFile, __VA_ARGS__); else LOGD(__VA_ARGS__); } while (false)
+#else
+#define DUMP_NAV_LOGD(...) LOGD(__VA_ARGS__)
+#endif
+#else
+#define DUMP_NAV_LOGD(...) ((void)0)
+#endif
+
+#endif
diff --git a/WebCore/platform/android/nav/CachedFrame.cpp b/WebCore/platform/android/nav/CachedFrame.cpp
new file mode 100644
index 0000000..657670d
--- /dev/null
+++ b/WebCore/platform/android/nav/CachedFrame.cpp
@@ -0,0 +1,1303 @@
+/*
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "CachedPrefix.h"
+#include "CachedHistory.h"
+#include "CachedNode.h"
+#include "CachedRoot.h"
+
+#include "CachedFrame.h"
+
+#define OFFSETOF(type, field) ((char*)&(((type*)1)->field) - (char*)1) // avoids gnu warning
+
+#define MIN_OVERLAP 3 // if rects overlap by 2 pixels or fewer, treat them as non-intersecting
+
+namespace android {
+
+bool CachedFrame::CheckBetween(Direction direction, const WebCore::IntRect& bestRect,
+ const WebCore::IntRect& prior, WebCore::IntRect* result)
+{
+ int left, top, width, height;
+ if (direction & UP_DOWN) {
+ top = direction == UP ? bestRect.bottom() : prior.bottom();
+ int bottom = direction == UP ? prior.y() : bestRect.y();
+ height = bottom - top;
+ if (height < 0)
+ return false;
+ left = prior.x();
+ int testLeft = bestRect.x();
+ if (left > testLeft)
+ left = testLeft;
+ int right = prior.right();
+ int testRight = bestRect.right();
+ if (right < testRight)
+ right = testRight;
+ width = right - left;
+ } else {
+ left = direction == LEFT ? bestRect.right() : prior.right();
+ int right = direction == LEFT ? prior.x() : bestRect.x();
+ width = right - left;
+ if (width < 0)
+ return false;
+ top = prior.y();
+ int testTop = bestRect.y();
+ if (top > testTop)
+ top = testTop;
+ int bottom = prior.bottom();
+ int testBottom = bestRect.bottom();
+ if (bottom < testBottom)
+ bottom = testBottom;
+ height = bottom - top;
+ }
+ *result = WebCore::IntRect(left, top, width, height);
+ return true;
+}
+
+bool CachedFrame::checkBetween(BestData* best, Direction direction)
+{
+ const WebCore::IntRect& bestRect = best->bounds();
+ BestData test;
+ test.mDistance = INT_MAX;
+ test.mNode = NULL;
+ int index = direction;
+ int limit = index + DIRECTION_COUNT;
+ do {
+ WebCore::IntRect edges;
+ Direction check = (Direction) (index & DIRECTION_MASK);
+ if (CheckBetween(check, bestRect,
+ history()->priorBounds(), &edges) == false)
+ continue;
+ WebCore::IntRect clip = mRoot->scrolledBounds();
+ clip.intersect(edges);
+ if (clip.isEmpty())
+ continue;
+ findClosest(&test, direction, check, &clip);
+ if (test.mNode == NULL)
+ continue;
+ if (direction == check)
+ break;
+ } while (++index < limit);
+ if (test.mNode == NULL)
+ return false;
+ *best = test;
+ return true;
+}
+
+bool CachedFrame::checkVisited(const CachedNode* node, Direction direction) const
+{
+ return history()->checkVisited(node, direction);
+}
+
+void CachedFrame::clearFocus()
+{
+ if (mFocus < 0)
+ return;
+ CachedNode& focus = mCachedNodes[mFocus];
+ focus.clearFocus(this);
+ mFocus = -1;
+}
+
+// the thing that sucks is that when you're on a link, you want to navigate next door to a link just like this one, but can't make it
+// so with all my other sucky compares, maybe there needs to be one that prefers links that are aligned with the current focus...
+
+// returns 0 if test is preferable to best, 1 if not preferable, or -1 if unknown
+int CachedFrame::compare(BestData& testData, const BestData& bestData, const CachedNode* focus) const
+{
+// start here;
+ // if the test minor axis line intersects the line segment between focus center and best center, choose it
+ // give more weight to exact major axis alignment (rows, columns)
+ if (testData.mInNav != bestData.mInNav) {
+ if (bestData.mInNav) {
+ testData.mNode->setCondition(CachedNode::IN_FOCUS);
+ return REJECT_TEST;
+ }
+ return TEST_IS_BEST;
+ }
+ if (testData.mInNav) {
+ if (bestData.mMajorDelta < testData.mMajorDelta) {
+ testData.mNode->setCondition(CachedNode::CLOSER_IN_FOCUS);
+ return REJECT_TEST;
+ }
+ if (testData.mMajorDelta < bestData.mMajorDelta)
+ return TEST_IS_BEST;
+ }
+ if (testData.mMajorDelta < 0 && bestData.mMajorDelta >= 0) {
+ testData.mNode->setCondition(CachedNode::FURTHER);
+ return REJECT_TEST;
+ }
+ if ((testData.mMajorDelta ^ bestData.mMajorDelta) < 0) // one above, one below (or one left, one right)
+ return TEST_IS_BEST;
+// SkFixed focusMultiplier = SK_Fixed1;
+// if (focus != NULL) {
+// if (testData.mMajorDelta < bestData.mMajorDelta) {
+// // use bestData.mMajorDelta,
+// } else if (bestData.mMajorDelta < testData.mMajorDelta) {
+//
+// }
+ bool bestInWorking = bestData.inOrSubsumesWorking();
+ bool testInWorking = testData.inOrSubsumesWorking();
+ if (bestInWorking && testData.mWorkingOutside && testData.mNavOutside) {
+ testData.mNode->setCondition(CachedNode::IN_WORKING);
+ return REJECT_TEST;
+ }
+ if (testInWorking && bestData.mWorkingOutside && bestData.mNavOutside)
+ return TEST_IS_BEST;
+ bool bestInNav = directionChange() && bestData.inOrSubsumesNav();
+ bool testInNav = directionChange() && testData.inOrSubsumesNav();
+ if (bestInWorking == false && testInWorking == false) {
+ if (bestInNav && testData.mNavOutside) {
+ testData.mNode->setCondition(CachedNode::IN_UMBRA);
+ return REJECT_TEST;
+ }
+ if (testInNav && bestData.mNavOutside)
+ return TEST_IS_BEST;
+ }
+#if 01 // hopefully butt test will remove need for this
+ if (testData.mFocusChild != bestData.mFocusChild) {
+ if (bestData.mFocusChild) {
+ testData.mNode->setCondition(CachedNode::IN_FOCUS_CHILDREN);
+ return REJECT_TEST;
+ }
+ return TEST_IS_BEST;
+ }
+#endif
+ bool bestTestIn = (bestInWorking || bestInNav) && (testInWorking || testInNav);
+ bool testOverlap = bestTestIn || (testData.mWorkingOverlap != 0 && bestData.mWorkingOverlap == 0);
+ bool bestOverlap = bestTestIn || (testData.mWorkingOverlap == 0 && bestData.mWorkingOverlap != 0);
+#if 01 // this isn't working?
+ if (testOverlap == bestOverlap) {
+ if (bestData.mMajorButt < 10 && testData.mMajorButt >= 40) {
+ testData.mNode->setCondition(CachedNode::BUTTED_UP);
+ return REJECT_TEST;
+ }
+ if (testData.mMajorButt < 10 && bestData.mMajorButt >= 40)
+ return TEST_IS_BEST;
+ }
+#endif
+ if (bestOverlap && bestData.mMajorDelta < testData.mMajorDelta) { // choose closest major axis center
+ testData.mNode->setCondition(CachedNode::CLOSER);
+ return REJECT_TEST;
+ }
+ if (testOverlap && testData.mMajorDelta < bestData.mMajorDelta)
+ return TEST_IS_BEST;
+ if (bestOverlap && bestData.mMajorDelta2 < testData.mMajorDelta2) {
+ testData.mNode->setCondition(CachedNode::CLOSER_TOP);
+ return REJECT_TEST;
+ }
+ if (testOverlap && testData.mMajorDelta2 < bestData.mMajorDelta2)
+ return TEST_IS_BEST;
+#if 01
+ if (bestOverlap && ((bestData.mSideDistance <= 0 && testData.mSideDistance > 0) ||
+ abs(bestData.mSideDistance) < abs(testData.mSideDistance))) {
+ testData.mNode->setCondition(CachedNode::LEFTMOST);
+ return REJECT_TEST;
+ }
+ if (testOverlap && ((testData.mSideDistance <= 0 && bestData.mSideDistance > 0) ||
+ abs(testData.mSideDistance) < abs(bestData.mSideDistance)))
+ return TEST_IS_BEST;
+// fix me : the following ASSERT fires -- not sure if this case should be handled or not
+// ASSERT(bestOverlap == false && testOverlap == false);
+#endif
+ SkFixed testMultiplier = testData.mWorkingOverlap > testData.mNavOverlap ?
+ testData.mWorkingOverlap : testData.mNavOverlap;
+ SkFixed bestMultiplier = bestData.mWorkingOverlap > bestData.mNavOverlap ?
+ bestData.mWorkingOverlap : bestData.mNavOverlap;
+ int testDistance = testData.mDistance;
+ int bestDistance = bestData.mDistance;
+// start here;
+ // this fails if they're off by 1
+ // try once again to implement sliding scale so that off by 1 is nearly like zero,
+ // and off by a lot causes sideDistance to have little or no effect
+ // try elliptical distance -- lengthen side contribution
+ // these ASSERTs should not fire, but do fire on mail.google.com
+ // can't debug yet, won't reproduce
+ ASSERT(testDistance >= 0);
+ ASSERT(bestDistance >= 0);
+ testDistance += testDistance; // multiply by 2
+ testDistance *= testDistance;
+ bestDistance += bestDistance; // multiply by 2
+ bestDistance *= bestDistance;
+ int side = testData.mSideDistance;
+ int negative = side < 0 && bestData.mSideDistance > 0;
+ side *= side;
+ if (negative)
+ side = -side;
+ testDistance += side;
+ side = bestData.mSideDistance;
+ negative = side < 0 && testData.mSideDistance > 0;
+ side *= side;
+ if (negative)
+ side = -side;
+ bestDistance += side;
+ if (testMultiplier > (SK_Fixed1 >> 1) || bestMultiplier > (SK_Fixed1 >> 1)) { // considerable working overlap?
+ testDistance = SkFixedMul(testDistance, bestMultiplier);
+ bestDistance = SkFixedMul(bestDistance, testMultiplier);
+ }
+ if (bestDistance < testDistance) {
+ testData.mNode->setCondition(CachedNode::CLOSER_OVERLAP);
+ return REJECT_TEST;
+ }
+ if (testDistance < bestDistance)
+ return TEST_IS_BEST;
+#if 0
+ int distance = testData.mDistance + testData.mSideDistance;
+ int best = bestData.mDistance + bestData.mSideDistance;
+ if (distance > best) {
+ testData.mNode->setCondition(CachedNode::CLOSER_RAW_DISTANCE);
+ return REJECT_TEST;
+ }
+ else if (distance < best)
+ return TEST_IS_BEST;
+ best = bestData.mSideDistance;
+ if (testData.mSideDistance > best) {
+ testData.mNode->setCondition(CachedNode::SIDE_DISTANCE);
+ return REJECT_TEST;
+ }
+ if (testData.mSideDistance < best)
+ return TEST_IS_BEST;
+#endif
+ if (testData.mPreferred < bestData.mPreferred) {
+ testData.mNode->setCondition(CachedNode::PREFERRED);
+ return REJECT_TEST;
+ }
+ if (testData.mPreferred > bestData.mPreferred)
+ return TEST_IS_BEST;
+ return UNDECIDED;
+}
+
+bool CachedFrame::containsFrame(const CachedFrame* test) const
+{
+ if (this == test)
+ return true;
+ for (const CachedFrame* frame = mCachedFrames.begin();
+ frame != mCachedFrames.end(); frame++) {
+ if (frame->containsFrame(test))
+ return true;
+ }
+ return false;
+}
+
+const CachedNode* CachedFrame::currentFocus(const CachedFrame** framePtr) const
+{
+ if (framePtr)
+ *framePtr = this;
+ if (mFocus < 0)
+ return NULL;
+ const CachedNode* result = &mCachedNodes[mFocus];
+ const CachedFrame* frame = hasFrame(result);
+ if (frame != NULL)
+ return frame->currentFocus(framePtr);
+ (const_cast<CachedNode*>(result))->fixUpFocusRects();
+ return result;
+}
+
+bool CachedFrame::directionChange() const
+{
+ return history()->directionChange();
+}
+
+#ifdef BROWSER_DEBUG
+CachedNode* CachedFrame::find(WebCore::Node* node) // !!! probably debugging only
+{
+ for (CachedNode* test = mCachedNodes.begin(); test != mCachedNodes.end(); test++)
+ if (node == test->webCoreNode())
+ return test;
+ for (CachedFrame* frame = mCachedFrames.begin(); frame != mCachedFrames.end();
+ frame++) {
+ CachedNode* result = frame->find(node);
+ if (result != NULL)
+ return result;
+ }
+ return NULL;
+}
+#endif
+
+const CachedNode* CachedFrame::findBestAt(const WebCore::IntRect& rect,
+ int* best, const CachedNode** directHit, const CachedFrame** framePtr, int* x, int* y) const
+{
+ const CachedNode* result = NULL;
+ int rectWidth = rect.width();
+ WebCore::IntPoint center = WebCore::IntPoint(rect.x() + (rectWidth >> 1),
+ rect.y() + (rect.height() >> 1));
+ mRoot->setupScrolledBounds();
+ for (const CachedNode* test = mCachedNodes.begin(); test != mCachedNodes.end(); test++) {
+ if (test->disabled())
+ continue;
+ size_t parts = test->navableRects();
+ BestData testData;
+ testData.mNode = test;
+ testData.mMouseBounds = testData.mNodeBounds = test->getBounds();
+ bool checkForHidden = true;
+ for (size_t part = 0; part < parts; part++) {
+ if (test->focusRings().at(part).intersects(rect)) {
+ if (checkForHidden && mRoot->maskIfHidden(&testData) == true)
+ break;
+ checkForHidden = false;
+ WebCore::IntRect testRect = test->focusRings().at(part);
+ testRect.intersect(testData.mMouseBounds);
+ if (testRect.contains(center)) {
+ // We have a direct hit.
+ if (*directHit == NULL) {
+ *directHit = test;
+ *framePtr = this;
+ *x = center.x();
+ *y = center.y();
+ } else {
+ // We have hit another one before
+ const CachedNode* d = *directHit;
+ if (d->getBounds().contains(testRect)) {
+ // This rectangle is inside the other one, so it is
+ // the best one.
+ *directHit = test;
+ *framePtr = this;
+ }
+ }
+ }
+ if (NULL != *directHit) {
+ // If we have a direct hit already, there is no need to
+ // calculate the distances, or check the other focusring parts
+ break;
+ }
+ WebCore::IntRect both = rect;
+ int smaller = testRect.width() < testRect.height() ?
+ testRect.width() : testRect.height();
+ smaller -= rectWidth;
+ int inset = smaller < rectWidth ? smaller : rectWidth;
+ inset >>= 1; // inflate doubles the width decrease
+ if (inset > 1)
+ both.inflate(1 - inset);
+ both.intersect(testRect);
+ if (both.isEmpty())
+ continue;
+ WebCore::IntPoint testCenter = WebCore::IntPoint(testRect.x() +
+ (testRect.width() >> 1), testRect.y() + (testRect.height() >> 1));
+ int dx = testCenter.x() - center.x();
+ int dy = testCenter.y() - center.y();
+ int distance = dx * dx + dy * dy;
+ if (*best > distance) {
+ *best = distance;
+ result = test;
+ *framePtr = this;
+ *x = both.x() + (both.width() >> 1);
+ *y = both.y() + (both.height() >> 1);
+ }
+ }
+ }
+ }
+ for (const CachedFrame* frame = mCachedFrames.begin();
+ frame != mCachedFrames.end(); frame++) {
+ const CachedNode* frameResult = frame->findBestAt(rect, best, directHit,
+ framePtr, x, y);
+ if (NULL != frameResult)
+ result = frameResult;
+ }
+ if (NULL != *directHit) {
+ result = *directHit;
+ }
+ return result;
+}
+
+const CachedFrame* CachedFrame::findBestFrameAt(int x, int y) const
+{
+ if (mLocalViewBounds.contains(x, y) == false)
+ return NULL;
+ const CachedFrame* result = this;
+ for (const CachedFrame* frame = mCachedFrames.begin();
+ frame != mCachedFrames.end(); frame++) {
+ const CachedFrame* frameResult = frame->findBestFrameAt(x, y);
+ if (NULL != frameResult)
+ result = frameResult;
+ }
+ return result;
+}
+
+const CachedNode* CachedFrame::findBestHitAt(const WebCore::IntRect& rect,
+ int* best, const CachedFrame** framePtr, int* x, int* y) const
+{
+ const CachedNode* result = NULL;
+ int rectWidth = rect.width();
+ WebCore::IntPoint center = WebCore::IntPoint(rect.x() + (rectWidth >> 1),
+ rect.y() + (rect.height() >> 1));
+ mRoot->setupScrolledBounds();
+ for (const CachedNode* test = mCachedNodes.begin(); test != mCachedNodes.end(); test++) {
+ if (test->disabled())
+ continue;
+ const WebCore::IntRect& testRect = test->hitBounds();
+ if (testRect.intersects(rect) == false)
+ continue;
+ BestData testData;
+ testData.mNode = test;
+ testData.mMouseBounds = testData.mNodeBounds = testRect;
+ if (mRoot->maskIfHidden(&testData) == true)
+ continue;
+ const WebCore::IntRect& bounds = testData.mMouseBounds;
+ WebCore::IntPoint testCenter = WebCore::IntPoint(bounds.x() +
+ (bounds.width() >> 1), bounds.y() + (bounds.height() >> 1));
+ int dx = testCenter.x() - center.x();
+ int dy = testCenter.y() - center.y();
+ int distance = dx * dx + dy * dy;
+ if (*best <= distance)
+ continue;
+ *best = distance;
+ result = test;
+ *framePtr = this;
+ const WebCore::IntRect& focusRect = test->focusRings().at(0);
+ *x = focusRect.x() + (focusRect.width() >> 1);
+ *y = focusRect.y() + (focusRect.height() >> 1);
+ }
+ for (const CachedFrame* frame = mCachedFrames.begin();
+ frame != mCachedFrames.end(); frame++) {
+ const CachedNode* frameResult = frame->findBestHitAt(rect, best,
+ framePtr, x, y);
+ if (NULL != frameResult)
+ result = frameResult;
+ }
+ return result;
+}
+
+void CachedFrame::findClosest(BestData* bestData, Direction originalDirection,
+ Direction direction, WebCore::IntRect* clip) const
+{
+ const CachedNode* test = mCachedNodes.begin();
+ while ((test = test->traverseNextNode()) != NULL) {
+ const CachedFrame* child = hasFrame(test);
+ if (child != NULL) {
+ const CachedNode* childDoc = child->validDocument();
+ if (childDoc == NULL)
+ continue;
+ child->findClosest(bestData, originalDirection, direction, clip);
+ }
+ if (test->noSecondChance())
+ continue;
+ if (test->isFocusable(*clip) == false)
+ continue;
+ if (checkVisited(test, originalDirection) == false)
+ continue;
+ size_t partMax = test->navableRects();
+ for (size_t part = 0; part < partMax; part++) {
+ WebCore::IntRect testBounds = test->focusRings().at(part);
+ if (clip->intersects(testBounds) == false)
+ continue;
+ if (clip->contains(testBounds) == false) {
+ if (direction & UP_DOWN) {
+// if (testBounds.x() > clip->x() || testBounds.right() < clip->right())
+// continue;
+ testBounds.setX(clip->x());
+ testBounds.setWidth(clip->width());
+ } else {
+// if (testBounds.y() > clip->y() || testBounds.bottom() < clip->bottom())
+// continue;
+ testBounds.setY(clip->y());
+ testBounds.setHeight(clip->height());
+ }
+ if (clip->contains(testBounds) == false)
+ continue;
+ }
+ int distance;
+ // seems like distance for UP for instance needs to be 'test top closest to
+ // clip bottom' -- keep the old code but try this instead
+ switch (direction) {
+#if 0
+ case LEFT: distance = testBounds.x() - clip->x(); break;
+ case RIGHT: distance = clip->right() - testBounds.right(); break;
+ case UP: distance = testBounds.y() - clip->y(); break;
+ case DOWN: distance = clip->bottom() - testBounds.bottom(); break;
+#else
+ case LEFT: distance = clip->right() - testBounds.x(); break;
+ case RIGHT: distance = testBounds.right() - clip->x(); break;
+ case UP: distance = clip->bottom() - testBounds.y(); break;
+ case DOWN: distance = testBounds.bottom() - clip->y(); break;
+#endif
+ default:
+ distance = 0; ASSERT(0);
+ }
+ if (distance < bestData->mDistance) {
+ bestData->mNode = test;
+ bestData->mFrame = this;
+ bestData->mDistance = distance;
+ bestData->mMouseBounds = bestData->mNodeBounds =
+ test->focusRings().at(part);
+ CachedHistory* cachedHistory = history();
+ switch (direction) {
+ case LEFT:
+ bestData->setLeftDirection(cachedHistory);
+ break;
+ case RIGHT:
+ bestData->setRightDirection(cachedHistory);
+ break;
+ case UP:
+ bestData->setUpDirection(cachedHistory);
+ break;
+ case DOWN:
+ bestData->setDownDirection(cachedHistory);
+ break;
+ default:
+ ASSERT(0);
+ }
+ }
+ }
+ }
+}
+
+bool CachedFrame::finishInit()
+{
+ CachedNode* lastCached = lastNode();
+ lastCached->setLast();
+ CachedFrame* child = mCachedFrames.begin();
+ while (child != mCachedFrames.end()) {
+ child->mParent = this;
+ if (child->finishInit())
+ setFocusIndex(child->indexInParent());
+ child++;
+ }
+ return focusIndex() > 0;
+}
+
+const CachedNode* CachedFrame::frameDown(const CachedNode* test, const CachedNode* limit, BestData* bestData,
+ const CachedNode* focus) const
+{
+ BestData originalData = *bestData;
+ do {
+ if (moveInFrame(&CachedFrame::frameDown, test, bestData, focus))
+ continue;
+ BestData testData;
+ if (frameNodeCommon(testData, test, bestData, &originalData, focus) == REJECT_TEST)
+ continue;
+ if (checkVisited(test, DOWN) == false)
+ continue;
+ size_t parts = test->navableRects();
+ for (size_t part = 0; part < parts; part++) {
+ testData.mNodeBounds = test->focusRings().at(part);
+ if (testData.setDownDirection(history()))
+ continue;
+ int result = framePartCommon(testData, test, bestData, focus);
+ if (result == REJECT_TEST)
+ continue;
+ if (result == 0 && limit == NULL) { // retry all data up to this point, since smaller may have replaced node preferable to larger
+ BestData innerData = testData;
+ frameDown(document(), test, &innerData, focus);
+ if (checkVisited(innerData.mNode, DOWN)) {
+ *bestData = innerData;
+ continue;
+ }
+ }
+ if (checkVisited(test, DOWN))
+ *bestData = testData;
+ }
+ } while ((test = test->traverseNextNode()) != limit);
+ ASSERT(focus == NULL || bestData->mNode != focus);
+ // does the best contain something (or, is it contained by an area which is not the focus?)
+ // if so, is the conainer/containee should have been chosen, but wasn't -- so there's a better choice
+ // in the doc list prior to this choice
+ //
+ return bestData->mNode;
+}
+
+const CachedNode* CachedFrame::frameLeft(const CachedNode* test, const CachedNode* limit, BestData* bestData,
+ const CachedNode* focus) const
+{
+ BestData originalData = *bestData;
+ do {
+ if (moveInFrame(&CachedFrame::frameLeft, test, bestData, focus))
+ continue;
+ BestData testData;
+ if (frameNodeCommon(testData, test, bestData, &originalData, focus) == REJECT_TEST)
+ continue;
+ if (checkVisited(test, LEFT) == false)
+ continue;
+ size_t parts = test->navableRects();
+ for (size_t part = 0; part < parts; part++) {
+ testData.mNodeBounds = test->focusRings().at(part);
+ if (testData.setLeftDirection(history()))
+ continue;
+ int result = framePartCommon(testData, test, bestData, focus);
+ if (result == REJECT_TEST)
+ continue;
+ if (result == 0 && limit == NULL) { // retry all data up to this point, since smaller may have replaced node preferable to larger
+ BestData innerData = testData;
+ frameLeft(document(), test, &innerData, focus);
+ if (checkVisited(innerData.mNode, LEFT)) {
+ *bestData = innerData;
+ continue;
+ }
+ }
+ if (checkVisited(test, LEFT))
+ *bestData = testData;
+ }
+ } while ((test = test->traverseNextNode()) != limit); // FIXME ??? left and up should use traversePreviousNode to choose reverse document order
+ ASSERT(focus == NULL || bestData->mNode != focus);
+ return bestData->mNode;
+}
+
+int CachedFrame::frameNodeCommon(BestData& testData, const CachedNode* test, BestData* bestData, BestData* originalData,
+ const CachedNode* focus) const
+{
+ testData.mFrame = this;
+ testData.mNode = test;
+ test->clearCondition();
+ if (test->disabled()) {
+ testData.mNode->setCondition(CachedNode::DISABLED);
+ return REJECT_TEST;
+ }
+ if (mRoot->scrolledBounds().intersects(test->bounds()) == false) {
+ testData.mNode->setCondition(CachedNode::FOCUSABLE);
+ return REJECT_TEST;
+ }
+// if (isFocusable(test, &testData.mNodeBounds, walk) == false) {
+// testData.mNode->setCondition(CachedNode::FOCUSABLE);
+// return REJECT_TEST;
+// }
+//
+ if (test == focus) {
+ testData.mNode->setCondition(CachedNode::NOT_FOCUS_NODE);
+ return REJECT_TEST;
+ }
+// if (test->bounds().contains(history()->focusBounds())) {
+// testData.mNode->setCondition(CachedNode::NOT_ENCLOSING_FOCUS);
+// return REJECT_TEST;
+// }
+ void* par = focus ? focus->parentGroup() : NULL;
+ testData.mFocusChild = test->parentGroup() == par;
+#if 0 // not debugged
+ if (focus && focus->hasMouseOver() && test->hasMouseOver() == false &&
+ focus->bounds().contains(test->bounds()))
+ return REJECT_TEST;
+#endif
+ if (bestData->mNode == NULL)
+ return TEST_IS_BEST;
+#if 0 // not debugged
+ if (focus && focus->hasMouseOver() && test->hasMouseOver() == false &&
+ focus->bounds().contains(test->bounds()))
+ return REJECT_TEST;
+ if (test->hasMouseOver() != bestData->mNode->hasMouseOver()) {
+ if (test->hasMouseOver()) {
+ if (test->bounds().contains(bestData->mNode->bounds())) {
+ const_cast<CachedNode*>(bestData->mNode)->setDisabled(true);
+ bestData->mNode = NULL; // force part tests to be ignored, yet still set up remaining test data for later comparison
+ return TEST_IS_BEST;
+ }
+ } else {
+ if (bestData->mNode->bounds().contains(test->bounds())) {
+ test->setCondition(CachedNode::ANCHOR_IN_ANCHOR);
+ return REJECT_TEST;
+ }
+ }
+ }
+#endif
+ if (focus && testData.mNode->parentIndex() != bestData->mNode->parentIndex()) {
+ int focusParentIndex = focus->parentIndex();
+ if (focusParentIndex >= 0) {
+ if (bestData->mNode->parentIndex() == focusParentIndex)
+ return REJECT_TEST;
+ if (testData.mNode->parentIndex() == focusParentIndex)
+ return TEST_IS_BEST;
+ }
+ }
+ if (testData.mNode->parent() == bestData->mNode) {
+ testData.mNode->setCondition(CachedNode::CHILD);
+ return REJECT_TEST;
+ }
+ if (testData.mNode == bestData->mNode->parent())
+ return TEST_IS_BEST;
+ int testInBest = testData.isContainer(bestData); /* -1 pick best over test, 0 no containership, 1 pick test over best */
+ if (testInBest == 1) {
+ if (test->isArea() || bestData->mNode->isArea())
+ return UNDECIDED;
+ bestData->mNode = NULL; // force part tests to be ignored, yet still set up remaining test data for later comparisons
+ return TEST_IS_BEST;
+ }
+ if (testInBest == -1) {
+ testData.mNode->setCondition(CachedNode::OUTSIDE_OF_BEST);
+ return REJECT_TEST;
+ }
+ if (originalData->mNode != NULL) { // test is best case
+ testInBest = testData.isContainer(originalData);
+ if (testInBest == -1) { /* test is inside best */
+ testData.mNode->setCondition(CachedNode::OUTSIDE_OF_ORIGINAL);
+ return REJECT_TEST;
+ }
+ }
+ return UNDECIDED;
+}
+
+int CachedFrame::framePartCommon(BestData& testData,
+ const CachedNode* test, BestData* bestData, const CachedNode* focus) const
+{
+ if (testData.mNodeBounds.contains(history()->focusBounds())) {
+ testData.mNode->setCondition(CachedNode::NOT_ENCLOSING_FOCUS);
+ return REJECT_TEST;
+ }
+ testData.setDistances();
+ if (bestData->mNode != NULL) {
+ int compared = compare(testData, *bestData, focus);
+ if (compared == 0 && test->isArea() == false && bestData->mNode->isArea() == false)
+ goto pickTest;
+ if (compared >= 0)
+ return compared;
+ }
+pickTest:
+ return -1; // pick test
+}
+
+const CachedNode* CachedFrame::frameRight(const CachedNode* test, const CachedNode* limit, BestData* bestData,
+ const CachedNode* focus) const
+{
+ BestData originalData = *bestData;
+ do {
+ if (moveInFrame(&CachedFrame::frameRight, test, bestData, focus))
+ continue;
+ BestData testData;
+ if (frameNodeCommon(testData, test, bestData, &originalData, focus) == REJECT_TEST)
+ continue;
+ if (checkVisited(test, RIGHT) == false)
+ continue;
+ size_t parts = test->navableRects();
+ for (size_t part = 0; part < parts; part++) {
+ testData.mNodeBounds = test->focusRings().at(part);
+ if (testData.setRightDirection(history()))
+ continue;
+ int result = framePartCommon(testData, test, bestData, focus);
+ if (result == REJECT_TEST)
+ continue;
+ if (result == 0 && limit == NULL) { // retry all data up to this point, since smaller may have replaced node preferable to larger
+ BestData innerData = testData;
+ frameRight(document(), test, &innerData, focus);
+ if (checkVisited(innerData.mNode, RIGHT)) {
+ *bestData = innerData;
+ continue;
+ }
+ }
+ if (checkVisited(test, RIGHT))
+ *bestData = testData;
+ }
+ } while ((test = test->traverseNextNode()) != limit);
+ ASSERT(focus == NULL || bestData->mNode != focus);
+ return bestData->mNode;
+}
+
+const CachedNode* CachedFrame::frameUp(const CachedNode* test, const CachedNode* limit, BestData* bestData,
+ const CachedNode* focus) const
+{
+ BestData originalData = *bestData;
+ do {
+ if (moveInFrame(&CachedFrame::frameUp, test, bestData, focus))
+ continue;
+ BestData testData;
+ if (frameNodeCommon(testData, test, bestData, &originalData, focus) == REJECT_TEST)
+ continue;
+ if (checkVisited(test, UP) == false)
+ continue;
+ size_t parts = test->navableRects();
+ for (size_t part = 0; part < parts; part++) {
+ testData.mNodeBounds = test->focusRings().at(part);
+ if (testData.setUpDirection(history()))
+ continue;
+ int result = framePartCommon(testData, test, bestData, focus);
+ if (result == REJECT_TEST)
+ continue;
+ if (result == 0 && limit == NULL) { // retry all data up to this point, since smaller may have replaced node preferable to larger
+ BestData innerData = testData;
+ frameUp(document(), test, &innerData, focus);
+ if (checkVisited(innerData.mNode, UP)) {
+ *bestData = innerData;
+ continue;
+ }
+ }
+ if (checkVisited(test, UP))
+ *bestData = testData;
+ }
+ } while ((test = test->traverseNextNode()) != limit); // FIXME ??? left and up should use traversePreviousNode to choose reverse document order
+ ASSERT(focus == NULL || bestData->mNode != focus);
+ return bestData->mNode;
+}
+
+const CachedFrame* CachedFrame::hasFrame(const CachedNode* node) const
+{
+ return node->isFrame() ? &mCachedFrames[node->childFrameIndex()] : NULL;
+}
+
+CachedHistory* CachedFrame::history() const
+{
+ return mRoot->rootHistory();
+}
+
+void CachedFrame::init(const CachedRoot* root, int childFrameIndex,
+ WebCore::FrameAndroid* frame)
+{
+ mContents = WebCore::IntRect(0, 0, 0, 0); // fixed up for real in setData()
+ mLocalViewBounds = WebCore::IntRect(0, 0, 0, 0);
+ mViewBounds = WebCore::IntRect(0, 0, 0, 0);
+ mRoot = root;
+ mFocus = -1;
+ mFrame = frame;
+ mParent = NULL; // set up parents after stretchy arrays are set up
+ mIndex = childFrameIndex;
+}
+
+int CachedFrame::minWorkingHorizontal() const
+{
+ return history()->minWorkingHorizontal();
+}
+
+int CachedFrame::minWorkingVertical() const
+{
+ return history()->minWorkingVertical();
+}
+
+int CachedFrame::maxWorkingHorizontal() const
+{
+ return history()->maxWorkingHorizontal();
+}
+
+int CachedFrame::maxWorkingVertical() const
+{
+ return history()->maxWorkingVertical();
+}
+
+bool CachedFrame::moveInFrame(MoveInDirection moveInDirection,
+ const CachedNode* test, BestData* bestData,
+ const CachedNode* focus) const
+{
+ const CachedFrame* frame = hasFrame(test);
+ if (frame == NULL)
+ return false; // if it's not a frame, let the caller have another swing at it
+ const CachedNode* childDoc = frame->validDocument();
+ if (childDoc == NULL)
+ return true;
+ (frame->*moveInDirection)(childDoc, NULL, bestData, focus);
+ return true;
+}
+
+const WebCore::IntRect& CachedFrame::_navBounds() const
+{
+ return history()->navBounds();
+}
+
+void CachedFrame::resetClippedOut()
+{
+ for (CachedNode* test = mCachedNodes.begin(); test != mCachedNodes.end(); test++)
+ {
+ if (test->clippedOut()) {
+ test->setDisabled(false);
+ test->setClippedOut(false);
+ }
+ }
+ for (CachedFrame* frame = mCachedFrames.begin(); frame != mCachedFrames.end();
+ frame++) {
+ frame->resetClippedOut();
+ }
+}
+
+void CachedFrame::setData()
+{
+ if (this != mRoot) {
+ mViewBounds = mLocalViewBounds;
+ mViewBounds.intersect(mRoot->mViewBounds);
+ }
+ int x, y;
+ if (parent() == NULL)
+ x = y = 0;
+ else {
+ x = mLocalViewBounds.x();
+ y = mLocalViewBounds.y();
+ }
+ mContents.setX(x);
+ mContents.setY(y);
+ CachedFrame* child = mCachedFrames.begin();
+ while (child != mCachedFrames.end()) {
+ child->setData();
+ child++;
+ }
+}
+
+bool CachedFrame::setFocus(WebCore::Frame* frame, WebCore::Node* node,
+ int x, int y)
+{
+ if (NULL == node) {
+ const_cast<CachedRoot*>(mRoot)->setCachedFocus(NULL, NULL);
+ return true;
+ }
+ if (mFrame != frame) {
+ for (CachedFrame* testF = mCachedFrames.begin(); testF != mCachedFrames.end();
+ testF++) {
+ if (testF->setFocus(frame, node, x, y))
+ return true;
+ }
+ DBG_NAV_LOGD("no frame frame=%p node=%p", frame, node);
+ return false;
+ }
+ bool first = true;
+ CachedNode const * const end = mCachedNodes.end();
+ do {
+ for (CachedNode* test = mCachedNodes.begin(); test != end; test++) {
+ if (test->nodePointer() != node && first)
+ continue;
+ size_t partMax = test->navableRects();
+ WTF::Vector<WebCore::IntRect>& focusRings = test->focusRings();
+ for (size_t part = 0; part < partMax; part++) {
+ const WebCore::IntRect& testBounds = focusRings.at(part);
+ if (testBounds.contains(x, y) == false)
+ continue;
+ if (test->isFocus()) {
+ DBG_NAV_LOGD("already set? test=%d frame=%p node=%p x=%d y=%d",
+ test->index(), frame, node, x, y);
+ return true;
+ }
+ const_cast<CachedRoot*>(mRoot)->setCachedFocus(this, test);
+ return true;
+ }
+ }
+ DBG_NAV_LOGD("moved? frame=%p node=%p x=%d y=%d", frame, node, x, y);
+ } while ((first ^= true) == false);
+failed:
+ DBG_NAV_LOGD("no match frame=%p node=%p", frame, node);
+ return false;
+}
+
+const CachedNode* CachedFrame::validDocument() const
+{
+ const CachedNode* doc = document();
+ return doc != NULL && mViewBounds.isEmpty() == false ? doc : NULL;
+}
+
+bool CachedFrame::BestData::canBeReachedByAnotherDirection()
+{
+ if (mMajorButt > -MIN_OVERLAP)
+ return false;
+ mMajorButt = -mMajorButt;
+ return mNavOutside;
+}
+
+int CachedFrame::BestData::isContainer(CachedFrame::BestData* other)
+{
+ int _x = x();
+ int otherRight = other->right();
+ if (_x >= otherRight)
+ return 0; // does not intersect
+ int _y = y();
+ int otherBottom = other->bottom();
+ if (_y >= otherBottom)
+ return 0; // does not intersect
+ int _right = right();
+ int otherX = other->x();
+ if (otherX >= _right)
+ return 0; // does not intersect
+ int _bottom = bottom();
+ int otherY = other->y();
+ if (otherY >= _bottom)
+ return 0; // does not intersect
+ int intoX = otherX - _x;
+ int intoY = otherY - _y;
+ int intoRight = otherRight - _right;
+ int intoBottom = otherBottom - _bottom;
+ bool contains = intoX >= 0 && intoY >= 0 && intoRight <= 0 && intoBottom <= 0;
+ if (contains && mNode->partRectsContains(other->mNode)) {
+// if (mIsArea == false && hasMouseOver())
+// other->mMouseOver = mNode;
+ return mNode->isArea() ? 1 : -1;
+ }
+ bool containedBy = intoX <= 0 && intoY <= 0 && intoRight >= 0 && intoBottom >= 0;
+ if (containedBy && other->mNode->partRectsContains(mNode)) {
+// if (other->mIsArea == false && other->hasMouseOver())
+// mMouseOver = other->mNode;
+ return other->mNode->isArea() ? -1 : 1;
+ }
+ return 0;
+}
+
+// distance scale factor factor as a 16.16 scalar
+SkFixed CachedFrame::BestData::Overlap(int span, int left, int right)
+{
+ unsigned result;
+ if (left > 0 && left < span && right > span)
+ result = (unsigned) left;
+ else if (right > 0 && right < span && left > span)
+ result = (unsigned) right;
+ else if (left > 0 && right > 0)
+ return SK_Fixed1;
+ else
+ return 0;
+ result = (result << 16) / (unsigned) span; // linear proportion, always less than fixed 1
+ return (SkFixed) result;
+// !!! experiment with weight -- enable if overlaps are preferred too much
+// or reverse weighting if overlaps are preferred to little
+// return (SkFixed) (result * result >> 16); // but fall off with square
+}
+
+void CachedFrame::BestData::setDistances()
+{
+ mDistance = abs(mMajorDelta);
+ int sideDistance = mWorkingDelta;
+ if (mWorkingOverlap < SK_Fixed1) {
+ if (mPreferred > 0)
+ sideDistance = mWorkingDelta2;
+ } else if (sideDistance >= 0 && mWorkingDelta2 >=- 0)
+ sideDistance = 0;
+ else {
+ ASSERT(sideDistance <= 0 && mWorkingDelta2 <= 0);
+ if (sideDistance < mWorkingDelta2)
+ sideDistance = mWorkingDelta2;
+ }
+ // if overlap, smaller abs mWorkingDelta is better, smaller abs majorDelta is better
+ // if not overlap, positive mWorkingDelta is better
+ mSideDistance = sideDistance;
+}
+
+bool CachedFrame::BestData::setDownDirection(const CachedHistory* history)
+{
+ const WebCore::IntRect& navBounds = history->navBounds();
+ mMajorButt = mNodeBounds.y() - navBounds.bottom();
+ int testX = mNodeBounds.x();
+ int testRight = mNodeBounds.right();
+ setNavOverlap(navBounds.width(), navBounds.right() - testX,
+ testRight - navBounds.x());
+ if (canBeReachedByAnotherDirection()) {
+ mNode->setCondition(CachedNode::BEST_DIRECTION);
+ return REJECT_TEST;
+ }
+ int inNavTop = mNodeBounds.y() - navBounds.y();
+ mMajorDelta2 = inNavTop;
+ mMajorDelta = mMajorDelta2 + ((mNodeBounds.height() -
+ navBounds.height()) >> 1);
+ if (mMajorDelta2 <= 1 && mMajorDelta <= 1) {
+ mNode->setCondition(CachedNode::CENTER_FURTHER); // never move up or sideways
+ return REJECT_TEST;
+ }
+ int inNavBottom = navBounds.bottom() - mNodeBounds.bottom();
+ setNavInclusion(testRight - navBounds.right(), navBounds.x() - testX);
+ bool subsumes = navBounds.height() > 0 && inOrSubsumesNav();
+ if (inNavTop <= 0 && inNavBottom <= 0 && subsumes) {
+ mNode->setCondition(CachedNode::NOT_ENCLOSING_FOCUS);
+ return REJECT_TEST;
+ }
+ int maxV = history->maxWorkingVertical();
+ int minV = history->minWorkingVertical();
+ setWorkingOverlap(testRight - testX, maxV - testX, testRight - minV);
+ setWorkingInclusion(testRight - maxV, minV - testX);
+ if (mWorkingOverlap == 0 && mNavOverlap == 0 && inNavBottom >= 0) {
+ mNode->setCondition(CachedNode::OVERLAP_OR_EDGE_FURTHER);
+ return REJECT_TEST;
+ }
+ mInNav = history->directionChange() && inNavTop >= 0 &&
+ inNavBottom > 0 && subsumes;
+ return false;
+}
+
+bool CachedFrame::BestData::setLeftDirection(const CachedHistory* history)
+{
+ const WebCore::IntRect& navBounds = history->navBounds();
+ mMajorButt = navBounds.x() - mNodeBounds.right();
+ int testY = mNodeBounds.y();
+ int testBottom = mNodeBounds.bottom();
+ setNavOverlap(navBounds.height(), navBounds.bottom() - testY,
+ testBottom - navBounds.y());
+ if (canBeReachedByAnotherDirection()) {
+ mNode->setCondition(CachedNode::BEST_DIRECTION);
+ return REJECT_TEST;
+ }
+ int inNavRight = navBounds.right() - mNodeBounds.right();
+ mMajorDelta2 = inNavRight;
+ mMajorDelta = mMajorDelta2 - ((navBounds.width() -
+ mNodeBounds.width()) >> 1);
+ if (mMajorDelta2 <= 1 && mMajorDelta <= 1) {
+ mNode->setCondition(CachedNode::CENTER_FURTHER); // never move right or sideways
+ return REJECT_TEST;
+ }
+ int inNavLeft = mNodeBounds.x() - navBounds.x();
+ setNavInclusion(navBounds.y() - testY, testBottom - navBounds.bottom());
+ bool subsumes = navBounds.width() > 0 && inOrSubsumesNav();
+ if (inNavLeft <= 0 && inNavRight <= 0 && subsumes) {
+ mNode->setCondition(CachedNode::NOT_ENCLOSING_FOCUS);
+ return REJECT_TEST;
+ }
+ int maxH = history->maxWorkingHorizontal();
+ int minH = history->minWorkingHorizontal();
+ setWorkingOverlap(testBottom - testY, maxH - testY, testBottom - minH);
+ setWorkingInclusion(minH - testY, testBottom - maxH);
+ if (mWorkingOverlap == 0 && mNavOverlap == 0 && inNavLeft >= 0) {
+ mNode->setCondition(CachedNode::OVERLAP_OR_EDGE_FURTHER);
+ return REJECT_TEST;
+ }
+ mInNav = history->directionChange() && inNavLeft >= 0 &&
+ inNavRight > 0 && subsumes; /* both L/R in or out */
+ return false;
+}
+
+bool CachedFrame::BestData::setRightDirection(const CachedHistory* history)
+{
+ const WebCore::IntRect& navBounds = history->navBounds();
+ mMajorButt = mNodeBounds.x() - navBounds.right();
+ int testY = mNodeBounds.y();
+ int testBottom = mNodeBounds.bottom();
+ setNavOverlap(navBounds.height(), navBounds.bottom() - testY,
+ testBottom - navBounds.y());
+ if (canBeReachedByAnotherDirection()) {
+ mNode->setCondition(CachedNode::BEST_DIRECTION);
+ return REJECT_TEST;
+ }
+ int inNavLeft = mNodeBounds.x() - navBounds.x();
+ mMajorDelta2 = inNavLeft;
+ mMajorDelta = mMajorDelta2 + ((mNodeBounds.width() -
+ navBounds.width()) >> 1);
+ if (mMajorDelta2 <= 1 && mMajorDelta <= 1) {
+ mNode->setCondition(CachedNode::CENTER_FURTHER); // never move left or sideways
+ return REJECT_TEST;
+ }
+ int inNavRight = navBounds.right() - mNodeBounds.right();
+ setNavInclusion(testBottom - navBounds.bottom(), navBounds.y() - testY);
+ bool subsumes = navBounds.width() > 0 && inOrSubsumesNav();
+ if (inNavLeft <= 0 && inNavRight <= 0 && subsumes) {
+ mNode->setCondition(CachedNode::NOT_ENCLOSING_FOCUS);
+ return REJECT_TEST;
+ }
+ int maxH = history->maxWorkingHorizontal();
+ int minH = history->minWorkingHorizontal();
+ setWorkingOverlap(testBottom - testY, testBottom - minH, maxH - testY);
+ setWorkingInclusion(testBottom - maxH, minH - testY);
+ if (mWorkingOverlap == 0 && mNavOverlap == 0 && inNavRight >= 0) {
+ mNode->setCondition(CachedNode::OVERLAP_OR_EDGE_FURTHER);
+ return REJECT_TEST;
+ }
+ mInNav = history->directionChange() && inNavLeft >= 0 &&
+ inNavRight > 0 && subsumes; /* both L/R in or out */
+ return false;
+}
+
+bool CachedFrame::BestData::setUpDirection(const CachedHistory* history)
+{
+ const WebCore::IntRect& navBounds = history->navBounds();
+ mMajorButt = navBounds.y() - mNodeBounds.bottom();
+ int testX = mNodeBounds.x();
+ int testRight = mNodeBounds.right();
+ setNavOverlap(navBounds.width(), navBounds.right() - testX,
+ testRight - navBounds.x());
+ if (canBeReachedByAnotherDirection()) {
+ mNode->setCondition(CachedNode::BEST_DIRECTION);
+ return REJECT_TEST;
+ }
+ int inNavBottom = navBounds.bottom() - mNodeBounds.bottom();
+ mMajorDelta2 = inNavBottom;
+ mMajorDelta = mMajorDelta2 - ((navBounds.height() -
+ mNodeBounds.height()) >> 1);
+ if (mMajorDelta2 <= 1 && mMajorDelta <= 1) {
+ mNode->setCondition(CachedNode::CENTER_FURTHER); // never move down or sideways
+ return REJECT_TEST;
+ }
+ int inNavTop = mNodeBounds.y() - navBounds.y();
+ setNavInclusion(navBounds.x() - testX, testRight - navBounds.right());
+ bool subsumes = navBounds.height() > 0 && inOrSubsumesNav();
+ if (inNavTop <= 0 && inNavBottom <= 0 && subsumes) {
+ mNode->setCondition(CachedNode::NOT_ENCLOSING_FOCUS);
+ return REJECT_TEST;
+ }
+ int maxV = history->maxWorkingVertical();
+ int minV = history->minWorkingVertical();
+ setWorkingOverlap(testRight - testX, testRight - minV, maxV - testX);
+ setWorkingInclusion(minV - testX, testRight - maxV);
+ if (mWorkingOverlap == 0 && mNavOverlap == 0 && inNavTop >= 0) {
+ mNode->setCondition(CachedNode::OVERLAP_OR_EDGE_FURTHER);
+ return REJECT_TEST;
+ }
+ mInNav = history->directionChange() && inNavTop >= 0 &&
+ inNavBottom > 0 && subsumes; /* both L/R in or out */
+ return false;
+}
+
+void CachedFrame::BestData::setNavInclusion(int left, int right)
+{
+ // if left and right <= 0, test node is completely in umbra of focus
+ // prefer leftmost center
+ // if left and right > 0, test node subsumes focus
+ mNavDelta = left;
+ mNavDelta2 = right;
+}
+
+void CachedFrame::BestData::setNavOverlap(int span, int left, int right)
+{
+ mNavOutside = left < MIN_OVERLAP || right < MIN_OVERLAP; // if left or right < 0, test node is not in umbra of focus
+ mNavOverlap = Overlap(span, left, right); // prefer smallest negative left
+}
+
+void CachedFrame::BestData::setWorkingInclusion(int left, int right)
+{
+ mWorkingDelta = left;
+ mWorkingDelta2 = right;
+}
+
+// distance scale factor factor as a 16.16 scalar
+void CachedFrame::BestData::setWorkingOverlap(int span, int left, int right)
+{
+ mWorkingOutside = left < MIN_OVERLAP || right < MIN_OVERLAP; // if left or right < 0, test node is not in umbra of focus
+ mWorkingOverlap = Overlap(span, left, right);
+ mPreferred = left <= 0 ? 0 : left;
+}
+
+#if DUMP_NAV_CACHE
+
+#define DEBUG_PRINT_RECT(prefix, debugName, field) \
+ { const WebCore::IntRect& r = b->field; \
+ DUMP_NAV_LOGD("%s DebugTestRect TEST%s_" #debugName "={%d, %d, %d, %d}; //" #field "\n", \
+ prefix, mFrameName, r.x(), r.y(), r.width(), r.height()); }
+
+CachedFrame* CachedFrame::Debug::base() const {
+ CachedFrame* nav = (CachedFrame*) ((char*) this - OFFSETOF(CachedFrame, mDebug));
+ return nav;
+}
+
+void CachedFrame::Debug::print() const
+{
+ CachedFrame* b = base();
+ DEBUG_PRINT_RECT("//", CONTENTS, mContents);
+ DEBUG_PRINT_RECT("", BOUNDS, mLocalViewBounds);
+ DEBUG_PRINT_RECT("//", VIEW, mViewBounds);
+ DUMP_NAV_LOGD("// CachedNode mCachedNodes={ // count=%d\n", b->mCachedNodes.size());
+ for (CachedNode* node = b->mCachedNodes.begin();
+ node != b->mCachedNodes.end(); node++)
+ node->mDebug.print();
+ DUMP_NAV_LOGD("// }; // end of nodes\n");
+ DUMP_NAV_LOGD("// CachedFrame mCachedFrames={ // count=%d\n", b->mCachedFrames.size());
+ for (CachedFrame* child = b->mCachedFrames.begin();
+ child != b->mCachedFrames.end(); child++)
+ {
+ child->mDebug.print();
+ }
+ DUMP_NAV_LOGD("// }; // end of child frames\n");
+ DUMP_NAV_LOGD("// void* mFrame=(void*) %p;\n", b->mFrame);
+ DUMP_NAV_LOGD("// CachedFrame* mParent=%p;\n", b->mParent);
+ DUMP_NAV_LOGD("// int mIndex=%d;\n", b->mIndex);
+ DUMP_NAV_LOGD("// const CachedRoot* mRoot=%p;\n", b->mRoot);
+ DUMP_NAV_LOGD("// int mFocus=%d;\n", b->mFocus);
+}
+
+bool CachedFrame::Debug::validate(const CachedNode* node) const
+{
+ const CachedFrame* b = base();
+ if (b->mCachedNodes.size() == 0)
+ return false;
+ if (node >= b->mCachedNodes.begin() && node < b->mCachedNodes.end())
+ return true;
+ for (const CachedFrame* child = b->mCachedFrames.begin();
+ child != b->mCachedFrames.end(); child++)
+ if (child->mDebug.validate(node))
+ return true;
+ return false;
+}
+
+#undef DEBUG_PRINT_RECT
+
+#endif
+
+}
diff --git a/WebCore/platform/android/nav/CachedFrame.h b/WebCore/platform/android/nav/CachedFrame.h
new file mode 100644
index 0000000..c7b1327
--- /dev/null
+++ b/WebCore/platform/android/nav/CachedFrame.h
@@ -0,0 +1,220 @@
+/*
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef CachedFrame_H
+#define CachedFrame_H
+
+#include "CachedNode.h"
+#include "IntRect.h"
+#include "SkFixed.h"
+#include "wtf/Vector.h"
+
+namespace WebCore {
+ class Frame;
+ class FrameAndroid;
+ class Node;
+}
+
+namespace android {
+
+class CachedHistory;
+class CachedRoot;
+
+ // first node referenced by cache is always document
+class CachedFrame {
+public:
+ enum Direction {
+ UNINITIALIZED = -1,
+ LEFT,
+ RIGHT,
+ UP,
+ DOWN,
+ DIRECTION_COUNT,
+ DIRECTION_MASK = DIRECTION_COUNT - 1,
+ UP_DOWN = UP & DOWN, // mask and result
+ RIGHT_DOWN = RIGHT & DOWN, // mask and result
+ };
+ enum Compare {
+ UNDECIDED = -1,
+ TEST_IS_BEST,
+ REJECT_TEST
+ };
+ CachedFrame() {}
+ void add(CachedNode& node) { mCachedNodes.append(node); }
+ void addFrame(CachedFrame& child) { mCachedFrames.append(child); }
+ bool checkVisited(const CachedNode* , CachedFrame::Direction ) const;
+ size_t childCount() { return mCachedFrames.size(); }
+ void clearFocus();
+ bool containsFrame(const CachedFrame* ) const;
+ const CachedNode* currentFocus() const { return currentFocus(NULL); }
+ const CachedNode* currentFocus(const CachedFrame** ) const;
+ bool directionChange() const;
+ const CachedNode* document() const { return mCachedNodes.begin(); }
+ bool empty() const { return mCachedNodes.size() < 2; } // must have 1 past doc
+ const CachedNode* findBestAt(const WebCore::IntRect& , int* best,
+ const CachedNode** , const CachedFrame** , int* x, int* y) const;
+ const CachedFrame* findBestFrameAt(int x, int y) const;
+ const CachedNode* findBestHitAt(const WebCore::IntRect& ,
+ int* best, const CachedFrame** , int* x, int* y) const;
+ bool finishInit();
+ CachedFrame* firstChild() { return mCachedFrames.begin(); }
+ const CachedFrame* firstChild() const { return mCachedFrames.begin(); }
+ int focusIndex() const { return mFocus; }
+ void* framePointer() const { return mFrame; }
+ CachedNode* getIndex(int index) { return index >= 0 ?
+ &mCachedNodes[index] : NULL; }
+ const CachedFrame* hasFrame(const CachedNode* node) const;
+ int indexInParent() const { return mIndex; }
+ void init(const CachedRoot* root, int index, WebCore::FrameAndroid* frame);
+ const CachedFrame* lastChild() const { return &mCachedFrames.last(); }
+ CachedNode* lastNode() { return &mCachedNodes.last(); }
+ CachedFrame* lastChild() { return &mCachedFrames.last(); }
+ const CachedFrame* parent() const { return mParent; }
+ CachedFrame* parent() { return mParent; }
+ void removeLast() { mCachedNodes.removeLast(); }
+ void resetClippedOut();
+ void setContentsSize(int width, int height) { mContents.setWidth(width);
+ mContents.setHeight(height); }
+ void setData();
+ bool setFocus(WebCore::Frame* , WebCore::Node* , int x, int y);
+ void setFocusIndex(int focusIndex) const { mFocus = focusIndex; }
+ void setLocalViewBounds(const WebCore::IntRect& bounds) { mLocalViewBounds = bounds; }
+ int size() { return mCachedNodes.size(); }
+ const CachedNode* validDocument() const;
+protected:
+ struct BestData {
+ WebCore::IntRect mNodeBounds;
+ WebCore::IntRect mMouseBounds;
+ int mDistance;
+ int mSideDistance;
+ int mMajorDelta; // difference of center of object
+ // used only when leading and trailing edges contain another set of edges
+ int mMajorDelta2; // difference of leading edge (only used when center is same)
+ int mMajorButt; // checks for next cell butting up against or close to previous one
+ int mWorkingDelta;
+ int mWorkingDelta2;
+ int mNavDelta;
+ int mNavDelta2;
+ const CachedFrame* mFrame;
+ const CachedNode* mNode;
+ SkFixed mWorkingOverlap; // this and below are fuzzy answers instead of bools
+ SkFixed mNavOverlap;
+ SkFixed mPreferred;
+ bool mFocusChild;
+ bool mInNav;
+ bool mNavOutside;
+ bool mWorkingOutside;
+ int bottom() const { return bounds().bottom(); }
+ const WebCore::IntRect& bounds() const { return mNodeBounds; }
+ bool canBeReachedByAnotherDirection();
+ int height() const { return bounds().height(); }
+ bool inOrSubsumesNav() const { return (mNavDelta ^ mNavDelta2) >= 0; }
+ bool inOrSubsumesWorking() const { return (mWorkingDelta ^ mWorkingDelta2) >= 0; }
+ int isContainer(BestData* );
+ static SkFixed Overlap(int span, int left, int right);
+ void reset() { mNode = NULL; }
+ int right() const { return bounds().right(); }
+ void setDistances();
+ bool setDownDirection(const CachedHistory* );
+ bool setLeftDirection(const CachedHistory* );
+ bool setRightDirection(const CachedHistory* );
+ bool setUpDirection(const CachedHistory* );
+ void setNavInclusion(int left, int right);
+ void setNavOverlap(int span, int left, int right);
+ void setWorkingInclusion(int left, int right);
+ void setWorkingOverlap(int span, int left, int right);
+ int width() const { return bounds().width(); }
+ int x() const { return bounds().x(); }
+ int y() const { return bounds().y(); }
+ };
+ typedef const CachedNode* (CachedFrame::*MoveInDirection)(
+ const CachedNode* test, const CachedNode* limit, BestData* bestData,
+ const CachedNode* focus) const;
+ void adjustToTextColumn(int* delta) const;
+ static bool CheckBetween(Direction , const WebCore::IntRect& bestRect,
+ const WebCore::IntRect& prior, WebCore::IntRect* result);
+ bool checkBetween(BestData* , Direction );
+ int compare(BestData& testData, const BestData& bestData, const
+ CachedNode* focus) const;
+ void findClosest(BestData* , Direction original, Direction test,
+ WebCore::IntRect* clip) const;
+ int frameNodeCommon(BestData& testData, const CachedNode* test,
+ BestData* bestData, BestData* originalData,
+ const CachedNode* focus) const;
+ int framePartCommon(BestData& testData, const CachedNode* test,
+ BestData* bestData, const CachedNode* focus) const;
+ const CachedNode* frameDown(const CachedNode* test, const CachedNode* limit,
+ BestData* , const CachedNode* focus) const;
+ const CachedNode* frameLeft(const CachedNode* test, const CachedNode* limit,
+ BestData* , const CachedNode* focus) const;
+ const CachedNode* frameRight(const CachedNode* test, const CachedNode* limit,
+ BestData* , const CachedNode* focus) const;
+ const CachedNode* frameUp(const CachedNode* test, const CachedNode* limit,
+ BestData* , const CachedNode* focus) const;
+ int minWorkingHorizontal() const;
+ int minWorkingVertical() const;
+ int maxWorkingHorizontal() const;
+ int maxWorkingVertical() const;
+ bool moveInFrame(MoveInDirection , const CachedNode* test, BestData* best,
+ const CachedNode* focus) const;
+ const WebCore::IntRect& _navBounds() const;
+ WebCore::IntRect mContents;
+ WebCore::IntRect mLocalViewBounds;
+ WebCore::IntRect mViewBounds;
+ WTF::Vector<CachedNode> mCachedNodes;
+ WTF::Vector<CachedFrame> mCachedFrames;
+ void* mFrame; // WebCore::Frame*, used only to compare pointers
+ CachedFrame* mParent;
+ int mIndex; // index within parent's array of children, or -1 if root
+ const CachedRoot* mRoot;
+ mutable int mFocus;
+private:
+ CachedHistory* history() const;
+#ifdef BROWSER_DEBUG
+public:
+ CachedNode* find(WebCore::Node* ); // !!! probably debugging only
+ int mDebugIndex;
+ int mDebugLoopbackOffset;
+#endif
+#if !defined NDEBUG || DUMP_NAV_CACHE
+public:
+ class Debug {
+public:
+ Debug() {
+#if DUMP_NAV_CACHE
+ mFrameName[0] = '\0';
+#endif
+#if !defined NDEBUG
+ mInUse = true;
+#endif
+ }
+#if !defined NDEBUG
+ ~Debug() { mInUse = false; }
+ bool mInUse;
+#endif
+#if DUMP_NAV_CACHE
+ CachedFrame* base() const;
+ void print() const;
+ bool validate(const CachedNode* ) const;
+ char mFrameName[256];
+#endif
+ } mDebug;
+#endif
+};
+
+}
+
+#endif
diff --git a/WebCore/platform/android/nav/CachedHistory.cpp b/WebCore/platform/android/nav/CachedHistory.cpp
new file mode 100644
index 0000000..589b64a
--- /dev/null
+++ b/WebCore/platform/android/nav/CachedHistory.cpp
@@ -0,0 +1,196 @@
+/*
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "CachedPrefix.h"
+#include "CachedFrame.h"
+#include "CachedNode.h"
+#if DUMP_NAV_CACHE
+#include "CachedRoot.h"
+#endif
+
+#include "CachedHistory.h"
+
+namespace android {
+
+CachedHistory::CachedHistory() {
+ memset(this, 0, sizeof(CachedHistory)); // this assume the class has no virtuals
+ mLastMove = CachedFrame::UNINITIALIZED;
+ mPriorMove = CachedFrame::UNINITIALIZED;
+}
+
+
+void CachedHistory::addToVisited(const CachedNode* node, CachedFrame::Direction direction)
+{
+ memmove(&mVisited[1], &mVisited[0], sizeof(mVisited) - sizeof(mVisited[0]));
+ mVisited[0].mNode = node;
+ mVisited[0].mDirection = direction;
+}
+
+bool CachedHistory::checkVisited(const CachedNode* node, CachedFrame::Direction direction) const
+{
+ // if the direction is unchanged and we've already visited this node, don't visit it again
+ int index = 0;
+ while (index < NAVIGATION_VISIT_DEPTH - 1) {
+ if (direction != mVisited[index].mDirection)
+ break;
+ index++; // compare with last direction, previous to last node (where the arrow took us from)
+ if (node == mVisited[index].mNode)
+ return false;
+ }
+ return true;
+}
+
+void CachedHistory::pinMaxMin(const WebCore::IntRect& viewBounds)
+{
+ if (mMinWorkingHorizontal < viewBounds.y() ||
+ mMinWorkingHorizontal >= viewBounds.bottom())
+ mMinWorkingHorizontal = viewBounds.y();
+ if (mMaxWorkingHorizontal > viewBounds.bottom() ||
+ mMaxWorkingHorizontal <= viewBounds.y())
+ mMaxWorkingHorizontal = viewBounds.bottom();
+ if (mMinWorkingVertical < viewBounds.x() ||
+ mMinWorkingVertical >= viewBounds.right())
+ mMinWorkingVertical = viewBounds.x();
+ if (mMaxWorkingVertical > viewBounds.right() ||
+ mMaxWorkingVertical <= viewBounds.x())
+ mMaxWorkingVertical = viewBounds.right();
+}
+
+void CachedHistory::reset()
+{
+ memset(mVisited, 0, sizeof(mVisited));
+// mLastScroll = 0;
+ mPriorBounds = mFocusBounds = WebCore::IntRect(0, 0, 0, 0);
+ mDirectionChange = false;
+ mFocusIsInput = false;
+ mPriorIsInput = false;
+ mDidFirstLayout = false;
+ mPriorMove = mLastMove = CachedFrame::UNINITIALIZED;
+ mMinWorkingHorizontal = mMinWorkingVertical = INT_MIN;
+ mMaxWorkingHorizontal = mMaxWorkingVertical = INT_MAX;
+}
+
+void CachedHistory::setWorking(CachedFrame::Direction newMove,
+ const CachedNode* focus, const WebCore::IntRect& viewBounds)
+{
+ CachedFrame::Direction lastAxis = (CachedFrame::Direction) (mLastMove & ~CachedFrame::RIGHT_DOWN); // up, left or uninitialized
+ CachedFrame::Direction newAxis = (CachedFrame::Direction) (newMove & ~CachedFrame::RIGHT_DOWN);
+ bool change = newAxis != lastAxis;
+ mDirectionChange = change && mLastMove != CachedFrame::UNINITIALIZED;
+ if (focus != NULL || mLastMove != CachedFrame::UNINITIALIZED) {
+ mPriorMove = mLastMove;
+ mLastMove = newMove;
+ }
+ const WebCore::IntRect* navBounds = &mNavBounds;
+ if (focus != NULL) {
+ WebCore::IntRect focusBounds;
+ focus->getBounds(&focusBounds);
+ if (focusBounds.isEmpty() == false && focusBounds != mFocusBounds)
+ mNavBounds = mFocusBounds = focusBounds;
+ mPriorIsInput = mFocusIsInput;
+ mFocusIsInput = focus->isInput(); // focus->localName() == "input";
+ } else
+ mFocusBounds = WebCore::IntRect(0, 0, 0, 0);
+ if (change) { // uninitialized or change in direction
+ if (lastAxis != CachedFrame::LEFT && navBounds->height() > 0) {
+ mMinWorkingHorizontal = navBounds->y();
+ mMaxWorkingHorizontal = navBounds->bottom();
+ }
+ if (lastAxis != CachedFrame::UP && navBounds->width() > 0) {
+ mMinWorkingVertical = navBounds->x();
+ mMaxWorkingVertical = navBounds->right();
+ }
+ } else if (mPriorIsInput) {
+ if (newAxis == CachedFrame::UP_DOWN) {
+ if (mPriorBounds.x() == mMinWorkingVertical && mPriorBounds.right() == mMaxWorkingVertical) {
+ mMinWorkingVertical = navBounds->x();
+ mMaxWorkingVertical = navBounds->right();
+ }
+ } else {
+ if (mPriorBounds.y() == mMinWorkingHorizontal && mPriorBounds.bottom() == mMaxWorkingHorizontal) {
+ mMinWorkingHorizontal = navBounds->y();
+ mMaxWorkingHorizontal = navBounds->bottom();
+ }
+ }
+ }
+ pinMaxMin(viewBounds);
+}
+
+#if DUMP_NAV_CACHE
+
+#define DEBUG_PRINT_BOOL(field) \
+ DUMP_NAV_LOGD("// bool " #field "=%s;\n", b->field ? "true" : "false")
+
+#define DEBUG_PRINT_RECT(field) \
+ { const WebCore::IntRect& r = b->field; \
+ DUMP_NAV_LOGD("// IntRect " #field "={%d, %d, %d, %d};\n", \
+ r.x(), r.y(), r.width(), r.height()); }
+
+CachedHistory* CachedHistory::Debug::base() const {
+ CachedHistory* nav = (CachedHistory*) ((char*) this - OFFSETOF(CachedHistory, mDebug));
+ return nav;
+}
+
+const char* CachedHistory::Debug::direction(CachedFrame::Direction d) const
+{
+ switch (d) {
+ case CachedFrame::LEFT: return "LEFT"; break;
+ case CachedFrame::RIGHT: return "RIGHT"; break;
+ case CachedFrame::UP: return "UP"; break;
+ case CachedFrame::DOWN: return "DOWN"; break;
+ default: return "UNINITIALIZED";
+ }
+}
+
+void CachedHistory::Debug::print(CachedRoot* root) const
+{
+ CachedHistory* b = base();
+ DUMP_NAV_LOGD("// Visited mVisited[]={\n");
+ for (size_t i = 0; i < NAVIGATION_VISIT_DEPTH; i++) {
+ const Visited& visit = b->mVisited[i];
+ const CachedNode* node = visit.mNode;
+ int index = root != NULL && root->CachedFrame::mDebug.validate(node) ?
+ node->index() : -1;
+ DUMP_NAV_LOGD(" // { 0x%p (%d), %s },\n", node, index, direction(visit.mDirection));
+ }
+ DUMP_NAV_LOGD("// };\n");
+// DUMP_NAV_LOGD("// int mLastScroll=%d;\n", b->mLastScroll);
+ DEBUG_PRINT_RECT(mFocusBounds);
+ DEBUG_PRINT_RECT(mNavBounds);
+ DEBUG_PRINT_RECT(mPriorBounds);
+ DEBUG_PRINT_BOOL(mDirectionChange);
+ DEBUG_PRINT_BOOL(mFocusIsInput);
+ DEBUG_PRINT_BOOL(mPriorIsInput);
+ DUMP_NAV_LOGD("// CachedFrame::Direction mLastMove=%s, mPriorMove=%s;\n",
+ direction(b->mLastMove), direction(b->mPriorMove));
+ int max = b->mMaxWorkingHorizontal;
+ DUMP_NAV_LOGD("static int TEST_MAX_H = %d;\n", max);
+ int min = b->mMinWorkingHorizontal;
+ if (min == INT_MIN)
+ min++;
+ DUMP_NAV_LOGD("static int TEST_MIN_H = %d;\n", min);
+ max = b->mMaxWorkingVertical;
+ DUMP_NAV_LOGD("static int TEST_MAX_V = %d;\n", max);
+ min = b->mMinWorkingVertical;
+ if (min == INT_MIN)
+ min++;
+ DUMP_NAV_LOGD("static int TEST_MIN_V = %d;\n", min);
+ DUMP_NAV_LOGD("\n");
+}
+
+#endif
+
+}
diff --git a/WebCore/platform/android/nav/CachedHistory.h b/WebCore/platform/android/nav/CachedHistory.h
new file mode 100644
index 0000000..818115e
--- /dev/null
+++ b/WebCore/platform/android/nav/CachedHistory.h
@@ -0,0 +1,83 @@
+/*
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef CachedHistory_H
+#define CachedHistory_H
+
+#include "CachedFrame.h"
+
+#define NAVIGATION_VISIT_DEPTH 8 // the number of nodes last visited -- used to detect ping-ponging (number should be tuned)
+
+namespace android {
+
+class CachedRoot;
+
+// CachedHistory is maintained even if DOM is rebuilt by running script.
+// It uses blind pointers for comparison in the previously visited nodes.
+class CachedHistory {
+public:
+ CachedHistory();
+ void addToVisited(const CachedNode* , CachedFrame::Direction );
+ bool checkVisited(const CachedNode* , CachedFrame::Direction ) const;
+ bool didFirstLayout() const { return mDidFirstLayout; }
+ bool directionChange() const { return mDirectionChange; }
+ const WebCore::IntRect& focusBounds() const { return mFocusBounds; }
+ int minWorkingHorizontal() const { return mMinWorkingHorizontal; }
+ int minWorkingVertical() const { return mMinWorkingVertical; }
+ int maxWorkingHorizontal() const { return mMaxWorkingHorizontal; }
+ int maxWorkingVertical() const { return mMaxWorkingVertical; }
+ const WebCore::IntRect& navBounds() const { return mNavBounds; }
+ const WebCore::IntRect& priorBounds() const { return mPriorBounds; }
+ void setDidFirstLayout(bool did) { mDidFirstLayout = did; }
+ void setNavBounds(const WebCore::IntRect& loc) { mNavBounds = loc; }
+ void setWorking(CachedFrame::Direction , const CachedNode* focus,
+ const WebCore::IntRect& viewBounds);
+ void reset();
+private:
+ void pinMaxMin(const WebCore::IntRect& viewBounds);
+ struct Visited {
+ const CachedNode* mNode;
+ CachedFrame::Direction mDirection;
+ } mVisited[NAVIGATION_VISIT_DEPTH];
+ WebCore::IntRect mFocusBounds; // chosen focus ring
+ WebCore::IntRect mMouseBounds; // constricted bounds, if focus ring is partially visible
+ WebCore::IntRect mNavBounds; // focus ring bounds plus optional keystroke movement
+ WebCore::IntRect mPriorBounds; // prior chosen focus ring (for reversing narrowing)
+ bool mDirectionChange;
+ bool mFocusIsInput; // defer max/min to non-focus node if focus is too broad
+ bool mPriorIsInput; // defer max/min to non-focus node if focus is too broad
+ bool mDidFirstLayout; // set true when page is newly laid out
+ CachedFrame::Direction mLastMove;
+ CachedFrame::Direction mPriorMove;
+ int mMinWorkingHorizontal;
+ int mMaxWorkingHorizontal;
+ int mMinWorkingVertical;
+ int mMaxWorkingVertical;
+ friend class CachedRoot;
+#if DUMP_NAV_CACHE
+public:
+ class Debug {
+public:
+ CachedHistory* base() const;
+ const char* direction(CachedFrame::Direction d) const;
+ void print(CachedRoot* ) const;
+ } mDebug;
+#endif
+};
+
+}
+
+#endif
diff --git a/WebCore/platform/android/nav/CachedNode.cpp b/WebCore/platform/android/nav/CachedNode.cpp
new file mode 100644
index 0000000..0545b9b
--- /dev/null
+++ b/WebCore/platform/android/nav/CachedNode.cpp
@@ -0,0 +1,332 @@
+/*
+ *
+ * Copyright 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CachedPrefix.h"
+#include "CachedFrame.h"
+#include "CachedHistory.h"
+#include "Node.h"
+#include "PlatformString.h"
+
+#include "android_graphics.h"
+#include "CachedNode.h"
+
+namespace android {
+
+void CachedNode::clearFocus(CachedFrame* parent)
+{
+ if (isFrame()) {
+ CachedFrame* child = const_cast<CachedFrame*>(parent->hasFrame(this));
+ child->clearFocus();
+ }
+ mIsFocus = false;
+}
+
+bool CachedNode::Clip(const WebCore::IntRect& outer, WebCore::IntRect* inner,
+ WTF::Vector<WebCore::IntRect>* rings)
+{
+ if (outer.contains(*inner))
+ return true;
+// DBG_NAV_LOGD("outer:{%d,%d,%d,%d} does not contain inner:{%d,%d,%d,%d}",
+// outer.x(), outer.y(), outer.width(), outer.height(),
+// inner->x(), inner->y(), inner->width(), inner->height());
+ bool intersects = outer.intersects(*inner);
+ size_t size = intersects ? rings->size() : 0;
+ *inner = WebCore::IntRect(0, 0, 0, 0);
+ if (intersects) {
+ WebCore::IntRect * const start = rings->begin();
+ WebCore::IntRect* ring = start + size - 1;
+ do {
+ ring->intersect(outer);
+ if (ring->isEmpty()) {
+ if ((size_t) (ring - start) != --size)
+ *ring = start[size];
+ } else
+ inner->unite(*ring);
+ } while (ring-- != start);
+ }
+ rings->shrink(size);
+// DBG_NAV_LOGD("size:%d", size);
+ return size != 0;
+}
+
+bool CachedNode::clip(const WebCore::IntRect& bounds)
+{
+ return Clip(bounds, &mBounds, &mFocusRing);
+}
+
+#define OVERLAP 3
+
+void CachedNode::fixUpFocusRects()
+{
+ if (mFixedUpFocusRects)
+ return;
+ mFixedUpFocusRects = true;
+ if (mNavableRects <= 1)
+ return;
+#if DEBUG_NAV_UI
+ {
+ WebCore::IntRect* boundsPtr = mFocusRing.begin() - 1;
+ const WebCore::IntRect* const boundsEnd = mFocusRing.begin() + mFocusRing.size();
+ while (++boundsPtr < boundsEnd)
+ LOGD("%s %d:(%d, %d, %d, %d)\n", __FUNCTION__, boundsPtr - mFocusRing.begin(),
+ boundsPtr->x(), boundsPtr->y(), boundsPtr->width(), boundsPtr->height());
+ }
+#endif
+ // q: need to know when rects are for drawing and hit-testing, but not mouse down calcs?
+ bool again;
+ do {
+ again = false;
+ size_t size = mFocusRing.size();
+ WebCore::IntRect* unitBoundsPtr = mFocusRing.begin() - 1;
+ const WebCore::IntRect* const unitBoundsEnd = mFocusRing.begin() + size;
+ while (++unitBoundsPtr < unitBoundsEnd) {
+ // any other unitBounds to the left or right of this one?
+ int unitTop = unitBoundsPtr->y();
+ int unitBottom = unitBoundsPtr->bottom();
+ int unitLeft = unitBoundsPtr->x();
+ int unitRight = unitBoundsPtr->right();
+ WebCore::IntRect* testBoundsPtr = mFocusRing.begin() - 1;
+ while (++testBoundsPtr < unitBoundsEnd) {
+ if (unitBoundsPtr == testBoundsPtr)
+ continue;
+ int testTop = testBoundsPtr->y();
+ int testBottom = testBoundsPtr->bottom();
+ int testLeft = testBoundsPtr->x();
+ int testRight = testBoundsPtr->right();
+ int candidateTop = unitTop > testTop ? unitTop : testTop;
+ int candidateBottom = unitBottom < testBottom ? unitBottom : testBottom;
+ int candidateLeft = unitRight < testLeft ? unitRight : testRight;
+ int candidateRight = unitRight > testLeft ? unitLeft : testLeft;
+ bool leftRight = true;
+ if (candidateTop + OVERLAP >= candidateBottom ||
+ candidateLeft + OVERLAP >= candidateRight) {
+ candidateTop = unitBottom < testTop ? unitBottom : testBottom;
+ candidateBottom = unitBottom > testTop ? unitTop : testTop;
+ candidateLeft = unitLeft > testLeft ? unitLeft : testLeft;
+ candidateRight = unitRight < testRight ? unitRight : testRight;
+ if (candidateTop + OVERLAP >= candidateBottom ||
+ candidateLeft + OVERLAP >= candidateRight)
+ continue;
+ leftRight = false;
+ }
+ // construct candidate to add
+ WebCore::IntRect candidate = WebCore::IntRect(candidateLeft, candidateTop,
+ candidateRight - candidateLeft, candidateBottom - candidateTop);
+ // does a different unit bounds intersect the candidate? if so, don't add
+ WebCore::IntRect* checkBoundsPtr = mFocusRing.begin() - 1;
+ while (++checkBoundsPtr < unitBoundsEnd) {
+ if (checkBoundsPtr->intersects(candidate) == false)
+ continue;
+ if (leftRight) {
+ if (candidateTop >= checkBoundsPtr->y() &&
+ candidateBottom > checkBoundsPtr->bottom())
+ candidateTop = checkBoundsPtr->bottom();
+ else if (candidateTop < checkBoundsPtr->y() &&
+ candidateBottom <= checkBoundsPtr->bottom())
+ candidateBottom = checkBoundsPtr->y();
+ else
+ goto nextCheck;
+ } else {
+ if (candidateLeft >= checkBoundsPtr->x() &&
+ candidateRight > checkBoundsPtr->right())
+ candidateLeft = checkBoundsPtr->right();
+ else if (candidateLeft < checkBoundsPtr->x() &&
+ candidateRight <= checkBoundsPtr->right())
+ candidateRight = checkBoundsPtr->x();
+ else
+ goto nextCheck;
+ }
+ }
+ candidate = WebCore::IntRect(candidateLeft, candidateTop,
+ candidateRight - candidateLeft, candidateBottom - candidateTop);
+ ASSERT(candidate.isEmpty() == false);
+#if DEBUG_NAV_UI
+ LOGD("%s %d:(%d, %d, %d, %d)\n", __FUNCTION__, mFocusRing.size(),
+ candidate.x(), candidate.y(), candidate.width(), candidate.height());
+#endif
+ mFocusRing.append(candidate);
+ again = true;
+ goto tryAgain;
+ nextCheck:
+ continue;
+ }
+ }
+tryAgain:
+ ;
+ } while (again);
+}
+
+
+void CachedNode::focusRingBounds(WebCore::IntRect* bounds) const
+{
+ int partMax = mNavableRects;
+ ASSERT(partMax > 0);
+ *bounds = mFocusRing[0];
+ for (int partIndex = 1; partIndex < partMax; partIndex++)
+ bounds->unite(mFocusRing[partIndex]);
+ bounds->inflate(FOCUS_RING_HIT_TEST_RADIUS);
+}
+
+void CachedNode::init(CachedFrame* frame, WebCore::Node* node)
+{
+ bzero(this, sizeof(CachedNode));
+ mExport = WebCore::String();
+ mName = WebCore::String();
+ mNode = node;
+ mParentIndex = mChildFrameIndex = -1;
+ mType = android::NORMAL_CACHEDNODETYPE;
+}
+
+void CachedNode::move(int x, int y)
+{
+ mBounds.move(x, y);
+ // mHitTestBounds will be moved by caller
+ WebCore::IntRect* first = mFocusRing.begin();
+ WebCore::IntRect* last = first + mFocusRing.size();
+ --first;
+ while (++first != last)
+ first->move(x, y);
+}
+
+bool CachedNode::partRectsContains(const CachedNode* other) const
+{
+ int outerIndex = 0;
+ int outerMax = mNavableRects;
+ int innerMax = other->mNavableRects;
+ do {
+ const WebCore::IntRect& outerBounds = mFocusRing[outerIndex];
+ int innerIndex = 0;
+ do {
+ const WebCore::IntRect& innerBounds = other->mFocusRing[innerIndex];
+ if (innerBounds.contains(outerBounds))
+ return true;
+ } while (++innerIndex < innerMax);
+ } while (++outerIndex < outerMax);
+ return false;
+}
+
+#if DUMP_NAV_CACHE
+
+#define DEBUG_PRINT_BOOL(field) \
+ DUMP_NAV_LOGD("// bool " #field "=%s;\n", b->field ? "true" : "false")
+
+#define DEBUG_PRINT_RECT(field) \
+ { const WebCore::IntRect& r = b->field; \
+ DUMP_NAV_LOGD("// IntRect " #field "={%d, %d, %d, %d};\n", \
+ r.x(), r.y(), r.width(), r.height()); }
+
+CachedNode* CachedNode::Debug::base() const {
+ CachedNode* nav = (CachedNode*) ((char*) this - OFFSETOF(CachedNode, mDebug));
+ return nav;
+}
+
+const char* CachedNode::Debug::condition(Condition t) const
+{
+ switch (t) {
+ case NOT_REJECTED: return "NOT_REJECTED"; break;
+ case BUTTED_UP: return "BUTTED_UP"; break;
+ case CENTER_FURTHER: return "CENTER_FURTHER"; break;
+ case CLOSER: return "CLOSER"; break;
+ case CLOSER_IN_FOCUS: return "CLOSER_IN_FOCUS"; break;
+ case CLOSER_OVERLAP: return "CLOSER_OVERLAP"; break;
+ case CLOSER_TOP: return "CLOSER_TOP"; break;
+ case FOCUSABLE: return "FOCUSABLE"; break;
+ case FURTHER: return "FURTHER"; break;
+ case IN_UMBRA: return "IN_UMBRA"; break;
+ case IN_WORKING: return "IN_WORKING"; break;
+ case LEFTMOST: return "LEFTMOST"; break;
+ case OVERLAP_OR_EDGE_FURTHER: return "OVERLAP_OR_EDGE_FURTHER"; break;
+ case PREFERRED: return "PREFERRED"; break;
+ case ANCHOR_IN_ANCHOR: return "ANCHOR_IN_ANCHOR"; break;
+ case BEST_DIRECTION: return "BEST_DIRECTION"; break;
+ case CHILD: return "CHILD"; break;
+ case DISABLED: return "DISABLED"; break;
+ case IN_FOCUS: return "IN_FOCUS"; break;
+ case IN_FOCUS_CHILDREN: return "IN_FOCUS_CHILDREN"; break;
+ case NOT_ENCLOSING_FOCUS: return "NOT_ENCLOSING_FOCUS"; break;
+ // case NOT_FOCUS_CHILD: return "NOT_FOCUS_CHILD"; break;
+ case NOT_FOCUS_NODE: return "NOT_FOCUS_NODE"; break;
+ case OUTSIDE_OF_BEST: return "OUTSIDE_OF_BEST"; break;
+ case OUTSIDE_OF_ORIGINAL: return "OUTSIDE_OF_ORIGINAL"; break;
+ default: return "???";
+ }
+}
+
+const char* CachedNode::Debug::type(android::CachedNodeType t) const
+{
+ switch (t) {
+ case NORMAL_CACHEDNODETYPE: return "NORMAL"; break;
+ case ADDRESS_CACHEDNODETYPE: return "ADDRESS"; break;
+ case EMAIL_CACHEDNODETYPE: return "EMAIL"; break;
+ case PHONE_CACHEDNODETYPE: return "PHONE"; break;
+ default: return "???";
+ }
+}
+
+void CachedNode::Debug::print() const
+{
+ CachedNode* b = base();
+ char scratch[256];
+ size_t index = snprintf(scratch, sizeof(scratch), "// char* mExport=\"");
+ const UChar* ch = b->mExport.characters();
+ while (ch && *ch && index < sizeof(scratch))
+ scratch[index++] = *ch++;
+ DUMP_NAV_LOGD("%.*s\"\n", index, scratch);
+ index = snprintf(scratch, sizeof(scratch), "// char* mName=\"");
+ ch = b->mName.characters();
+ while (ch && *ch && index < sizeof(scratch))
+ scratch[index++] = *ch++;
+ DUMP_NAV_LOGD("%.*s\"\n", index, scratch);
+ DEBUG_PRINT_RECT(mBounds);
+ const WTF::Vector<WebCore::IntRect>& rects = b->focusRings();
+ size_t size = rects.size();
+ DUMP_NAV_LOGD("// IntRect focusRings={ // size=%d\n", size);
+ for (size_t i = 0; i < size; i++)
+ DUMP_NAV_LOGD(" // {%d, %d, %d, %d}, // %d\n", rects[i].x(), rects[i].y(),
+ rects[i].width(), rects[i].height(), i);
+ DUMP_NAV_LOGD("// };\n");
+ DUMP_NAV_LOGD("// void* mNode=%p; // (%d) \n", b->mNode, mNodeIndex);
+ DUMP_NAV_LOGD("// void* mParentGroup=%p; // (%d) \n", b->mParentGroup, mParentGroupIndex);
+ DUMP_NAV_LOGD("// int mChildFrameIndex=%d;\n", b->mChildFrameIndex);
+ DUMP_NAV_LOGD("// int mIndex=%d;\n", b->mIndex);
+ DUMP_NAV_LOGD("// int mMaxLength=%d;\n", b->mMaxLength);
+ DUMP_NAV_LOGD("// int mNavableRects=%d;\n", b->mNavableRects);
+ DUMP_NAV_LOGD("// int mParentIndex=%d;\n", b->mParentIndex);
+ DUMP_NAV_LOGD("// int mTextSize=%d;\n", b->mTextSize);
+ DUMP_NAV_LOGD("// Condition mCondition=%s;\n", condition(b->mCondition));
+ DUMP_NAV_LOGD("// Type mType=%s;\n", type(b->mType));
+ DEBUG_PRINT_BOOL(mClippedOut);
+ DEBUG_PRINT_BOOL(mDisabled);
+ DEBUG_PRINT_BOOL(mFixedUpFocusRects);
+ DEBUG_PRINT_BOOL(mHasMouseOver);
+ DEBUG_PRINT_BOOL(mIsAnchor);
+ DEBUG_PRINT_BOOL(mIsArea);
+ DEBUG_PRINT_BOOL(mIsFocus);
+ DEBUG_PRINT_BOOL(mIsInput);
+ DEBUG_PRINT_BOOL(mIsParentAnchor);
+ DEBUG_PRINT_BOOL(mIsPassword);
+ DEBUG_PRINT_BOOL(mIsTextArea);
+ DEBUG_PRINT_BOOL(mIsTextField);
+ DEBUG_PRINT_BOOL(mIsTransparent);
+ DEBUG_PRINT_BOOL(mIsUnclipped);
+ DEBUG_PRINT_BOOL(mLast);
+ DUMP_NAV_LOGD("\n");
+}
+
+#endif
+
+}
diff --git a/WebCore/platform/android/nav/CachedNode.h b/WebCore/platform/android/nav/CachedNode.h
new file mode 100644
index 0000000..5cc493d
--- /dev/null
+++ b/WebCore/platform/android/nav/CachedNode.h
@@ -0,0 +1,217 @@
+/*
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef CachedNode_H
+#define CachedNode_H
+
+#include "AtomicString.h"
+#include "CachedDebug.h"
+#include "CachedNodeType.h"
+#include "IntRect.h"
+#include "PlatformString.h"
+#include "wtf/Vector.h"
+
+namespace WebCore {
+ class Node;
+}
+
+namespace android {
+
+class CachedFrame;
+
+class CachedNode {
+public:
+// Nodes are rejected because either they are spacially not the best (first set)
+// or because they have the wrong DOM attribute (in focus, a focused child, etc)
+// findClosest() gives only spacially rejected nodes a second chance
+ enum Condition { // if bigger than 32, increase bitfield size below
+ // rejections that get a second chance
+ NOT_REJECTED = 0,
+ SECOND_CHANCE_START = NOT_REJECTED, // must be first in list
+ BUTTED_UP,
+ CENTER_FURTHER,
+ CLOSER,
+ CLOSER_IN_FOCUS,
+ CLOSER_OVERLAP,
+ CLOSER_TOP,
+ FOCUSABLE,
+ FURTHER,
+ IN_UMBRA,
+ IN_WORKING,
+ LEFTMOST,
+ OVERLAP_OR_EDGE_FURTHER,
+ PREFERRED, // better overlap measure
+ SECOND_CHANCE_END = PREFERRED, // must be last in list
+ // rejections that don't get a second chance
+ ANCHOR_IN_ANCHOR,
+ BEST_DIRECTION, // can be reached by another direction
+ CHILD,
+ DISABLED,
+ IN_FOCUS,
+ IN_FOCUS_CHILDREN,
+ NOT_ENCLOSING_FOCUS,
+ // NOT_FOCUS_CHILD,
+ NOT_FOCUS_NODE,
+ OUTSIDE_OF_BEST, // containership
+ OUTSIDE_OF_ORIGINAL, // containership
+ CONDITION_SIZE // FIXME: test that CONDITION_SIZE fits in mCondition
+ };
+ CachedNode() {}
+ bool anchorHasSrcUrl() const { return mAnchorHasSrcUrl; }
+ const WebCore::IntRect& bounds() const { return mBounds; }
+ WebCore::IntRect* boundsPtr() { return &mBounds; }
+ int childFrameIndex() const { return mChildFrameIndex; }
+ void clearCondition() const { mCondition = NOT_REJECTED; }
+ void clearFocus(CachedFrame* );
+ static bool Clip(const WebCore::IntRect& outer, WebCore::IntRect* inner,
+ WTF::Vector<WebCore::IntRect>* rings);
+ bool clip(const WebCore::IntRect& );
+ bool clippedOut() { return mClippedOut; }
+ bool disabled() const { return mDisabled; }
+ const CachedNode* document() const { return &this[-mIndex]; }
+ void fixUpFocusRects();
+ void focusRingBounds(WebCore::IntRect* ) const;
+ WTF::Vector<WebCore::IntRect>& focusRings() { return mFocusRing; }
+ const WTF::Vector<WebCore::IntRect>& focusRings() const { return mFocusRing; }
+ const WebCore::IntRect& getBounds() const { return mBounds; }
+ void getBounds(WebCore::IntRect* bounds) const { *bounds = mBounds; }
+ const WebCore::String& getExport() const { return mExport; }
+ bool hasFocusRing() const { return mHasFocusRing; }
+ bool hasMouseOver() const { return mHasMouseOver; }
+ const WebCore::IntRect& hitBounds() const { return mHitBounds; }
+ int index() const { return mIndex; }
+ void init(CachedFrame* , WebCore::Node* node);
+ bool isAnchor() const { return mIsAnchor; }
+ bool isArea() const { return mIsArea; }
+ bool isFocus() const { return mIsFocus; }
+ bool isFocusable(const WebCore::IntRect& clip) const {
+ return clip.intersects(mBounds);
+ }
+ bool isFrame() const { return mChildFrameIndex >= 0 ; }
+ bool isInput() const { return mIsInput; }
+ bool isPassword() const { return mIsPassword; }
+ bool isRtlText() const { return mIsRtlText; }
+ bool isTextArea() const { return mIsTextArea; }
+ bool isTextField() const { return mIsTextField; }
+ bool isTransparent() const { return mIsTransparent; }
+ bool isUnclipped() const { return mIsUnclipped; }
+ int maxLength() const { return mMaxLength; };
+ void move(int x, int y);
+ const WebCore::String& name() const { return mName; }
+ int navableRects() const { return mNavableRects; }
+ void* nodePointer() const { return mNode; }
+ bool noSecondChance() const { return mCondition > SECOND_CHANCE_END; }
+ const CachedNode* parent() const { return document() + mParentIndex; }
+ void* parentGroup() const { return mParentGroup; }
+ int parentIndex() const { return mParentIndex; }
+ bool partRectsContains(const CachedNode* other) const;
+ void reset();
+ void setAnchorHasSrcUrl(bool isURL) { mAnchorHasSrcUrl = isURL; }
+ void setBounds(const WebCore::IntRect& bounds) { mBounds = bounds; }
+ void setChildFrameIndex(int index) { mChildFrameIndex = index; }
+ void setClippedOut(bool clipped) { mClippedOut = clipped; }
+ void setCondition(Condition condition) const { mCondition = condition; }
+ void setDisabled(bool disabled) { mDisabled = disabled; }
+ void setExport(const WebCore::String& exported) { mExport = exported; }
+ void setHasFocusRing(bool hasFocusRing) { mHasFocusRing = hasFocusRing; }
+ void setHasMouseOver(bool hasMouseOver) { mHasMouseOver = hasMouseOver; }
+ void setHitBounds(const WebCore::IntRect& bounds) { mHitBounds = bounds; }
+ void setIndex(int index) { mIndex = index; }
+ void setIsAnchor(bool isAnchor) { mIsAnchor = isAnchor; }
+ void setIsArea(bool isArea) { mIsArea = isArea; }
+ void setIsFocus(bool isFocus) { mIsFocus = isFocus; }
+ void setIsInput(bool isInput) { mIsInput = isInput; }
+ void setIsParentAnchor(bool isAnchor) { mIsParentAnchor = isAnchor; }
+ void setIsPassword(bool isPassword) { mIsPassword = isPassword; }
+ void setIsRtlText(bool isRtlText) { mIsRtlText = isRtlText; }
+ void setIsTextArea(bool isTextArea) { mIsTextArea = isTextArea; }
+ void setIsTextField(bool isTextField) { mIsTextField = isTextField; }
+ void setIsTransparent(bool isTransparent) { mIsTransparent = isTransparent; }
+ void setIsUnclipped(bool unclipped) { mIsUnclipped = unclipped; }
+ void setLast() { mLast = true; }
+ void setMaxLength(int maxLength) { mMaxLength = maxLength; }
+ void setName(const WebCore::String& name) { mName = name; }
+ void setNavableRects() { mNavableRects = mFocusRing.size(); }
+ void setParentGroup(void* group) { mParentGroup = group; }
+ void setParentIndex(int parent) { mParentIndex = parent; }
+ void setTextSize(int textSize) { mTextSize = textSize; }
+ void setType(CachedNodeType type) { mType = type; }
+ const CachedNode* traverseNextNode() const { return mLast ? NULL : &this[1]; }
+ int textSize() const { return mTextSize; }
+ CachedNodeType type() const { return mType; }
+private:
+ WebCore::String mExport;
+ WebCore::String mName;
+ WebCore::IntRect mBounds;
+ WebCore::IntRect mHitBounds;
+ WTF::Vector<WebCore::IntRect> mFocusRing;
+ void* mNode; // WebCore::Node*, only used to match pointers
+ void* mParentGroup; // WebCore::Node*, only used to match pointers
+ int mChildFrameIndex; // set to -1 if node is not a frame
+ int mIndex; // index of itself, to find first in array (document)
+ int mMaxLength;
+ int mNavableRects; // FIXME: could be bitfield once I limit max number of rects
+ int mParentIndex;
+ int mTextSize;
+ mutable Condition mCondition : 5; // why the node was not chosen on the first pass
+ CachedNodeType mType : 3;
+ bool mAnchorHasSrcUrl : 1;
+ bool mClippedOut : 1;
+ bool mDisabled : 1;
+ bool mFixedUpFocusRects : 1;
+ bool mHasFocusRing : 1;
+ bool mHasMouseOver : 1;
+ bool mIsAnchor : 1;
+ bool mIsArea : 1;
+ bool mIsFocus : 1;
+ bool mIsInput : 1;
+ bool mIsParentAnchor : 1;
+ bool mIsPassword : 1;
+ bool mIsRtlText : 1;
+ bool mIsTextArea : 1;
+ bool mIsTextField : 1;
+ bool mIsTransparent : 1;
+ bool mIsUnclipped : 1;
+ bool mLast : 1;
+#ifdef BROWSER_DEBUG
+public:
+ WebCore::Node* webCoreNode() const { return (WebCore::Node*) mNode; }
+ bool mDisplayMeasure;
+ mutable bool mInCompare;
+ // mutable int mCondition;
+ int mSideDistance;
+ int mSecondSide;
+#endif
+#if DEBUG_NAV_UI || DUMP_NAV_CACHE
+public:
+ class Debug {
+public:
+ CachedNode* base() const;
+ const char* condition(Condition t) const;
+ void print() const;
+ const char* type(CachedNodeType t) const;
+#if DUMP_NAV_CACHE
+ int mNodeIndex;
+ int mParentGroupIndex;
+#endif
+ } mDebug;
+ friend class CachedNode::Debug;
+#endif
+};
+
+}
+
+#endif
diff --git a/WebCore/platform/android/nav/CachedNodeType.h b/WebCore/platform/android/nav/CachedNodeType.h
new file mode 100644
index 0000000..93f4345
--- /dev/null
+++ b/WebCore/platform/android/nav/CachedNodeType.h
@@ -0,0 +1,32 @@
+/*
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef CachedNodeType_H
+#define CachedNodeType_H
+
+namespace android {
+
+enum CachedNodeType {
+ NORMAL_CACHEDNODETYPE = 0,
+ ADDRESS_CACHEDNODETYPE = 1,
+ EMAIL_CACHEDNODETYPE = 2,
+ PHONE_CACHEDNODETYPE = 4,
+ ALL_CACHEDNODETYPES = 7
+};
+
+}
+
+#endif
diff --git a/WebCore/platform/android/nav/CachedPrefix.h b/WebCore/platform/android/nav/CachedPrefix.h
new file mode 100644
index 0000000..3994a5a
--- /dev/null
+++ b/WebCore/platform/android/nav/CachedPrefix.h
@@ -0,0 +1,35 @@
+/*
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef CachedPrefix_H
+#define CachedPrefix_H
+
+#ifndef LOG_TAG
+#define LOG_TAG "navcache"
+#endif
+
+#include "config.h"
+#include "CachedDebug.h"
+
+#ifdef LOG
+#undef LOG
+#endif
+
+#include <utils/Log.h>
+
+#define OFFSETOF(type, field) ((char*)&(((type*)1)->field) - (char*)1) // avoids gnu warning
+
+#endif
diff --git a/WebCore/platform/android/nav/CachedRoot.cpp b/WebCore/platform/android/nav/CachedRoot.cpp
new file mode 100644
index 0000000..07b31b7
--- /dev/null
+++ b/WebCore/platform/android/nav/CachedRoot.cpp
@@ -0,0 +1,1054 @@
+/*
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "CachedPrefix.h"
+#include "CachedHistory.h"
+#include "CachedNode.h"
+#include "SkBitmap.h"
+#include "SkBounder.h"
+#include "SkCanvas.h"
+#include "SkRegion.h"
+
+#include "CachedRoot.h"
+
+#ifdef DUMP_NAV_CACHE_USING_PRINTF
+ extern android::Mutex gWriteLogMutex;
+#endif
+
+namespace android {
+
+class CommonCheck : public SkBounder {
+public:
+ enum Type {
+ kNo_Type,
+ kDrawBitmap_Type,
+ kDrawGlyph_Type,
+ kDrawPaint_Type,
+ kDrawPath_Type,
+ kDrawPicture_Type,
+ kDrawPoints_Type,
+ kDrawPosText_Type,
+ kDrawPosTextH_Type,
+ kDrawRect_Type,
+ kDrawSprite_Type,
+ kDrawText_Type,
+ kDrawTextOnPath_Type
+ };
+
+ static bool isTextType(Type t) {
+ return t == kDrawPosTextH_Type || t == kDrawText_Type;
+ }
+
+ CommonCheck() : mType(kNo_Type), mAllOpaque(true), mIsOpaque(true) {
+ setEmpty();
+ }
+
+ bool doRect(Type type) {
+ mType = type;
+ return doIRect(mUnion);
+ }
+
+ bool joinGlyphs(const SkIRect& rect) {
+ bool isGlyph = mType == kDrawGlyph_Type;
+ if (isGlyph)
+ mUnion.join(rect);
+ return isGlyph;
+ }
+
+ void setAllOpaque(bool opaque) { mAllOpaque = opaque; }
+ void setEmpty() { mUnion.setEmpty(); }
+ void setIsOpaque(bool opaque) { mIsOpaque = opaque; }
+ void setType(Type type) { mType = type; }
+
+ Type mType;
+ SkIRect mUnion;
+ bool mAllOpaque;
+ bool mIsOpaque;
+};
+
+#if DEBUG_NAV_UI && !defined BROWSER_DEBUG
+ static const char* TypeNames[] = {
+ "kNo_Type",
+ "kDrawBitmap_Type",
+ "kDrawGlyph_Type",
+ "kDrawPaint_Type",
+ "kDrawPath_Type",
+ "kDrawPicture_Type",
+ "kDrawPoints_Type",
+ "kDrawPosText_Type",
+ "kDrawPosTextH_Type",
+ "kDrawRect_Type",
+ "kDrawSprite_Type",
+ "kDrawText_Type",
+ "kDrawTextOnPath_Type"
+ };
+#endif
+
+#define kMargin 16
+#define kSlop 2
+
+class BoundsCheck : public CommonCheck {
+public:
+ BoundsCheck() {
+ mAllDrawnIn.setEmpty();
+ mLastAll.setEmpty();
+ mLastOver.setEmpty();
+ }
+
+ static int Area(SkIRect test) {
+ return test.width() * test.height();
+ }
+
+ void checkLast() {
+ if (mAllDrawnIn.isEmpty())
+ return;
+ if (mLastAll.isEmpty() || Area(mLastAll) < Area(mAllDrawnIn)) {
+ mLastAll = mAllDrawnIn;
+ mDrawnOver.setEmpty();
+ }
+ mAllDrawnIn.setEmpty();
+ }
+
+ bool hidden() {
+ return (mLastAll.isEmpty() && mLastOver.isEmpty()) ||
+ mDrawnOver.contains(mBounds);
+ }
+
+ virtual bool onIRect(const SkIRect& rect) {
+ if (joinGlyphs(rect))
+ return false;
+ bool interestingType = mType == kDrawBitmap_Type ||
+ mType == kDrawRect_Type || isTextType(mType);
+ if (SkIRect::Intersects(mBounds, rect) == false) {
+#if DEBUG_NAV_UI && !defined BROWSER_DEBUG
+ LOGD("%s (no intersect) rect={%d,%d,%d,%d} mType=%s\n", __FUNCTION__,
+ rect.fLeft, rect.fTop, rect.fRight, rect.fBottom,
+ TypeNames[mType]);
+#endif
+ if (interestingType)
+ checkLast();
+ return false;
+ }
+ if (interestingType == false)
+ return false;
+ if (mBoundsSlop.contains(rect) ||
+ (mBounds.fLeft == rect.fLeft && mBounds.fRight == rect.fRight &&
+ mBounds.fTop >= rect.fTop && mBounds.fBottom <= rect.fBottom) ||
+ (mBounds.fTop == rect.fTop && mBounds.fBottom == rect.fBottom &&
+ mBounds.fLeft >= rect.fLeft && mBounds.fRight <= rect.fRight)) {
+ mDrawnOver.setEmpty();
+ mAllDrawnIn.join(rect);
+#if DEBUG_NAV_UI && !defined BROWSER_DEBUG
+ LOGD("%s (contains) rect={%d,%d,%d,%d}"
+ " mAllDrawnIn={%d,%d,%d,%d} mType=%s\n", __FUNCTION__,
+ rect.fLeft, rect.fTop, rect.fRight, rect.fBottom,
+ mAllDrawnIn.fLeft, mAllDrawnIn.fTop, mAllDrawnIn.fRight, mAllDrawnIn.fBottom,
+ TypeNames[mType]);
+#endif
+ } else {
+ checkLast();
+ if (!isTextType(mType)) {
+ if (
+#if 0
+// should the opaqueness of the bitmap disallow its ability to draw over?
+// not sure that this test is needed
+ (mType != kDrawBitmap_Type ||
+ (mIsOpaque && mAllOpaque)) &&
+#endif
+ mLastAll.isEmpty() == false)
+ mDrawnOver.op(rect, SkRegion::kUnion_Op);
+ } else {
+// FIXME
+// sometimes the text is not drawn entirely inside the focus area, even though
+// it is the correct text. Until I figure out why, I allow text drawn at the
+// end that is not covered up by something else to represent the focusable link
+// example that triggers this that should be figured out:
+// http://cdn.labpixies.com/campaigns/blackjack/blackjack.html?lang=en&country=US&libs=assets/feature/core
+// ( http://tinyurl.com/ywsyzb )
+ mLastOver = rect;
+ }
+#if DEBUG_NAV_UI && !defined BROWSER_DEBUG
+ const SkIRect& drawnOver = mDrawnOver.getBounds();
+ LOGD("%s (overlaps) rect={%d,%d,%d,%d}"
+ " mDrawnOver={%d,%d,%d,%d} mType=%s mIsOpaque=%s mAllOpaque=%s\n", __FUNCTION__,
+ rect.fLeft, rect.fTop, rect.fRight, rect.fBottom,
+ drawnOver.fLeft, drawnOver.fTop, drawnOver.fRight, drawnOver.fBottom,
+ TypeNames[mType], mIsOpaque ? "true" : "false", mAllOpaque ? "true" : "false");
+#endif
+ }
+ return false;
+ }
+
+ SkIRect mBounds;
+ SkIRect mBoundsSlop;
+ SkRegion mDrawnOver;
+ SkIRect mLastOver;
+ SkIRect mAllDrawnIn;
+ SkIRect mLastAll;
+};
+
+class BoundsCanvas : public SkCanvas {
+public:
+
+ BoundsCanvas(CommonCheck* bounder) : mBounder(*bounder) {
+ mTransparentLayer = 0;
+ setBounder(bounder);
+ }
+
+ virtual ~BoundsCanvas() {
+ setBounder(NULL);
+ }
+
+ virtual void drawPaint(const SkPaint& paint) {
+ mBounder.setType(CommonCheck::kDrawPaint_Type);
+ SkCanvas::drawPaint(paint);
+ }
+
+ virtual void drawPoints(PointMode mode, size_t count, const SkPoint pts[],
+ const SkPaint& paint) {
+ mBounder.setType(CommonCheck::kDrawPoints_Type);
+ SkCanvas::drawPoints(mode, count, pts, paint);
+ }
+
+ virtual void drawRect(const SkRect& rect, const SkPaint& paint) {
+ mBounder.setType(CommonCheck::kDrawRect_Type);
+ SkCanvas::drawRect(rect, paint);
+ }
+
+ virtual void drawPath(const SkPath& path, const SkPaint& paint) {
+ mBounder.setType(CommonCheck::kDrawPath_Type);
+ SkCanvas::drawPath(path, paint);
+ }
+
+ virtual void commonDrawBitmap(const SkBitmap& bitmap,
+ const SkMatrix& matrix, const SkPaint& paint) {
+ mBounder.setType(CommonCheck::kDrawBitmap_Type);
+ mBounder.setIsOpaque(bitmap.isOpaque());
+ SkCanvas::commonDrawBitmap(bitmap, matrix, paint);
+ }
+
+ virtual void drawSprite(const SkBitmap& bitmap, int left, int top,
+ const SkPaint* paint = NULL) {
+ mBounder.setType(CommonCheck::kDrawSprite_Type);
+ mBounder.setIsOpaque(bitmap.isOpaque());
+ SkCanvas::drawSprite(bitmap, left, top, paint);
+ }
+
+ virtual void drawText(const void* text, size_t byteLength, SkScalar x,
+ SkScalar y, const SkPaint& paint) {
+ mBounder.setEmpty();
+ mBounder.setType(CommonCheck::kDrawGlyph_Type);
+ SkCanvas::drawText(text, byteLength, x, y, paint);
+ mBounder.doRect(CommonCheck::kDrawText_Type);
+ }
+
+ virtual void drawPosText(const void* text, size_t byteLength,
+ const SkPoint pos[], const SkPaint& paint) {
+ mBounder.setEmpty();
+ mBounder.setType(CommonCheck::kDrawGlyph_Type);
+ SkCanvas::drawPosText(text, byteLength, pos, paint);
+ mBounder.doRect(CommonCheck::kDrawPosText_Type);
+ }
+
+ virtual void drawPosTextH(const void* text, size_t byteLength,
+ const SkScalar xpos[], SkScalar constY,
+ const SkPaint& paint) {
+ mBounder.setEmpty();
+ mBounder.setType(CommonCheck::kDrawGlyph_Type);
+ SkCanvas::drawPosTextH(text, byteLength, xpos, constY, paint);
+ if (mBounder.mUnion.isEmpty())
+ return;
+ SkPaint::FontMetrics metrics;
+ paint.getFontMetrics(&metrics);
+ SkPoint upDown[2] = { {xpos[0], constY + metrics.fAscent},
+ {xpos[0], constY + metrics.fDescent} };
+ const SkMatrix& matrix = getTotalMatrix();
+ matrix.mapPoints(upDown, 2);
+ if (upDown[0].fX == upDown[1].fX) {
+ mBounder.mUnion.fTop = SkScalarFloor(upDown[0].fY);
+ mBounder.mUnion.fBottom = SkScalarFloor(upDown[1].fY);
+ }
+ mBounder.doRect(CommonCheck::kDrawPosTextH_Type);
+ }
+
+ virtual void drawTextOnPath(const void* text, size_t byteLength,
+ const SkPath& path, const SkMatrix* matrix,
+ const SkPaint& paint) {
+ mBounder.setEmpty();
+ mBounder.setType(CommonCheck::kDrawGlyph_Type);
+ SkCanvas::drawTextOnPath(text, byteLength, path, matrix, paint);
+ mBounder.doRect(CommonCheck::kDrawTextOnPath_Type);
+ }
+
+ virtual void drawPicture(SkPicture& picture) {
+ mBounder.setType(CommonCheck::kDrawPicture_Type);
+ SkCanvas::drawPicture(picture);
+ }
+
+ virtual int saveLayer(const SkRect* bounds, const SkPaint* paint,
+ SaveFlags flags) {
+ int depth = SkCanvas::saveLayer(bounds, paint, flags);
+ if (mTransparentLayer == 0 && paint && paint->getAlpha() < 255) {
+ mTransparentLayer = depth;
+ mBounder.setAllOpaque(false);
+ }
+ return depth;
+ }
+
+ virtual void restore() {
+ int depth = getSaveCount();
+ if (depth == mTransparentLayer) {
+ mTransparentLayer = 0;
+ mBounder.setAllOpaque(true);
+ }
+ SkCanvas::restore();
+ }
+
+ int mTransparentLayer;
+ CommonCheck& mBounder;
+};
+
+/*
+CenterCheck examines the text in a picture, within a viewable rectangle,
+and returns via center() the optimal amount to scroll in x to display the
+paragraph of text.
+
+The caller of CenterCheck has configured (but not allocated) a bitmap
+the height and three times the width of the view. The picture is drawn centered
+in the bitmap, so text that would be revealed, if the view was scrolled up to
+a view-width to the left or right, is considered.
+*/
+class CenterCheck : public CommonCheck {
+public:
+ CenterCheck(int x, int y, int width) : mX(x), mY(y),
+ mHitLeft(x), mHitRight(x), mMostLeft(INT_MAX), mMostRight(-INT_MAX),
+ mViewLeft(width), mViewRight(width << 1) {
+ mHit.set(x - CENTER_SLOP, y - CENTER_SLOP,
+ x + CENTER_SLOP, y + CENTER_SLOP);
+ mPartial.setEmpty();
+ }
+
+ int center() {
+ doRect(); // process the final line of text
+ /* If the touch coordinates aren't near any text, return 0 */
+ if (mHitLeft == mHitRight) {
+ DBG_NAV_LOGD("abort: mHitLeft=%d ==mHitRight", mHitLeft);
+ return 0;
+ }
+ int leftOver = mHitLeft - mViewLeft;
+ int rightOver = mHitRight - mViewRight;
+ int center;
+ /* If the touched text is too large to entirely fit on the screen,
+ center it. */
+ if (leftOver < 0 && rightOver > 0) {
+ center = (leftOver + rightOver) >> 1;
+ DBG_NAV_LOGD("overlap: leftOver=%d rightOver=%d center=%d",
+ leftOver, rightOver, center);
+ return center;
+ }
+ center = (mMostLeft + mMostRight) >> 1; // the paragraph center
+ if (leftOver > 0 && rightOver >= 0) { // off to the right
+ if (center > mMostLeft) // move to center loses left-most text?
+ center = mMostLeft;
+ } else if (rightOver < 0 && leftOver <= 0) { // off to the left
+ if (center < mMostRight) // move to center loses right-most text?
+ center = mMostRight;
+ } else {
+#ifdef DONT_CENTER_IF_ALREADY_VISIBLE
+ center = 0; // paragraph is already fully visible
+#endif
+ }
+ DBG_NAV_LOGD("scroll: leftOver=%d rightOver=%d center=%d",
+ leftOver, rightOver, center);
+ return center;
+ }
+
+protected:
+ virtual bool onIRect(const SkIRect& rect) {
+ if (joinGlyphs(rect)) // assembles glyphs into a text string
+ return false;
+ if (!isTextType(mType))
+ return false;
+ /* Text on one line may be broken into several parts. Reassemble
+ the text into a rectangle before considering it. */
+ if (rect.fTop < mPartial.fBottom && rect.fBottom >
+ mPartial.fTop && mPartial.fRight + CENTER_SLOP >= rect.fLeft) {
+ DBG_NAV_LOGD("join mPartial=(%d, %d, %d, %d) rect=(%d, %d, %d, %d)",
+ mPartial.fLeft, mPartial.fTop, mPartial.fRight, mPartial.fBottom,
+ rect.fLeft, rect.fTop, rect.fRight, rect.fBottom);
+ mPartial.join(rect);
+ return false;
+ }
+ if (mPartial.isEmpty() == false)
+ doRect(); // process the previous line of text
+ mPartial = rect;
+ return false;
+ }
+
+ void doRect()
+ {
+ /* Record the outer bounds of the lines of text that was 'hit' by the
+ touch coordinates, given some slop */
+ if (SkIRect::Intersects(mPartial, mHit)) {
+ if (mHitLeft > mPartial.fLeft)
+ mHitLeft = mPartial.fLeft;
+ if (mHitRight < mPartial.fRight)
+ mHitRight = mPartial.fRight;
+ DBG_NAV_LOGD("mHitLeft=%d mHitRight=%d", mHitLeft, mHitRight);
+ }
+ /* If the considered text is completely to the left or right of the
+ touch coordinates, skip it */
+ if (mPartial.fLeft > mX || mPartial.fRight < mX)
+ return;
+ int leftOver = mPartial.fLeft - mViewLeft;
+ int rightOver = mPartial.fRight - mViewRight;
+ /* If leftOver <= 0, the text starts off the screen.
+ If rightOver >= 0, the text ends off the screen.
+ */
+ if (leftOver <= 0 && rightOver >= 0) // discard wider than screen
+ return;
+#ifdef DONT_CENTER_IF_ALREADY_VISIBLE
+ if (leftOver > 0 && rightOver < 0) // discard already visible
+ return;
+#endif
+ /* record the smallest margins on the left and right */
+ if (mMostLeft > leftOver)
+ mMostLeft = leftOver;
+ if (mMostRight < rightOver)
+ mMostRight = rightOver;
+ DBG_NAV_LOGD("leftOver=%d rightOver=%d mMostLeft=%d mMostRight=%d",
+ leftOver, rightOver, mMostLeft, mMostRight);
+ }
+
+ static const int CENTER_SLOP = 10; // space between text parts and lines
+ /* const */ SkIRect mHit; // sloppy hit rectangle
+ SkIRect mPartial; // accumulated text bounds, per line
+ const int mX; // touch location
+ const int mY;
+ int mHitLeft; // touched text extremes
+ int mHitRight;
+ int mMostLeft; // paragraph extremes
+ int mMostRight;
+ const int mViewLeft; // middle third of 3x-wide view
+ const int mViewRight;
+};
+
+class ImageCheck : public CommonCheck {
+public:
+ ImageCheck() : mLastIsImage(false) {}
+
+ virtual bool onIRect(const SkIRect& rect) {
+ if (joinGlyphs(rect))
+ return false;
+ mLastIsImage = mType == kDrawBitmap_Type;
+ return false;
+ }
+
+ bool mLastIsImage;
+};
+
+class JiggleCheck : public CommonCheck {
+public:
+ JiggleCheck(int delta, int width) : mDelta(delta), mMaxX(width) {
+ mMaxJiggle = 0;
+ mMinX = mMinJiggle = abs(delta);
+ mMaxWidth = width + mMinX;
+ }
+
+ int jiggle() {
+ if (mMinJiggle > mMaxJiggle)
+ return mDelta;
+ int avg = (mMinJiggle + mMaxJiggle + 1) >> 1;
+ return mDelta < 0 ? -avg : avg;
+ }
+
+ virtual bool onIRect(const SkIRect& rect) {
+ if (joinGlyphs(rect))
+ return false;
+ if (mType != kDrawBitmap_Type && !isTextType(mType))
+ return false;
+ int min, max;
+ if (mDelta < 0) {
+ min = mMinX - rect.fLeft;
+ max = mMaxWidth - rect.fRight;
+ } else {
+ min = rect.fRight - mMaxX;
+ max = rect.fLeft;
+ }
+ if (min <= 0)
+ return false;
+ if (max >= mMinX)
+ return false;
+ if (mMinJiggle > min)
+ mMinJiggle = min;
+ if (mMaxJiggle < max)
+ mMaxJiggle = max;
+ return false;
+ }
+
+ int mDelta;
+ int mMaxJiggle;
+ int mMaxX;
+ int mMinJiggle;
+ int mMinX;
+ int mMaxWidth;
+};
+
+bool CachedRoot::adjustForScroll(BestData* best, CachedFrame::Direction direction,
+ WebCore::IntPoint* scrollPtr, bool findClosest)
+{
+ WebCore::IntRect newOutset;
+ const CachedNode* newNode = best->mNode;
+ // see if there's a middle node
+ // if the middle node is in the visited list,
+ // or if none was computed and the newNode is in the visited list,
+ // treat result as NULL
+ if (newNode != NULL && findClosest) {
+ if (best->bounds().intersects(mHistory->mPriorBounds) == false &&
+ checkBetween(best, direction))
+ newNode = best->mNode;
+ if (findClosest && maskIfHidden(best)) {
+ innerMove(document(), best, direction, scrollPtr, false);
+ return true;
+ }
+ newNode->focusRingBounds(&newOutset);
+ }
+ int delta;
+ bool newNodeInView = scrollDelta(newOutset, direction, &delta);
+ if (delta && scrollPtr && (newNode == NULL || newNodeInView == false ||
+ (best->mNavOutside && best->mWorkingOutside)))
+ *scrollPtr = WebCore::IntPoint(direction & UP_DOWN ? 0 : delta,
+ direction & UP_DOWN ? delta : 0);
+ return false;
+}
+
+
+int CachedRoot::checkForCenter(int x, int y) const
+{
+ int width = mViewBounds.width();
+ CenterCheck centerCheck(x + width - mViewBounds.x(), y - mViewBounds.y(),
+ width);
+ BoundsCanvas checker(&centerCheck);
+ SkBitmap bitmap;
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config, width * 3,
+ mViewBounds.height());
+ checker.setBitmapDevice(bitmap);
+ checker.translate(SkIntToScalar(width - mViewBounds.x()),
+ SkIntToScalar(-mViewBounds.y()));
+ checker.drawPicture(*mPicture);
+ return centerCheck.center();
+}
+
+void CachedRoot::checkForJiggle(int* xDeltaPtr) const
+{
+ int xDelta = *xDeltaPtr;
+ JiggleCheck jiggleCheck(xDelta, mViewBounds.width());
+ BoundsCanvas checker(&jiggleCheck);
+ SkBitmap bitmap;
+ int absDelta = abs(xDelta);
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config, mViewBounds.width() +
+ absDelta, mViewBounds.height());
+ checker.setBitmapDevice(bitmap);
+ checker.translate(SkIntToScalar(-mViewBounds.x() -
+ (xDelta < 0 ? xDelta : 0)), SkIntToScalar(-mViewBounds.y()));
+ checker.drawPicture(*mPicture);
+ *xDeltaPtr = jiggleCheck.jiggle();
+}
+
+const CachedNode* CachedRoot::findAt(const WebCore::IntRect& rect,
+ const CachedFrame** framePtr, int* x, int* y) const
+{
+ int best = INT_MAX;
+ (const_cast<CachedRoot*>(this))->resetClippedOut();
+ const CachedNode* directHit = NULL;
+ const CachedNode* node = findBestAt(rect, &best, &directHit, framePtr, x, y);
+ DBG_NAV_LOGD("node=%d (%p)", node == NULL ? 0 : node->index(),
+ node == NULL ? NULL : node->nodePointer());
+ if (node == NULL) {
+ node = findBestHitAt(rect, &best, framePtr, x, y);
+ DBG_NAV_LOGD("node=%d (%p)", node == NULL ? 0 : node->index(),
+ node == NULL ? NULL : node->nodePointer());
+ }
+ if (node == NULL) {
+ *framePtr = findBestFrameAt(rect.x() + (rect.width() >> 1),
+ rect.y() + (rect.height() >> 1));
+ }
+ return node;
+}
+
+WebCore::IntPoint CachedRoot::focusLocation() const
+{
+ const WebCore::IntRect& bounds = mHistory->mNavBounds;
+ return WebCore::IntPoint(bounds.x() + (bounds.width() >> 1),
+ bounds.y() + (bounds.height() >> 1));
+}
+
+// These reset the values because we only want to get the selection the first time.
+// After that, the selection is no longer accurate.
+int CachedRoot::getAndResetSelectionEnd()
+{
+ int end = mSelectionEnd;
+ mSelectionEnd = -1;
+ return end;
+}
+
+int CachedRoot::getAndResetSelectionStart()
+{
+ int start = mSelectionStart;
+ mSelectionStart = -1;
+ return start;
+}
+
+void CachedRoot::getSimulatedMousePosition(WebCore::IntPoint* point)
+{
+#ifndef NDEBUG
+ ASSERT(CachedFrame::mDebug.mInUse);
+#endif
+ const WebCore::IntRect& mouseBounds = mHistory->mMouseBounds;
+ point->setX(mouseBounds.x() + (mouseBounds.width() >> 1));
+ point->setY(mouseBounds.y() + (mouseBounds.height() >> 1));
+#if DEBUG_NAV_UI && !defined BROWSER_DEBUG
+ const WebCore::IntRect& navBounds = mHistory->mNavBounds;
+ LOGD("%s mHistory->mNavBounds={%d,%d,%d,%d} "
+ "mHistory->mMouseBounds={%d,%d,%d,%d} point={%d,%d}\n", __FUNCTION__,
+ navBounds.x(), navBounds.y(), navBounds.width(), navBounds.height(),
+ mouseBounds.x(), mouseBounds.y(), mouseBounds.width(), mouseBounds.height(),
+ point->x(), point->y());
+#endif
+}
+
+void CachedRoot::init(WebCore::FrameAndroid* frame, CachedHistory* history)
+{
+ CachedFrame::init(this, -1, frame);
+ reset();
+ mHistory = history;
+ mPicture = NULL;
+}
+
+bool CachedRoot::innerDown(const CachedNode* test, BestData* bestData) const
+{
+ ASSERT(minWorkingVertical() >= mViewBounds.x());
+ ASSERT(maxWorkingVertical() <= mViewBounds.right());
+ setupScrolledBounds();
+ // (line up)
+ mScrolledBounds.setHeight(mScrolledBounds.height() + mMaxYScroll);
+ int testTop = mScrolledBounds.y();
+ int viewBottom = mViewBounds.bottom();
+ if (mHistory->mFocusBounds.isEmpty() == false &&
+ mHistory->mFocusBounds.bottom() > viewBottom && viewBottom < mContents.height())
+ return false;
+ if (mHistory->mNavBounds.isEmpty() == false) {
+ int navTop = mHistory->mNavBounds.y();
+ int scrollBottom;
+ if (testTop < navTop && navTop < (scrollBottom = mScrolledBounds.bottom())) {
+ mScrolledBounds.setHeight(scrollBottom - navTop);
+ mScrolledBounds.setY(navTop);
+ }
+ }
+ frameDown(test, NULL, bestData, currentFocus());
+ return true;
+}
+
+bool CachedRoot::innerLeft(const CachedNode* test, BestData* bestData) const
+{
+ ASSERT(minWorkingHorizontal() >= mViewBounds.y());
+ ASSERT(maxWorkingHorizontal() <= mViewBounds.bottom());
+ setupScrolledBounds();
+ mScrolledBounds.setX(mScrolledBounds.x() - mMaxXScroll);
+ mScrolledBounds.setWidth(mScrolledBounds.width() + mMaxXScroll);
+ int testRight = mScrolledBounds.right();
+ int viewLeft = mViewBounds.x();
+ if (mHistory->mFocusBounds.isEmpty() == false &&
+ mHistory->mFocusBounds.x() < viewLeft && viewLeft > mContents.x())
+ return false;
+ if (mHistory->mNavBounds.isEmpty() == false) {
+ int navRight = mHistory->mNavBounds.right();
+ int scrollLeft;
+ if (testRight > navRight && navRight > (scrollLeft = mScrolledBounds.x()))
+ mScrolledBounds.setWidth(navRight - scrollLeft);
+ }
+ frameLeft(test, NULL, bestData, currentFocus());
+ return true;
+}
+
+
+void CachedRoot::innerMove(const CachedNode* node, BestData* bestData,
+ Direction direction, WebCore::IntPoint* scroll, bool firstCall)
+{
+ bestData->reset();
+ mFocusChild = false;
+ bool outOfFocus = mFocus < 0;
+ bool firstTime = mHistory->didFirstLayout() && outOfFocus;
+#if DEBUG_NAV_UI && !defined BROWSER_DEBUG
+ LOGD("%s mHistory->didFirstLayout()=%s && mFocus=%d\n", __FUNCTION__,
+ mHistory->didFirstLayout() ? "true" : "false", mFocus);
+#endif
+ if (firstTime)
+ mHistory->reset();
+ mHistory->setWorking(direction, currentFocus(), mViewBounds);
+ bool findClosest = false;
+ if (mScrollOnly == false) {
+ switch (direction) {
+ case LEFT:
+ if (outOfFocus)
+ mHistory->mNavBounds = WebCore::IntRect(mViewBounds.right(),
+ mViewBounds.y(), 1, mViewBounds.height());
+ findClosest = innerLeft(node, bestData);
+ break;
+ case RIGHT:
+ if (outOfFocus)
+ mHistory->mNavBounds = WebCore::IntRect(mViewBounds.x() - 1,
+ mViewBounds.y(), 1, mViewBounds.height());
+ findClosest = innerRight(node, bestData);
+ break;
+ case UP:
+ if (outOfFocus)
+ mHistory->mNavBounds = WebCore::IntRect(mViewBounds.x(),
+ mViewBounds.bottom(), mViewBounds.width(), 1);
+ findClosest = innerUp(node, bestData);
+ break;
+ case DOWN:
+ if (outOfFocus)
+ mHistory->mNavBounds = WebCore::IntRect(mViewBounds.x(),
+ mViewBounds.y() - 1, mViewBounds.width(), 1);
+ findClosest = innerDown(node, bestData);
+ break;
+ case UNINITIALIZED:
+ default:
+ ASSERT(0);
+ }
+ }
+ if (firstCall)
+ mHistory->mPriorBounds = mHistory->mNavBounds; // bounds always advances, even if new node is ultimately NULL
+ bestData->mMouseBounds = bestData->mNodeBounds;
+ if (adjustForScroll(bestData, direction, scroll, findClosest))
+ return;
+ if (bestData->mNode != NULL) {
+ mHistory->addToVisited(bestData->mNode, direction);
+ mHistory->mNavBounds = mHistory->mFocusBounds = bestData->mNodeBounds;
+ mHistory->mMouseBounds = bestData->mMouseBounds;
+ } else if (scroll->x() != 0 || scroll->y() != 0) {
+ WebCore::IntRect newBounds = mHistory->mNavBounds;
+ int offsetX = scroll->x();
+ int offsetY = scroll->y();
+ newBounds.move(offsetX, offsetY);
+ if (mViewBounds.x() > newBounds.x())
+ offsetX = mViewBounds.x() - mHistory->mNavBounds.x();
+ else if (mViewBounds.right() < newBounds.right())
+ offsetX = mViewBounds.right() - mHistory->mNavBounds.right();
+ if (mViewBounds.y() > newBounds.y())
+ offsetY = mViewBounds.y() - mHistory->mNavBounds.y();
+ else if (mViewBounds.bottom() < newBounds.bottom())
+ offsetY = mViewBounds.bottom() - mHistory->mNavBounds.bottom();
+ mHistory->mNavBounds.move(offsetX, offsetY);
+ }
+ mHistory->setDidFirstLayout(false);
+}
+
+bool CachedRoot::innerRight(const CachedNode* test, BestData* bestData) const
+{
+ ASSERT(minWorkingHorizontal() >= mViewBounds.y());
+ ASSERT(maxWorkingHorizontal() <= mViewBounds.bottom());
+ setupScrolledBounds();
+ // (align)
+ mScrolledBounds.setWidth(mScrolledBounds.width() + mMaxXScroll);
+ int testLeft = mScrolledBounds.x();
+ int viewRight = mViewBounds.right();
+ if (mHistory->mFocusBounds.isEmpty() == false &&
+ mHistory->mFocusBounds.right() > viewRight && viewRight < mContents.width())
+ return false;
+ if (mHistory->mNavBounds.isEmpty() == false) {
+ int navLeft = mHistory->mNavBounds.x();
+ int scrollRight;
+ if (testLeft < navLeft && navLeft < (scrollRight = mScrolledBounds.right())) {
+ mScrolledBounds.setWidth(scrollRight - navLeft);
+ mScrolledBounds.setX(navLeft);
+ }
+ }
+ frameRight(test, NULL, bestData, currentFocus());
+ return true;
+}
+
+bool CachedRoot::innerUp(const CachedNode* test, BestData* bestData) const
+{
+ ASSERT(minWorkingVertical() >= mViewBounds.x());
+ ASSERT(maxWorkingVertical() <= mViewBounds.right());
+ setupScrolledBounds();
+ mScrolledBounds.setY(mScrolledBounds.y() - mMaxYScroll);
+ mScrolledBounds.setHeight(mScrolledBounds.height() + mMaxYScroll);
+ int testBottom = mScrolledBounds.bottom();
+ int viewTop = mViewBounds.y();
+ if (mHistory->mFocusBounds.isEmpty() == false &&
+ mHistory->mFocusBounds.y() < viewTop && viewTop > mContents.y())
+ return false;
+ if (mHistory->mNavBounds.isEmpty() == false) {
+ int navBottom = mHistory->mNavBounds.bottom();
+ int scrollTop;
+ if (testBottom > navBottom && navBottom > (scrollTop = mScrolledBounds.y()))
+ mScrolledBounds.setHeight(navBottom - scrollTop);
+ }
+ frameUp(test, NULL, bestData, currentFocus());
+ return true;
+}
+
+bool CachedRoot::isImage(int x, int y) const
+{
+ ImageCheck imageCheck;
+ BoundsCanvas checker(&imageCheck);
+ SkBitmap bitmap;
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config, 1, 1);
+ checker.setBitmapDevice(bitmap);
+ checker.translate(SkIntToScalar(-x), SkIntToScalar(-y));
+ checker.drawPicture(*mPicture);
+ return imageCheck.mLastIsImage;
+}
+
+bool CachedRoot::maskIfHidden(BestData* best) const
+{
+ if (mPicture == NULL) {
+#if DEBUG_NAV_UI && !defined BROWSER_DEBUG
+ LOGD("%s missing picture\n", __FUNCTION__);
+#endif
+ return false;
+ }
+ const CachedNode* bestNode = best->mNode;
+ if (bestNode->isUnclipped())
+ return false;
+ // given the picture matching this nav cache
+ // create an SkBitmap with dimensions of the focus intersected w/ extended view
+ const WebCore::IntRect& nodeBounds = bestNode->getBounds();
+ WebCore::IntRect bounds = nodeBounds;
+ bounds.intersect(mScrolledBounds);
+ int leftMargin = bounds.x() == nodeBounds.x() ? kMargin : 0;
+ int topMargin = bounds.y() == nodeBounds.y() ? kMargin : 0;
+ int rightMargin = bounds.right() == nodeBounds.right() ? kMargin : 0;
+ int bottomMargin = bounds.bottom() == nodeBounds.bottom() ? kMargin : 0;
+ bool unclipped = (leftMargin & topMargin & rightMargin & bottomMargin) != 0;
+ WebCore::IntRect marginBounds = nodeBounds;
+ marginBounds.inflate(kMargin);
+ marginBounds.intersect(mScrolledBounds);
+ BoundsCheck boundsCheck;
+ BoundsCanvas checker(&boundsCheck);
+ boundsCheck.mBounds.set(leftMargin, topMargin,
+ leftMargin + bounds.width(), topMargin + bounds.height());
+ boundsCheck.mBoundsSlop = boundsCheck.mBounds;
+ boundsCheck.mBoundsSlop.inset(-kSlop, -kSlop);
+ SkBitmap bitmap;
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config, marginBounds.width(),
+ marginBounds.height());
+ checker.setBitmapDevice(bitmap);
+ // insert probes to be called when the data corresponding to this focus ring is drawn
+ // need to know if focus ring was generated by text, image, or parent (like div)
+ // ? need to know (like imdb menu bar) to give up sometimes (when?)
+ checker.translate(SkIntToScalar(leftMargin - bounds.x()),
+ SkIntToScalar(topMargin - bounds.y()));
+ checker.drawPicture(*mPicture);
+ boundsCheck.checkLast();
+ // was it not drawn or clipped out?
+ if (boundsCheck.hidden()) { // if hidden, return false so that nav can try again
+ CachedNode* node = const_cast<CachedNode*>(best->mNode);
+#if DEBUG_NAV_UI && !defined BROWSER_DEBUG
+ const SkIRect& m = boundsCheck.mBounds;
+ const SkIRect& s = boundsCheck.mBoundsSlop;
+ LOGD("%s hidden node:%p (%d) mBounds={%d,%d,%d,%d} mBoundsSlop="
+ "{%d,%d,%d,%d}\n", __FUNCTION__, node, node->index(),
+ m.fLeft, m.fTop, m.fRight, m.fBottom,
+ s.fLeft, s.fTop, s.fRight, s.fBottom);
+ const SkIRect& o = boundsCheck.mDrawnOver.getBounds();
+ const SkIRect& l = boundsCheck.mLastAll;
+ const SkIRect& u = boundsCheck.mUnion;
+ LOGD("%s hidden mDrawnOver={%d,%d,%d,%d} mLastAll={%d,%d,%d,%d}"
+ " mUnion={%d,%d,%d,%d}\n", __FUNCTION__,
+ o.fLeft, o.fTop, o.fRight, o.fBottom,
+ l.fLeft, l.fTop, l.fRight, l.fBottom,
+ u.fLeft, u.fTop, u.fRight, u.fBottom);
+ const SkIRect& a = boundsCheck.mAllDrawnIn;
+ const WebCore::IntRect& c = mScrolledBounds;
+ const WebCore::IntRect& b = nodeBounds;
+ LOGD("%s hidden mAllDrawnIn={%d,%d,%d,%d} mScrolledBounds={%d,%d,%d,%d}"
+ " nodeBounds={%d,%d,%d,%d}\n", __FUNCTION__,
+ a.fLeft, a.fTop, a.fRight, a.fBottom,
+ c.x(), c.y(), c.right(), c.bottom(),
+ b.x(), b.y(), b.right(), b.bottom());
+ LOGD("%s bits.mWidth=%d bits.mHeight=%d transX=%d transY=%d\n", __FUNCTION__,
+ marginBounds.width(),marginBounds.height(),
+ kMargin - bounds.x(), kMargin - bounds.y());
+#endif
+ node->setDisabled(true);
+ node->setClippedOut(unclipped == false);
+ return true;
+ }
+ // was it partially occluded by later drawing?
+ // if partially occluded, modify the bounds so that the mouse click has a better x,y
+ const SkIRect& over = boundsCheck.mDrawnOver.getBounds();
+ if (over.isEmpty() == false) {
+#if DEBUG_NAV_UI && !defined BROWSER_DEBUG
+ SkIRect orig = boundsCheck.mBounds;
+#endif
+ SkIRect& base = boundsCheck.mBounds;
+ if (base.fLeft < over.fRight && base.fRight > over.fRight)
+ base.fLeft = over.fRight;
+ else if (base.fRight > over.fLeft && base.fLeft < over.fLeft)
+ base.fRight = over.fLeft;
+ if (base.fTop < over.fBottom && base.fBottom > over.fBottom)
+ base.fTop = over.fBottom;
+ else if (base.fBottom > over.fTop && base.fTop < over.fTop)
+ base.fBottom = over.fTop;
+#if DEBUG_NAV_UI && !defined BROWSER_DEBUG
+ const SkIRect& modded = boundsCheck.mBounds;
+ LOGD("%s partially occluded node:%p (%d) old:{%d,%d,%d,%d} new:{%d,%d,%d,%d}\n",
+ __FUNCTION__, best->mNode, best->mNode->index(),
+ orig.fLeft, orig.fTop, orig.fRight, orig.fBottom,
+ base.fLeft, base.fTop, base.fRight, base.fBottom);
+#endif
+ best->mMouseBounds = WebCore::IntRect(bounds.x() + base.fLeft - kMargin,
+ bounds.y() + base.fTop - kMargin, base.width(), base.height());
+ }
+ return false;
+}
+
+const CachedNode* CachedRoot::moveFocus(Direction direction, const CachedFrame** framePtr,
+ WebCore::IntPoint* scroll)
+{
+#ifndef NDEBUG
+ ASSERT(CachedFrame::mDebug.mInUse);
+#endif
+ CachedRoot* frame = this;
+ const CachedNode* node = frame->document();
+ if (node == NULL)
+ return NULL;
+ if (mViewBounds.isEmpty())
+ return NULL;
+ resetClippedOut();
+ setData();
+ BestData bestData;
+ innerMove(node, &bestData, direction, scroll, true);
+ *framePtr = bestData.mFrame;
+ return const_cast<CachedNode*>(bestData.mNode);
+}
+
+void CachedRoot::reset()
+{
+#ifndef NDEBUG
+ ASSERT(CachedFrame::mDebug.mInUse);
+#endif
+ mContents = mViewBounds = WebCore::IntRect(0, 0, 0, 0);
+ mMaxXScroll = mMaxYScroll = 0;
+ mSelectionStart = mSelectionEnd = -1;
+ mScrollOnly = false;
+// resetNavClipBounds();
+}
+
+bool CachedRoot::scrollDelta(WebCore::IntRect& newOutset, Direction direction, int* delta)
+{
+ switch (direction) {
+ case LEFT:
+ *delta = -mMaxXScroll;
+ return newOutset.x() >= mViewBounds.x();
+ case RIGHT:
+ *delta = mMaxXScroll;
+ return newOutset.right() <= mViewBounds.right();
+ case UP:
+ *delta = -mMaxYScroll;
+ return newOutset.y() >= mViewBounds.y();
+ case DOWN:
+ *delta = mMaxYScroll;
+ return newOutset.bottom() <= mViewBounds.bottom();
+ default:
+ *delta = 0;
+ ASSERT(0);
+ }
+ return false;
+}
+
+void CachedRoot::setCachedFocus(CachedFrame* frame, CachedNode* node)
+{
+#if !defined NDEBUG
+ ASSERT(CachedFrame::mDebug.mInUse);
+#endif
+#if DEBUG_NAV_UI && !defined BROWSER_DEBUG
+ const CachedNode* focus = currentFocus();
+ WebCore::IntRect bounds;
+ if (focus)
+ bounds = focus->bounds();
+ LOGD("%s old focus %d (nodePointer=%p) bounds={%d,%d,%d,%d}\n", __FUNCTION__,
+ focus ? focus->index() : 0,
+ focus ? focus->nodePointer() : NULL, bounds.x(), bounds.y(),
+ bounds.width(), bounds.height());
+#endif
+ clearFocus();
+ if (node == NULL)
+ return;
+ node->setIsFocus(true);
+ ASSERT(node->isFrame() == false);
+ frame->setFocusIndex(node - frame->document());
+ ASSERT(frame->focusIndex() > 0 && frame->focusIndex() < (int) frame->size());
+ CachedFrame* parent;
+ while ((parent = frame->parent()) != NULL) {
+ parent->setFocusIndex(frame->indexInParent());
+ frame = parent;
+ }
+#if DEBUG_NAV_UI && !defined BROWSER_DEBUG
+ focus = currentFocus();
+ bounds = WebCore::IntRect(0, 0, 0, 0);
+ if (focus)
+ bounds = focus->bounds();
+ LOGD("%s new focus %d (nodePointer=%p) bounds={%d,%d,%d,%d}\n", __FUNCTION__,
+ focus ? focus->index() : 0,
+ focus ? focus->nodePointer() : NULL, bounds.x(), bounds.y(),
+ bounds.width(), bounds.height());
+#endif
+}
+
+void CachedRoot::setupScrolledBounds() const
+{
+ mScrolledBounds = mViewBounds;
+}
+
+#if DUMP_NAV_CACHE
+
+#define DEBUG_PRINT_BOOL(field) \
+ DUMP_NAV_LOGD("// bool " #field "=%s;\n", b->field ? "true" : "false")
+
+CachedRoot* CachedRoot::Debug::base() const {
+ CachedRoot* nav = (CachedRoot*) ((char*) this - OFFSETOF(CachedRoot, mDebug));
+ return nav;
+}
+
+void CachedRoot::Debug::print() const
+{
+#ifdef DUMP_NAV_CACHE_USING_PRINTF
+ gWriteLogMutex.lock();
+ ASSERT(gNavCacheLogFile == NULL);
+ gNavCacheLogFile = fopen(NAV_CACHE_LOG_FILE, "a");
+#endif
+ CachedRoot* b = base();
+ b->CachedFrame::mDebug.print();
+ b->mHistory->mDebug.print(b);
+ DUMP_NAV_LOGD("// int mMaxXScroll=%d, mMaxYScroll=%d;\n",
+ b->mMaxXScroll, b->mMaxYScroll);
+ DEBUG_PRINT_BOOL(mFocusChild);
+#ifdef DUMP_NAV_CACHE_USING_PRINTF
+ if (gNavCacheLogFile)
+ fclose(gNavCacheLogFile);
+ gNavCacheLogFile = NULL;
+ gWriteLogMutex.unlock();
+#endif
+}
+
+#endif
+
+}
diff --git a/WebCore/platform/android/nav/CachedRoot.h b/WebCore/platform/android/nav/CachedRoot.h
new file mode 100644
index 0000000..e28141e
--- /dev/null
+++ b/WebCore/platform/android/nav/CachedRoot.h
@@ -0,0 +1,101 @@
+/*
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef CachedRoot_H
+#define CachedRoot_H
+
+#include "CachedFrame.h"
+#include "IntPoint.h"
+#include "SkPicture.h"
+
+namespace android {
+
+class CachedHistory;
+class CachedNode;
+
+class CachedRoot : public CachedFrame {
+public:
+ bool adjustForScroll(BestData* , Direction , WebCore::IntPoint* scrollPtr,
+ bool findClosest);
+ int checkForCenter(int x, int y) const;
+ void checkForJiggle(int* ) const;
+ int documentHeight() { return mContents.height(); }
+ int documentWidth() { return mContents.width(); }
+ const CachedNode* findAt(const WebCore::IntRect& , const CachedFrame** ,
+ int* x, int* y) const;
+ bool focusChild() const { return mFocusChild; }
+ WebCore::IntPoint focusLocation() const;
+ int generation() const { return mGeneration; }
+ int textGeneration() const { return mTextGeneration; }
+ int getAndResetSelectionEnd();
+ int getAndResetSelectionStart();
+// const WebCore::IntRect& navClipBounds() const { return mClippedBounds; }
+ void getSimulatedMousePosition(WebCore::IntPoint* );
+// bool hasNavClipBounds() { return mClippedBounds.isEmpty() == false; }
+ void init(WebCore::FrameAndroid* , CachedHistory* );
+ bool innerDown(const CachedNode* , BestData* ) const;
+ bool innerLeft(const CachedNode* , BestData* ) const;
+ void innerMove(const CachedNode* ,BestData* bestData, Direction ,
+ WebCore::IntPoint* scroll, bool firstCall);
+ bool innerRight(const CachedNode* , BestData* ) const;
+ bool innerUp(const CachedNode* , BestData* ) const;
+ bool isImage(int x, int y) const;
+ bool maskIfHidden(BestData* ) const;
+ const CachedNode* moveFocus(Direction , const CachedFrame** , WebCore::IntPoint* scroll);
+ void reset();
+// void resetNavClipBounds() { mClippedBounds = WebCore::IntRect(-1, -1, 0, 0); }
+ CachedHistory* rootHistory() const { return mHistory; }
+ bool scrollDelta(WebCore::IntRect& focusRingBounds, Direction , int* delta);
+ const WebCore::IntRect& scrolledBounds() const { return mScrolledBounds; }
+ void setCachedFocus(CachedFrame* , CachedNode* );
+ void setGeneration(int generation) { mGeneration = generation; }
+ void setTextGeneration(int textGeneration) { mTextGeneration = textGeneration; }
+ void setFocusChild(bool state) const { mFocusChild = state; }
+ void setMaxScroll(int x, int y) { mMaxXScroll = x; mMaxYScroll = y; }
+// void setNavClipBounds(const WebCore::IntRect& r) { mClippedBounds = r; }
+ void setPicture(SkPicture* picture) { mPicture = picture; }
+ void setScrollOnly(bool state) { mScrollOnly = state; }
+ void setSelection(int start, int end) { mSelectionStart = start; mSelectionEnd = end; }
+ void setupScrolledBounds() const;
+ void setVisibleRect(const WebCore::IntRect& r) { mViewBounds = r; }
+ int width() const { return mPicture ? mPicture->width() : 0; }
+private:
+ CachedHistory* mHistory;
+ SkPicture* mPicture;
+ // WebCore::IntRect mClippedBounds;
+ mutable WebCore::IntRect mScrolledBounds; // view bounds + amount visible as result of scroll
+ int mGeneration;
+ int mTextGeneration;
+ int mMaxXScroll;
+ int mMaxYScroll;
+ // These two are ONLY used when the tree is rebuilt and the focus is a textfield/area
+ int mSelectionStart;
+ int mSelectionEnd;
+ mutable bool mFocusChild; // temporary state set if walked nodes are children of focus
+ bool mScrollOnly;
+#if DUMP_NAV_CACHE
+public:
+ class Debug {
+public:
+ CachedRoot* base() const;
+ void print() const;
+ } mDebug;
+#endif
+};
+
+}
+
+#endif
diff --git a/WebCore/platform/android/nav/SelectText.cpp b/WebCore/platform/android/nav/SelectText.cpp
new file mode 100644
index 0000000..e84d2dc
--- /dev/null
+++ b/WebCore/platform/android/nav/SelectText.cpp
@@ -0,0 +1,246 @@
+/*
+ * Copyright 2008, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "webcoreglue"
+
+#include <config.h>
+#include "CachedDebug.h"
+#include "SelectText.h"
+#include "SkBitmap.h"
+#include "SkBounder.h"
+#include "SkCanvas.h"
+#include "SkMatrix.h"
+#include "SkPicture.h"
+#include "SkPoint.h"
+#include "SkRect.h"
+#include "SkRegion.h"
+
+#ifdef LOG
+#undef LOG
+#endif
+
+#include <utils/Log.h>
+
+class CommonCheck : public SkBounder {
+public:
+ CommonCheck() : mMatrix(NULL), mPaint(NULL) {}
+
+ virtual void setUp(const SkPaint& paint, const SkMatrix& matrix, SkScalar y) {
+ mMatrix = &matrix;
+ mPaint = &paint;
+ mY = y;
+ mTop = INT_MAX;
+ mBottom = INT_MAX;
+ }
+
+ int top() {
+ if (mTop == INT_MAX) {
+ SkPoint result;
+ SkPaint::FontMetrics metrics;
+ mPaint->getFontMetrics(&metrics);
+ mMatrix->mapXY(0, metrics.fAscent + mY, &result);
+ mTop = SkScalarFloor(result.fY);
+ DBG_NAV_LOGD("mMatrix:(%d, %d) mTop=%g",
+ mMatrix->getTranslateX(), mMatrix->getTranslateY(), mTop);
+ }
+ return mTop;
+ }
+
+ int bottom() {
+ if (mBottom == INT_MAX) {
+ SkPoint result;
+ SkPaint::FontMetrics metrics;
+ mPaint->getFontMetrics(&metrics);
+ mMatrix->mapXY(0, metrics.fDescent + mY, &result);
+ mBottom = SkScalarCeil(result.fY);
+ }
+ return mBottom;
+ }
+
+protected:
+ const SkMatrix* mMatrix;
+ const SkPaint* mPaint;
+ int mBottom;
+ int mTop;
+ SkScalar mY;
+};
+
+class FirstCheck : public CommonCheck {
+public:
+ FirstCheck(int x, int y)
+ : mDistance(INT_MAX), mFocusX(x), mFocusY(y) {
+ mBestBounds.setEmpty();
+ }
+
+ const SkIRect& bestBounds() {
+ DBG_NAV_LOGD("mBestBounds:(%d, %d, %d, %d) mTop=%g mBottom=%g",
+ mBestBounds.fLeft, mBestBounds.fTop, mBestBounds.fRight,
+ mBestBounds.fBottom, SkScalarToFloat(mTop), SkScalarToFloat(mBottom));
+ return mBestBounds;
+ }
+
+ void offsetBounds(int dx, int dy) {
+ mBestBounds.offset(dx, dy);
+ }
+
+ virtual bool onIRect(const SkIRect& rect) {
+ if (mBestBounds.isEmpty()) {
+ mBestBounds.set(rect.fLeft, top(), rect.fRight, bottom());
+ } else {
+ int dx = ((rect.fLeft + rect.fRight) >> 1) - mFocusX;
+ int dy = SkScalarRound(((top() + bottom()) / 2)) - mFocusY;
+ int distance = dx * dx + dy * dy;
+ if (mDistance > distance) {
+ mDistance = distance;
+ mBestBounds.set(rect.fLeft, top(), rect.fRight, bottom());
+ }
+ }
+ return false;
+ }
+protected:
+ SkIRect mBestBounds;
+ int mDistance;
+ int mFocusX;
+ int mFocusY;
+};
+
+class MultilineBuilder : public CommonCheck {
+public:
+ MultilineBuilder(const SkIRect& start, const SkIRect& end, int dx, int dy,
+ SkRegion* region)
+ : mStart(start), mEnd(end), mSelectRegion(region), mCapture(false) {
+ mLast.setEmpty();
+ mStart.offset(-dx, -dy);
+ mEnd.offset(-dx, -dy);
+ }
+
+ virtual bool onIRect(const SkIRect& rect) {
+ bool captureLast = false;
+ if ((rect.fLeft == mStart.fLeft && rect.fRight == mStart.fRight &&
+ top() == mStart.fTop && bottom() == mStart.fBottom) ||
+ (rect.fLeft == mEnd.fLeft && rect.fRight == mEnd.fRight &&
+ top() == mEnd.fTop && bottom() == mEnd.fBottom)) {
+ captureLast = mCapture;
+ mCapture ^= true;
+ }
+ if (mCapture || captureLast) {
+ SkIRect full;
+ full.set(rect.fLeft, top(), rect.fRight, bottom());
+ if (mLast.fTop < full.fBottom && mLast.fBottom > full.fTop) {
+ if (full.fLeft > mLast.fRight)
+ full.fLeft = mLast.fRight;
+ else if (full.fRight < mLast.fLeft)
+ full.fRight = mLast.fLeft;
+ }
+ mSelectRegion->op(full, SkRegion::kUnion_Op);
+ mLast = full;
+ if (mStart == mEnd)
+ mCapture = false;
+ }
+ return false;
+ }
+protected:
+ SkIRect mStart;
+ SkIRect mEnd;
+ SkIRect mLast;
+ SkRegion* mSelectRegion;
+ bool mCapture;
+};
+
+class TextCanvas : public SkCanvas {
+public:
+
+ TextCanvas(CommonCheck* bounder, const SkPicture& picture, const SkIRect& area)
+ : mBounder(*bounder) {
+ setBounder(bounder);
+ SkBitmap bitmap;
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config, area.width(),
+ area.height());
+ setBitmapDevice(bitmap);
+ translate(SkIntToScalar(-area.fLeft), SkIntToScalar(-area.fTop));
+ }
+
+ virtual ~TextCanvas() {
+ setBounder(NULL);
+ }
+
+ virtual void drawPaint(const SkPaint& paint) {
+ }
+
+ virtual void drawPoints(PointMode mode, size_t count, const SkPoint pts[],
+ const SkPaint& paint) {
+ }
+
+ virtual void drawRect(const SkRect& rect, const SkPaint& paint) {
+ }
+
+ virtual void drawPath(const SkPath& path, const SkPaint& paint) {
+ }
+
+ virtual void commonDrawBitmap(const SkBitmap& bitmap,
+ const SkMatrix& matrix, const SkPaint& paint) {
+ }
+
+ virtual void drawSprite(const SkBitmap& bitmap, int left, int top,
+ const SkPaint* paint = NULL) {
+ }
+
+ virtual void drawText(const void* text, size_t byteLength, SkScalar x,
+ SkScalar y, const SkPaint& paint) {
+ mBounder.setUp(paint, getTotalMatrix(), y);
+ SkCanvas::drawText(text, byteLength, x, y, paint);
+ }
+
+ virtual void drawPosTextH(const void* text, size_t byteLength,
+ const SkScalar xpos[], SkScalar constY,
+ const SkPaint& paint) {
+ mBounder.setUp(paint, getTotalMatrix(), constY);
+ SkCanvas::drawPosTextH(text, byteLength, xpos, constY, paint);
+ }
+
+ virtual void drawVertices(VertexMode vmode, int vertexCount,
+ const SkPoint vertices[], const SkPoint texs[],
+ const SkColor colors[], SkXfermode* xmode,
+ const uint16_t indices[], int indexCount,
+ const SkPaint& paint) {
+ }
+
+ CommonCheck& mBounder;
+};
+
+void CopyPaste::buildSelection(const SkPicture& picture, const SkIRect& area,
+ const SkIRect& selStart, const SkIRect& selEnd, SkRegion* region) {
+ DBG_NAV_LOGD("area=(%d, %d, %d, %d) selStart=(%d, %d, %d, %d)"
+ " selEnd=(%d, %d, %d, %d)",
+ area.fLeft, area.fTop, area.fRight, area.fBottom,
+ selStart.fLeft, selStart.fTop, selStart.fRight, selStart.fBottom,
+ selEnd.fLeft, selEnd.fTop, selEnd.fRight, selEnd.fBottom);
+ MultilineBuilder builder(selStart, selEnd, area.fLeft, area.fTop, region);
+ TextCanvas checker(&builder, picture, area);
+ checker.drawPicture(const_cast<SkPicture&>(picture));
+ region->translate(area.fLeft, area.fTop);
+}
+
+SkIRect CopyPaste::findClosest(const SkPicture& picture, const SkIRect& area,
+ int x, int y) {
+ FirstCheck _check(x - area.fLeft, y - area.fTop);
+ DBG_NAV_LOGD("area=(%d, %d, %d, %d) x=%d y=%d", area.fLeft, area.fTop,
+ area.fRight, area.fBottom, x, y);
+ TextCanvas checker(&_check, picture, area);
+ checker.drawPicture(const_cast<SkPicture&>(picture));
+ _check.offsetBounds(area.fLeft, area.fTop);
+ return _check.bestBounds();
+}
diff --git a/WebCore/platform/android/nav/SelectText.h b/WebCore/platform/android/nav/SelectText.h
new file mode 100644
index 0000000..ba0b089
--- /dev/null
+++ b/WebCore/platform/android/nav/SelectText.h
@@ -0,0 +1,34 @@
+/*
+ *
+ * Copyright 2008, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SELECT_TEXT_H
+#define SELECT_TEXT_H
+
+class SkPicture;
+struct SkIRect;
+struct SkIPoint;
+class SkRegion;
+
+class CopyPaste {
+public:
+ static void buildSelection(const SkPicture& , const SkIRect& area,
+ const SkIRect& selStart, const SkIRect& selEnd, SkRegion* region);
+ static SkIRect findClosest(const SkPicture& , const SkIRect& area,
+ int x, int y);
+};
+
+#endif
diff --git a/WebCore/platform/android/nav/WebView.cpp b/WebCore/platform/android/nav/WebView.cpp
new file mode 100644
index 0000000..7e4791d
--- /dev/null
+++ b/WebCore/platform/android/nav/WebView.cpp
@@ -0,0 +1,1922 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "webviewglue"
+
+#include <config.h>
+
+#include "android_graphics.h"
+#include "AtomicString.h"
+#include "CachedFrame.h"
+#include "CachedNode.h"
+#include "CachedRoot.h"
+#include "Frame.h"
+#include "GraphicsJNI.h"
+#include "IntPoint.h"
+#include "IntRect.h"
+#include "Node.h"
+#include "PlatformGraphicsContext.h"
+#include "PlatformString.h"
+#include "SelectText.h"
+#include "SkCanvas.h"
+#include "SkPath.h"
+#include "SkPicture.h"
+#include "SkPixelXorXfermode.h"
+#include "SkRect.h"
+#include "SkTime.h"
+#include "WebViewCore.h"
+
+#ifdef LOG // WebKit may define this as well; if so, undefine it so LOGD will work
+#undef LOG
+#endif
+
+#ifdef GET_NATIVE_VIEW
+#undef GET_NATIVE_VIEW
+#endif
+
+#define GET_NATIVE_VIEW(env, obj) ((WebView*)env->GetIntField(obj, gWebViewField))
+
+#include <ui/KeycodeLabels.h>
+#include <utils/Log.h>
+#include <JNIHelp.h>
+#include <jni.h>
+
+#define REPLAY_BUFFER_SIZE 4096
+
+namespace android {
+
+// This class provides JNI for making calls into native code from the UI side
+// of the multi-threaded WebView.
+struct CommonParams {
+ enum Trigger {
+ NO_DATA,
+ CLEAR_FOCUS_PARAMS,
+ FIRST_MOVE_FOCUS_PARAMS,
+ MOVE_FOCUS_PARAMS,
+ MOTION_UP_PARAMS
+ } mTrigger;
+ int mGeneration;
+};
+
+struct CacheParams {
+ void setFocus(const CachedNode* node,
+ const CachedFrame* frame, const CachedRoot* root,
+ const WebCore::IntPoint& focusLocation)
+ {
+ mNode = (WebCore::Node* ) (node ? node->nodePointer() : NULL);
+ mFrame = (WebCore::Frame* ) (node ? frame->framePointer() : NULL);
+ mX = focusLocation.x();
+ mY = focusLocation.y();
+ }
+
+ WebCore::Node* mNode;
+ WebCore::Frame* mFrame;
+ int mX;
+ int mY;
+};
+
+struct ClearFocusParams {
+ CommonParams d;
+ CacheParams c;
+ int mX;
+ int mY;
+};
+
+struct MotionUpParams {
+ CommonParams d;
+ int mX;
+ int mY;
+ int mSlop;
+ bool mIsClick;
+};
+
+struct FirstMoveFocusParams {
+ CommonParams d;
+ int mKeyCode;
+ int mCount;
+ bool mIgnoreScroll;
+};
+
+struct MoveFocusParams {
+ FirstMoveFocusParams d;
+ CacheParams c;
+ void* mSentFocus;
+ WebCore::IntRect mClipRect;
+ WebCore::IntRect mSentBounds;
+ WebCore::IntRect mVisibleRect;
+ CachedHistory mHistory; // FIXME: make this a subset
+ int mXMax;
+ int mYMax;
+};
+
+typedef MoveFocusParams LargestParams;
+
+#if DEBUG_NAV_UI
+static const char* TriggerNames[] = {
+ "*** no data ! ***",
+ "clearFocus",
+ "firstMoveFocus",
+ "moveFocus",
+ "motionUp"
+};
+#endif
+
+class FocusReplay {
+public:
+FocusReplay() : mStart(mBuffer), mEnd(mBuffer), mLastGeneration(0)
+{
+}
+
+// find the most recent common data
+void add(const CommonParams& data, size_t len)
+{
+ DBG_NAV_LOGD("mStart=%d mEnd=%d trigger=%s moveGeneration=%d", mStart - mBuffer,
+ mEnd - mBuffer, TriggerNames[data.mTrigger], data.mGeneration);
+ mLastGeneration = data.mGeneration;
+ char* limit = mBuffer + sizeof(mBuffer);
+ int used = mEnd - mStart;
+ if (used < 0)
+ used += sizeof(mBuffer);
+ int needed = (int) len - ((int) sizeof(mBuffer) - used);
+ if (needed >= 0)
+ reclaim(++needed);
+ if (mEnd + len <= limit) {
+ memcpy(mEnd, (void*) &data, len);
+ mEnd += len;
+ DBG_NAV_LOGD("mStart=%d mEnd=%d", mStart - mBuffer, mEnd - mBuffer);
+ return;
+ }
+ size_t partial = limit - mEnd;
+ memcpy(mEnd, (void*) &data, partial);
+ const void* remainder = (const void*) ((const char*) &data + partial);
+ partial = len - partial;
+ memcpy(mBuffer, remainder, partial);
+ mEnd = mBuffer + partial;
+ DBG_NAV_LOGD("wrap mStart=%d mEnd=%d",
+ mStart - mBuffer, mEnd - mBuffer);
+}
+
+int count()
+{
+ DBG_NAV_LOGD("mStart=%d mEnd=%d",
+ mStart - mBuffer, mEnd - mBuffer);
+ if (mStart == mEnd)
+ return 0;
+ char* limit = mBuffer + sizeof(mBuffer);
+ char* saveStart = mStart;
+ int result = 0;
+ while (true) {
+ ++result;
+ mStart += triggerSize();
+ if (mStart == mEnd)
+ break;
+ if (mStart >= limit)
+ mStart -= sizeof(mBuffer);
+ }
+ mStart = saveStart;
+ DBG_NAV_LOGD("count=%d", result);
+ return result;
+}
+
+void discard(int generation)
+{
+ DBG_NAV_LOGD("generation=%d", generation);
+ LargestParams storage;
+ const CommonParams& params = storage.d.d;
+ char* pos = position();
+ retrieve(&storage.d.d);
+ if (params.mGeneration > generation) {
+ DBG_NAV_LOGD("params.mGeneration=%d > generation=%d",
+ params.mGeneration, generation);
+ rewind(pos);
+ DBG_NAV_LOGD("mStart=%d mEnd=%d", mStart - mBuffer, mEnd - mBuffer);
+ return;
+ }
+ LOG_ASSERT(params.mGeneration == generation, "params.mGeneration != generation");
+ DBG_NAV_LOGD("mStart=%d mEnd=%d", mStart - mBuffer, mEnd - mBuffer);
+}
+
+int lastAdd()
+{
+ return mLastGeneration;
+}
+
+char* position()
+{
+ return mStart;
+}
+
+int retrieve(CommonParams* data)
+{
+ if (mEnd == mStart) {
+ // changed from LOGD to LOGV, as it always fires when I click to center
+ // text (mrr)
+ LOGV("%s *** no data to retrieve (error condition) ***", __FUNCTION__);
+ data->mTrigger = CommonParams::NO_DATA;
+ return data->mGeneration = INT_MAX;
+ }
+ DBG_NAV_LOGD("mStart=%d mEnd=%d",
+ mStart - mBuffer, mEnd - mBuffer);
+ char* limit = mBuffer + sizeof(mBuffer);
+ size_t size = triggerSize();
+ if (mStart < mEnd) {
+ LOG_ASSERT((size_t) (mEnd - mStart) >= size, "mEnd - mStart < size");
+ memcpy(data, mStart, size);
+ mStart += size;
+ } else {
+ int partial = limit - mStart;
+ if (partial > (int) size)
+ partial = size;
+ memcpy(data, mStart, partial);
+ mStart += partial;
+ void* remainder = (void*) ((char*) data + partial);
+ partial = size - partial;
+ if (partial > 0) {
+ memcpy(remainder, mBuffer, partial);
+ mStart = mBuffer + partial;
+ LOG_ASSERT(mStart <= mEnd, "mStart > mEnd");
+ }
+ }
+ if (mStart == limit) {
+ mStart = mBuffer;
+ if (mEnd == limit)
+ mEnd = mBuffer;
+ }
+ DBG_NAV_LOGD("mStart=%d mEnd=%d trigger=%s moveGeneration=%d",
+ mStart - mBuffer, mEnd - mBuffer, TriggerNames[data->mTrigger],
+ data->mGeneration);
+ return data->mGeneration;
+}
+
+void rewind(char* pos)
+{
+ mStart = pos;
+}
+
+private:
+void reclaim(int needed)
+{
+ DBG_NAV_LOGD("needed=%d", needed);
+ char* limit = mBuffer + sizeof(mBuffer);
+ do {
+ size_t size = triggerSize();
+ mStart += size;
+ needed -= size;
+ if (mStart >= limit) {
+ mStart = mBuffer + (mStart - limit);
+ if (mEnd == limit)
+ mEnd = mBuffer;
+ }
+ } while (needed > 0 && mStart != mEnd);
+ DBG_NAV_LOGD("mStart=%d mEnd=%d",
+ mStart - mBuffer, mEnd - mBuffer);
+}
+
+size_t triggerSize()
+{
+ LOG_ASSERT(mStart != mEnd, "mStart == mEnd");
+ char* limit = mBuffer + sizeof(mBuffer);
+ LOG_ASSERT(mStart + sizeof(CommonParams::Trigger) <= limit, "trigger not in limit");
+ CommonParams::Trigger trigger;
+ memcpy(&trigger, mStart, sizeof(trigger));
+ switch (trigger) {
+ case CommonParams::CLEAR_FOCUS_PARAMS:
+ return sizeof(ClearFocusParams);
+ case CommonParams::FIRST_MOVE_FOCUS_PARAMS:
+ return sizeof(FirstMoveFocusParams);
+ case CommonParams::MOVE_FOCUS_PARAMS:
+ return sizeof(MoveFocusParams);
+ case CommonParams::MOTION_UP_PARAMS:
+ return sizeof(MotionUpParams);
+ default:
+ LOG_ASSERT(0, "trigger undefined");
+ }
+ return 0;
+}
+
+char mBuffer[REPLAY_BUFFER_SIZE];
+char* mStart;
+char* mEnd;
+int mLastGeneration;
+}; // end of helper class ReplayFocus
+
+static jfieldID gWebViewField;
+
+//-------------------------------------
+
+extern JavaVM* jnienv_to_javavm(JNIEnv* env);
+extern JNIEnv* javavm_to_jnienv(JavaVM* vm);
+
+static bool checkException(JNIEnv* env)
+{
+ if (env->ExceptionCheck() != 0)
+ {
+ LOGE("*** Uncaught exception returned from Java call!\n");
+ env->ExceptionDescribe();
+ return true;
+ }
+ return false;
+}
+
+static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], const char signature[])
+{
+ jmethodID m = env->GetMethodID(clazz, name, signature);
+ LOG_ASSERT(m, "Could not find method %s", name);
+ return m;
+}
+
+//-------------------------------------
+class WebView
+{
+public:
+enum FrameCachePermission {
+ DONT_ALLOW_NEWER,
+ ALLOW_NEWER,
+ ALLOW_NEWEST
+};
+
+enum OutOfFocusFix {
+ DO_NOTHING,
+ CLEAR_TEXT_ENTRY,
+ UPDATE_TEXT_ENTRY
+};
+
+struct JavaGlue
+{
+ JavaVM* mJVM;
+ jobject mObj;
+ jmethodID mClearTextEntry;
+ jmethodID mScrollBy;
+ jmethodID mSendFinalFocus;
+ jmethodID mSendKitFocus;
+ jmethodID mSendMotionUp;
+ jmethodID mSetFocusData;
+ jmethodID mGetScaledMaxXScroll;
+ jmethodID mGetScaledMaxYScroll;
+ jmethodID mGetVisibleRect;
+ jmethodID mUpdateTextEntry;
+ jmethodID mViewInvalidate;
+ jmethodID mPostInvalidateDelayed;
+ jfieldID mRectLeft;
+ jfieldID mRectTop;
+ jmethodID mRectWidth;
+ jmethodID mRectHeight;
+ jfieldID mFocusNode;
+ jmethodID mSetAll;
+} mJavaGlue;
+
+WebView(JNIEnv* env, jobject javaWebView, int viewImpl)
+{
+ jclass clazz = env->FindClass("android/webkit/WebView");
+ // mJavaGlue = new JavaGlue;
+ mJavaGlue.mJVM = jnienv_to_javavm(env);
+ mJavaGlue.mObj = env->NewGlobalRef(javaWebView);
+ mJavaGlue.mScrollBy = GetJMethod(env, clazz, "setContentScrollBy", "(II)V");
+ mJavaGlue.mClearTextEntry = GetJMethod(env, clazz, "clearTextEntry", "()V");
+ mJavaGlue.mSendFinalFocus = GetJMethod(env, clazz, "sendFinalFocus", "(IIII)V");
+ mJavaGlue.mSendKitFocus = GetJMethod(env, clazz, "sendKitFocus", "()V");
+ mJavaGlue.mSendMotionUp = GetJMethod(env, clazz, "sendMotionUp", "(IIIIIIIZZ)V");
+ mJavaGlue.mSetFocusData = GetJMethod(env, clazz, "setFocusData", "(IIIIIIZ)V");
+ mJavaGlue.mGetScaledMaxXScroll = GetJMethod(env, clazz, "getScaledMaxXScroll", "()I");
+ mJavaGlue.mGetScaledMaxYScroll = GetJMethod(env, clazz, "getScaledMaxYScroll", "()I");
+ mJavaGlue.mGetVisibleRect = GetJMethod(env, clazz, "sendOurVisibleRect", "()Landroid/graphics/Rect;");
+ mJavaGlue.mUpdateTextEntry = GetJMethod(env, clazz, "updateTextEntry", "()V");
+ mJavaGlue.mViewInvalidate = GetJMethod(env, clazz, "viewInvalidate", "()V");
+ jclass viewClass = env->FindClass("android/view/View");
+ mJavaGlue.mPostInvalidateDelayed = GetJMethod(env, viewClass,
+ "postInvalidateDelayed", "(JIIII)V");
+ jclass rectClass = env->FindClass("android/graphics/Rect");
+ LOG_ASSERT(rectClass, "Could not find Rect class");
+ mJavaGlue.mRectLeft = env->GetFieldID(rectClass, "left", "I");
+ mJavaGlue.mRectTop = env->GetFieldID(rectClass, "top", "I");
+ mJavaGlue.mRectWidth = GetJMethod(env, rectClass, "width", "()I");
+ mJavaGlue.mRectHeight = GetJMethod(env, rectClass, "height", "()I");
+
+ // Set up class for updateFocusNode
+ jclass focusnodeClass = env->FindClass("android/webkit/WebView$FocusNode");
+ LOG_ASSERT(focusnodeClass, "Could not find FocusNode class!");
+ mJavaGlue.mFocusNode = env->GetFieldID(clazz, "mFocusNode", "Landroid/webkit/WebView$FocusNode;");
+ mJavaGlue.mSetAll = GetJMethod(env, focusnodeClass, "setAll", "(ZZZZZIIIIIIIILjava/lang/String;Ljava/lang/String;I)V");
+ env->DeleteLocalRef(focusnodeClass);
+
+ env->SetIntField(javaWebView, gWebViewField, (jint)this);
+ mViewImpl = (WebViewCore*) viewImpl;
+ mFrameCacheUI = NULL;
+ mNavPictureUI = NULL;
+ mInvalidNode = NULL;
+ mGeneration = 0;
+ mHeightCanMeasure = false;
+ mFollowedLink = false;
+ mLastDx = 0;
+ mLastDxTime = 0;
+ mRingAnimationEnd = 0;
+ mUIButtons = NULL;
+ mSelStart.setEmpty();
+ mSelEnd.setEmpty();
+}
+
+~WebView()
+{
+ if (mJavaGlue.mObj)
+ {
+ JNIEnv* env = javavm_to_jnienv(mJavaGlue.mJVM);
+ env->DeleteGlobalRef(mJavaGlue.mObj);
+ mJavaGlue.mObj = 0;
+ }
+ delete mFrameCacheUI;
+ delete mNavPictureUI;
+ if (mUIButtons != NULL) {
+ mUIButtons->deleteAll();
+ delete mUIButtons;
+ }
+}
+
+void clearFocus(int x, int y, bool inval)
+{
+ DBG_NAV_LOGD("x=%d y=%d inval=%s", x, y,
+ inval ? "true" : "false");
+ clearTextEntry();
+ CachedRoot* root = getFrameCache(ALLOW_NEWER);
+ if (root == NULL)
+ return;
+ const CachedFrame* oldFrame = NULL;
+ const CachedNode* oldFocusNode = root->currentFocus(&oldFrame);
+ WebCore::IntPoint focusLocation = WebCore::IntPoint(0, 0);
+ setFocusData(root->generation(), NULL, NULL, x, y, oldFocusNode == NULL);
+ sendKitFocus();
+ if (oldFocusNode != NULL) {
+ DBG_NAV_LOG("oldFocusNode != NULL");
+ focusLocation = root->focusLocation();
+ root->setCachedFocus(NULL, NULL);
+ if (inval)
+ viewInvalidate();
+ }
+ ClearFocusParams params;
+ params.d.mTrigger = CommonParams::CLEAR_FOCUS_PARAMS;
+ params.d.mGeneration = mGeneration;
+ params.c.setFocus(oldFocusNode, oldFrame, root, focusLocation);
+ params.mX = x;
+ params.mY = y;
+ mReplay.add(params.d, sizeof(params));
+}
+
+void clearTextEntry()
+{
+ DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
+ JNIEnv* env = javavm_to_jnienv(mJavaGlue.mJVM);
+ env->CallVoidMethod(mJavaGlue.mObj, mJavaGlue.mClearTextEntry);
+ checkException(env);
+}
+
+#if DUMP_NAV_CACHE
+void debugDump()
+{
+ CachedRoot* root = getFrameCache(DONT_ALLOW_NEWER);
+ if (root)
+ root->mDebug.print();
+}
+#endif
+
+#ifdef BUCKET_EXPERIMENT
+void clearContentPicture() {
+ if (mViewImpl != NULL) {
+ mViewImpl->mUIBuckets.clear();
+ }
+}
+
+void drawContentPicture(SkCanvas* canvas) {
+ WTF::Vector<WebViewCore::Bucket>& buckets = mViewImpl->mUIBuckets;
+ const WebViewCore::Bucket* const end = buckets.end();
+ for (WebViewCore::Bucket* bucket = buckets.begin(); bucket != end; bucket++) {
+ SkRect bounds;
+ const WebCore::IntRect& buckB = bucket->mBounds;
+ bounds.set(SkIntToScalar(buckB.x()), SkIntToScalar(buckB.y()),
+ SkIntToScalar(buckB.right()), SkIntToScalar(buckB.bottom()));
+ if (canvas->quickReject(bounds, SkCanvas::kBW_EdgeType)) {
+ continue;
+ }
+ canvas->drawPicture(*bucket->mPicture);
+ }
+}
+#endif
+
+// Traverse our stored array of buttons that are in our picture, and update
+// their subpictures according to their current focus state.
+// Called from the UI thread. This is the one place in the UI thread where we
+// access the buttons stored in the WebCore thread.
+void nativeRecordButtons()
+{
+ // Check to see if the WebCore thread has created a new set of buttons.
+ // We don't have to grab the mutex for this test, since the only place it
+ // could be set to null is right below, or in WebViewCore's constructor.
+ if (mViewImpl->mButtons != NULL) {
+ if (mUIButtons != NULL) {
+ mUIButtons->deleteAll();
+ delete mUIButtons;
+ }
+ // Transfer ownership of the array from the WebCore thread (viewimpl) to
+ // the UI thread
+ mViewImpl->gButtonMutex.lock();
+ mUIButtons = mViewImpl->mButtons;
+ mViewImpl->mButtons = NULL;
+ mViewImpl->gButtonMutex.unlock();
+ }
+
+ // If mUIButtons has never been set, or it has been set with an array of no
+ // buttons (which happens if a page does not have any buttons), then return.
+ if (mUIButtons == NULL || mUIButtons->count() == 0)
+ return;
+
+ // Find the focused node so we can determine which node has focus, and
+ // therefore which state to paint them in.
+ // FIXME: In a future change, we should keep track of whether the focus has
+ // changed to short circuit (note that we would still need to update if we
+ // received new buttons from the WebCore thread).
+ WebCore::Node* focus = NULL;
+ CachedRoot* root = getFrameCache(DONT_ALLOW_NEWER);
+ if (root != NULL) {
+ const CachedNode* cachedNode = root->currentFocus();
+ if (cachedNode != NULL)
+ focus = (WebCore::Node*) cachedNode->nodePointer();
+ }
+
+ // Traverse the array, and update each button, depending on whether it is
+ // focused.
+ Container** end = mUIButtons->end();
+ for (Container** ptr = mUIButtons->begin(); ptr != end; ptr++) {
+ (*ptr)->updateFocusState(focus);
+ }
+}
+
+void drawFocusRing(SkCanvas* canvas)
+{
+ const CachedRoot* root = getFrameCache(ALLOW_NEWER);
+ if (root == NULL) {
+ DBG_NAV_LOG("root==NULL");
+ mFollowedLink = false;
+ return;
+ }
+ const CachedNode* node = root->currentFocus();
+ if (node == NULL) {
+ DBG_NAV_LOG("node==NULL");
+ mFollowedLink = false;
+ return;
+ }
+ if (node->hasFocusRing() == false) {
+ DBG_NAV_LOG("node->hasFocusRing() == false");
+ return;
+ }
+ const WTF::Vector<WebCore::IntRect>& rings = node->focusRings();
+ if (0 == rings.size()) {
+ DBG_NAV_LOG("rings.size()==0");
+ return;
+ }
+
+ bool isButton = false;
+ // If this is a button drawn by us (rather than webkit) do not draw the
+ // focus ring, since its focus will be shown by a change in what we draw.
+ if (mUIButtons != NULL) {
+ // Should be in sync with recordButtons, since that will be called
+ // before this.
+ if (mUIButtons->count() > 0) {
+ WebCore::Node* focusPointer = (WebCore::Node*) node->nodePointer();
+ Container** end = mUIButtons->end();
+ for (Container** ptr = mUIButtons->begin(); ptr != end; ptr++) {
+ if ((*ptr)->matches(focusPointer)) {
+ isButton = true;
+ break;
+ }
+ }
+ }
+ }
+ FocusRing::Flavor flavor = isButton ? FocusRing::BUTTON_NO_RING :
+ node->type() != NORMAL_CACHEDNODETYPE ?
+ FocusRing::FAKE_FLAVOR : node->nodePointer() == mInvalidNode ?
+ FocusRing::INVALID_FLAVOR : FocusRing::NORMAL_FLAVOR;
+ if (flavor != FocusRing::INVALID_FLAVOR && mFollowedLink) {
+ flavor = (FocusRing::Flavor) (flavor + FocusRing::NORMAL_ANIMATING);
+ }
+#if DEBUG_NAV_UI
+ const WebCore::IntRect& ring = rings[0];
+ DBG_NAV_LOGD("cachedFocusNode=%d (nodePointer=%p) flavor=%s rings=%d"
+ " (%d, %d, %d, %d)", node->index(), node->nodePointer(),
+ flavor == FocusRing::FAKE_FLAVOR ? "FAKE_FLAVOR" :
+ flavor == FocusRing::INVALID_FLAVOR ? "INVALID_FLAVOR" :
+ flavor == FocusRing::NORMAL_ANIMATING ? "NORMAL_ANIMATING" :
+ flavor == FocusRing::FAKE_ANIMATING ? "FAKE_ANIMATING" :
+ flavor == FocusRing::BUTTON_NO_RING ? "BUTTON_NO_RING" :
+ flavor == FocusRing::BUTTON_ANIMATING ? "BUTTON_ANIMATING" : "NORMAL_FLAVOR",
+ rings.size(), ring.x(), ring.y(), ring.width(), ring.height());
+#endif
+ if (flavor >= FocusRing::NORMAL_ANIMATING) {
+ SkMSec time = SkTime::GetMSecs();
+ if (time < mRingAnimationEnd) {
+ WebCore::IntRect bounds = node->bounds();
+ bounds.inflate(SkScalarCeil(FOCUS_RING_OUTER_DIAMETER));
+ postInvalidateDelayed(mRingAnimationEnd - time, bounds);
+ } else {
+ mFollowedLink = false;
+ flavor = (FocusRing::Flavor) (flavor - FocusRing::NORMAL_ANIMATING);
+ }
+ }
+ FocusRing::DrawRing(canvas, rings, flavor);
+}
+
+OutOfFocusFix fixOutOfDateFocus(bool useReplay)
+{
+ if (mFrameCacheUI == NULL) {
+ DBG_NAV_LOG("mFrameCacheUI == NULL");
+ return DO_NOTHING;
+ }
+ const CachedFrame* cachedFrame = NULL;
+ const CachedNode* cachedFocusNode = mFrameCacheUI->currentFocus(&cachedFrame);
+ if (cachedFocusNode == NULL) {
+ DBG_NAV_LOG("cachedFocusNode == NULL");
+ return DO_NOTHING;
+ }
+ CachedRoot* webRoot = mViewImpl->mFrameCacheKit;
+ if (webRoot == NULL) {
+ DBG_NAV_LOG("webRoot == NULL");
+ return DO_NOTHING;
+ }
+ int uiWidth = mFrameCacheUI->width();
+ int webWidth = webRoot->width();
+ if (uiWidth != webWidth) {
+ DBG_NAV_LOGD("uiWidth=%d webWidth=%d", uiWidth, webWidth);
+ } else {
+ WebCore::IntRect cachedBounds = cachedFocusNode->bounds();
+ const CachedFrame* webFrame = NULL;
+ const CachedNode* webFocusNode = webRoot->currentFocus(&webFrame);
+ if (webFocusNode != NULL && webRoot->containsFrame(cachedFrame)) {
+ if (useReplay && mReplay.count() == 0) {
+ DBG_NAV_LOG("mReplay.count() == 0");
+ return DO_NOTHING;
+ }
+ if (webFocusNode->index() == cachedFocusNode->index() &&
+ webFrame->indexInParent() == cachedFrame->indexInParent())
+ {
+ DBG_NAV_LOG("index ==");
+ return DO_NOTHING;
+ }
+ WebCore::IntRect webBounds = webFocusNode->bounds();
+ if (cachedBounds.contains(webBounds)) {
+ DBG_NAV_LOG("contains");
+ return DO_NOTHING;
+ }
+ if (webBounds.contains(cachedBounds)) {
+ DBG_NAV_LOG("webBounds contains");
+ return DO_NOTHING;
+ }
+ }
+ const CachedFrame* foundFrame = NULL;
+ int x, y;
+ const CachedNode* found = findAt(webRoot, cachedBounds, &foundFrame, &x, &y);
+#if DEBUG_NAV_UI
+ DBG_NAV_LOGD("found=%p (%d) frame=%p (%d)",
+ found, found != NULL ? found->index() : -1,
+ foundFrame, foundFrame != NULL ? foundFrame->indexInParent() : -1);
+ if (found != NULL) {
+ WebCore::IntRect newBounds = found->bounds();
+ DBG_NAV_LOGD("cachedBounds=(%d,%d,%d,%d) found=(%d,%d,%d,%d)",
+ cachedBounds.x(), cachedBounds.y(), cachedBounds.width(), cachedBounds.height(),
+ newBounds.x(), newBounds.y(), newBounds.width(), newBounds.height());
+ }
+#endif
+ webRoot->setCachedFocus(const_cast<CachedFrame*>(foundFrame),
+ const_cast<CachedNode*>(found));
+ if (found != NULL)
+ webRoot->rootHistory()->setNavBounds(found->bounds());
+ WebCore::Frame* framePointer = foundFrame != NULL ? (WebCore::Frame*) foundFrame->framePointer() : NULL;
+ WebCore::Node* nodePointer = found != NULL ? (WebCore::Node*) found->nodePointer() : NULL;
+ setFocusData(webRoot->generation(), framePointer, nodePointer, x, y, found == NULL);
+ sendFinalFocus(framePointer, nodePointer, x, y);
+ if (found && (found->isTextArea() || found->isTextField()))
+ return UPDATE_TEXT_ENTRY;
+ }
+checkOldFocus:
+ return cachedFocusNode->isTextArea() || cachedFocusNode->isTextField() ? CLEAR_TEXT_ENTRY : DO_NOTHING;
+}
+
+bool focusIsTextArea(FrameCachePermission allowNewer)
+{
+ CachedRoot* root = getFrameCache(allowNewer);
+ if (root == NULL) {
+ DBG_NAV_LOG("root==NULL");
+ return false;
+ }
+ const CachedNode* focus = root->currentFocus();
+ if (focus == NULL)
+ return false;
+ return focus->isTextArea() || focus->isTextField();
+}
+
+void focusRingBounds(WebCore::IntRect* bounds)
+{
+ DBG_NAV_LOGD("%s", "");
+ CachedRoot* root = getFrameCache(DONT_ALLOW_NEWER);
+ if (root != NULL) {
+ const CachedNode* cachedNode = root->currentFocus();
+ if (cachedNode != NULL) {
+ cachedNode->focusRingBounds(bounds);
+ DBG_NAV_LOGD("bounds={%d,%d,%d,%d}", bounds->x(), bounds->y(),
+ bounds->width(), bounds->height());
+ return;
+ }
+ }
+ *bounds = WebCore::IntRect(0, 0, 0, 0);
+}
+
+CachedRoot* getFrameCache(FrameCachePermission allowNewer)
+{
+ if (mViewImpl->mUpdatedFrameCache == false)
+ return mFrameCacheUI;
+ mViewImpl->gRecomputeFocusMutex.lock();
+ bool recomputeInProgress = mViewImpl->mRecomputeEvents.size() > 0;
+ mViewImpl->gRecomputeFocusMutex.unlock();
+ if (allowNewer != ALLOW_NEWEST && recomputeInProgress)
+ return mFrameCacheUI;
+ if (allowNewer == DONT_ALLOW_NEWER && mViewImpl->mLastGeneration < mGeneration)
+ return mFrameCacheUI;
+ DBG_NAV_LOGD("%s", "mViewImpl->mUpdatedFrameCache == true");
+ mViewImpl->gFrameCacheMutex.lock();
+ OutOfFocusFix fix = DO_NOTHING;
+ if (allowNewer != DONT_ALLOW_NEWER)
+ fix = fixOutOfDateFocus(mViewImpl->mUseReplay);
+ delete mFrameCacheUI;
+ delete mNavPictureUI;
+ mViewImpl->mUpdatedFrameCache = false;
+ mFrameCacheUI = mViewImpl->mFrameCacheKit;
+ mNavPictureUI = mViewImpl->mNavPictureKit;
+ mViewImpl->mFrameCacheKit = NULL;
+ mViewImpl->mNavPictureKit = NULL;
+ mViewImpl->gFrameCacheMutex.unlock();
+ if (fix == UPDATE_TEXT_ENTRY)
+ updateTextEntry();
+ else if (fix == CLEAR_TEXT_ENTRY)
+ clearTextEntry();
+ return mFrameCacheUI;
+}
+
+int getScaledMaxXScroll()
+{
+ LOG_ASSERT(mJavaGlue.mObj, "A java object was not associated with this native WebView!");
+ JNIEnv* env = javavm_to_jnienv(mJavaGlue.mJVM);
+ int result = env->CallIntMethod(mJavaGlue.mObj, mJavaGlue.mGetScaledMaxXScroll);
+ checkException(env);
+ return result;
+}
+
+int getScaledMaxYScroll()
+{
+ LOG_ASSERT(mJavaGlue.mObj, "A java object was not associated with this native WebView!");
+ JNIEnv* env = javavm_to_jnienv(mJavaGlue.mJVM);
+ int result = env->CallIntMethod(mJavaGlue.mObj, mJavaGlue.mGetScaledMaxYScroll);
+ checkException(env);
+ return result;
+}
+
+void getVisibleRect(WebCore::IntRect* rect)
+{
+ LOG_ASSERT(mJavaGlue.mObj, "A java object was not associated with this native WebView!");
+ JNIEnv* env = javavm_to_jnienv(mJavaGlue.mJVM);
+ jobject jRect = env->CallObjectMethod(mJavaGlue.mObj, mJavaGlue.mGetVisibleRect);
+ checkException(env);
+ int left = (int) env->GetIntField(jRect, mJavaGlue.mRectLeft);
+ checkException(env);
+ rect->setX(left);
+ int top = (int) env->GetIntField(jRect, mJavaGlue.mRectTop);
+ checkException(env);
+ rect->setY(top);
+ int width = (int) env->CallIntMethod(jRect, mJavaGlue.mRectWidth);
+ checkException(env);
+ rect->setWidth(width);
+ int height = (int) env->CallIntMethod(jRect, mJavaGlue.mRectHeight);
+ checkException(env);
+ rect->setHeight(height);
+ env->DeleteLocalRef(jRect);
+ checkException(env);
+}
+
+bool hasSrcUrl()
+{
+ const CachedRoot* root = getFrameCache(DONT_ALLOW_NEWER);
+ if (NULL == root)
+ return false;
+ const CachedNode* cachedNode = root->currentFocus();
+ return NULL == cachedNode ? false : cachedNode->anchorHasSrcUrl();
+}
+
+static CachedFrame::Direction KeyToDirection(KeyCode keyCode)
+{
+ switch (keyCode) {
+ case kKeyCodeDpadRight:
+ DBG_NAV_LOGD("keyCode=%s", "right");
+ return CachedFrame::RIGHT;
+ case kKeyCodeDpadLeft:
+ DBG_NAV_LOGD("keyCode=%s", "left");
+ return CachedFrame::LEFT;
+ case kKeyCodeDpadDown:
+ DBG_NAV_LOGD("keyCode=%s", "down");
+ return CachedFrame::DOWN;
+ case kKeyCodeDpadUp:
+ DBG_NAV_LOGD("keyCode=%s", "up");
+ return CachedFrame::UP;
+ default:
+ LOGD("------- bad key sent to WebView::moveFocus");
+ return CachedFrame::UNINITIALIZED;
+ }
+}
+
+bool invalidFrame(WebCore::Frame* frame, const CachedRoot* root)
+{
+ if (frame == NULL)
+ return false;
+ int frameBuild = mViewImpl->retrieveFrameGeneration(frame);
+ int rootBuild = root->generation();
+ return frameBuild > rootBuild;
+}
+
+bool isImage(int x, int y)
+{
+ const CachedRoot* root = getFrameCache(DONT_ALLOW_NEWER);
+ return root ? root->isImage(x, y) : false;
+}
+
+/* returns true if the key had no effect (neither scrolled nor changed focus) */
+bool moveFocus(int keyCode, int count, bool ignoreScroll, bool inval,
+ void* lastSentFocus, const WebCore::IntRect* lastSentBounds)
+{
+ CachedRoot* root = getFrameCache(ALLOW_NEWER);
+ if (root == NULL) {
+ DBG_NAV_LOG("root == NULL");
+ setFocusData(0, NULL, NULL, 0, 0, true);
+ sendKitFocus(); // will build cache and retry
+ FirstMoveFocusParams params;
+ params.d.mTrigger = CommonParams::FIRST_MOVE_FOCUS_PARAMS;
+ params.d.mGeneration = mGeneration;
+ params.mKeyCode = keyCode;
+ params.mCount = count;
+ params.mIgnoreScroll = ignoreScroll;
+ mReplay.add(params.d, sizeof(params));
+ return true;
+ }
+
+ CachedFrame::Direction direction = KeyToDirection((KeyCode) keyCode);
+ const CachedFrame* cachedFrame, * oldFrame = NULL;
+ const CachedNode* focus = root->currentFocus(&oldFrame);
+ WebCore::IntPoint focusLocation = root->focusLocation();
+ DBG_NAV_LOGD("old focus %d (nativeNode=%p) focusLocation={%d, %d}",
+ focus ? focus->index() : 0,
+ focus ? focus->nodePointer() : NULL, focusLocation.x(), focusLocation.y());
+ WebCore::IntRect visibleRect;
+ getVisibleRect(&visibleRect);
+ DBG_NAV_LOGD("getVisibleRect %d,%d,%d,%d",
+ visibleRect.x(), visibleRect.y(), visibleRect.width(), visibleRect.height());
+ root->setVisibleRect(visibleRect);
+ int xMax = getScaledMaxXScroll();
+ int yMax = getScaledMaxYScroll();
+ root->setMaxScroll(xMax, yMax);
+ CachedHistory savedHistory = *root->rootHistory();
+#if 0 && DUMP_NAV_CACHE
+ savedHistory.mDebug.print(root);
+#endif
+ bool oldNodeIsTextArea = focusIsTextArea(DONT_ALLOW_NEWER);
+ const CachedNode* cachedNode = NULL;
+ int dx = 0;
+ int dy = 0;
+ int counter = count;
+ root->setScrollOnly(mFollowedLink);
+ while (--counter >= 0) {
+ WebCore::IntPoint scroll = WebCore::IntPoint(0, 0);
+ cachedNode = root->moveFocus(direction, &cachedFrame, &scroll);
+ dx += scroll.x();
+ dy += scroll.y();
+ }
+ DBG_NAV_LOGD("new focus %d (nativeNode=%p) focusLocation={%d, %d}",
+ cachedNode ? cachedNode->index() : 0,
+ cachedNode ? cachedNode->nodePointer() : NULL, root->focusLocation().x(),
+ root->focusLocation().y());
+ // If !mHeightCanMeasure (such as in the browser), we want to scroll no
+ // matter what
+#if 0 && DUMP_NAV_CACHE
+ root->rootHistory()->mDebug.print(root);
+#endif
+ if (ignoreScroll == false && (mHeightCanMeasure == false ||
+ NULL == cachedNode ||
+ (focus && focus->nodePointer() == cachedNode->nodePointer())))
+ {
+ if (count == 1 && dx != 0 && dy == 0 && -mLastDx == dx &&
+ SkTime::GetMSecs() - mLastDxTime < 1000)
+ root->checkForJiggle(&dx);
+ DBG_NAV_LOGD("scrollBy %d,%d", dx, dy);
+ if ((dx | dy) != 0)
+ this->scrollBy(dx, dy);
+ mLastDx = dx;
+ mLastDxTime = SkTime::GetMSecs();
+ ignoreScroll = true; // if move re-executes, don't scroll the second time
+ }
+ bool result = false;
+ if (cachedNode != NULL) {
+ WebCore::IntPoint pos;
+ root->setCachedFocus((CachedFrame*) cachedFrame, (CachedNode*) cachedNode);
+ root->getSimulatedMousePosition(&pos);
+ if (lastSentFocus == cachedNode->nodePointer() && lastSentBounds &&
+ *lastSentBounds == cachedNode->bounds())
+ {
+ sendFinalFocus((WebCore::Frame*) cachedFrame->framePointer(),
+ (WebCore::Node*) cachedNode->nodePointer(), pos.x(), pos.y());
+ } else {
+ setFocusData(root->generation(),
+ (WebCore::Frame*) cachedFrame->framePointer(),
+ (WebCore::Node*) cachedNode->nodePointer(), pos.x(), pos.y(),
+ true);
+ sendKitFocus();
+ if (inval)
+ viewInvalidate();
+ MoveFocusParams params;
+ params.d.d.mTrigger = CommonParams::MOVE_FOCUS_PARAMS;
+ params.d.d.mGeneration = mGeneration;
+ params.c.setFocus(focus, oldFrame, root, focusLocation);
+ params.mSentFocus = cachedNode->nodePointer();
+ params.mSentBounds = cachedNode->bounds();
+ params.mVisibleRect = visibleRect;
+ params.mHistory = savedHistory;
+ DBG_NAV_LOGD("history.mDidFirstLayout=%s",
+ params.mHistory.didFirstLayout() ? "true" : "false");
+ params.mXMax = xMax;
+ params.mYMax = yMax;
+ params.d.mKeyCode = keyCode;
+ params.d.mCount = count;
+ params.d.mIgnoreScroll = ignoreScroll;
+ mReplay.add(params.d.d, sizeof(params));
+ }
+ } else {
+ if (visibleRect.intersects(root->rootHistory()->focusBounds()) == false) {
+ setFocusData(root->generation(), NULL, NULL, 0, 0, true);
+ sendKitFocus(); // will build cache and retry
+ }
+ FirstMoveFocusParams params;
+ params.d.mTrigger = CommonParams::FIRST_MOVE_FOCUS_PARAMS;
+ params.d.mGeneration = mGeneration;
+ params.mKeyCode = keyCode;
+ params.mCount = count;
+ params.mIgnoreScroll = ignoreScroll;
+ mReplay.add(params.d, sizeof(params));
+ int docHeight = root->documentHeight();
+ int docWidth = root->documentWidth();
+ if (visibleRect.bottom() + dy > docHeight)
+ dy = docHeight - visibleRect.bottom();
+ else if (visibleRect.y() + dy < 0)
+ dy = -visibleRect.y();
+ if (visibleRect.right() + dx > docWidth)
+ dx = docWidth - visibleRect.right();
+ else if (visibleRect.x() < 0)
+ dx = -visibleRect.x();
+ result = direction == CachedFrame::LEFT ? dx >= 0 :
+ direction == CachedFrame::RIGHT ? dx <= 0 :
+ direction == CachedFrame::UP ? dy >= 0 : dy <= 0;
+ }
+ if (focusIsTextArea(DONT_ALLOW_NEWER))
+ updateTextEntry();
+ else if (oldNodeIsTextArea)
+ clearTextEntry();
+ return result;
+}
+
+void notifyFocusSet(FrameCachePermission inEditingMode)
+{
+ if (focusIsTextArea(inEditingMode))
+ updateTextEntry();
+ else if (inEditingMode)
+ clearTextEntry();
+#if DEBUG_NAV_UI
+ if (mFrameCacheUI != NULL) {
+ const CachedNode* focus = mFrameCacheUI->currentFocus();
+ DBG_NAV_LOGD("focus %d (nativeNode=%p)",
+ focus ? focus->index() : 0,
+ focus ? focus->nodePointer() : NULL);
+ }
+#endif
+}
+
+void notifyProgressFinished()
+{
+ DBG_NAV_LOGD("focusIsTextArea=%d", focusIsTextArea(DONT_ALLOW_NEWER));
+ updateTextEntry();
+#if DEBUG_NAV_UI
+ if (mFrameCacheUI != NULL) {
+ const CachedNode* focus = mFrameCacheUI->currentFocus();
+ DBG_NAV_LOGD("focus %d (nativeNode=%p)",
+ focus ? focus->index() : 0,
+ focus ? focus->nodePointer() : NULL);
+ }
+#endif
+}
+
+void recomputeFocus()
+{
+ int generation;
+ do {
+ mViewImpl->gRecomputeFocusMutex.lock();
+ if (mViewImpl->mRecomputeEvents.size() == 0) {
+ mViewImpl->gRecomputeFocusMutex.unlock();
+ return;
+ }
+ generation = mViewImpl->mRecomputeEvents.first();
+ mViewImpl->mRecomputeEvents.remove(0);
+ mViewImpl->gRecomputeFocusMutex.unlock();
+ DBG_NAV_LOGD("generation=%d", generation);
+ CachedRoot* root = getFrameCache(ALLOW_NEWEST);
+ if (root == NULL) {
+ DBG_NAV_LOG("root==NULL");
+ return;
+ }
+ LargestParams storage;
+ const CommonParams& params = storage.d.d;
+ char* pos = mReplay.position();
+ while (mReplay.retrieve(&storage.d.d) < generation)
+ DBG_NAV_LOGD("dropped ", params.mGeneration);
+ if (params.mGeneration > generation) {
+ DBG_NAV_LOGD("params.mGeneration=%d > generation=%d",
+ params.mGeneration, generation);
+ mReplay.rewind(pos);
+ return;
+ }
+ int lastAdd = mReplay.lastAdd();
+ do {
+ LOG_ASSERT(params.mTrigger != CommonParams::NO_DATA, "expected data");
+ bool inval = generation == mGeneration;
+ switch (params.mTrigger) {
+ case CommonParams::CLEAR_FOCUS_PARAMS: {
+ const ClearFocusParams& sParams = *(ClearFocusParams*) &storage;
+ const CacheParams& cParams = sParams.c;
+ if (invalidFrame(cParams.mFrame, root)) {
+ DBG_NAV_LOGD("dropped %s generation=%d",
+ TriggerNames[params.mTrigger], generation);
+ return;
+ }
+ root->setFocus(cParams.mFrame, cParams.mNode, cParams.mX, cParams.mY);
+ clearFocus(sParams.mX, sParams.mY, inval);
+ DBG_NAV_LOGD("clearFocus(x,y)={%d,%d}", sParams.mX, sParams.mY);
+ } break;
+ case CommonParams::MOTION_UP_PARAMS: {
+ const MotionUpParams& mParams = *(MotionUpParams*) &storage;
+ // const CacheParams& cParams = mParams.c;
+ // if (invalidFrame(cParams.mFrame, root) == false)
+ // root->setFocus(cParams.mFrame, cParams.mNode,
+ // cParams.mX, cParams.mY);
+ motionUp(mParams.mX, mParams.mY, mParams.mSlop, mParams.mIsClick, inval, true);
+ DBG_NAV_LOGD("motionUp mX=%d mY=%d", mParams.mX, mParams.mY);
+ } break;
+ case CommonParams::FIRST_MOVE_FOCUS_PARAMS: {
+ if (invalidFrame((WebCore::Frame*) root->framePointer(), root)) {
+ DBG_NAV_LOGD("dropped %s generation=%d",
+ TriggerNames[params.mTrigger], generation);
+ return;
+ }
+ const FirstMoveFocusParams& fParams = *(FirstMoveFocusParams*) &storage;
+ DBG_NAV_LOGD("first moveFocus keyCode=%d count=%d"
+ " ignoreScroll=%s", fParams.mKeyCode, fParams.mCount,
+ fParams.mIgnoreScroll ? "true" : "false");
+ moveFocus(fParams.mKeyCode, fParams.mCount,
+ fParams.mIgnoreScroll, inval, NULL, NULL);
+ } break;
+ case CommonParams::MOVE_FOCUS_PARAMS: {
+ const MoveFocusParams& mParams = *(MoveFocusParams*) &storage;
+ const CacheParams& cParams = mParams.c;
+ if (invalidFrame(cParams.mFrame, root)) {
+ DBG_NAV_LOGD("dropped %s generation=%d",
+ TriggerNames[params.mTrigger], generation);
+ return;
+ }
+ DBG_NAV_LOGD("moveFocus keyCode=%d count=%d ignoreScroll=%s "
+ "history.mDidFirstLayout=%s", mParams.d.mKeyCode,
+ mParams.d.mCount, mParams.d.mIgnoreScroll ? "true" : "false",
+ mParams.mHistory.didFirstLayout() ? "true" : "false");
+ if (root->setFocus(cParams.mFrame, cParams.mNode,
+ cParams.mX, cParams.mY) == false) {
+ DBG_NAV_LOGD("can't restore focus frame=%p node=%p",
+ "x=%d y=%d %s", cParams.mFrame, cParams.mNode,
+ cParams.mX, cParams.mY, TriggerNames[params.mTrigger]);
+ return;
+ }
+ root->setVisibleRect(mParams.mVisibleRect);
+ root->setMaxScroll(mParams.mXMax, mParams.mYMax);
+ *root->rootHistory() = mParams.mHistory;
+ moveFocus(mParams.d.mKeyCode, mParams.d.mCount,
+ mParams.d.mIgnoreScroll, inval,
+ mParams.mSentFocus, &mParams.mSentBounds);
+ } break;
+ default:
+ LOG_ASSERT(0, "unknown trigger");
+ }
+ if (params.mGeneration >= lastAdd)
+ break;
+ root = getFrameCache(DONT_ALLOW_NEWER); // re-execution may have retrieved newer cache
+ mReplay.retrieve(&storage.d.d);
+ DBG_NAV_LOGD("continuation mGeneration %d", params.mGeneration);
+ } while (true);
+ } while (true);
+}
+
+void resetFocus()
+{
+ DEBUG_NAV_UI_LOGD("%s", __FUNCTION__);
+ CachedRoot* root = getFrameCache(ALLOW_NEWER);
+ if (root == NULL)
+ return;
+ root->setCachedFocus(NULL, NULL);
+}
+
+const CachedNode* findAt(CachedRoot* root, const WebCore::IntRect& rect,
+ const CachedFrame** framePtr, int* rxPtr, int* ryPtr)
+{
+ *rxPtr = 0;
+ *ryPtr = 0;
+ *framePtr = NULL;
+ if (root == NULL)
+ return NULL;
+ WebCore::IntRect visibleRect;
+ getVisibleRect(&visibleRect);
+ root->setVisibleRect(visibleRect);
+ return root->findAt(rect, framePtr, rxPtr, ryPtr);
+}
+
+void selectBestAt(const WebCore::IntRect& rect)
+{
+ const CachedFrame* frame;
+ int rx, ry;
+ CachedRoot* root = getFrameCache(DONT_ALLOW_NEWER);
+ const CachedNode* node = findAt(root, rect, &frame, &rx, &ry);
+ int rootGeneration = root != NULL ? root->generation() : 0;
+ setFocusData(rootGeneration,
+ frame ? (WebCore::Frame*) frame->framePointer() : NULL,
+ node ? (WebCore::Node*) node->nodePointer() : NULL, rx, ry, false);
+ if (node == NULL) {
+ DBG_NAV_LOGD("no nodes found root=%p", root);
+ if (root != NULL) {
+ root->clearFocus();
+ root->setCachedFocus(NULL, NULL);
+ }
+ sendKitFocus();
+ viewInvalidate();
+ clearTextEntry();
+ return;
+ }
+ DBG_NAV_LOGD("CachedNode:%p (%d)", node, node->index());
+ const CachedFrame* oldFrame = NULL;
+ const CachedNode* oldFocusNode = root->currentFocus(&oldFrame);
+ bool oldNodeIsTextArea = focusIsTextArea(DONT_ALLOW_NEWER);
+ root->setCachedFocus(const_cast<CachedFrame*>(frame),
+ const_cast<CachedNode*>(node));
+ viewInvalidate();
+ if (focusIsTextArea(DONT_ALLOW_NEWER))
+ updateTextEntry();
+ else if (oldNodeIsTextArea)
+ clearTextEntry();
+}
+
+WebCore::IntRect getNavBounds()
+{
+ CachedRoot* root = getFrameCache(DONT_ALLOW_NEWER);
+ if (NULL == root)
+ return WebCore::IntRect(0, 0, 0, 0);
+ return root->rootHistory()->navBounds();
+}
+
+void setNavBounds(const WebCore::IntRect& rect)
+{
+ CachedRoot* root = getFrameCache(DONT_ALLOW_NEWER);
+ if (NULL == root)
+ return;
+ root->rootHistory()->setNavBounds(rect);
+}
+
+void markNodeInvalid(WebCore::Node* node)
+{
+ DBG_NAV_LOGD("node=%p", node);
+ mInvalidNode = node;
+ viewInvalidate();
+}
+
+void motionUp(int x, int y, int slop, bool isClick, bool inval, bool retry)
+{
+ mFollowedLink = false;
+ const CachedFrame* frame;
+ WebCore::IntRect rect = WebCore::IntRect(x - slop, y - slop, slop * 2, slop * 2);
+ int rx, ry;
+ CachedRoot* root = getFrameCache(ALLOW_NEWER);
+ const CachedNode* result = findAt(root, rect, &frame, &rx, &ry);
+ if (result == NULL) {
+ DBG_NAV_LOGD("no nodes found root=%p", root);
+ int rootGeneration = 0;
+ if (root != NULL) {
+ root->clearFocus();
+ rootGeneration = root->generation();
+ if (retry == false) { // scroll first time only
+ int dx = root->checkForCenter(x, y);
+ if (dx != 0) {
+ scrollBy(dx, 0);
+ retry = true; // don't recompute later since we scrolled
+ }
+ }
+ }
+ sendMotionUp(rootGeneration, frame ?
+ (WebCore::Frame*) frame->framePointer() : NULL,
+ NULL, x, y, slop, isClick, retry);
+ if (inval)
+ viewInvalidate();
+ if (retry == false) {
+ MotionUpParams params;
+ params.d.mTrigger = CommonParams::MOTION_UP_PARAMS;
+ params.d.mGeneration = mGeneration;
+ params.mX = x;
+ params.mY = y;
+ params.mSlop = slop;
+ params.mIsClick = isClick;
+ mReplay.add(params.d, sizeof(params));
+ }
+ clearTextEntry();
+ return;
+ }
+ DBG_NAV_LOGD("CachedNode:%p (%d) x=%d y=%d rx=%d ry=%d", result,
+ result->index(), x, y, rx, ry);
+ // const CachedFrame* oldFrame = NULL;
+ // const CachedNode* oldFocusNode = root->currentFocus(&oldFrame);
+ // WebCore::IntPoint focusLocation = root->focusLocation();
+ bool oldNodeIsTextArea = retry == false && focusIsTextArea(DONT_ALLOW_NEWER);
+ root->setCachedFocus(const_cast<CachedFrame*>(frame),
+ const_cast<CachedNode*>(result));
+ bool newNodeIsTextArea = focusIsTextArea(DONT_ALLOW_NEWER);
+ const WebCore::String& exported = result->getExport();
+ if (exported.length() == 0 || newNodeIsTextArea) {
+ sendMotionUp(root->generation(),
+ frame ? (WebCore::Frame*) frame->framePointer() : NULL,
+ result ? (WebCore::Node*) result->nodePointer() : NULL, rx, ry,
+ slop, isClick, retry);
+ if (inval)
+ viewInvalidate();
+ if (retry == false) {
+ MotionUpParams params;
+ params.d.mTrigger = CommonParams::MOTION_UP_PARAMS;
+ params.d.mGeneration = mGeneration;
+ params.mX = x;
+ params.mY = y;
+ params.mSlop = slop;
+ params.mIsClick = isClick;
+ // params.c.setFocus(oldFocusNode, oldFrame, root, focusLocation);
+ mReplay.add(params.d, sizeof(params));
+ }
+ } else if (inval)
+ viewInvalidate();
+ if (newNodeIsTextArea)
+ updateTextEntry();
+ else {
+ if (isClick)
+ setFollowedLink(true);
+ if (oldNodeIsTextArea)
+ clearTextEntry();
+ }
+}
+
+void setFollowedLink(bool followed)
+{
+ if ((mFollowedLink = followed) != false) {
+ mRingAnimationEnd = SkTime::GetMSecs() + 500;
+ viewInvalidate();
+ }
+}
+
+void setHeightCanMeasure(bool measure)
+{
+ mHeightCanMeasure = measure;
+}
+
+SkIRect mSelStart, mSelEnd;
+SkRegion mSelRegion;
+#define MIN_ARROW_DISTANCE (20 * 20)
+
+void moveSelection(int x, int y, bool extendSelection) {
+ CachedRoot* root = getFrameCache(DONT_ALLOW_NEWER);
+ if (NULL == root)
+ return;
+ const SkPicture& picture = *mNavPictureUI;
+ WebCore::IntRect r;
+ getVisibleRect(&r);
+ SkIRect area;
+ area.set(r.x(), r.y(), r.right(), r.bottom());
+ if (extendSelection == false)
+ mSelStart = mSelEnd = CopyPaste::findClosest(picture, area, x, y);
+ else
+ mSelEnd = CopyPaste::findClosest(picture, area, x, y);
+ DBG_NAV_LOGD("x=%d y=%d extendSelection=%s mSelStart=(%d, %d, %d, %d)"
+ " mSelEnd=(%d, %d, %d, %d)", x, y, extendSelection ? "true" : "false",
+ mSelStart.fLeft, mSelStart.fTop, mSelStart.fRight, mSelStart.fBottom,
+ mSelEnd.fLeft, mSelEnd.fTop, mSelEnd.fRight, mSelEnd.fBottom);
+}
+
+const SkRegion& getSelection() {
+ return mSelRegion;
+}
+
+void drawSelection(SkCanvas* canvas, int x, int y, bool extendSelection) {
+ if (extendSelection == false) {
+ int dx = x - mSelStart.fLeft;
+ dx *= dx;
+ int otherX = x - mSelStart.fRight;
+ if (dx > (otherX *= otherX))
+ dx = otherX;
+ int dy = y - mSelStart.fTop;
+ int dist = dx * dx + dy * dy;
+ if (dist > MIN_ARROW_DISTANCE)
+ drawSelectionArrow(canvas, x, y);
+ else
+ drawSelectionPointer(canvas, x, y, true);
+ } else {
+ drawSelectionRegion(canvas);
+ drawSelectionPointer(canvas, x, y, false);
+ }
+}
+
+void drawSelectionRegion(SkCanvas* canvas) {
+ CachedRoot* root = getFrameCache(DONT_ALLOW_NEWER);
+ if (NULL == root)
+ return;
+ WebCore::IntRect r;
+ getVisibleRect(&r);
+ SkIRect area;
+ area.set(r.x(), r.y(), r.right(), r.bottom());
+ mSelRegion.setEmpty();
+ CopyPaste::buildSelection(*mNavPictureUI, area, mSelStart, mSelEnd, &mSelRegion);
+ SkPath path;
+ mSelRegion.getBoundaryPath(&path);
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setColor(SkColorSetARGB(0x40, 255, 51, 204));
+ canvas->drawPath(path, paint);
+}
+
+void drawSelectionPointer(SkCanvas* canvas, int x, int y, bool gridded) {
+ SkPath path;
+ getSelectionCaret(&path);
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setColor(SK_ColorBLACK);
+ SkPixelXorXfermode xorMode(SK_ColorWHITE);
+ paint.setXfermode(&xorMode);
+ int sc = canvas->save();
+ if (gridded) {
+ bool useLeft = x <= (mSelStart.fLeft + mSelStart.fRight) >> 1;
+ canvas->translate(SkIntToScalar(useLeft ? mSelStart.fLeft :
+ mSelStart.fRight), SkIntToScalar(mSelStart.fTop));
+ } else
+ canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
+ canvas->drawPath(path, paint);
+ canvas->restoreToCount(sc);
+}
+
+void drawSelectionArrow(SkCanvas* canvas, int x, int y) {
+ SkPath path;
+ getSelectionArrow(&path);
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setColor(SK_ColorBLACK);
+ paint.setStrokeWidth(SK_Scalar1 * 2);
+ int sc = canvas->save();
+ canvas->translate(SkIntToScalar(x), SkIntToScalar(y));
+ canvas->drawPath(path, paint);
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setColor(SK_ColorWHITE);
+ canvas->drawPath(path, paint);
+ canvas->restoreToCount(sc);
+}
+
+void getSelectionArrow(SkPath* path) {
+ const int arrow[] = {
+ 0, 14, 3, 11, 5, 15, 9, 15, 7, 11, 11, 11
+ };
+ for (unsigned index = 0; index < sizeof(arrow)/sizeof(arrow[0]); index += 2)
+ path->lineTo(SkIntToScalar(arrow[index]), SkIntToScalar(arrow[index + 1]));
+ path->close();
+}
+
+void getSelectionCaret(SkPath* path) {
+ SkScalar height = SkIntToScalar(mSelStart.fBottom - mSelStart.fTop);
+ SkScalar dist = height / 4;
+ path->lineTo(0, height);
+ SkScalar bottom = height + dist;
+ path->lineTo(-dist, bottom);
+ SkScalar edge = bottom - SK_Scalar1/2;
+ path->moveTo(-dist, edge);
+ path->lineTo(dist, edge);
+ path->moveTo(dist, bottom);
+ path->lineTo(0, height);
+}
+
+void sendFinalFocus(WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y)
+{
+ DBG_NAV_LOGD("framePtr=%p nodePtr=%p x=%d y=%d", framePtr, nodePtr, x, y);
+ LOG_ASSERT(mJavaGlue.mObj, "A java object was not associated with this native WebView!");
+ JNIEnv* env = javavm_to_jnienv(mJavaGlue.mJVM);
+ env->CallVoidMethod(mJavaGlue.mObj, mJavaGlue.mSendFinalFocus,
+ (jint) framePtr, (jint) nodePtr, x, y);
+ checkException(env);
+}
+
+void sendKitFocus()
+{
+ LOG_ASSERT(mJavaGlue.mObj, "A java object was not associated with this native WebView!");
+ JNIEnv* env = javavm_to_jnienv(mJavaGlue.mJVM);
+ env->CallVoidMethod(mJavaGlue.mObj, mJavaGlue.mSendKitFocus);
+ checkException(env);
+}
+
+void sendMotionUp(int buildGeneration,
+ WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y, int slop,
+ bool isClick, bool retry)
+{
+ mViewImpl->mTouchGeneration = mViewImpl->mGeneration = ++mGeneration;
+ DBG_NAV_LOGD("buildGeneration=%d mGeneration=%d framePtr=%p nodePtr=%p"
+ " x=%d y=%d slop=%d", buildGeneration,
+ mGeneration, framePtr, nodePtr, x, y, slop);
+ LOG_ASSERT(mJavaGlue.mObj, "A WebView was not associated with this WebViewNative!");
+ JNIEnv* env = javavm_to_jnienv(mJavaGlue.mJVM);
+ env->CallVoidMethod(mJavaGlue.mObj, mJavaGlue.mSendMotionUp, mGeneration,
+ buildGeneration, (jint) framePtr, (jint) nodePtr, x, y, slop, isClick, retry);
+ checkException(env);
+}
+
+void setFocusData(int buildGeneration, WebCore::Frame* framePtr,
+ WebCore::Node* nodePtr, int x, int y, bool ignoreNullFocus)
+{
+ mViewImpl->mMoveGeneration = mViewImpl->mGeneration = ++mGeneration;
+ DBG_NAV_LOGD("moveGeneration=%d buildGeneration=%d framePtr=%p nodePtr=%p"
+ " x=%d y=%d", mGeneration, buildGeneration, framePtr, nodePtr, x, y);
+ LOG_ASSERT(mJavaGlue.mObj, "A java object was not associated with this native WebView!");
+ JNIEnv* env = javavm_to_jnienv(mJavaGlue.mJVM);
+ env->CallVoidMethod(mJavaGlue.mObj, mJavaGlue.mSetFocusData, mGeneration,
+ buildGeneration, (jint) framePtr, (jint) nodePtr, x, y, ignoreNullFocus);
+ checkException(env);
+}
+
+void scrollBy(int dx, int dy)
+{
+ LOG_ASSERT(mJavaGlue.mObj, "A java object was not associated with this native WebView!");
+
+ JNIEnv* env = javavm_to_jnienv(mJavaGlue.mJVM);
+ env->CallVoidMethod(mJavaGlue.mObj, mJavaGlue.mScrollBy, dx, dy);
+ checkException(env);
+}
+
+bool updateFocusNode(JNIEnv* env)
+{
+ CachedRoot* root = getFrameCache(DONT_ALLOW_NEWER);
+ if (root == NULL) {
+ DBG_NAV_LOG("root==NULL");
+ return false;
+ }
+ const CachedFrame* cachedFrame = NULL;
+ const CachedNode* cachedFocusNode = root->currentFocus(&cachedFrame);
+ if (cachedFocusNode == NULL) {
+ DBG_NAV_LOG("cachedFocusNode==NULL");
+ return false;
+ }
+ DBG_NAV_LOGD("cachedFocusNode=%d (nodePointer=%p)",
+ cachedFocusNode->index(),
+ cachedFocusNode->nodePointer());
+ jobject focusnode = env->GetObjectField(mJavaGlue.mObj, mJavaGlue.mFocusNode);
+ LOG_ASSERT(focusnode, "Could not find WebView's FocusNode");
+
+ bool isTextArea = cachedFocusNode->isTextArea();
+ bool isTextField = cachedFocusNode->isTextField();
+ int maxLength;
+ jstring jName;
+ if (isTextField) {
+ maxLength = cachedFocusNode->maxLength();
+ const WebCore::String& name = cachedFocusNode->name();
+ jName = env->NewString((jchar*)name.characters(), name.length());
+ } else {
+ maxLength = -1;
+ jName = NULL;
+ }
+ WebCore::IntRect bounds = cachedFocusNode->bounds();
+ WebCore::String value = cachedFocusNode->getExport();
+ jstring val = !value.isEmpty() ? env->NewString((jchar *)value.characters(), value.length()) : NULL;
+ env->CallVoidMethod(focusnode, mJavaGlue.mSetAll, isTextField, isTextArea, cachedFocusNode->isPassword(),
+ cachedFocusNode->isAnchor(), cachedFocusNode->isRtlText(), maxLength, cachedFocusNode->textSize(),
+ bounds.x(), bounds.y(), bounds.right(), bounds.bottom(), (int)(cachedFocusNode->nodePointer()),
+ (int)(cachedFrame->framePointer()), val, jName, root->textGeneration());
+ env->DeleteLocalRef(val);
+ env->DeleteLocalRef(focusnode);
+ if (isTextField)
+ env->DeleteLocalRef(jName);
+ return true;
+}
+
+void updateTextEntry()
+{
+ JNIEnv* env = javavm_to_jnienv(mJavaGlue.mJVM);
+ env->CallVoidMethod(mJavaGlue.mObj, mJavaGlue.mUpdateTextEntry);
+ checkException(env);
+}
+
+void viewInvalidate()
+{
+ JNIEnv* env = javavm_to_jnienv(mJavaGlue.mJVM);
+ env->CallVoidMethod(mJavaGlue.mObj, mJavaGlue.mViewInvalidate);
+ checkException(env);
+}
+
+void postInvalidateDelayed(int64_t delay, const WebCore::IntRect& bounds)
+{
+ JNIEnv* env = javavm_to_jnienv(mJavaGlue.mJVM);
+ env->CallVoidMethod(mJavaGlue.mObj, mJavaGlue.mPostInvalidateDelayed,
+ delay, bounds.x(), bounds.y(), bounds.right(), bounds.bottom());
+ checkException(env);
+}
+
+private: // local state for WebView
+ // private to getFrameCache(); other functions operate in a different thread
+ CachedRoot* mFrameCacheUI; // navigation data ready for use
+ FocusReplay mReplay;
+ WebViewCore* mViewImpl;
+ SkTDArray<Container*>* mUIButtons;
+ WebCore::Node* mInvalidNode;
+ int mGeneration; // associate unique ID with sent kit focus to match with ui
+ SkPicture* mNavPictureUI;
+ bool mFollowedLink;
+ SkMSec mRingAnimationEnd;
+ // Corresponds to the same-named boolean on the java side.
+ bool mHeightCanMeasure;
+ int mLastDx;
+ SkMSec mLastDxTime;
+}; // end of WebView class
+
+/*
+ * Native JNI methods
+ */
+static jstring WebCoreStringToJString(JNIEnv *env, WebCore::String string)
+{
+ int length = string.length();
+ if (0 == length)
+ return 0;
+ jstring ret = env->NewString((jchar *)string.characters(), length);
+ env->DeleteLocalRef(ret);
+ return ret;
+}
+
+#ifdef BUCKET_EXPERIMENT
+static void nativeClearContentPicture(JNIEnv *env, jobject obj)
+{
+ WebView* view = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
+ view->clearContentPicture();
+}
+#endif
+
+static void nativeClearFocus(JNIEnv *env, jobject obj, int x, int y)
+{
+ WebView* view = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
+ view->clearFocus(x, y, true);
+}
+
+static void nativeCreate(JNIEnv *env, jobject obj, int viewImpl)
+{
+ WebView* webview = new WebView(env, obj, viewImpl);
+ // NEED THIS OR SOMETHING LIKE IT!
+ //Release(obj);
+}
+
+static void nativeDebugDump(JNIEnv *env, jobject obj)
+{
+#if DUMP_NAV_CACHE
+ WebView* view = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
+ view->debugDump();
+#endif
+}
+
+#ifdef BUCKET_EXPERIMENT
+static void nativeDrawContentPicture(JNIEnv *env, jobject obj,
+ jobject canv)
+{
+ SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
+ if (canv == NULL) {
+ DBG_NAV_LOG("canv==NULL");
+ return;
+ }
+ WebView* view = GET_NATIVE_VIEW(env, obj);
+ if (view == NULL) {
+ DBG_NAV_LOG("view==NULL");
+ return;
+ }
+ view->drawContentPicture(canvas);
+}
+#endif
+
+static void nativeDrawFocusRing(JNIEnv *env, jobject obj,
+ jobject canv)
+{
+ SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
+ if (canv == NULL) {
+ DBG_NAV_LOG("canv==NULL");
+ return;
+ }
+ WebView* view = GET_NATIVE_VIEW(env, obj);
+ if (view == NULL) {
+ DBG_NAV_LOG("view==NULL");
+ return;
+ }
+ view->drawFocusRing(canvas);
+}
+
+static void nativeDrawSelection(JNIEnv *env, jobject obj,
+ jobject canv, jint x, jint y, bool ex)
+{
+ SkCanvas* canvas = GraphicsJNI::getNativeCanvas(env, canv);
+ if (canv == NULL) {
+ DBG_NAV_LOG("canv==NULL");
+ return;
+ }
+ WebView* view = GET_NATIVE_VIEW(env, obj);
+ if (view == NULL) {
+ DBG_NAV_LOG("view==NULL");
+ return;
+ }
+ view->drawSelection(canvas, x, y, ex);
+}
+
+static bool nativeHasSrcUrl(JNIEnv *env, jobject obj)
+{
+ WebView* view = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
+ return view->hasSrcUrl();
+}
+
+static bool nativeIsImage(JNIEnv *env, jobject obj, jint x, jint y)
+{
+ WebView* view = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
+ return view->isImage(x,y);
+}
+
+static WebCore::IntRect jrect_to_webrect(JNIEnv* env, jobject obj)
+{
+ int L, T, R, B;
+ GraphicsJNI::get_jrect(env, obj, &L, &T, &R, &B);
+ return WebCore::IntRect(L, T, R - L, B - T);
+}
+
+static void nativeSelectBestAt(JNIEnv *env, jobject obj, jobject jrect)
+{
+ WebView* view = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
+ WebCore::IntRect rect = jrect_to_webrect(env, jrect);
+ view->selectBestAt(rect);
+}
+
+static void nativeMarkNodeInvalid(JNIEnv *env, jobject obj, int node)
+{
+ WebView* view = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
+ view->markNodeInvalid((WebCore::Node*) node);
+}
+
+static void nativeMotionUp(JNIEnv *env, jobject obj,
+ int x, int y, int slop, bool isClick)
+{
+ WebView* view = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
+ view->motionUp(x, y, slop, isClick, true, false);
+}
+
+static bool nativeUpdateFocusNode(JNIEnv *env, jobject obj)
+{
+ WebView* view = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
+ return view->updateFocusNode(env);
+}
+
+static bool nativeMoveFocus(JNIEnv *env, jobject obj,
+ int key, int count, bool ignoreScroll)
+{
+ WebView* view = GET_NATIVE_VIEW(env, obj);
+ DBG_NAV_LOGD("env=%p obj=%p view=%p", env, obj, view);
+ LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
+ return view->moveFocus(key, count, ignoreScroll, true, NULL, NULL);
+}
+
+static void nativeNotifyFocusSet(JNIEnv *env, jobject obj, bool inEditingMode)
+{
+ WebView* view = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
+ view->notifyFocusSet((WebView::FrameCachePermission) inEditingMode);
+}
+
+static void nativeRecomputeFocus(JNIEnv *env, jobject obj)
+{
+ WebView* view = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
+ view->recomputeFocus();
+}
+
+static void nativeRecordButtons(JNIEnv* env, jobject obj)
+{
+ WebView* view = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
+ view->nativeRecordButtons();
+}
+
+static void nativeResetFocus(JNIEnv *env, jobject obj)
+{
+ WebView* view = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
+ view->resetFocus();
+}
+
+static void nativeSetFollowedLink(JNIEnv *env, jobject obj, bool followed)
+{
+ WebView* view = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
+ view->setFollowedLink(followed);
+}
+
+static void nativeSetHeightCanMeasure(JNIEnv *env, jobject obj, bool measure)
+{
+ WebView* view = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(view, "view not set in nativeSetHeightCanMeasure");
+ view->setHeightCanMeasure(measure);
+}
+
+static jobject nativeGetFocusRingBounds(JNIEnv *env, jobject obj)
+{
+ WebView* view = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
+ jclass rectClass = env->FindClass("android/graphics/Rect");
+ LOG_ASSERT(rectClass, "Could not find Rect class!");
+ jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
+ LOG_ASSERT(init, "Could not find constructor for Rect");
+ WebCore::IntRect webRect;
+ view->focusRingBounds(&webRect);
+ jobject rect = env->NewObject(rectClass, init, webRect.x(),
+ webRect.y(), webRect.right(), webRect.bottom());
+ return rect;
+}
+
+static jobject nativeGetNavBounds(JNIEnv *env, jobject obj)
+{
+ WebView* view = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
+ jclass rectClass = env->FindClass("android/graphics/Rect");
+ LOG_ASSERT(rectClass, "Could not find Rect class!");
+ jmethodID init = env->GetMethodID(rectClass, "<init>", "(IIII)V");
+ LOG_ASSERT(init, "Could not find constructor for Rect");
+ WebCore::IntRect webRect = view->getNavBounds();
+ jobject rect = env->NewObject(rectClass, init, webRect.x(),
+ webRect.y(), webRect.right(), webRect.bottom());
+ return rect;
+}
+
+static void nativeSetNavBounds(JNIEnv *env, jobject obj, jobject jrect)
+{
+ WebView* view = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
+ WebCore::IntRect rect = jrect_to_webrect(env, jrect);
+ view->setNavBounds(rect);
+}
+
+static void nativeUpdateCachedTextfield(JNIEnv *env, jobject obj, jstring updatedText, jint generation)
+{
+ WebView* view = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(view, "view not set in nativeUpdateCachedTextfield");
+ CachedRoot* root = view->getFrameCache(WebView::DONT_ALLOW_NEWER);
+ if (!root)
+ return;
+ const CachedNode* cachedFocusNode = root->currentFocus();
+ if (!cachedFocusNode || (!cachedFocusNode->isTextField() && !cachedFocusNode->isTextArea()))
+ return;
+ WebCore::String webcoreString;
+ const jchar* outputChars = NULL == updatedText ? NULL : env->GetStringChars(updatedText, NULL);
+ if (outputChars != NULL) {
+ webcoreString = WebCore::String((const UChar*) outputChars, env->GetStringLength(updatedText));
+ }
+ (const_cast<CachedNode*>(cachedFocusNode))->setExport(webcoreString);
+ root->setTextGeneration(generation);
+ if (outputChars)
+ env->ReleaseStringChars(updatedText, outputChars);
+ checkException(env);
+}
+
+static void nativeDestroy(JNIEnv *env, jobject obj)
+{
+ WebView* view = GET_NATIVE_VIEW(env, obj);
+ LOGD("nativeDestroy view: %p", view);
+ LOG_ASSERT(view, "view not set in nativeDestroy");
+ delete view;
+}
+
+static void nativeMoveSelection(JNIEnv *env, jobject obj, int x, int y, bool ex)
+{
+ WebView* view = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
+ view->moveSelection(x, y, ex);
+}
+
+static jobject nativeGetSelection(JNIEnv *env, jobject obj)
+{
+ WebView* view = GET_NATIVE_VIEW(env, obj);
+ LOG_ASSERT(view, "view not set in %s", __FUNCTION__);
+ return GraphicsJNI::createRegion(env, new SkRegion(view->getSelection()));
+}
+
+/*
+ * JNI registration
+ */
+static JNINativeMethod gJavaWebViewMethods[] = {
+#ifdef BUCKET_EXPERIMENT
+ { "nativeClearContentPicture", "()V",
+ (void*) nativeClearContentPicture },
+#endif
+ { "nativeClearFocus", "(II)V",
+ (void*) nativeClearFocus },
+ { "nativeCreate", "(I)V",
+ (void*) nativeCreate },
+ { "nativeDebugDump", "()V",
+ (void*) nativeDebugDump },
+ { "nativeDestroy", "()V",
+ (void*) nativeDestroy },
+#ifdef BUCKET_EXPERIMENT
+ { "nativeDrawContentPicture", "(Landroid/graphics/Canvas;)V",
+ (void*) nativeDrawContentPicture },
+#endif
+ { "nativeDrawFocusRing", "(Landroid/graphics/Canvas;)V",
+ (void*) nativeDrawFocusRing },
+ { "nativeDrawSelection", "(Landroid/graphics/Canvas;IIZ)V",
+ (void*) nativeDrawSelection },
+ { "nativeUpdateFocusNode", "()Z",
+ (void*) nativeUpdateFocusNode },
+ { "nativeGetFocusRingBounds", "()Landroid/graphics/Rect;",
+ (void*) nativeGetFocusRingBounds },
+ { "nativeGetNavBounds", "()Landroid/graphics/Rect;",
+ (void*) nativeGetNavBounds },
+ { "nativeHasSrcUrl", "()Z",
+ (void*) nativeHasSrcUrl },
+ { "nativeMarkNodeInvalid", "(I)V",
+ (void*) nativeMarkNodeInvalid },
+ { "nativeMotionUp", "(IIIZ)V",
+ (void*) nativeMotionUp },
+ { "nativeMoveFocus", "(IIZ)Z",
+ (void*) nativeMoveFocus },
+ { "nativeNotifyFocusSet", "(Z)V",
+ (void*) nativeNotifyFocusSet },
+ { "nativeRecomputeFocus", "()V",
+ (void*) nativeRecomputeFocus },
+ { "nativeRecordButtons", "()V",
+ (void*) nativeRecordButtons },
+ { "nativeResetFocus", "()V",
+ (void*) nativeResetFocus },
+ { "nativeSelectBestAt", "(Landroid/graphics/Rect;)V",
+ (void*) nativeSelectBestAt },
+ { "nativeSetFollowedLink", "(Z)V",
+ (void*) nativeSetFollowedLink },
+ { "nativeSetHeightCanMeasure", "(Z)V",
+ (void*) nativeSetHeightCanMeasure },
+ { "nativeSetNavBounds", "(Landroid/graphics/Rect;)V",
+ (void*) nativeSetNavBounds },
+ { "nativeIsImage", "(II)Z",
+ (void*) nativeIsImage },
+ { "nativeUpdateCachedTextfield", "(Ljava/lang/String;I)V",
+ (void*) nativeUpdateCachedTextfield },
+ { "nativeMoveSelection", "(IIZ)V",
+ (void*) nativeMoveSelection },
+ { "nativeGetSelection", "()Landroid/graphics/Region;",
+ (void*) nativeGetSelection }
+};
+
+int register_webview(JNIEnv* env)
+{
+ jclass clazz = env->FindClass("android/webkit/WebView");
+ LOG_ASSERT(clazz != NULL, "Unable to find class android/webkit/WebView");
+ gWebViewField = env->GetFieldID(clazz, "mNativeClass", "I");
+ LOG_ASSERT(gWebViewField != NULL, "Unable to find android/webkit/WebView.mNativeClass");
+
+ return jniRegisterNativeMethods(env, "android/webkit/WebView", gJavaWebViewMethods, NELEM(gJavaWebViewMethods));
+}
+
+} // namespace android
diff --git a/WebCore/platform/android/sort.cpp b/WebCore/platform/android/sort.cpp
new file mode 100644
index 0000000..58b620d
--- /dev/null
+++ b/WebCore/platform/android/sort.cpp
@@ -0,0 +1,48 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "config.h"
+
+namespace std
+{
+ void sort(const void** start, const void** end, const void** temp, Comparator comp)
+ {
+ size_t endlen = end - start;
+ size_t midlen = endlen / 2;
+ const void** mid = start + midlen;
+ if (midlen > 1)
+ sort(start, mid, temp, comp);
+ if (end - mid > 1)
+ sort(mid, end, temp, comp);
+ memcpy(temp, start, midlen * sizeof(*start));
+ size_t i = 0;
+ size_t j = midlen;
+ size_t off = 0;
+ while (i < midlen && j < endlen)
+ start[off++] = (*comp)(start[j], temp[i]) ? start[j++] : temp[i++];
+ if (i < midlen)
+ memcpy(&start[off], &temp[i], (midlen - i) * sizeof(*start));
+ }
+
+ void sort(const void** start, const void** end, Comparator comp) {
+ if (end - start > 1) {
+ const void** temp = new sortType[(end - start) / 2];
+ sort(start, end, temp, comp);
+ delete[] temp;
+ }
+ }
+}
diff --git a/WebCore/platform/android/stl/algorithm b/WebCore/platform/android/stl/algorithm
new file mode 100644
index 0000000..9657ceb
--- /dev/null
+++ b/WebCore/platform/android/stl/algorithm
@@ -0,0 +1,237 @@
+#ifdef __cplusplus
+
+/*
+ *
+ * Copyright (c) 1994
+ * Hewlett-Packard Company
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Hewlett-Packard Company makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ *
+ * Copyright (c) 1996-1998
+ * Silicon Graphics Computer Systems, Inc.
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Silicon Graphics makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ */
+
+ // extracted from stl_algobase.h
+ // full STL is not compatible with the ARM build
+ // a limited number of STL functions is used by webkit: swap, max, and min are
+ // included below for webkit compatibility
+
+#ifdef __GLIBCPP_INTERNAL_ALGOBASE_H
+#error "real STL defined"
+#endif
+
+#ifndef __ANDROID_ALGORITHM
+#define __ANDROID_ALGORITHM
+
+#ifndef __ANDROID_LIMITS
+#include <limits>
+#endif
+
+#include <SkScalar.h> // for SK_ScalarNaN
+#ifdef PREFIX_FOR_WEBCORE
+#include <SkTSearch.h>
+namespace WebCore {
+ class InlineTextBox;
+ class RenderLayer;
+}
+#endif
+#include <float.h>
+#include <math.h>
+#include <stdint.h>
+
+#ifndef WCHAR_MAX
+ #define WCHAR_MAX 0xFFFF
+#endif
+
+namespace std
+{
+ template<typename _Tp>
+ inline void
+ swap(_Tp& __a, _Tp& __b)
+ {
+ _Tp __tmp = __a;
+ __a = __b;
+ __b = __tmp;
+ }
+
+ #undef min
+ #undef max
+
+ template<typename _Tp>
+ inline const _Tp&
+ min(const _Tp& __a, const _Tp& __b)
+ {
+ return __b < __a ? __b : __a;
+ }
+
+ template<typename _Tp>
+ inline const _Tp&
+ max(const _Tp& __a, const _Tp& __b)
+ {
+ return __a < __b ? __b : __a;
+ }
+
+template <class _InputIter, class _OutputIter>
+inline _OutputIter copy(_InputIter __first, _InputIter __last,
+ _OutputIter __result)
+{
+ for (size_t __n = __last - __first; __n > 0; --__n) {
+ *__result = *__first;
+ ++__first;
+ ++__result;
+ }
+ return __result;
+}
+
+template <class _ForwardIter, class _Tp>
+void fill(_ForwardIter __first, _ForwardIter __last, const _Tp& __value) {
+ for ( ; __first != __last; ++__first)
+ *__first = __value;
+}
+
+#ifndef UINTPTR_MAX
+#define UINTPTR_MAX UINT32_MAX
+#endif
+
+#ifndef UINT32_MAX
+#define UINT32_MAX (0xffffffff)
+#endif
+
+template <typename T>
+struct numeric_limits {
+ /// Returns the minimum value for type T.
+ static inline T min (void) { return (T(0)); }
+ /// Returns the minimum value for type T.
+ static inline T max (void) { return (T(0)); }
+ static const bool is_signed = false; ///< True if the type is signed.
+ static const bool is_integer = false; ///< True if stores an exact value.
+ static const bool is_integral = false; ///< True if fixed size and cast-copyable.
+};
+
+template <typename T>
+struct numeric_limits<T*> {
+ static inline T* min (void) { return (NULL); }
+ static inline T* max (void) { return (UINTPTR_MAX); }
+ static const bool is_signed = false;
+ static const bool is_integer = true;
+ static const bool is_integral = true;
+};
+
+#define _NUMERIC_LIMITS(type, minVal, maxVal, quietNaN, bSigned, bInteger, bIntegral) \
+template <> \
+struct numeric_limits<type> { \
+ static inline type infinity (void) { return (maxVal); } \
+ static inline type min (void) { return (minVal); } \
+ static inline type max (void) { return (maxVal); } \
+ static inline type quiet_NaN() { return (quietNaN); } \
+ static const bool is_signed = bSigned; \
+ static const bool is_integer = bInteger; \
+ static const bool is_integral = bIntegral; \
+}
+
+//--------------------------------------------------------------------------------------
+// type min max NaN signed integer integral
+//--------------------------------------------------------------------------------------
+_NUMERIC_LIMITS (bool, false, true, 0, false, true, true);
+_NUMERIC_LIMITS (char, SCHAR_MIN, SCHAR_MAX, 0, true, true, true);
+_NUMERIC_LIMITS (int, INT_MIN, INT_MAX, 0, true, true, true);
+_NUMERIC_LIMITS (short, SHRT_MIN, SHRT_MAX, 0, true, true, true);
+_NUMERIC_LIMITS (long, LONG_MIN, LONG_MAX, 0, true, true, true);
+#if HAVE_THREE_CHAR_TYPES
+_NUMERIC_LIMITS (signed char, SCHAR_MIN, SCHAR_MAX, 0, true, true, true);
+#endif
+_NUMERIC_LIMITS (unsigned char, 0, UCHAR_MAX, 0, false, true, true);
+_NUMERIC_LIMITS (unsigned int, 0, UINT_MAX, 0, false, true, true);
+_NUMERIC_LIMITS (unsigned short,0, USHRT_MAX, 0, false, true, true);
+_NUMERIC_LIMITS (unsigned long, 0, ULONG_MAX, 0, false, true, true);
+_NUMERIC_LIMITS (wchar_t, 0, WCHAR_MAX, 0, false, true, true);
+_NUMERIC_LIMITS (float, FLT_MIN, FLT_MAX, SK_ScalarNaN, true, false, true);
+_NUMERIC_LIMITS (double, DBL_MIN, DBL_MAX, SK_ScalarNaN, true, false, true);
+_NUMERIC_LIMITS (long double, LDBL_MIN, LDBL_MAX, SK_ScalarNaN, true, false, true);
+#ifdef HAVE_LONG_LONG
+_NUMERIC_LIMITS (long long, LLONG_MIN, LLONG_MAX, 0, true, true, true);
+_NUMERIC_LIMITS (unsigned long long, 0, ULLONG_MAX, 0, false, true, true);
+#endif
+//--------------------------------------------------------------------------------------
+
+typedef int ptrdiff_t;
+
+#ifdef PREFIX_FOR_WEBCORE
+ typedef const void* sortType;
+ typedef bool (* Comparator)(const void*, const void*);
+
+ inline bool binary_search(const unsigned short* const base,
+ const unsigned short* const end,
+ short target)
+ {
+ return SkTSearch<unsigned short>(base, end - base, target, sizeof(unsigned short)) >= 0;
+ }
+
+ extern void sort(const void** start, const void** end, Comparator comp);
+
+ inline void sort (WebCore::InlineTextBox** start, WebCore::InlineTextBox**end,
+ bool (* comp)(const WebCore::InlineTextBox*, const WebCore::InlineTextBox*))
+ {
+ sort((const void**) start, (const void**) end, (Comparator) comp);
+ }
+
+ template<typename P> inline void stable_sort(P** start, P** end,
+ bool (* comp)(P*, P*))
+ {
+ sort((const void**) start, (const void**) end, (Comparator) comp);
+ }
+
+ template<typename P> void stable_sort(P* start, P* end, P* temp,
+ bool (& comp)(const P&, const P&)) {
+ size_t endlen = end - start;
+ size_t midlen = endlen / 2;
+ P* mid = start + midlen;
+ if (midlen > 1)
+ stable_sort(start, mid, temp, comp);
+ if (end - mid > 1)
+ stable_sort(mid, end, temp, comp);
+ memcpy(temp, start, midlen * sizeof(*start));
+ size_t i = 0;
+ size_t j = midlen;
+ size_t off = 0;
+ while (i < midlen && j < endlen)
+ start[off++] = (comp)(start[j], temp[i]) ? start[j++] : temp[i++];
+ if (i < midlen)
+ memcpy(&start[off], &temp[i], (midlen - i) * sizeof(*start));
+ }
+
+ template<typename P> void stable_sort(P* start, P* end,
+ bool (& comp)(const P&, const P&)) {
+ if (end - start > 1) {
+ P* temp = new P[(end - start) / 2];
+ stable_sort(start, end, temp, comp);
+ delete[] temp;
+ }
+ }
+
+ class ostream {
+ int this_class_intentionally_left_empty;
+ };
+#endif
+
+}
+
+#endif
+
+#endif // __cplusplus
+
diff --git a/WebCore/platform/android/stl/concept_checks.h b/WebCore/platform/android/stl/concept_checks.h
new file mode 100644
index 0000000..36df283
--- /dev/null
+++ b/WebCore/platform/android/stl/concept_checks.h
@@ -0,0 +1,811 @@
+/*
+ * Copyright (c) 1999
+ * Silicon Graphics Computer Systems, Inc.
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Silicon Graphics makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ */
+
+#ifndef __CONCEPT_CHECKS_H
+#define __CONCEPT_CHECKS_H
+
+/*
+ Use these macro like assertions, but they assert properties
+ on types (usually template arguments). In technical terms they
+ verify whether a type "models" a "concept".
+
+ This set of requirements and the terminology used here is derived
+ from the book "Generic Programming and the STL" by Matt Austern
+ (Addison Wesley). For further information please consult that
+ book. The requirements also are intended to match the ANSI/ISO C++
+ standard.
+
+ This file covers the basic concepts and the iterator concepts.
+ There are several other files that provide the requirements
+ for the STL containers:
+ container_concepts.h
+ sequence_concepts.h
+ assoc_container_concepts.h
+
+ Jeremy Siek, 1999
+
+ TO DO:
+ - some issues with regards to concept classification and mutability
+ including AssociativeContianer -> ForwardContainer
+ and SortedAssociativeContainer -> ReversibleContainer
+ - HashedAssociativeContainer
+ - Allocator
+ - Function Object Concepts
+
+ */
+
+#ifndef __STL_USE_CONCEPT_CHECKS
+
+// Some compilers lack the features that are necessary for concept checks.
+// On those compilers we define the concept check macros to do nothing.
+#define __STL_REQUIRES(__type_var, __concept) do {} while(0)
+#define __STL_CLASS_REQUIRES(__type_var, __concept) \
+ static int __##__type_var##_##__concept
+#define __STL_CONVERTIBLE(__type_x, __type_y) do {} while(0)
+#define __STL_REQUIRES_SAME_TYPE(__type_x, __type_y) do {} while(0)
+#define __STL_CLASS_REQUIRES_SAME_TYPE(__type_x, __type_y) \
+ static int __##__type_x##__type_y##_require_same_type
+#define __STL_GENERATOR_CHECK(__func, __ret) do {} while(0)
+#define __STL_CLASS_GENERATOR_CHECK(__func, __ret) \
+ static int __##__func##__ret##_generator_check
+#define __STL_UNARY_FUNCTION_CHECK(__func, __ret, __arg) do {} while(0)
+#define __STL_CLASS_UNARY_FUNCTION_CHECK(__func, __ret, __arg) \
+ static int __##__func##__ret##__arg##_unary_function_check
+#define __STL_BINARY_FUNCTION_CHECK(__func, __ret, __first, __second) \
+ do {} while(0)
+#define __STL_CLASS_BINARY_FUNCTION_CHECK(__func, __ret, __first, __second) \
+ static int __##__func##__ret##__first##__second##_binary_function_check
+#define __STL_REQUIRES_BINARY_OP(__opname, __ret, __first, __second) \
+ do {} while(0)
+#define __STL_CLASS_REQUIRES_BINARY_OP(__opname, __ret, __first, __second) \
+ static int __##__opname##__ret##__first##__second##_require_binary_op
+
+#else /* __STL_USE_CONCEPT_CHECKS */
+
+// This macro tests whether the template argument "__type_var"
+// satisfies the requirements of "__concept". Here is a list of concepts
+// that we know how to check:
+// _Allocator
+// _Assignable
+// _DefaultConstructible
+// _EqualityComparable
+// _LessThanComparable
+// _TrivialIterator
+// _InputIterator
+// _OutputIterator
+// _ForwardIterator
+// _BidirectionalIterator
+// _RandomAccessIterator
+// _Mutable_TrivialIterator
+// _Mutable_ForwardIterator
+// _Mutable_BidirectionalIterator
+// _Mutable_RandomAccessIterator
+
+#define __STL_REQUIRES(__type_var, __concept) \
+do { \
+ void (*__x)( __type_var ) = __concept##_concept_specification< __type_var >\
+ ::__concept##_requirement_violation; __x = __x; } while (0)
+
+// Use this to check whether type X is convertible to type Y
+#define __STL_CONVERTIBLE(__type_x, __type_y) \
+do { \
+ void (*__x)( __type_x , __type_y ) = _STL_CONVERT_ERROR< __type_x , \
+ __type_y >::__type_X_is_not_convertible_to_type_Y; \
+ __x = __x; } while (0)
+
+// Use this to test whether two template arguments are the same type
+#define __STL_REQUIRES_SAME_TYPE(__type_x, __type_y) \
+do { \
+ void (*__x)( __type_x , __type_y ) = _STL_SAME_TYPE_ERROR< __type_x, \
+ __type_y >::__type_X_not_same_as_type_Y; \
+ __x = __x; } while (0)
+
+
+// function object checks
+#define __STL_GENERATOR_CHECK(__func, __ret) \
+do { \
+ __ret (*__x)( __func&) = \
+ _STL_GENERATOR_ERROR< \
+ __func, __ret>::__generator_requirement_violation; \
+ __x = __x; } while (0)
+
+
+#define __STL_UNARY_FUNCTION_CHECK(__func, __ret, __arg) \
+do { \
+ __ret (*__x)( __func&, const __arg& ) = \
+ _STL_UNARY_FUNCTION_ERROR< \
+ __func, __ret, __arg>::__unary_function_requirement_violation; \
+ __x = __x; } while (0)
+
+
+#define __STL_BINARY_FUNCTION_CHECK(__func, __ret, __first, __second) \
+do { \
+ __ret (*__x)( __func&, const __first&, const __second& ) = \
+ _STL_BINARY_FUNCTION_ERROR< \
+ __func, __ret, __first, __second>::__binary_function_requirement_violation; \
+ __x = __x; } while (0)
+
+
+#define __STL_REQUIRES_BINARY_OP(__opname, __ret, __first, __second) \
+ do { \
+ __ret (*__x)( __first&, __second& ) = _STL_BINARY##__opname##_ERROR< \
+ __ret, __first, __second>::__binary_operator_requirement_violation; \
+ __ret (*__y)( const __first&, const __second& ) = \
+ _STL_BINARY##__opname##_ERROR< __ret, __first, __second>:: \
+ __const_binary_operator_requirement_violation; \
+ __y = __y; __x = __x; } while (0)
+
+
+#ifdef __STL_NO_FUNCTION_PTR_IN_CLASS_TEMPLATE
+
+#define __STL_CLASS_REQUIRES(__type_var, __concept)
+#define __STL_CLASS_REQUIRES_SAME_TYPE(__type_x, __type_y)
+#define __STL_CLASS_GENERATOR_CHECK(__func, __ret)
+#define __STL_CLASS_UNARY_FUNCTION_CHECK(__func, __ret, __arg)
+#define __STL_CLASS_BINARY_FUNCTION_CHECK(__func, __ret, __first, __second)
+#define __STL_CLASS_REQUIRES_BINARY_OP(__opname, __ret, __first, __second)
+
+#else
+
+// Use this macro inside of template classes, where you would
+// like to place requirements on the template arguments to the class
+// Warning: do not pass pointers and such (e.g. T*) in as the __type_var,
+// since the type_var is used to construct identifiers. Instead typedef
+// the pointer type, then use the typedef name for the __type_var.
+#define __STL_CLASS_REQUIRES(__type_var, __concept) \
+ typedef void (* __func##__type_var##__concept)( __type_var ); \
+ template <__func##__type_var##__concept _Tp1> \
+ struct __dummy_struct_##__type_var##__concept { }; \
+ static __dummy_struct_##__type_var##__concept< \
+ __concept##_concept_specification< \
+ __type_var>::__concept##_requirement_violation> \
+ __dummy_ptr_##__type_var##__concept
+
+
+#define __STL_CLASS_REQUIRES_SAME_TYPE(__type_x, __type_y) \
+ typedef void (* __func_##__type_x##__type_y##same_type)( __type_x, \
+ __type_y ); \
+ template < __func_##__type_x##__type_y##same_type _Tp1> \
+ struct __dummy_struct_##__type_x##__type_y##_same_type { }; \
+ static __dummy_struct_##__type_x##__type_y##_same_type< \
+ _STL_SAME_TYPE_ERROR<__type_x, __type_y>::__type_X_not_same_as_type_Y> \
+ __dummy_ptr_##__type_x##__type_y##_same_type
+
+
+#define __STL_CLASS_GENERATOR_CHECK(__func, __ret) \
+ typedef __ret (* __f_##__func##__ret##_generator)( __func& ); \
+ template <__f_##__func##__ret##_generator _Tp1> \
+ struct __dummy_struct_##__func##__ret##_generator { }; \
+ static __dummy_struct_##__func##__ret##_generator< \
+ _STL_GENERATOR_ERROR< \
+ __func, __ret>::__generator_requirement_violation> \
+ __dummy_ptr_##__func##__ret##_generator
+
+
+#define __STL_CLASS_UNARY_FUNCTION_CHECK(__func, __ret, __arg) \
+ typedef __ret (* __f_##__func##__ret##__arg##_unary_check)( __func&, \
+ const __arg& ); \
+ template <__f_##__func##__ret##__arg##_unary_check _Tp1> \
+ struct __dummy_struct_##__func##__ret##__arg##_unary_check { }; \
+ static __dummy_struct_##__func##__ret##__arg##_unary_check< \
+ _STL_UNARY_FUNCTION_ERROR< \
+ __func, __ret, __arg>::__unary_function_requirement_violation> \
+ __dummy_ptr_##__func##__ret##__arg##_unary_check
+
+
+#define __STL_CLASS_BINARY_FUNCTION_CHECK(__func, __ret, __first, __second) \
+ typedef __ret (* __f_##__func##__ret##__first##__second##_binary_check)( __func&, const __first&,\
+ const __second& ); \
+ template <__f_##__func##__ret##__first##__second##_binary_check _Tp1> \
+ struct __dummy_struct_##__func##__ret##__first##__second##_binary_check { }; \
+ static __dummy_struct_##__func##__ret##__first##__second##_binary_check< \
+ _STL_BINARY_FUNCTION_ERROR<__func, __ret, __first, __second>:: \
+ __binary_function_requirement_violation> \
+ __dummy_ptr_##__func##__ret##__first##__second##_binary_check
+
+
+#define __STL_CLASS_REQUIRES_BINARY_OP(__opname, __ret, __first, __second) \
+ typedef __ret (* __f_##__func##__ret##__first##__second##_binary_op)(const __first&, \
+ const __second& ); \
+ template <__f_##__func##__ret##__first##__second##_binary_op _Tp1> \
+ struct __dummy_struct_##__func##__ret##__first##__second##_binary_op { }; \
+ static __dummy_struct_##__func##__ret##__first##__second##_binary_op< \
+ _STL_BINARY##__opname##_ERROR<__ret, __first, __second>:: \
+ __binary_operator_requirement_violation> \
+ __dummy_ptr_##__func##__ret##__first##__second##_binary_op
+
+#endif
+
+/* helper class for finding non-const version of a type. Need to have
+ something to assign to etc. when testing constant iterators. */
+
+template <class _Tp>
+struct _Mutable_trait {
+ typedef _Tp _Type;
+};
+template <class _Tp>
+struct _Mutable_trait<const _Tp> {
+ typedef _Tp _Type;
+};
+
+
+/* helper function for avoiding compiler warnings about unused variables */
+template <class _Type>
+void __sink_unused_warning(_Type) { }
+
+template <class _TypeX, class _TypeY>
+struct _STL_CONVERT_ERROR {
+ static void
+ __type_X_is_not_convertible_to_type_Y(_TypeX __x, _TypeY) {
+ _TypeY __y = __x;
+ __sink_unused_warning(__y);
+ }
+};
+
+
+template <class _Type> struct __check_equal { };
+
+template <class _TypeX, class _TypeY>
+struct _STL_SAME_TYPE_ERROR {
+ static void
+ __type_X_not_same_as_type_Y(_TypeX , _TypeY ) {
+ __check_equal<_TypeX> t1 = __check_equal<_TypeY>();
+ }
+};
+
+
+// Some Functon Object Checks
+
+template <class _Func, class _Ret>
+struct _STL_GENERATOR_ERROR {
+ static _Ret __generator_requirement_violation(_Func& __f) {
+ return __f();
+ }
+};
+
+template <class _Func>
+struct _STL_GENERATOR_ERROR<_Func, void> {
+ static void __generator_requirement_violation(_Func& __f) {
+ __f();
+ }
+};
+
+
+template <class _Func, class _Ret, class _Arg>
+struct _STL_UNARY_FUNCTION_ERROR {
+ static _Ret
+ __unary_function_requirement_violation(_Func& __f,
+ const _Arg& __arg) {
+ return __f(__arg);
+ }
+};
+
+template <class _Func, class _Arg>
+struct _STL_UNARY_FUNCTION_ERROR<_Func, void, _Arg> {
+ static void
+ __unary_function_requirement_violation(_Func& __f,
+ const _Arg& __arg) {
+ __f(__arg);
+ }
+};
+
+template <class _Func, class _Ret, class _First, class _Second>
+struct _STL_BINARY_FUNCTION_ERROR {
+ static _Ret
+ __binary_function_requirement_violation(_Func& __f,
+ const _First& __first,
+ const _Second& __second) {
+ return __f(__first, __second);
+ }
+};
+
+template <class _Func, class _First, class _Second>
+struct _STL_BINARY_FUNCTION_ERROR<_Func, void, _First, _Second> {
+ static void
+ __binary_function_requirement_violation(_Func& __f,
+ const _First& __first,
+ const _Second& __second) {
+ __f(__first, __second);
+ }
+};
+
+
+#define __STL_DEFINE_BINARY_OP_CHECK(_OP, _NAME) \
+template <class _Ret, class _First, class _Second> \
+struct _STL_BINARY##_NAME##_ERROR { \
+ static _Ret \
+ __const_binary_operator_requirement_violation(const _First& __first, \
+ const _Second& __second) { \
+ return __first _OP __second; \
+ } \
+ static _Ret \
+ __binary_operator_requirement_violation(_First& __first, \
+ _Second& __second) { \
+ return __first _OP __second; \
+ } \
+}
+
+__STL_DEFINE_BINARY_OP_CHECK(==, _OP_EQUAL);
+__STL_DEFINE_BINARY_OP_CHECK(!=, _OP_NOT_EQUAL);
+__STL_DEFINE_BINARY_OP_CHECK(<, _OP_LESS_THAN);
+__STL_DEFINE_BINARY_OP_CHECK(<=, _OP_LESS_EQUAL);
+__STL_DEFINE_BINARY_OP_CHECK(>, _OP_GREATER_THAN);
+__STL_DEFINE_BINARY_OP_CHECK(>=, _OP_GREATER_EQUAL);
+__STL_DEFINE_BINARY_OP_CHECK(+, _OP_PLUS);
+__STL_DEFINE_BINARY_OP_CHECK(*, _OP_TIMES);
+__STL_DEFINE_BINARY_OP_CHECK(/, _OP_DIVIDE);
+__STL_DEFINE_BINARY_OP_CHECK(-, _OP_SUBTRACT);
+__STL_DEFINE_BINARY_OP_CHECK(%, _OP_MOD);
+// ...
+
+// TODO, add unary operators (prefix and postfix)
+
+/*
+ The presence of this class is just to trick EDG into displaying
+ these error messages before any other errors. Without the
+ classes, the errors in the functions get reported after
+ other class errors deep inside the library. The name
+ choice just makes for an eye catching error message :)
+ */
+struct _STL_ERROR {
+
+ template <class _Type>
+ static _Type
+ __default_constructor_requirement_violation(_Type) {
+ return _Type();
+ }
+ template <class _Type>
+ static _Type
+ __assignment_operator_requirement_violation(_Type __a) {
+ __a = __a;
+ return __a;
+ }
+ template <class _Type>
+ static _Type
+ __copy_constructor_requirement_violation(_Type __a) {
+ _Type __c(__a);
+ return __c;
+ }
+ template <class _Type>
+ static _Type
+ __const_parameter_required_for_copy_constructor(_Type /* __a */,
+ const _Type& __b) {
+ _Type __c(__b);
+ return __c;
+ }
+ template <class _Type>
+ static _Type
+ __const_parameter_required_for_assignment_operator(_Type __a,
+ const _Type& __b) {
+ __a = __b;
+ return __a;
+ }
+ template <class _Type>
+ static _Type
+ __less_than_comparable_requirement_violation(_Type __a, _Type __b) {
+ if (__a < __b || __a > __b || __a <= __b || __a >= __b) return __a;
+ return __b;
+ }
+ template <class _Type>
+ static _Type
+ __equality_comparable_requirement_violation(_Type __a, _Type __b) {
+ if (__a == __b || __a != __b) return __a;
+ return __b;
+ }
+ template <class _Iterator>
+ static void
+ __dereference_operator_requirement_violation(_Iterator __i) {
+ __sink_unused_warning(*__i);
+ }
+ template <class _Iterator>
+ static void
+ __dereference_operator_and_assignment_requirement_violation(_Iterator __i) {
+ *__i = *__i;
+ }
+ template <class _Iterator>
+ static void
+ __preincrement_operator_requirement_violation(_Iterator __i) {
+ ++__i;
+ }
+ template <class _Iterator>
+ static void
+ __postincrement_operator_requirement_violation(_Iterator __i) {
+ __i++;
+ }
+ template <class _Iterator>
+ static void
+ __predecrement_operator_requirement_violation(_Iterator __i) {
+ --__i;
+ }
+ template <class _Iterator>
+ static void
+ __postdecrement_operator_requirement_violation(_Iterator __i) {
+ __i--;
+ }
+ template <class _Iterator, class _Type>
+ static void
+ __postincrement_operator_and_assignment_requirement_violation(_Iterator __i,
+ _Type __t) {
+ *__i++ = __t;
+ }
+ template <class _Iterator, class _Distance>
+ static _Iterator
+ __iterator_addition_assignment_requirement_violation(_Iterator __i,
+ _Distance __n) {
+ __i += __n;
+ return __i;
+ }
+ template <class _Iterator, class _Distance>
+ static _Iterator
+ __iterator_addition_requirement_violation(_Iterator __i, _Distance __n) {
+ __i = __i + __n;
+ __i = __n + __i;
+ return __i;
+ }
+ template <class _Iterator, class _Distance>
+ static _Iterator
+ __iterator_subtraction_assignment_requirement_violation(_Iterator __i,
+ _Distance __n) {
+ __i -= __n;
+ return __i;
+ }
+ template <class _Iterator, class _Distance>
+ static _Iterator
+ __iterator_subtraction_requirement_violation(_Iterator __i, _Distance __n) {
+ __i = __i - __n;
+ return __i;
+ }
+ template <class _Iterator, class _Distance>
+ static _Distance
+ __difference_operator_requirement_violation(_Iterator __i, _Iterator __j,
+ _Distance __n) {
+ __n = __i - __j;
+ return __n;
+ }
+ template <class _Exp, class _Type, class _Distance>
+ static _Type
+ __element_access_operator_requirement_violation(_Exp __x, _Type*,
+ _Distance __n) {
+ return __x[__n];
+ }
+ template <class _Exp, class _Type, class _Distance>
+ static void
+ __element_assignment_operator_requirement_violation(_Exp __x,
+ _Type* __t,
+ _Distance __n) {
+ __x[__n] = *__t;
+ }
+
+}; /* _STL_ERROR */
+
+/* Associated Type Requirements */
+
+__STL_BEGIN_NAMESPACE
+template <class _Iterator> struct iterator_traits;
+__STL_END_NAMESPACE
+
+template <class _Iter>
+struct __value_type_type_definition_requirement_violation {
+ typedef typename __STD::iterator_traits<_Iter>::value_type value_type;
+};
+
+template <class _Iter>
+struct __difference_type_type_definition_requirement_violation {
+ typedef typename __STD::iterator_traits<_Iter>::difference_type
+ difference_type;
+};
+
+template <class _Iter>
+struct __reference_type_definition_requirement_violation {
+ typedef typename __STD::iterator_traits<_Iter>::reference reference;
+};
+
+template <class _Iter>
+struct __pointer_type_definition_requirement_violation {
+ typedef typename __STD::iterator_traits<_Iter>::pointer pointer;
+};
+
+template <class _Iter>
+struct __iterator_category_type_definition_requirement_violation {
+ typedef typename __STD::iterator_traits<_Iter>::iterator_category
+ iterator_category;
+};
+
+/* Assignable Requirements */
+
+
+template <class _Type>
+struct _Assignable_concept_specification {
+ static void _Assignable_requirement_violation(_Type __a) {
+ _STL_ERROR::__assignment_operator_requirement_violation(__a);
+ _STL_ERROR::__copy_constructor_requirement_violation(__a);
+ _STL_ERROR::__const_parameter_required_for_copy_constructor(__a,__a);
+ _STL_ERROR::__const_parameter_required_for_assignment_operator(__a,__a);
+ }
+};
+
+/* DefaultConstructible Requirements */
+
+
+template <class _Type>
+struct _DefaultConstructible_concept_specification {
+ static void _DefaultConstructible_requirement_violation(_Type __a) {
+ _STL_ERROR::__default_constructor_requirement_violation(__a);
+ }
+};
+
+/* EqualityComparable Requirements */
+
+template <class _Type>
+struct _EqualityComparable_concept_specification {
+ static void _EqualityComparable_requirement_violation(_Type __a) {
+ _STL_ERROR::__equality_comparable_requirement_violation(__a, __a);
+ }
+};
+
+/* LessThanComparable Requirements */
+template <class _Type>
+struct _LessThanComparable_concept_specification {
+ static void _LessThanComparable_requirement_violation(_Type __a) {
+ _STL_ERROR::__less_than_comparable_requirement_violation(__a, __a);
+ }
+};
+
+/* TrivialIterator Requirements */
+
+template <class _TrivialIterator>
+struct _TrivialIterator_concept_specification {
+static void
+_TrivialIterator_requirement_violation(_TrivialIterator __i) {
+ typedef typename
+ __value_type_type_definition_requirement_violation<_TrivialIterator>::
+ value_type __T;
+ // Refinement of Assignable
+ _Assignable_concept_specification<_TrivialIterator>::
+ _Assignable_requirement_violation(__i);
+ // Refinement of DefaultConstructible
+ _DefaultConstructible_concept_specification<_TrivialIterator>::
+ _DefaultConstructible_requirement_violation(__i);
+ // Refinement of EqualityComparable
+ _EqualityComparable_concept_specification<_TrivialIterator>::
+ _EqualityComparable_requirement_violation(__i);
+ // Valid Expressions
+ _STL_ERROR::__dereference_operator_requirement_violation(__i);
+}
+};
+
+template <class _TrivialIterator>
+struct _Mutable_TrivialIterator_concept_specification {
+static void
+_Mutable_TrivialIterator_requirement_violation(_TrivialIterator __i) {
+ _TrivialIterator_concept_specification<_TrivialIterator>::
+ _TrivialIterator_requirement_violation(__i);
+ // Valid Expressions
+ _STL_ERROR::__dereference_operator_and_assignment_requirement_violation(__i);
+}
+};
+
+/* InputIterator Requirements */
+
+template <class _InputIterator>
+struct _InputIterator_concept_specification {
+static void
+_InputIterator_requirement_violation(_InputIterator __i) {
+ // Refinement of TrivialIterator
+ _TrivialIterator_concept_specification<_InputIterator>::
+ _TrivialIterator_requirement_violation(__i);
+ // Associated Types
+ __difference_type_type_definition_requirement_violation<_InputIterator>();
+ __reference_type_definition_requirement_violation<_InputIterator>();
+ __pointer_type_definition_requirement_violation<_InputIterator>();
+ __iterator_category_type_definition_requirement_violation<_InputIterator>();
+ // Valid Expressions
+ _STL_ERROR::__preincrement_operator_requirement_violation(__i);
+ _STL_ERROR::__postincrement_operator_requirement_violation(__i);
+}
+};
+
+/* OutputIterator Requirements */
+
+template <class _OutputIterator>
+struct _OutputIterator_concept_specification {
+static void
+_OutputIterator_requirement_violation(_OutputIterator __i) {
+ // Refinement of Assignable
+ _Assignable_concept_specification<_OutputIterator>::
+ _Assignable_requirement_violation(__i);
+ // Associated Types
+ __iterator_category_type_definition_requirement_violation<_OutputIterator>();
+ // Valid Expressions
+ _STL_ERROR::__dereference_operator_requirement_violation(__i);
+ _STL_ERROR::__preincrement_operator_requirement_violation(__i);
+ _STL_ERROR::__postincrement_operator_requirement_violation(__i);
+ _STL_ERROR::
+ __postincrement_operator_and_assignment_requirement_violation(__i, *__i);
+}
+};
+
+/* ForwardIterator Requirements */
+
+template <class _ForwardIterator>
+struct _ForwardIterator_concept_specification {
+static void
+_ForwardIterator_requirement_violation(_ForwardIterator __i) {
+ // Refinement of InputIterator
+ _InputIterator_concept_specification<_ForwardIterator>::
+ _InputIterator_requirement_violation(__i);
+}
+};
+
+template <class _ForwardIterator>
+struct _Mutable_ForwardIterator_concept_specification {
+static void
+_Mutable_ForwardIterator_requirement_violation(_ForwardIterator __i) {
+ _ForwardIterator_concept_specification<_ForwardIterator>::
+ _ForwardIterator_requirement_violation(__i);
+ // Refinement of OutputIterator
+ _OutputIterator_concept_specification<_ForwardIterator>::
+ _OutputIterator_requirement_violation(__i);
+}
+};
+
+/* BidirectionalIterator Requirements */
+
+template <class _BidirectionalIterator>
+struct _BidirectionalIterator_concept_specification {
+static void
+_BidirectionalIterator_requirement_violation(_BidirectionalIterator __i) {
+ // Refinement of ForwardIterator
+ _ForwardIterator_concept_specification<_BidirectionalIterator>::
+ _ForwardIterator_requirement_violation(__i);
+ // Valid Expressions
+ _STL_ERROR::__predecrement_operator_requirement_violation(__i);
+ _STL_ERROR::__postdecrement_operator_requirement_violation(__i);
+}
+};
+
+template <class _BidirectionalIterator>
+struct _Mutable_BidirectionalIterator_concept_specification {
+static void
+_Mutable_BidirectionalIterator_requirement_violation(
+ _BidirectionalIterator __i)
+{
+ _BidirectionalIterator_concept_specification<_BidirectionalIterator>::
+ _BidirectionalIterator_requirement_violation(__i);
+ // Refinement of mutable_ForwardIterator
+ _Mutable_ForwardIterator_concept_specification<_BidirectionalIterator>::
+ _Mutable_ForwardIterator_requirement_violation(__i);
+ typedef typename
+ __value_type_type_definition_requirement_violation<
+ _BidirectionalIterator>::value_type __T;
+ typename _Mutable_trait<__T>::_Type* __tmp_ptr = 0;
+ // Valid Expressions
+ _STL_ERROR::
+ __postincrement_operator_and_assignment_requirement_violation(__i,
+ *__tmp_ptr);
+}
+};
+
+/* RandomAccessIterator Requirements */
+
+template <class _RandAccIter>
+struct _RandomAccessIterator_concept_specification {
+static void
+_RandomAccessIterator_requirement_violation(_RandAccIter __i) {
+ // Refinement of BidirectionalIterator
+ _BidirectionalIterator_concept_specification<_RandAccIter>::
+ _BidirectionalIterator_requirement_violation(__i);
+ // Refinement of LessThanComparable
+ _LessThanComparable_concept_specification<_RandAccIter>::
+ _LessThanComparable_requirement_violation(__i);
+ typedef typename
+ __value_type_type_definition_requirement_violation<_RandAccIter>
+ ::value_type
+ value_type;
+ typedef typename
+ __difference_type_type_definition_requirement_violation<_RandAccIter>
+ ::difference_type
+ _Dist;
+ typedef typename _Mutable_trait<_Dist>::_Type _MutDist;
+
+ // Valid Expressions
+ _STL_ERROR::__iterator_addition_assignment_requirement_violation(__i,
+ _MutDist());
+ _STL_ERROR::__iterator_addition_requirement_violation(__i,
+ _MutDist());
+ _STL_ERROR::
+ __iterator_subtraction_assignment_requirement_violation(__i,
+ _MutDist());
+ _STL_ERROR::__iterator_subtraction_requirement_violation(__i,
+ _MutDist());
+ _STL_ERROR::__difference_operator_requirement_violation(__i, __i,
+ _MutDist());
+ typename _Mutable_trait<value_type>::_Type* __dummy_ptr = 0;
+ _STL_ERROR::__element_access_operator_requirement_violation(__i,
+ __dummy_ptr,
+ _MutDist());
+}
+};
+
+template <class _RandAccIter>
+struct _Mutable_RandomAccessIterator_concept_specification {
+static void
+_Mutable_RandomAccessIterator_requirement_violation(_RandAccIter __i)
+{
+ _RandomAccessIterator_concept_specification<_RandAccIter>::
+ _RandomAccessIterator_requirement_violation(__i);
+ // Refinement of mutable_BidirectionalIterator
+ _Mutable_BidirectionalIterator_concept_specification<_RandAccIter>::
+ _Mutable_BidirectionalIterator_requirement_violation(__i);
+ typedef typename
+ __value_type_type_definition_requirement_violation<_RandAccIter>
+ ::value_type
+ value_type;
+ typedef typename
+ __difference_type_type_definition_requirement_violation<_RandAccIter>
+ ::difference_type
+ _Dist;
+
+ typename _Mutable_trait<value_type>::_Type* __tmp_ptr = 0;
+ // Valid Expressions
+ _STL_ERROR::__element_assignment_operator_requirement_violation(__i,
+ __tmp_ptr, _Dist());
+}
+};
+
+#define __STL_TYPEDEF_REQUIREMENT(__REQUIREMENT) \
+template <class Type> \
+struct __##__REQUIREMENT##__typedef_requirement_violation { \
+ typedef typename Type::__REQUIREMENT __REQUIREMENT; \
+}
+
+__STL_TYPEDEF_REQUIREMENT(value_type);
+__STL_TYPEDEF_REQUIREMENT(difference_type);
+__STL_TYPEDEF_REQUIREMENT(size_type);
+__STL_TYPEDEF_REQUIREMENT(reference);
+__STL_TYPEDEF_REQUIREMENT(const_reference);
+__STL_TYPEDEF_REQUIREMENT(pointer);
+__STL_TYPEDEF_REQUIREMENT(const_pointer);
+
+
+template <class _Alloc>
+struct _Allocator_concept_specification {
+static void
+_Allocator_requirement_violation(_Alloc __a) {
+ // Refinement of DefaultConstructible
+ _DefaultConstructible_concept_specification<_Alloc>::
+ _DefaultConstructible_requirement_violation(__a);
+ // Refinement of EqualityComparable
+ _EqualityComparable_concept_specification<_Alloc>::
+ _EqualityComparable_requirement_violation(__a);
+ // Associated Types
+ __value_type__typedef_requirement_violation<_Alloc>();
+ __difference_type__typedef_requirement_violation<_Alloc>();
+ __size_type__typedef_requirement_violation<_Alloc>();
+ __reference__typedef_requirement_violation<_Alloc>();
+ __const_reference__typedef_requirement_violation<_Alloc>();
+ __pointer__typedef_requirement_violation<_Alloc>();
+ __const_pointer__typedef_requirement_violation<_Alloc>();
+ typedef typename _Alloc::value_type _Tp;
+ //__STL_REQUIRES_SAME_TYPE(typename _Alloc::__STL_TEMPLATE rebind<_Tp>::other,
+ // _Alloc);
+}
+};
+
+#endif /* __STL_USE_CONCEPT_CHECKS */
+
+#endif /* __CONCEPT_CHECKS_H */
+
+// Local Variables:
+// mode:C++
+// End:
diff --git a/WebCore/platform/android/stl/cstring b/WebCore/platform/android/stl/cstring
new file mode 100644
index 0000000..77c9175
--- /dev/null
+++ b/WebCore/platform/android/stl/cstring
@@ -0,0 +1,128 @@
+// -*- C++ -*- forwarding header.
+
+// Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002
+// Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 2, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING. If not, write to the Free
+// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+// USA.
+
+// As a special exception, you may use this file as part of a free software
+// library without restriction. Specifically, if other files instantiate
+// templates or use macros or inline functions from this file, or you compile
+// this file and link it with other files to produce an executable, this
+// file does not by itself cause the resulting executable to be covered by
+// the GNU General Public License. This exception does not however
+// invalidate any other reasons why the executable file might be covered by
+// the GNU General Public License.
+
+//
+// ISO C++ 14882: 20.4.6 C library
+//
+
+/** @file cstring
+ * This is a Standard C++ Library file. You should @c #include this file
+ * in your programs, rather than any of the "*.h" implementation files.
+ *
+ * This is the C++ version of the Standard C Library header @c string.h,
+ * and its contents are (mostly) the same as that header, but are all
+ * contained in the namespace @c std.
+ */
+
+#ifndef _GLIBCXX_CSTRING
+#define _GLIBCXX_CSTRING 1
+
+#pragma GCC system_header
+
+#include <cstddef>
+
+#include <string.h>
+
+// Get rid of those macros defined in <string.h> in lieu of real functions.
+#undef memcpy
+#undef memmove
+#undef strcpy
+#undef strncpy
+#undef strcat
+#undef strncat
+#undef memcmp
+#undef strcmp
+#undef strcoll
+#undef strncmp
+#undef strxfrm
+#undef memchr
+#undef strchr
+#undef strcspn
+#undef strpbrk
+#undef strrchr
+#undef strspn
+#undef strstr
+#undef strtok
+#undef memset
+#undef strerror
+#undef strlen
+
+namespace std
+{
+ using ::memcpy;
+ using ::memmove;
+ using ::strcpy;
+ using ::strncpy;
+ using ::strcat;
+ using ::strncat;
+ using ::memcmp;
+ using ::strcmp;
+// using ::strcoll;
+ using ::strncmp;
+// using ::strxfrm;
+ using ::strcspn;
+ using ::strspn;
+ using ::strtok;
+ using ::memset;
+ using ::strerror;
+ using ::strlen;
+
+ using ::memchr;
+
+ inline void*
+ memchr(void* __p, int __c, size_t __n)
+ { return memchr(const_cast<const void*>(__p), __c, __n); }
+
+ using ::strchr;
+
+ inline char*
+ strchr(char* __s1, int __n)
+ { return __builtin_strchr(const_cast<const char*>(__s1), __n); }
+
+ using ::strpbrk;
+
+ inline char*
+ strpbrk(char* __s1, const char* __s2)
+ { return __builtin_strpbrk(const_cast<const char*>(__s1), __s2); }
+
+ using ::strrchr;
+
+ inline char*
+ strrchr(char* __s1, int __n)
+ { return __builtin_strrchr(const_cast<const char*>(__s1), __n); }
+
+ using ::strstr;
+
+ inline char*
+ strstr(char* __s1, const char* __s2)
+ { return __builtin_strstr(const_cast<const char*>(__s1), __s2); }
+}
+
+#endif
diff --git a/WebCore/platform/android/stl/heap.h b/WebCore/platform/android/stl/heap.h
new file mode 100644
index 0000000..d1fb319
--- /dev/null
+++ b/WebCore/platform/android/stl/heap.h
@@ -0,0 +1,47 @@
+/*
+ *
+ * Copyright (c) 1994
+ * Hewlett-Packard Company
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Hewlett-Packard Company makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * Copyright (c) 1997
+ * Silicon Graphics Computer Systems, Inc.
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Silicon Graphics makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ */
+
+#ifndef __SGI_STL_HEAP_H
+#define __SGI_STL_HEAP_H
+
+#include <concept_checks.h>
+#include <stl_config.h>
+#include <stl_heap.h>
+
+#ifdef __STL_USE_NAMESPACES
+
+using __STD::push_heap;
+using __STD::pop_heap;
+using __STD::make_heap;
+using __STD::sort_heap;
+
+#endif /* __STL_USE_NAMESPACES */
+
+
+#endif /* __SGI_STL_HEAP_H */
+
+// Local Variables:
+// mode:C++
+// End:
diff --git a/WebCore/platform/android/stl/iostream.h b/WebCore/platform/android/stl/iostream.h
new file mode 100644
index 0000000..2b7d968
--- /dev/null
+++ b/WebCore/platform/android/stl/iostream.h
@@ -0,0 +1 @@
+// this file intentionally left blank
diff --git a/WebCore/platform/android/stl/limits b/WebCore/platform/android/stl/limits
new file mode 100644
index 0000000..d4d7960
--- /dev/null
+++ b/WebCore/platform/android/stl/limits
@@ -0,0 +1,23 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef __ANDROID_LIMITS
+#define __ANDROID_LIMITS
+
+#include <limits.h>
+
+#endif // __ANDROID_LIMITS
diff --git a/WebCore/platform/android/stl/memory b/WebCore/platform/android/stl/memory
new file mode 100644
index 0000000..b224c33
--- /dev/null
+++ b/WebCore/platform/android/stl/memory
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 1997-1999
+ * Silicon Graphics Computer Systems, Inc.
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Silicon Graphics makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+
+//minimal file to get build to work
+
+#ifdef _CPP_MEMORY
+#error "real STL defined"
+#endif
+
+#ifndef __ANDROID_MEMORY
+#define __ANDROID_MEMORY
+//we good to do this?
+#define __STL_MEMBER_TEMPLATES
+
+#define __STL_NOTHROW
+
+/*#if defined(__SGI_STL_USE_AUTO_PTR_CONVERSIONS) && \*/
+
+#if defined(__STL_MEMBER_TEMPLATES)
+template<class _Tp1> struct auto_ptr_ref {
+ _Tp1* _M_ptr;
+ auto_ptr_ref(_Tp1* __p) : _M_ptr(__p) {}
+};
+#endif
+
+namespace std {
+
+template <class _Tp> class auto_ptr {
+private:
+ _Tp* _M_ptr;
+
+public:
+ typedef _Tp element_type;
+
+ explicit auto_ptr(_Tp* __p = 0) __STL_NOTHROW : _M_ptr(__p) {}
+ auto_ptr(auto_ptr& __a) __STL_NOTHROW : _M_ptr(__a.release()) {}
+
+#ifdef __STL_MEMBER_TEMPLATES
+ template <class _Tp1> auto_ptr(auto_ptr<_Tp1>& __a) __STL_NOTHROW
+ : _M_ptr(__a.release()) {}
+#endif /* __STL_MEMBER_TEMPLATES */
+
+ auto_ptr& operator=(auto_ptr& __a) __STL_NOTHROW {
+ if (&__a != this) {
+ delete _M_ptr;
+ _M_ptr = __a.release();
+ }
+ return *this;
+ }
+
+#ifdef __STL_MEMBER_TEMPLATES
+ template <class _Tp1>
+ auto_ptr& operator=(auto_ptr<_Tp1>& __a) __STL_NOTHROW {
+ if (__a.get() != this->get()) {
+ delete _M_ptr;
+ _M_ptr = __a.release();
+ }
+ return *this;
+ }
+#endif /* __STL_MEMBER_TEMPLATES */
+
+ // Note: The C++ standard says there is supposed to be an empty throw
+ // specification here, but omitting it is standard conforming. Its
+ // presence can be detected only if _Tp::~_Tp() throws, but (17.4.3.6/2)
+ // this is prohibited.
+ ~auto_ptr() { delete _M_ptr; }
+
+ _Tp& operator*() const __STL_NOTHROW {
+ return *_M_ptr;
+ }
+ _Tp* operator->() const __STL_NOTHROW {
+ return _M_ptr;
+ }
+ _Tp* get() const __STL_NOTHROW {
+ return _M_ptr;
+ }
+ _Tp* release() __STL_NOTHROW {
+ _Tp* __tmp = _M_ptr;
+ _M_ptr = 0;
+ return __tmp;
+ }
+ void reset(_Tp* __p = 0) __STL_NOTHROW {
+ if (__p != _M_ptr) {
+ delete _M_ptr;
+ _M_ptr = __p;
+ }
+ }
+
+/*#if defined(__SGI_STL_USE_AUTO_PTR_CONVERSIONS) && \*/
+#if defined(__STL_MEMBER_TEMPLATES)
+
+public:
+ auto_ptr(auto_ptr_ref<_Tp> __ref) __STL_NOTHROW
+ : _M_ptr(__ref._M_ptr) {}
+
+ auto_ptr& operator=(auto_ptr_ref<_Tp> __ref) __STL_NOTHROW {
+ if (__ref._M_ptr != this->get()) {
+ delete _M_ptr;
+ _M_ptr = __ref._M_ptr;
+ }
+ return *this;
+ }
+
+ template <class _Tp1> operator auto_ptr_ref<_Tp1>() __STL_NOTHROW
+ { return auto_ptr_ref<_Tp1>(this->release()); }
+ template <class _Tp1> operator auto_ptr<_Tp1>() __STL_NOTHROW
+ { return auto_ptr<_Tp1>(this->release()); }
+
+#endif /* auto ptr conversions && member templates */
+
+};
+
+} //namespace std
+
+#endif /* __ANDROID_MEMORY */
+
+
+// Local Variables:
+// mode:C++
+// End:
+
diff --git a/WebCore/platform/android/stl/new.h b/WebCore/platform/android/stl/new.h
new file mode 100644
index 0000000..13d6d4e
--- /dev/null
+++ b/WebCore/platform/android/stl/new.h
@@ -0,0 +1,17 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
diff --git a/WebCore/platform/android/stl/stl_config.h b/WebCore/platform/android/stl/stl_config.h
new file mode 100644
index 0000000..8c107c1
--- /dev/null
+++ b/WebCore/platform/android/stl/stl_config.h
@@ -0,0 +1,576 @@
+/*
+ *
+ * Copyright (c) 1994
+ * Hewlett-Packard Company
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Hewlett-Packard Company makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * Copyright (c) 1997
+ * Silicon Graphics
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Silicon Graphics makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+
+#ifndef __STL_CONFIG_H
+# define __STL_CONFIG_H
+
+// Flags:
+// * __STL_NO_BOOL: defined if the compiler doesn't have bool as a builtin
+// type.
+// * __STL_HAS_WCHAR_T: defined if the compier has wchar_t as a builtin type.
+// * __STL_NO_DRAND48: defined if the compiler doesn't have the drand48
+// function.
+// * __STL_STATIC_TEMPLATE_MEMBER_BUG: defined if the compiler can't handle
+// static members of template classes.
+// * __STL_STATIC_CONST_INIT_BUG: defined if the compiler can't handle a
+// constant-initializer in the declaration of a static const data member
+// of integer type. (See section 9.4.2, paragraph 4, of the C++ standard.)
+// * __STL_CLASS_PARTIAL_SPECIALIZATION: defined if the compiler supports
+// partial specialization of template classes.
+// * __STL_PARTIAL_SPECIALIZATION_SYNTAX: defined if the compiler
+// supports partial specialization syntax for full specialization of
+// class templates. (Even if it doesn't actually support partial
+// specialization itself.)
+// * __STL_FUNCTION_TMPL_PARTIAL_ORDER: defined if the compiler supports
+// partial ordering of function templates. (a.k.a partial specialization
+// of function templates.)
+// * __STL_MEMBER_TEMPLATES: defined if the compiler supports template
+// member functions of classes.
+// * __STL_MEMBER_TEMPLATE_CLASSES: defined if the compiler supports
+// nested classes that are member templates of other classes.
+// * __STL_TEMPLATE_FRIENDS: defined if the compiler supports templatized
+// friend declarations.
+// * __STL_EXPLICIT_FUNCTION_TMPL_ARGS: defined if the compiler
+// supports calling a function template by providing its template
+// arguments explicitly.
+// * __STL_LIMITED_DEFAULT_TEMPLATES: defined if the compiler is unable
+// to handle default template parameters that depend on previous template
+// parameters.
+// * __STL_NON_TYPE_TMPL_PARAM_BUG: defined if the compiler has trouble with
+// function template argument deduction for non-type template parameters.
+// * __SGI_STL_NO_ARROW_OPERATOR: defined if the compiler is unable
+// to support the -> operator for iterators.
+// * __STL_DEFAULT_CONSTRUCTOR_BUG: defined if T() does not work properly
+// when T is a builtin type.
+// * __STL_USE_EXCEPTIONS: defined if the compiler (in the current compilation
+// mode) supports exceptions.
+// * __STL_USE_NAMESPACES: defined if the compiler has the necessary
+// support for namespaces.
+// * __STL_NO_EXCEPTION_HEADER: defined if the compiler does not have a
+// standard-conforming header <exception>.
+// * __STL_NO_BAD_ALLOC: defined if the compiler does not have a <new>
+// header, or if <new> does not contain a bad_alloc class. If a bad_alloc
+// class exists, it is assumed to be in namespace std.
+// * __STL_SGI_THREADS: defined if this is being compiled for an SGI IRIX
+// system in multithreaded mode, using native SGI threads instead of
+// pthreads.
+// * __STL_WIN32THREADS: defined if this is being compiled on a WIN32
+// compiler in multithreaded mode.
+// * __STL_PTHREADS: defined if we should use portable pthreads
+// synchronization.
+// * __STL_UITHREADS: defined if we should use UI / solaris / UnixWare threads
+// synchronization. UIthreads are similar to pthreads, but are based
+// on an earlier version of the Posix threads standard.
+// * __STL_LONG_LONG if the compiler has long long and unsigned long long
+// types. (They're not in the C++ standard, but they are expected to be
+// included in the forthcoming C9X standard.)
+// * __STL_THREADS is defined if thread safety is needed.
+// * __STL_VOLATILE is defined to be "volatile" if threads are being
+// used, and the empty string otherwise.
+// * __STL_USE_CONCEPT_CHECKS enables some extra compile-time error
+// checking to make sure that user-defined template arguments satisfy
+// all of the appropriate requirements. This may result in more
+// comprehensible error messages. It incurs no runtime overhead. This
+// feature requires member templates and partial specialization.
+// * __STL_NO_USING_CLAUSE_IN_CLASS: The compiler does not handle "using"
+// clauses inside of class definitions.
+// * __STL_NO_FRIEND_TEMPLATE_CLASS: The compiler does not handle friend
+// declaractions where the friend is a template class.
+// * __STL_NO_FUNCTION_PTR_IN_CLASS_TEMPLATE: The compiler does not
+// support the use of a function pointer type as the argument
+// for a template.
+// * __STL_MEMBER_TEMPLATE_KEYWORD: standard C++ requires the template
+// keyword in a few new places (14.2.4). This flag is set for
+// compilers that support (and require) this usage.
+
+
+// User-settable macros that control compilation:
+// * __STL_USE_SGI_ALLOCATORS: if defined, then the STL will use older
+// SGI-style allocators, instead of standard-conforming allocators,
+// even if the compiler supports all of the language features needed
+// for standard-conforming allocators.
+// * __STL_NO_NAMESPACES: if defined, don't put the library in namespace
+// std, even if the compiler supports namespaces.
+// * __STL_NO_RELOPS_NAMESPACE: if defined, don't put the relational
+// operator templates (>, <=. >=, !=) in namespace std::rel_ops, even
+// if the compiler supports namespaces and partial ordering of
+// function templates.
+// * __STL_ASSERTIONS: if defined, then enable runtime checking through the
+// __stl_assert macro.
+// * _PTHREADS: if defined, use Posix threads for multithreading support.
+// * _UITHREADS:if defined, use SCO/Solaris/UI threads for multithreading
+// support
+// * _NOTHREADS: if defined, don't use any multithreading support.
+// * _STL_NO_CONCEPT_CHECKS: if defined, disables the error checking that
+// we get from __STL_USE_CONCEPT_CHECKS.
+// * __STL_USE_NEW_IOSTREAMS: if defined, then the STL will use new,
+// standard-conforming iostreams (e.g. the <iosfwd> header). If not
+// defined, the STL will use old cfront-style iostreams (e.g. the
+// <iostream.h> header).
+
+// Other macros defined by this file:
+
+// * bool, true, and false, if __STL_NO_BOOL is defined.
+// * typename, as a null macro if it's not already a keyword.
+// * explicit, as a null macro if it's not already a keyword.
+// * namespace-related macros (__STD, __STL_BEGIN_NAMESPACE, etc.)
+// * exception-related macros (__STL_TRY, __STL_UNWIND, etc.)
+// * __stl_assert, either as a test or as a null macro, depending on
+// whether or not __STL_ASSERTIONS is defined.
+
+# if defined(_PTHREADS) && !defined(_NOTHREADS)
+# define __STL_PTHREADS
+# endif
+
+# if defined(_UITHREADS) && !defined(_PTHREADS) && !defined(_NOTHREADS)
+# define __STL_UITHREADS
+# endif
+
+# if defined(__sgi) && !defined(__GNUC__)
+# include <standards.h>
+# if !defined(_BOOL)
+# define __STL_NO_BOOL
+# endif
+# if defined(_MIPS_SIM) && _MIPS_SIM == _ABIO32
+# define __STL_STATIC_CONST_INIT_BUG
+# endif
+# if defined(_WCHAR_T_IS_KEYWORD)
+# define __STL_HAS_WCHAR_T
+# endif
+# if !defined(_TYPENAME_IS_KEYWORD)
+# define __STL_NEED_TYPENAME
+# endif
+# ifdef _PARTIAL_SPECIALIZATION_OF_CLASS_TEMPLATES
+# define __STL_CLASS_PARTIAL_SPECIALIZATION
+# endif
+# if (_COMPILER_VERSION >= 730) && defined(_MIPS_SIM) && _MIPS_SIM != _ABIO32
+# define __STL_FUNCTION_TMPL_PARTIAL_ORDER
+# endif
+# ifdef _MEMBER_TEMPLATES
+# define __STL_MEMBER_TEMPLATES
+# define __STL_TEMPLATE_FRIENDS
+# define __STL_MEMBER_TEMPLATE_CLASSES
+# endif
+# if defined(_MEMBER_TEMPLATE_KEYWORD)
+# define __STL_MEMBER_TEMPLATE_KEYWORD
+# endif
+# if defined(_STANDARD_C_PLUS_PLUS)
+# define __STL_EXPLICIT_FUNCTION_TMPL_ARGS
+# endif
+# if (_COMPILER_VERSION >= 730) && defined(_MIPS_SIM) && _MIPS_SIM != _ABIO32
+# define __STL_MEMBER_TEMPLATE_KEYWORD
+# endif
+# if COMPILER_VERSION < 720 || (defined(_MIPS_SIM) && _MIPS_SIM == _ABIO32)
+# define __STL_DEFAULT_CONSTRUCTOR_BUG
+# endif
+# if !defined(_EXPLICIT_IS_KEYWORD)
+# define __STL_NEED_EXPLICIT
+# endif
+# ifdef __EXCEPTIONS
+# define __STL_USE_EXCEPTIONS
+# endif
+# if (_COMPILER_VERSION >= 721) && defined(_NAMESPACES)
+# define __STL_HAS_NAMESPACES
+# endif
+# if (_COMPILER_VERSION < 721) || \
+ !defined(__STL_HAS_NAMESPACES) || defined(__STL_NO_NAMESPACES)
+# define __STL_NO_EXCEPTION_HEADER
+# endif
+# if _COMPILER_VERSION < 730 || !defined(_STANDARD_C_PLUS_PLUS) || \
+ !defined(_NAMESPACES)
+# define __STL_NO_BAD_ALLOC
+# endif
+# if !defined(_NOTHREADS) && !defined(__STL_PTHREADS)
+# define __STL_SGI_THREADS
+# endif
+# if defined(_LONGLONG) && defined(_SGIAPI) && _SGIAPI
+# define __STL_LONG_LONG
+# endif
+# if _COMPILER_VERSION >= 730 && defined(_STANDARD_C_PLUS_PLUS)
+# define __STL_USE_NEW_IOSTREAMS
+# endif
+# if _COMPILER_VERSION >= 730 && defined(_STANDARD_C_PLUS_PLUS)
+# define __STL_CAN_THROW_RANGE_ERRORS
+# endif
+# if _COMPILER_VERSION >= 730 && defined(_STANDARD_C_PLUS_PLUS)
+# define __SGI_STL_USE_AUTO_PTR_CONVERSIONS
+# endif
+# endif
+
+
+/*
+ * Jochen Schlick '1999 - added new #defines (__STL)_UITHREADS (for
+ * providing SCO / Solaris / UI thread support)
+ * - added the necessary defines for the SCO UDK 7
+ * compiler (and its template friend behavior)
+ * - all UDK7 specific STL changes are based on the
+ * macro __USLC__ being defined
+ */
+// SCO UDK 7 compiler (UnixWare 7x, OSR 5, UnixWare 2x)
+# if defined(__USLC__)
+# define __STL_HAS_WCHAR_T
+# define __STL_CLASS_PARTIAL_SPECIALIZATION
+# define __STL_PARTIAL_SPECIALIZATION_SYNTAX
+# define __STL_FUNCTION_TMPL_PARTIAL_ORDER
+# define __STL_MEMBER_TEMPLATES
+# define __STL_MEMBER_TEMPLATE_CLASSES
+# define __STL_USE_EXCEPTIONS
+# define __STL_HAS_NAMESPACES
+# define __STL_USE_NAMESPACES
+# define __STL_LONG_LONG
+# if defined(_REENTRANT)
+# define _UITHREADS /* if UnixWare < 7.0.1 */
+# define __STL_UITHREADS
+// use the following defines instead of the UI threads defines when
+// you want to use POSIX threads
+//# define _PTHREADS /* only if UnixWare >=7.0.1 */
+//# define __STL_PTHREADS
+# endif
+# endif
+
+
+
+# ifdef __GNUC__
+# if __GNUC__ == 2 && __GNUC_MINOR__ <= 7
+# define __STL_STATIC_TEMPLATE_MEMBER_BUG
+# endif
+# if __GNUC__ < 2
+# define __STL_NEED_TYPENAME
+# define __STL_NEED_EXPLICIT
+# endif
+# if __GNUC__ == 2 && __GNUC_MINOR__ <= 8
+# define __STL_NO_EXCEPTION_HEADER
+# define __STL_NO_BAD_ALLOC
+# endif
+# if __GNUC__ == 2 && __GNUC_MINOR__ >= 8 || __GNUC__ > 2
+# define __STL_CLASS_PARTIAL_SPECIALIZATION
+# define __STL_FUNCTION_TMPL_PARTIAL_ORDER
+# define __STL_EXPLICIT_FUNCTION_TMPL_ARGS
+# define __STL_MEMBER_TEMPLATES
+# define __STL_CAN_THROW_RANGE_ERRORS
+ // g++ 2.8.1 supports member template functions, but not member
+ // template nested classes.
+# if __GNUC_MINOR__ >= 9 || __GNUC__ > 2
+# define __STL_MEMBER_TEMPLATE_CLASSES
+# define __STL_TEMPLATE_FRIENDS
+# define __SGI_STL_USE_AUTO_PTR_CONVERSIONS
+# define __STL_HAS_NAMESPACES
+//# define __STL_USE_NEW_IOSTREAMS
+# endif
+# endif
+# define __STL_DEFAULT_CONSTRUCTOR_BUG
+# ifdef __EXCEPTIONS
+# define __STL_USE_EXCEPTIONS
+# endif
+# ifdef _REENTRANT
+# define __STL_PTHREADS
+# endif
+# if (__GNUC__ < 2) || (__GNUC__ == 2 && __GNUC_MINOR__ < 95)
+# define __STL_NO_FUNCTION_PTR_IN_CLASS_TEMPLATE
+# endif
+# endif
+
+# if defined(__SUNPRO_CC)
+# define __STL_NO_BOOL
+# define __STL_NEED_TYPENAME
+# define __STL_NEED_EXPLICIT
+# define __STL_USE_EXCEPTIONS
+# ifdef _REENTRANT
+# define __STL_PTHREADS
+# endif
+# define __SGI_STL_NO_ARROW_OPERATOR
+# define __STL_PARTIAL_SPECIALIZATION_SYNTAX
+# define __STL_NO_EXCEPTION_HEADER
+# define __STL_NO_BAD_ALLOC
+# endif
+
+# if defined(__COMO__)
+# define __STL_MEMBER_TEMPLATES
+# define __STL_MEMBER_TEMPLATE_CLASSES
+# define __STL_TEMPLATE_FRIENDS
+# define __STL_CLASS_PARTIAL_SPECIALIZATION
+# define __STL_USE_EXCEPTIONS
+# define __STL_HAS_NAMESPACES
+# endif
+
+// Intel compiler, which uses the EDG front end.
+# if defined(__ICL)
+# define __STL_LONG_LONG
+# define __STL_MEMBER_TEMPLATES
+# define __STL_MEMBER_TEMPLATE_CLASSES
+# define __STL_TEMPLATE_FRIENDS
+# define __STL_FUNCTION_TMPL_PARTIAL_ORDER
+# define __STL_CLASS_PARTIAL_SPECIALIZATION
+# define __STL_NO_DRAND48
+# define __STL_HAS_NAMESPACES
+# define __STL_USE_EXCEPTIONS
+# define __STL_MEMBER_TEMPLATE_KEYWORD
+# ifdef _CPPUNWIND
+# define __STL_USE_EXCEPTIONS
+# endif
+# ifdef _MT
+# define __STL_WIN32THREADS
+# endif
+# endif
+
+// Mingw32, egcs compiler using the Microsoft C runtime
+# if defined(__MINGW32__)
+# define __STL_NO_DRAND48
+# ifdef _MT
+# define __STL_WIN32THREADS
+# endif
+# endif
+
+// Cygwin32, egcs compiler on MS Windows
+# if defined(__CYGWIN__)
+# define __STL_NO_DRAND48
+# endif
+
+
+
+// Microsoft compiler.
+# if defined(_MSC_VER) && !defined(__ICL) && !defined(__MWERKS__)
+# define __STL_NO_DRAND48
+# define __STL_STATIC_CONST_INIT_BUG
+# define __STL_NEED_TYPENAME
+# define __STL_NO_USING_CLAUSE_IN_CLASS
+# define __STL_NO_FRIEND_TEMPLATE_CLASS
+# if _MSC_VER < 1100 /* 1000 is version 4.0, 1100 is 5.0, 1200 is 6.0. */
+# define __STL_NEED_EXPLICIT
+# define __STL_NO_BOOL
+# define __STL_NO_BAD_ALLOC
+# endif
+# if _MSC_VER > 1000
+# include <yvals.h>
+# define __STL_DONT_USE_BOOL_TYPEDEF
+# endif
+# define __STL_NON_TYPE_TMPL_PARAM_BUG
+# define __SGI_STL_NO_ARROW_OPERATOR
+# define __STL_DEFAULT_CONSTRUCTOR_BUG
+# ifdef _CPPUNWIND
+# define __STL_USE_EXCEPTIONS
+# endif
+# ifdef _MT
+# define __STL_WIN32THREADS
+# endif
+# if _MSC_VER >= 1200
+# define __STL_PARTIAL_SPECIALIZATION_SYNTAX
+# define __STL_HAS_NAMESPACES
+# define __STL_CAN_THROW_RANGE_ERRORS
+# define NOMINMAX
+# undef min
+# undef max
+// disable warning 'initializers put in unrecognized initialization area'
+# pragma warning ( disable : 4075 )
+// disable warning 'empty controlled statement found'
+# pragma warning ( disable : 4390 )
+// disable warning 'debug symbol greater than 255 chars'
+# pragma warning ( disable : 4786 )
+# endif
+# if _MSC_VER < 1100
+# define __STL_NO_EXCEPTION_HEADER
+# define __STL_NO_BAD_ALLOC
+# endif
+ // Because of a Microsoft front end bug, we must not provide a
+ // namespace qualifier when declaring a friend function.
+# define __STD_QUALIFIER
+# endif
+
+# if defined(__BORLANDC__)
+# define __STL_NO_BAD_ALLOC
+# define __STL_NO_DRAND48
+# define __STL_DEFAULT_CONSTRUCTOR_BUG
+# if __BORLANDC__ >= 0x540 /* C++ Builder 4.0 */
+# define __STL_CLASS_PARTIAL_SPECIALIZATION
+# define __STL_FUNCTION_TMPL_PARTIAL_ORDER
+# define __STL_EXPLICIT_FUNCTION_TMPL_ARGS
+# define __STL_MEMBER_TEMPLATES
+# define __STL_TEMPLATE_FRIENDS
+# else
+# define __STL_NEED_TYPENAME
+# define __STL_LIMITED_DEFAULT_TEMPLATES
+# define __SGI_STL_NO_ARROW_OPERATOR
+# define __STL_NON_TYPE_TMPL_PARAM_BUG
+# endif
+# ifdef _CPPUNWIND
+# define __STL_USE_EXCEPTIONS
+# endif
+# ifdef __MT__
+# define __STL_WIN32THREADS
+# endif
+# endif
+
+# if defined(__STL_NO_BOOL) && !defined(__STL_DONT_USE_BOOL_TYPEDEF)
+ typedef int bool;
+# define true 1
+# define false 0
+# endif
+
+# ifdef __STL_NEED_TYPENAME
+# define typename
+# endif
+
+# ifdef __STL_LIMITED_DEFAULT_TEMPLATES
+# define __STL_DEPENDENT_DEFAULT_TMPL(_Tp)
+# else
+# define __STL_DEPENDENT_DEFAULT_TMPL(_Tp) = _Tp
+# endif
+
+# ifdef __STL_MEMBER_TEMPLATE_KEYWORD
+# define __STL_TEMPLATE template
+# else
+# define __STL_TEMPLATE
+# endif
+
+# ifdef __STL_NEED_EXPLICIT
+# define explicit
+# endif
+
+# ifdef __STL_EXPLICIT_FUNCTION_TMPL_ARGS
+# define __STL_NULL_TMPL_ARGS <>
+# else
+# define __STL_NULL_TMPL_ARGS
+# endif
+
+# if defined(__STL_CLASS_PARTIAL_SPECIALIZATION) \
+ || defined (__STL_PARTIAL_SPECIALIZATION_SYNTAX)
+# define __STL_TEMPLATE_NULL template<>
+# else
+# define __STL_TEMPLATE_NULL
+# endif
+
+// Use standard-conforming allocators if we have the necessary language
+// features. __STL_USE_SGI_ALLOCATORS is a hook so that users can
+// disable new-style allocators, and continue to use the same kind of
+// allocators as before, without having to edit library headers.
+# if defined(__STL_CLASS_PARTIAL_SPECIALIZATION) && \
+ defined(__STL_MEMBER_TEMPLATES) && \
+ defined(__STL_MEMBER_TEMPLATE_CLASSES) && \
+ !defined(__STL_NO_BOOL) && \
+ !defined(__STL_NON_TYPE_TMPL_PARAM_BUG) && \
+ !defined(__STL_LIMITED_DEFAULT_TEMPLATES) && \
+ !defined(__STL_USE_SGI_ALLOCATORS)
+# define __STL_USE_STD_ALLOCATORS
+# endif
+
+# ifndef __STL_DEFAULT_ALLOCATOR
+# ifdef __STL_USE_STD_ALLOCATORS
+# define __STL_DEFAULT_ALLOCATOR(T) allocator< T >
+# else
+# define __STL_DEFAULT_ALLOCATOR(T) alloc
+# endif
+# endif
+
+// __STL_NO_NAMESPACES is a hook so that users can disable namespaces
+// without having to edit library headers. __STL_NO_RELOPS_NAMESPACE is
+// a hook so that users can disable the std::rel_ops namespace, keeping
+// the relational operator template in namespace std, without having to
+// edit library headers.
+# if defined(__STL_HAS_NAMESPACES) && !defined(__STL_NO_NAMESPACES)
+# define __STL_USE_NAMESPACES
+# define __STD std
+# define __STL_BEGIN_NAMESPACE namespace std {
+# define __STL_END_NAMESPACE }
+# if defined(__STL_FUNCTION_TMPL_PARTIAL_ORDER) && \
+ !defined(__STL_NO_RELOPS_NAMESPACE)
+# define __STL_USE_NAMESPACE_FOR_RELOPS
+# define __STL_BEGIN_RELOPS_NAMESPACE namespace std { namespace rel_ops {
+# define __STL_END_RELOPS_NAMESPACE } }
+# define __STD_RELOPS std::rel_ops
+# else /* Use std::rel_ops namespace */
+# define __STL_USE_NAMESPACE_FOR_RELOPS
+# define __STL_BEGIN_RELOPS_NAMESPACE namespace std {
+# define __STL_END_RELOPS_NAMESPACE }
+# define __STD_RELOPS std
+# endif /* Use std::rel_ops namespace */
+# else
+# define __STD
+# define __STL_BEGIN_NAMESPACE
+# define __STL_END_NAMESPACE
+# undef __STL_USE_NAMESPACE_FOR_RELOPS
+# define __STL_BEGIN_RELOPS_NAMESPACE
+# define __STL_END_RELOPS_NAMESPACE
+# define __STD_RELOPS
+# undef __STL_USE_NAMESPACES
+# endif
+
+// Some versions of the EDG front end sometimes require an explicit
+// namespace spec where they shouldn't. This macro facilitates that.
+// If the bug becomes irrelevant, then all uses of __STD_QUALIFIER
+// should be removed. The 7.3 beta SGI compiler has this bug, but the
+// MR version is not expected to have it.
+
+# if defined(__STL_USE_NAMESPACES) && !defined(__STD_QUALIFIER)
+# define __STD_QUALIFIER std::
+# else
+# define __STD_QUALIFIER
+# endif
+
+# ifdef __STL_USE_EXCEPTIONS
+# define __STL_TRY try
+# define __STL_CATCH_ALL catch(...)
+# define __STL_THROW(x) throw x
+# define __STL_RETHROW throw
+# define __STL_NOTHROW throw()
+# define __STL_UNWIND(action) catch(...) { action; throw; }
+# else
+# define __STL_TRY
+# define __STL_CATCH_ALL if (false)
+# define __STL_THROW(x)
+# define __STL_RETHROW
+# define __STL_NOTHROW
+# define __STL_UNWIND(action)
+# endif
+
+#ifdef __STL_ASSERTIONS
+# include <stdio.h>
+# define __stl_assert(expr) \
+ if (!(expr)) { fprintf(stderr, "%s:%d STL assertion failure: %s\n", \
+ __FILE__, __LINE__, # expr); abort(); }
+#else
+# define __stl_assert(expr)
+#endif
+
+#if defined(__STL_WIN32THREADS) || defined(__STL_SGI_THREADS) \
+ || defined(__STL_PTHREADS) || defined(__STL_UITHREADS)
+# define __STL_THREADS
+# define __STL_VOLATILE volatile
+#else
+# define __STL_VOLATILE
+#endif
+
+#if defined(__STL_CLASS_PARTIAL_SPECIALIZATION) \
+ && defined(__STL_MEMBER_TEMPLATES) \
+ && !defined(_STL_NO_CONCEPT_CHECKS)
+# define __STL_USE_CONCEPT_CHECKS
+#endif
+
+
+#endif /* __STL_CONFIG_H */
+
+// Local Variables:
+// mode:C++
+// End:
diff --git a/WebCore/platform/android/stl/stl_heap.h b/WebCore/platform/android/stl/stl_heap.h
new file mode 100644
index 0000000..651d21a
--- /dev/null
+++ b/WebCore/platform/android/stl/stl_heap.h
@@ -0,0 +1,297 @@
+/*
+ *
+ * Copyright (c) 1994
+ * Hewlett-Packard Company
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Hewlett-Packard Company makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * Copyright (c) 1997
+ * Silicon Graphics Computer Systems, Inc.
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Silicon Graphics makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ */
+
+/* NOTE: This is an internal header file, included by other STL headers.
+ * You should not attempt to use it directly.
+ */
+
+#ifndef __SGI_STL_INTERNAL_HEAP_H
+#define __SGI_STL_INTERNAL_HEAP_H
+
+__STL_BEGIN_NAMESPACE
+
+#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
+#pragma set woff 1209
+#endif
+
+// Heap-manipulation functions: push_heap, pop_heap, make_heap, sort_heap.
+
+template <class _RandomAccessIterator, class _Distance, class _Tp>
+void
+__push_heap(_RandomAccessIterator __first,
+ _Distance __holeIndex, _Distance __topIndex, _Tp __value)
+{
+ _Distance __parent = (__holeIndex - 1) / 2;
+ while (__holeIndex > __topIndex && *(__first + __parent) < __value) {
+ *(__first + __holeIndex) = *(__first + __parent);
+ __holeIndex = __parent;
+ __parent = (__holeIndex - 1) / 2;
+ }
+ *(__first + __holeIndex) = __value;
+}
+
+template <class _RandomAccessIterator, class _Distance, class _Tp>
+inline void
+__push_heap_aux(_RandomAccessIterator __first,
+ _RandomAccessIterator __last, _Distance*, _Tp*)
+{
+ __push_heap(__first, _Distance((__last - __first) - 1), _Distance(0),
+ _Tp(*(__last - 1)));
+}
+
+template <class _RandomAccessIterator>
+inline void
+push_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
+{
+ __STL_REQUIRES(_RandomAccessIterator, _Mutable_RandomAccessIterator);
+ __STL_REQUIRES(typename iterator_traits<_RandomAccessIterator>::value_type,
+ _LessThanComparable);
+ __push_heap_aux(__first, __last,
+ __DISTANCE_TYPE(__first), __VALUE_TYPE(__first));
+}
+
+template <class _RandomAccessIterator, class _Distance, class _Tp,
+ class _Compare>
+void
+__push_heap(_RandomAccessIterator __first, _Distance __holeIndex,
+ _Distance __topIndex, _Tp __value, _Compare __comp)
+{
+ _Distance __parent = (__holeIndex - 1) / 2;
+ while (__holeIndex > __topIndex && __comp(*(__first + __parent), __value)) {
+ *(__first + __holeIndex) = *(__first + __parent);
+ __holeIndex = __parent;
+ __parent = (__holeIndex - 1) / 2;
+ }
+ *(__first + __holeIndex) = __value;
+}
+
+template <class _RandomAccessIterator, class _Compare,
+ class _Distance, class _Tp>
+inline void
+__push_heap_aux(_RandomAccessIterator __first,
+ _RandomAccessIterator __last, _Compare __comp,
+ _Distance*, _Tp*)
+{
+ __push_heap(__first, _Distance((__last - __first) - 1), _Distance(0),
+ _Tp(*(__last - 1)), __comp);
+}
+
+template <class _RandomAccessIterator, class _Compare>
+inline void
+push_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
+ _Compare __comp)
+{
+ __STL_REQUIRES(_RandomAccessIterator, _Mutable_RandomAccessIterator);
+ __push_heap_aux(__first, __last, __comp,
+ __DISTANCE_TYPE(__first), __VALUE_TYPE(__first));
+}
+
+template <class _RandomAccessIterator, class _Distance, class _Tp>
+void
+__adjust_heap(_RandomAccessIterator __first, _Distance __holeIndex,
+ _Distance __len, _Tp __value)
+{
+ _Distance __topIndex = __holeIndex;
+ _Distance __secondChild = 2 * __holeIndex + 2;
+ while (__secondChild < __len) {
+ if (*(__first + __secondChild) < *(__first + (__secondChild - 1)))
+ __secondChild--;
+ *(__first + __holeIndex) = *(__first + __secondChild);
+ __holeIndex = __secondChild;
+ __secondChild = 2 * (__secondChild + 1);
+ }
+ if (__secondChild == __len) {
+ *(__first + __holeIndex) = *(__first + (__secondChild - 1));
+ __holeIndex = __secondChild - 1;
+ }
+ __push_heap(__first, __holeIndex, __topIndex, __value);
+}
+
+template <class _RandomAccessIterator, class _Tp, class _Distance>
+inline void
+__pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
+ _RandomAccessIterator __result, _Tp __value, _Distance*)
+{
+ *__result = *__first;
+ __adjust_heap(__first, _Distance(0), _Distance(__last - __first), __value);
+}
+
+template <class _RandomAccessIterator, class _Tp>
+inline void
+__pop_heap_aux(_RandomAccessIterator __first, _RandomAccessIterator __last,
+ _Tp*)
+{
+ __pop_heap(__first, __last - 1, __last - 1,
+ _Tp(*(__last - 1)), __DISTANCE_TYPE(__first));
+}
+
+template <class _RandomAccessIterator>
+inline void pop_heap(_RandomAccessIterator __first,
+ _RandomAccessIterator __last)
+{
+ __STL_REQUIRES(_RandomAccessIterator, _Mutable_RandomAccessIterator);
+ __STL_REQUIRES(typename iterator_traits<_RandomAccessIterator>::value_type,
+ _LessThanComparable);
+ __pop_heap_aux(__first, __last, __VALUE_TYPE(__first));
+}
+
+template <class _RandomAccessIterator, class _Distance,
+ class _Tp, class _Compare>
+void
+__adjust_heap(_RandomAccessIterator __first, _Distance __holeIndex,
+ _Distance __len, _Tp __value, _Compare __comp)
+{
+ _Distance __topIndex = __holeIndex;
+ _Distance __secondChild = 2 * __holeIndex + 2;
+ while (__secondChild < __len) {
+ if (__comp(*(__first + __secondChild), *(__first + (__secondChild - 1))))
+ __secondChild--;
+ *(__first + __holeIndex) = *(__first + __secondChild);
+ __holeIndex = __secondChild;
+ __secondChild = 2 * (__secondChild + 1);
+ }
+ if (__secondChild == __len) {
+ *(__first + __holeIndex) = *(__first + (__secondChild - 1));
+ __holeIndex = __secondChild - 1;
+ }
+ __push_heap(__first, __holeIndex, __topIndex, __value, __comp);
+}
+
+template <class _RandomAccessIterator, class _Tp, class _Compare,
+ class _Distance>
+inline void
+__pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
+ _RandomAccessIterator __result, _Tp __value, _Compare __comp,
+ _Distance*)
+{
+ *__result = *__first;
+ __adjust_heap(__first, _Distance(0), _Distance(__last - __first),
+ __value, __comp);
+}
+
+template <class _RandomAccessIterator, class _Tp, class _Compare>
+inline void
+__pop_heap_aux(_RandomAccessIterator __first,
+ _RandomAccessIterator __last, _Tp*, _Compare __comp)
+{
+ __pop_heap(__first, __last - 1, __last - 1, _Tp(*(__last - 1)), __comp,
+ __DISTANCE_TYPE(__first));
+}
+
+template <class _RandomAccessIterator, class _Compare>
+inline void
+pop_heap(_RandomAccessIterator __first,
+ _RandomAccessIterator __last, _Compare __comp)
+{
+ __STL_REQUIRES(_RandomAccessIterator, _Mutable_RandomAccessIterator);
+ __pop_heap_aux(__first, __last, __VALUE_TYPE(__first), __comp);
+}
+
+template <class _RandomAccessIterator, class _Tp, class _Distance>
+void
+__make_heap(_RandomAccessIterator __first,
+ _RandomAccessIterator __last, _Tp*, _Distance*)
+{
+ if (__last - __first < 2) return;
+ _Distance __len = __last - __first;
+ _Distance __parent = (__len - 2)/2;
+
+ while (true) {
+ __adjust_heap(__first, __parent, __len, _Tp(*(__first + __parent)));
+ if (__parent == 0) return;
+ __parent--;
+ }
+}
+
+template <class _RandomAccessIterator>
+inline void
+make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
+{
+ __STL_REQUIRES(_RandomAccessIterator, _Mutable_RandomAccessIterator);
+ __STL_REQUIRES(typename iterator_traits<_RandomAccessIterator>::value_type,
+ _LessThanComparable);
+ __make_heap(__first, __last,
+ __VALUE_TYPE(__first), __DISTANCE_TYPE(__first));
+}
+
+template <class _RandomAccessIterator, class _Compare,
+ class _Tp, class _Distance>
+void
+__make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
+ _Compare __comp, _Tp*, _Distance*)
+{
+ if (__last - __first < 2) return;
+ _Distance __len = __last - __first;
+ _Distance __parent = (__len - 2)/2;
+
+ while (true) {
+ __adjust_heap(__first, __parent, __len, _Tp(*(__first + __parent)),
+ __comp);
+ if (__parent == 0) return;
+ __parent--;
+ }
+}
+
+template <class _RandomAccessIterator, class _Compare>
+inline void
+make_heap(_RandomAccessIterator __first,
+ _RandomAccessIterator __last, _Compare __comp)
+{
+ __STL_REQUIRES(_RandomAccessIterator, _Mutable_RandomAccessIterator);
+ __make_heap(__first, __last, __comp,
+ __VALUE_TYPE(__first), __DISTANCE_TYPE(__first));
+}
+
+template <class _RandomAccessIterator>
+void sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
+{
+ __STL_REQUIRES(_RandomAccessIterator, _Mutable_RandomAccessIterator);
+ __STL_REQUIRES(typename iterator_traits<_RandomAccessIterator>::value_type,
+ _LessThanComparable);
+ while (__last - __first > 1)
+ pop_heap(__first, __last--);
+}
+
+template <class _RandomAccessIterator, class _Compare>
+void
+sort_heap(_RandomAccessIterator __first,
+ _RandomAccessIterator __last, _Compare __comp)
+{
+ __STL_REQUIRES(_RandomAccessIterator, _Mutable_RandomAccessIterator);
+ while (__last - __first > 1)
+ pop_heap(__first, __last--, __comp);
+}
+
+#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
+#pragma reset woff 1209
+#endif
+
+__STL_END_NAMESPACE
+
+#endif /* __SGI_STL_INTERNAL_HEAP_H */
+
+// Local Variables:
+// mode:C++
+// End:
diff --git a/WebCore/platform/android/stl/stl_iterator_base.h b/WebCore/platform/android/stl/stl_iterator_base.h
new file mode 100644
index 0000000..d03332b
--- /dev/null
+++ b/WebCore/platform/android/stl/stl_iterator_base.h
@@ -0,0 +1,273 @@
+/*
+ *
+ * Copyright (c) 1994
+ * Hewlett-Packard Company
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Hewlett-Packard Company makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ *
+ * Copyright (c) 1996-1998
+ * Silicon Graphics Computer Systems, Inc.
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Silicon Graphics makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ */
+
+/* NOTE: This is an internal header file, included by other STL headers.
+ * You should not attempt to use it directly.
+ */
+
+#ifndef __SGI_STL_INTERNAL_ITERATOR_BASE_H
+#define __SGI_STL_INTERNAL_ITERATOR_BASE_H
+
+// This file contains all of the general iterator-related utilities.
+// The internal file stl_iterator.h contains predefined iterators,
+// such as front_insert_iterator and istream_iterator.
+
+#include <concept_checks.h>
+
+struct input_iterator_tag {};
+struct output_iterator_tag {};
+struct forward_iterator_tag : public input_iterator_tag {};
+struct bidirectional_iterator_tag : public forward_iterator_tag {};
+struct random_access_iterator_tag : public bidirectional_iterator_tag {};
+
+// The base classes input_iterator, output_iterator, forward_iterator,
+// bidirectional_iterator, and random_access_iterator are not part of
+// the C++ standard. (They have been replaced by struct iterator.)
+// They are included for backward compatibility with the HP STL.
+
+template <class _Tp, class _Distance> struct input_iterator {
+ typedef input_iterator_tag iterator_category;
+ typedef _Tp value_type;
+ typedef _Distance difference_type;
+ typedef _Tp* pointer;
+ typedef _Tp& reference;
+};
+
+struct output_iterator {
+ typedef output_iterator_tag iterator_category;
+ typedef void value_type;
+ typedef void difference_type;
+ typedef void pointer;
+ typedef void reference;
+};
+
+template <class _Tp, class _Distance> struct forward_iterator {
+ typedef forward_iterator_tag iterator_category;
+ typedef _Tp value_type;
+ typedef _Distance difference_type;
+ typedef _Tp* pointer;
+ typedef _Tp& reference;
+};
+
+
+template <class _Tp, class _Distance> struct bidirectional_iterator {
+ typedef bidirectional_iterator_tag iterator_category;
+ typedef _Tp value_type;
+ typedef _Distance difference_type;
+ typedef _Tp* pointer;
+ typedef _Tp& reference;
+};
+
+template <class _Tp, class _Distance> struct random_access_iterator {
+ typedef random_access_iterator_tag iterator_category;
+ typedef _Tp value_type;
+ typedef _Distance difference_type;
+ typedef _Tp* pointer;
+ typedef _Tp& reference;
+};
+
+template <class _Category, class _Tp, class _Distance = ptrdiff_t,
+ class _Pointer = _Tp*, class _Reference = _Tp&>
+struct iterator {
+ typedef _Category iterator_category;
+ typedef _Tp value_type;
+ typedef _Distance difference_type;
+ typedef _Pointer pointer;
+ typedef _Reference reference;
+};
+
+template <class _Iterator>
+struct iterator_traits {
+ typedef typename _Iterator::iterator_category iterator_category;
+ typedef typename _Iterator::value_type value_type;
+ typedef typename _Iterator::difference_type difference_type;
+ typedef typename _Iterator::pointer pointer;
+ typedef typename _Iterator::reference reference;
+};
+
+template <class _Tp>
+struct iterator_traits<_Tp*> {
+ typedef random_access_iterator_tag iterator_category;
+ typedef _Tp value_type;
+ typedef ptrdiff_t difference_type;
+ typedef _Tp* pointer;
+ typedef _Tp& reference;
+};
+
+template <class _Tp>
+struct iterator_traits<const _Tp*> {
+ typedef random_access_iterator_tag iterator_category;
+ typedef _Tp value_type;
+ typedef ptrdiff_t difference_type;
+ typedef const _Tp* pointer;
+ typedef const _Tp& reference;
+};
+
+// The overloaded functions iterator_category, distance_type, and
+// value_type are not part of the C++ standard. (They have been
+// replaced by struct iterator_traits.) They are included for
+// backward compatibility with the HP STL.
+
+// We introduce internal names for these functions.
+
+template <class _Iter>
+inline typename iterator_traits<_Iter>::iterator_category
+__iterator_category(const _Iter&)
+{
+ typedef typename iterator_traits<_Iter>::iterator_category _Category;
+ return _Category();
+}
+
+template <class _Iter>
+inline typename iterator_traits<_Iter>::difference_type*
+__distance_type(const _Iter&)
+{
+ return static_cast<typename iterator_traits<_Iter>::difference_type*>(0);
+}
+
+template <class _Iter>
+inline typename iterator_traits<_Iter>::value_type*
+__value_type(const _Iter&)
+{
+ return static_cast<typename iterator_traits<_Iter>::value_type*>(0);
+}
+
+template <class _Iter>
+inline typename iterator_traits<_Iter>::iterator_category
+iterator_category(const _Iter& __i) { return __iterator_category(__i); }
+
+
+template <class _Iter>
+inline typename iterator_traits<_Iter>::difference_type*
+distance_type(const _Iter& __i) { return __distance_type(__i); }
+
+template <class _Iter>
+inline typename iterator_traits<_Iter>::value_type*
+value_type(const _Iter& __i) { return __value_type(__i); }
+
+#define __ITERATOR_CATEGORY(__i) __iterator_category(__i)
+#define __DISTANCE_TYPE(__i) __distance_type(__i)
+#define __VALUE_TYPE(__i) __value_type(__i)
+
+template <class _InputIterator, class _Distance>
+inline void __distance(_InputIterator __first, _InputIterator __last,
+ _Distance& __n, input_iterator_tag)
+{
+ while (__first != __last) { ++__first; ++__n; }
+}
+
+template <class _RandomAccessIterator, class _Distance>
+inline void __distance(_RandomAccessIterator __first,
+ _RandomAccessIterator __last,
+ _Distance& __n, random_access_iterator_tag)
+{
+ __STL_REQUIRES(_RandomAccessIterator, _RandomAccessIterator);
+ __n += __last - __first;
+}
+
+template <class _InputIterator, class _Distance>
+inline void distance(_InputIterator __first,
+ _InputIterator __last, _Distance& __n)
+{
+ __STL_REQUIRES(_InputIterator, _InputIterator);
+ __distance(__first, __last, __n, iterator_category(__first));
+}
+
+#ifdef __STL_CLASS_PARTIAL_SPECIALIZATION
+
+template <class _InputIterator>
+inline typename iterator_traits<_InputIterator>::difference_type
+__distance(_InputIterator __first, _InputIterator __last, input_iterator_tag)
+{
+ typename iterator_traits<_InputIterator>::difference_type __n = 0;
+ while (__first != __last) {
+ ++__first; ++__n;
+ }
+ return __n;
+}
+
+template <class _RandomAccessIterator>
+inline typename iterator_traits<_RandomAccessIterator>::difference_type
+__distance(_RandomAccessIterator __first, _RandomAccessIterator __last,
+ random_access_iterator_tag) {
+ __STL_REQUIRES(_RandomAccessIterator, _RandomAccessIterator);
+ return __last - __first;
+}
+
+template <class _InputIterator>
+inline typename iterator_traits<_InputIterator>::difference_type
+distance(_InputIterator __first, _InputIterator __last) {
+ typedef typename iterator_traits<_InputIterator>::iterator_category
+ _Category;
+ __STL_REQUIRES(_InputIterator, _InputIterator);
+ return __distance(__first, __last, _Category());
+}
+
+#endif /* __STL_CLASS_PARTIAL_SPECIALIZATION */
+
+template <class _InputIter, class _Distance>
+inline void __advance(_InputIter& __i, _Distance __n, input_iterator_tag) {
+ while (__n--) ++__i;
+}
+
+#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
+#pragma set woff 1183
+#endif
+
+template <class _BidirectionalIterator, class _Distance>
+inline void __advance(_BidirectionalIterator& __i, _Distance __n,
+ bidirectional_iterator_tag) {
+ __STL_REQUIRES(_BidirectionalIterator, _BidirectionalIterator);
+ if (__n >= 0)
+ while (__n--) ++__i;
+ else
+ while (__n++) --__i;
+}
+
+#if defined(__sgi) && !defined(__GNUC__) && (_MIPS_SIM != _MIPS_SIM_ABI32)
+#pragma reset woff 1183
+#endif
+
+template <class _RandomAccessIterator, class _Distance>
+inline void __advance(_RandomAccessIterator& __i, _Distance __n,
+ random_access_iterator_tag) {
+ __STL_REQUIRES(_RandomAccessIterator, _RandomAccessIterator);
+ __i += __n;
+}
+
+template <class _InputIterator, class _Distance>
+inline void advance(_InputIterator& __i, _Distance __n) {
+ __STL_REQUIRES(_InputIterator, _InputIterator);
+ __advance(__i, __n, iterator_category(__i));
+}
+
+#endif /* __SGI_STL_INTERNAL_ITERATOR_BASE_H */
+
+
+
+// Local Variables:
+// mode:C++
+// End:
diff --git a/WebCore/platform/android/stl/strings.h b/WebCore/platform/android/stl/strings.h
new file mode 100644
index 0000000..13d6d4e
--- /dev/null
+++ b/WebCore/platform/android/stl/strings.h
@@ -0,0 +1,17 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
diff --git a/WebCore/platform/cf/KURLCFNet.cpp b/WebCore/platform/cf/KURLCFNet.cpp
index f060b28..2130667 100644
--- a/WebCore/platform/cf/KURLCFNet.cpp
+++ b/WebCore/platform/cf/KURLCFNet.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004, 2008 Apple 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
@@ -27,6 +27,7 @@
#include "KURL.h"
#include <wtf/RetainPtr.h>
+#include <wtf/Vector.h>
#include <CoreFoundation/CFURL.h>
using namespace std;
@@ -35,46 +36,35 @@ namespace WebCore {
KURL::KURL(CFURLRef url)
{
- if (!url) {
- parse(0, 0);
- return;
- }
-
- CFIndex bytesLength = CFURLGetBytes(url, 0, 0);
- Vector<char, 512> buffer(bytesLength + 6); // 5 for "file:", 1 for null character to end C string
- char* bytes = &buffer[5];
- CFURLGetBytes(url, reinterpret_cast<UInt8*>(bytes), bytesLength);
- bytes[bytesLength] = '\0';
- if (bytes[0] != '/') {
- parse(bytes, 0);
- return;
- }
-
- buffer[0] = 'f';
- buffer[1] = 'i';
- buffer[2] = 'l';
- buffer[3] = 'e';
- buffer[4] = ':';
-
- parse(buffer.data(), 0);
+ if (url) {
+ CFIndex bytesLength = CFURLGetBytes(url, 0, 0);
+ Vector<char, 2048> buffer(bytesLength + 6); // 6 for "file:", 1 for NUL terminator
+ char* bytes = &buffer[5];
+ CFURLGetBytes(url, (UInt8*)bytes, bytesLength);
+ bytes[bytesLength] = '\0';
+ if (bytes[0] == '/') {
+ buffer[0] = 'f';
+ buffer[1] = 'i';
+ buffer[2] = 'l';
+ buffer[3] = 'e';
+ buffer[4] = ':';
+ parse(buffer.data(), 0);
+ } else
+ parse(bytes, 0);
+ } else
+ parse("", 0);
}
CFURLRef KURL::createCFURL() const
{
- // FIXME: What should this return for invalid URLs?
- // Currently it throws away the high bytes of the characters in the string in that case,
- // which is clearly wrong.
-
- Vector<char, 512> buffer;
- copyToBuffer(buffer);
-
+ const UInt8 *bytes = (const UInt8 *)urlString.latin1();
// NOTE: We use UTF-8 here since this encoding is used when computing strings when returning URL components
// (e.g calls to NSURL -path). However, this function is not tolerant of illegal UTF-8 sequences, which
// could either be a malformed string or bytes in a different encoding, like Shift-JIS, so we fall back
// onto using ISO Latin-1 in those cases.
- CFURLRef result = CFURLCreateAbsoluteURLWithBytes(0, reinterpret_cast<const UInt8*>(buffer.data()), buffer.size(), kCFStringEncodingUTF8, 0, true);
+ CFURLRef result = CFURLCreateAbsoluteURLWithBytes(0, bytes, urlString.length(), kCFStringEncodingUTF8, 0, true);
if (!result)
- result = CFURLCreateAbsoluteURLWithBytes(0, reinterpret_cast<const UInt8*>(buffer.data()), buffer.size(), kCFStringEncodingISOLatin1, 0, true);
+ result = CFURLCreateAbsoluteURLWithBytes(0, bytes, urlString.length(), kCFStringEncodingISOLatin1, 0, true);
return result;
}
@@ -89,7 +79,9 @@ String KURL::fileSystemPath() const
#else
CFURLPathStyle pathStyle = kCFURLPOSIXPathStyle;
#endif
- return RetainPtr<CFStringRef>(AdoptCF, CFURLCopyFileSystemPath(cfURL.get(), pathStyle)).get();
+
+ RetainPtr<CFStringRef> path(AdoptCF, CFURLCopyFileSystemPath(cfURL.get(), pathStyle));
+ return path.get();
}
}
diff --git a/WebCore/platform/graphics/AffineTransform.h b/WebCore/platform/graphics/AffineTransform.h
index 2ba4ce7..c0dc72f 100644
--- a/WebCore/platform/graphics/AffineTransform.h
+++ b/WebCore/platform/graphics/AffineTransform.h
@@ -32,6 +32,8 @@
#include <QMatrix>
#elif PLATFORM(CAIRO)
#include <cairo.h>
+#elif PLATFORM(SGL)
+#include "SkMatrix.h"
#elif PLATFORM(WX) && USE(WXGC)
#include <wx/defs.h>
#include <wx/graphics.h>
@@ -111,6 +113,8 @@ public:
operator QMatrix() const;
#elif PLATFORM(CAIRO)
operator cairo_matrix_t() const;
+#elif PLATFORM(SGL)
+ operator SkMatrix() const;
#elif PLATFORM(WX) && USE(WXGC)
operator wxGraphicsMatrix() const;
#endif
@@ -127,6 +131,8 @@ private:
QMatrix m_transform;
#elif PLATFORM(CAIRO)
cairo_matrix_t m_transform;
+#elif PLATFORM(SGL)
+ SkMatrix m_transform;
#elif PLATFORM(WX) && USE(WXGC)
wxGraphicsMatrix m_transform;
#endif
diff --git a/WebCore/platform/graphics/BitmapImage.cpp b/WebCore/platform/graphics/BitmapImage.cpp
index 9ef1d6a..e731ed6 100644
--- a/WebCore/platform/graphics/BitmapImage.cpp
+++ b/WebCore/platform/graphics/BitmapImage.cpp
@@ -92,8 +92,10 @@ void BitmapImage::destroyDecodedData(bool incremental)
if (!incremental) {
// Reset the image source, since Image I/O has an underlying cache that it uses
// while animating that it seems to never clear.
+#if !PLATFORM(SGL)
m_source.clear();
m_source.setData(m_data.get(), m_allDataReceived);
+#endif
}
}
}
@@ -232,7 +234,7 @@ void BitmapImage::resetAnimation()
m_repetitionsComplete = 0;
m_animationFinished = false;
int frameSize = m_size.width() * m_size.height() * 4;
-
+
// For extremely large animations, when the animation is reset, we just throw everything away.
if (frameCount() * frameSize > cLargeAnimationCutoff)
destroyDecodedData();
diff --git a/WebCore/platform/graphics/BitmapImage.h b/WebCore/platform/graphics/BitmapImage.h
index 0185027..154d829 100644
--- a/WebCore/platform/graphics/BitmapImage.h
+++ b/WebCore/platform/graphics/BitmapImage.h
@@ -44,6 +44,10 @@ class NSImage;
typedef struct HBITMAP__ *HBITMAP;
#endif
+#if PLATFORM(SGL)
+ class SkBitmapRef;
+#endif
+
namespace WebCore {
struct FrameData;
}
@@ -127,6 +131,11 @@ public:
virtual bool getHBITMAPOfSize(HBITMAP, LPSIZE);
#endif
+#if PLATFORM(SGL)
+ virtual SkBitmapRef* getBitmap();
+ virtual void setURL(const String& str);
+#endif
+
virtual NativeImagePtr nativeImageForCurrentFrame() { return frameAtIndex(currentFrame()); }
private:
@@ -184,6 +193,10 @@ private:
mutable RetainPtr<CFDataRef> m_tiffRep; // Cached TIFF rep for frame 0. Only built lazily if someone queries for one.
#endif
+#if PLATFORM(SGL)
+ SkBitmapRef* m_bitmapRef;
+#endif
+
Color m_solidColor; // If we're a 1x1 solid color, this is the color to use to fill.
bool m_isSolidColor; // Whether or not we are a 1x1 solid image.
diff --git a/WebCore/platform/graphics/Color.cpp b/WebCore/platform/graphics/Color.cpp
index 52d2bd7..b0efff1 100644
--- a/WebCore/platform/graphics/Color.cpp
+++ b/WebCore/platform/graphics/Color.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003, 2004, 2005, 2006, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2004, 2005, 2006 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
@@ -26,6 +26,7 @@
#include "config.h"
#include "Color.h"
+#include "DeprecatedString.h"
#include "PlatformString.h"
#include <math.h>
#include <wtf/Assertions.h>
@@ -34,7 +35,6 @@
#include "ColorData.c"
using namespace std;
-using namespace WTF;
namespace WebCore {
@@ -92,26 +92,24 @@ RGBA32 makeRGBAFromHSLA(double hue, double saturation, double lightness, double
// originally moved here from the CSS parser
bool Color::parseHexColor(const String& name, RGBA32& rgb)
{
- unsigned length = name.length();
- if (length != 3 && length != 6)
- return false;
- unsigned value = 0;
- for (unsigned i = 0; i < length; ++i) {
- if (!isASCIIHexDigit(name[i]))
- return false;
- value <<= 4;
- value |= toASCIIHexValue(name[i]);
+ int len = name.length();
+ if (len == 3 || len == 6) {
+ bool ok;
+ int val = name.deprecatedString().toInt(&ok, 16);
+ if (ok) {
+ if (len == 6) {
+ rgb = 0xFF000000 | val;
+ return true;
+ }
+ // #abc converts to #aabbcc according to the specs
+ rgb = 0xFF000000
+ | (val & 0xF00) << 12 | (val & 0xF00) << 8
+ | (val & 0xF0) << 8 | (val & 0xF0) << 4
+ | (val & 0xF) << 4 | (val & 0xF);
+ return true;
+ }
}
- if (length == 6) {
- rgb = 0xFF000000 | value;
- return true;
- }
- // #abc converts to #aabbcc
- rgb = 0xFF000000
- | (value & 0xF00) << 12 | (value & 0xF00) << 8
- | (value & 0xF0) << 8 | (value & 0xF0) << 4
- | (value & 0xF) << 4 | (value & 0xF);
- return true;
+ return false;
}
int differenceSquared(const Color& c1, const Color& c2)
@@ -149,25 +147,10 @@ String Color::name() const
return String::format("#%02X%02X%02X", red(), green(), blue());
}
-static inline const NamedColor* findNamedColor(const String& name)
-{
- char buffer[64]; // easily big enough for the longest color name
- unsigned length = name.length();
- if (length > sizeof(buffer) - 1)
- return 0;
- for (unsigned i = 0; i < length; ++i) {
- UChar c = name[i];
- if (!c || c > 0x7F)
- return 0;
- buffer[i] = toASCIILower(static_cast<char>(c));
- }
- buffer[length] = '\0';
- return findColor(buffer, length);
-}
-
void Color::setNamedColor(const String& name)
{
- const NamedColor* foundColor = findNamedColor(name);
+ DeprecatedString dname = name.deprecatedString();
+ const NamedColor* foundColor = dname.isAllASCII() ? findColor(dname.latin1(), dname.length()) : 0;
m_color = foundColor ? foundColor->RGBValue : 0;
m_color |= 0xFF000000;
m_valid = foundColor;
diff --git a/WebCore/platform/graphics/Color.h b/WebCore/platform/graphics/Color.h
index 5706c6f..7bbca18 100644
--- a/WebCore/platform/graphics/Color.h
+++ b/WebCore/platform/graphics/Color.h
@@ -118,6 +118,10 @@ public:
static const RGBA32 lightGray = 0xFFC0C0C0;
static const RGBA32 transparent = 0x00000000;
+#ifdef ANDROID_CSS_TAP_HIGHLIGHT_COLOR
+ static const RGBA32 tap = 0x4D1A1A1A;
+#endif
+
private:
RGBA32 m_color;
bool m_valid : 1;
diff --git a/WebCore/platform/graphics/Font.cpp b/WebCore/platform/graphics/Font.cpp
index 05704d3..82bf3b1 100644
--- a/WebCore/platform/graphics/Font.cpp
+++ b/WebCore/platform/graphics/Font.cpp
@@ -63,7 +63,12 @@ Font::CodePath Font::codePath = Auto;
struct WidthIterator {
WidthIterator(const Font* font, const TextRun& run);
- void advance(int to, GlyphBuffer* glyphBuffer = 0);
+#ifdef ANDROID_GLYPHBUFFER_HAS_ADJUSTED_WIDTHS
+ bool
+#else
+ void
+#endif
+ advance(int to, GlyphBuffer* glyphBuffer = 0);
bool advanceOneCharacter(float& width, GlyphBuffer* glyphBuffer = 0);
const Font* m_font;
@@ -107,7 +112,13 @@ WidthIterator::WidthIterator(const Font* font, const TextRun& run)
}
}
+#ifdef ANDROID_GLYPHBUFFER_HAS_ADJUSTED_WIDTHS
+#define SIGNAL_ADJUSTED_WIDTHS() adjustedWidths = true
+bool WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer)
+#else
+#define SIGNAL_ADJUSTED_WIDTHS()
void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer)
+#endif
{
if (offset > m_end)
offset = m_end;
@@ -121,6 +132,10 @@ void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer)
float runWidthSoFar = m_runWidthSoFar;
float lastRoundingWidth = m_finalRoundingWidth;
+#ifdef ANDROID_GLYPHBUFFER_HAS_ADJUSTED_WIDTHS
+ bool adjustedWidths = false;
+#endif
+
while (currentCharacter < offset) {
UChar32 c = *cp;
unsigned clusterLength = 1;
@@ -162,20 +177,27 @@ void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer)
if (c == '\t' && m_run.allowTabs()) {
float tabWidth = m_font->tabWidth();
width = tabWidth - fmodf(m_run.xPos() + runWidthSoFar, tabWidth);
+ SIGNAL_ADJUSTED_WIDTHS();
} else {
width = fontData->widthForGlyph(glyph);
+#ifndef ANDROID_NEVER_ROUND_FONT_METRICS
// 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 (width == fontData->m_spaceWidth && (fontData->m_treatAsFixedPitch || glyph == fontData->m_spaceGlyph) && m_run.applyWordRounding())
+ if (width == fontData->m_spaceWidth && (fontData->m_treatAsFixedPitch || glyph == fontData->m_spaceGlyph) && m_run.applyWordRounding()) {
width = fontData->m_adjustedSpaceWidth;
+ SIGNAL_ADJUSTED_WIDTHS();
+ }
+#endif
}
if (hasExtraSpacing && !m_run.spacingDisabled()) {
// Account for letter-spacing.
- if (width && m_font->letterSpacing())
+ if (width && m_font->letterSpacing()) {
width += m_font->letterSpacing();
+ SIGNAL_ADJUSTED_WIDTHS();
+ }
if (Font::treatAsSpace(c)) {
// Account for padding. WebCore uses space padding to justify text.
@@ -189,12 +211,15 @@ void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer)
width += m_padPerSpace;
m_padding -= m_padPerSpace;
}
+ SIGNAL_ADJUSTED_WIDTHS();
}
// Account for word spacing.
// We apply additional space between "words" by adding width to the space character.
- if (currentCharacter != 0 && !Font::treatAsSpace(cp[-1]) && m_font->wordSpacing())
+ if (currentCharacter != 0 && !Font::treatAsSpace(cp[-1]) && m_font->wordSpacing()) {
width += m_font->wordSpacing();
+ SIGNAL_ADJUSTED_WIDTHS();
+ }
}
}
@@ -209,10 +234,13 @@ void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer)
float oldWidth = width;
+#ifndef ANDROID_NEVER_ROUND_FONT_METRICS
// 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 (m_run.applyWordRounding() && Font::isRoundingHackCharacter(c))
+ if (m_run.applyWordRounding() && Font::isRoundingHackCharacter(c)) {
width = ceilf(width);
+ SIGNAL_ADJUSTED_WIDTHS();
+ }
// Check to see if the next character is a "rounding hack character", if so, adjust
// width so that the total run width will be on an integer boundary.
@@ -220,7 +248,9 @@ void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer)
|| (m_run.applyRunRounding() && currentCharacter >= m_end)) {
float totalWidth = runWidthSoFar + width;
width += ceilf(totalWidth) - totalWidth;
+ SIGNAL_ADJUSTED_WIDTHS();
}
+#endif
runWidthSoFar += width;
@@ -233,6 +263,10 @@ void WidthIterator::advance(int offset, GlyphBuffer* glyphBuffer)
m_currentCharacter = currentCharacter;
m_runWidthSoFar = runWidthSoFar;
m_finalRoundingWidth = lastRoundingWidth;
+
+#ifdef ANDROID_GLYPHBUFFER_HAS_ADJUSTED_WIDTHS
+ return adjustedWidths;
+#endif
}
bool WidthIterator::advanceOneCharacter(float& width, GlyphBuffer* glyphBuffer)
@@ -621,8 +655,11 @@ void Font::drawSimpleText(GraphicsContext* context, const TextRun& run, const Fl
WidthIterator it(this, run);
it.advance(from);
float beforeWidth = it.m_runWidthSoFar;
+#ifdef ANDROID_GLYPHBUFFER_HAS_ADJUSTED_WIDTHS
+ bool adjustedWidths =
+#endif
it.advance(to, &glyphBuffer);
-
+
// We couldn't generate any glyphs for the run. Give up.
if (glyphBuffer.isEmpty())
return;
@@ -633,6 +670,9 @@ void Font::drawSimpleText(GraphicsContext* context, const TextRun& run, const Fl
float finalRoundingWidth = it.m_finalRoundingWidth;
it.advance(run.length());
startX += finalRoundingWidth + it.m_runWidthSoFar - afterWidth;
+#ifdef ANDROID_GLYPHBUFFER_HAS_ADJUSTED_WIDTHS
+ adjustedWidths = true; // give up on simple/fast case
+#endif
} else
startX += beforeWidth;
@@ -641,6 +681,11 @@ void Font::drawSimpleText(GraphicsContext* context, const TextRun& run, const Fl
for (int i = 0, end = glyphBuffer.size() - 1; i < glyphBuffer.size() / 2; ++i, --end)
glyphBuffer.swap(i, end);
+#ifdef ANDROID_GLYPHBUFFER_HAS_ADJUSTED_WIDTHS
+ // mark the GlyphBuffer as having adjusted widths or not
+ // used by drawGlyph as an optimization hint
+ glyphBuffer.setHasAdjustedWidths(adjustedWidths);
+#endif
// Calculate the starting point of the glyphs to be displayed by adding
// all the advances up to the first glyph.
FloatPoint startPoint(startX, point.y());
diff --git a/WebCore/platform/graphics/Font.h b/WebCore/platform/graphics/Font.h
index 0ea04eb..84048ed 100644
--- a/WebCore/platform/graphics/Font.h
+++ b/WebCore/platform/graphics/Font.h
@@ -266,7 +266,8 @@ public:
FontSelector* fontSelector() const;
#endif
static bool treatAsSpace(UChar c) { return c == ' ' || c == '\t' || c == '\n' || c == 0x00A0; }
- static bool treatAsZeroWidthSpace(UChar c) { return c < 0x20 || (c >= 0x7F && c < 0xA0) || c == 0x200e || c == 0x200f || c >= 0x202a && c <= 0x202e; }
+// ANDROID: extra parentheses around expressions to suppress warnings
+ static bool treatAsZeroWidthSpace(UChar c) { return c < 0x20 || (c >= 0x7F && c < 0xA0) || c == 0x200e || c == 0x200f || (c >= 0x202a && c <= 0x202e); }
private:
FontDescription m_fontDescription;
#if !PLATFORM(QT)
diff --git a/WebCore/platform/graphics/FontFallbackList.cpp b/WebCore/platform/graphics/FontFallbackList.cpp
index 0fdd99c..049cf7f 100644
--- a/WebCore/platform/graphics/FontFallbackList.cpp
+++ b/WebCore/platform/graphics/FontFallbackList.cpp
@@ -36,11 +36,10 @@
namespace WebCore {
FontFallbackList::FontFallbackList()
- : RefCounted<FontFallbackList>(0)
- , m_familyIndex(0)
- , m_pitch(UnknownPitch)
- , m_loadingCustomFonts(false)
- , m_fontSelector(0)
+: m_familyIndex(0)
+, m_pitch(UnknownPitch)
+, m_loadingCustomFonts(false)
+, m_fontSelector(0)
{
}
diff --git a/WebCore/platform/graphics/FontFamily.cpp b/WebCore/platform/graphics/FontFamily.cpp
index c87c661..a185756 100644
--- a/WebCore/platform/graphics/FontFamily.cpp
+++ b/WebCore/platform/graphics/FontFamily.cpp
@@ -29,7 +29,7 @@
namespace WebCore {
FontFamily::FontFamily(const FontFamily& other)
- : RefCounted<FontFamily>(0)
+ : RefCounted<FontFamily>()
, m_family(other.m_family)
, m_next(other.m_next)
{
diff --git a/WebCore/platform/graphics/FontFamily.h b/WebCore/platform/graphics/FontFamily.h
index 7a382cc..65a64b4 100644
--- a/WebCore/platform/graphics/FontFamily.h
+++ b/WebCore/platform/graphics/FontFamily.h
@@ -34,7 +34,7 @@ namespace WebCore {
class FontFamily : public RefCounted<FontFamily> {
public:
- FontFamily() : RefCounted<FontFamily>(0) { }
+ FontFamily() { }
FontFamily(const FontFamily&);
FontFamily& operator=(const FontFamily&);
diff --git a/WebCore/platform/graphics/FontSelector.h b/WebCore/platform/graphics/FontSelector.h
index b0e9dfa..c5b3651 100644
--- a/WebCore/platform/graphics/FontSelector.h
+++ b/WebCore/platform/graphics/FontSelector.h
@@ -36,9 +36,8 @@ class FontDescription;
class FontSelector : public RefCounted<FontSelector> {
public:
- FontSelector() : RefCounted<FontSelector>(0) { }
- virtual ~FontSelector() { }
- virtual FontData* getFontData(const FontDescription&, const AtomicString& familyName) = 0;
+ virtual ~FontSelector() {};
+ virtual FontData* getFontData(const FontDescription& fontDescription, const AtomicString& familyName) = 0;
};
} // namespace WebCore
diff --git a/WebCore/platform/graphics/GlyphBuffer.h b/WebCore/platform/graphics/GlyphBuffer.h
index f65996d..c8e308c 100644
--- a/WebCore/platform/graphics/GlyphBuffer.h
+++ b/WebCore/platform/graphics/GlyphBuffer.h
@@ -53,6 +53,9 @@ typedef FloatSize GlyphBufferAdvance;
#elif PLATFORM(WX)
typedef Glyph GlyphBufferGlyph;
typedef FloatSize GlyphBufferAdvance;
+#elif PLATFORM(SGL)
+typedef Glyph GlyphBufferGlyph;
+typedef FloatSize GlyphBufferAdvance;
#elif PLATFORM(QT)
typedef unsigned short GlyphBufferGlyph;
typedef FloatSize GlyphBufferAdvance;
@@ -60,6 +63,10 @@ typedef FloatSize GlyphBufferAdvance;
class GlyphBuffer {
public:
+#ifdef ANDROID_GLYPHBUFFER_HAS_ADJUSTED_WIDTHS
+ GlyphBuffer() : m_hasAdjustedWidths(true) {}
+#endif
+
bool isEmpty() const { return m_fontData.isEmpty(); }
int size() const { return m_fontData.size(); }
@@ -103,7 +110,7 @@ public:
Glyph glyphAt(int index) const
{
-#if PLATFORM(CG) || PLATFORM(QT) || PLATFORM(WX)
+#if PLATFORM(CG) || PLATFORM(QT) || PLATFORM(WX) || PLATFORM(SGL)
return m_glyphs[index];
#elif PLATFORM(CAIRO)
return m_glyphs[index].index;
@@ -114,7 +121,7 @@ public:
{
#if PLATFORM(CG)
return m_advances[index].width;
-#elif PLATFORM(CAIRO) || PLATFORM(QT) || PLATFORM(WX)
+#elif PLATFORM(CAIRO) || PLATFORM(QT) || PLATFORM(WX) || PLATFORM(SGL)
return m_advances[index].width();
#endif
}
@@ -142,7 +149,7 @@ public:
cairoGlyph.index = glyph;
m_glyphs.append(cairoGlyph);
m_advances.append(FloatSize(width, 0));
-#elif PLATFORM(QT) || PLATFORM(WX)
+#elif PLATFORM(QT) || PLATFORM(WX) || PLATFORM(SGL)
m_glyphs.append(glyph);
m_advances.append(FloatSize(width, 0));
#endif
@@ -154,6 +161,18 @@ public:
#endif
}
+#ifdef ANDROID_GLYPHBUFFER_HAS_ADJUSTED_WIDTHS
+ void setHasAdjustedWidths(bool adjustedWidths) {
+ m_hasAdjustedWidths = adjustedWidths;
+ }
+ /** Returns true in the general case, which means that one or more of the
+ glyphs may have a width or height that has been changed from the raw
+ value returned by the font. If this returns false, then the drawing
+ code can use that as a hint if it means it can draw the run faster.
+ */
+ bool hasAdjustedWidths() const { return m_hasAdjustedWidths; }
+#endif
+
private:
Vector<const SimpleFontData*, 2048> m_fontData;
Vector<GlyphBufferGlyph, 2048> m_glyphs;
@@ -161,6 +180,12 @@ private:
#if PLATFORM(WIN)
Vector<FloatSize, 2048> m_offsets;
#endif
+#ifdef ANDROID_GLYPHBUFFER_HAS_ADJUSTED_WIDTHS
+ // defaults to true for general case. Set to false sometimes in
+ // drawSimpleText as a hint to drawGlphs that the widths are exactly those
+ // from the font (i.e. no tweaks for rounding or CSS styling
+ bool m_hasAdjustedWidths;
+#endif
};
}
diff --git a/WebCore/platform/graphics/GlyphPageTreeNode.h b/WebCore/platform/graphics/GlyphPageTreeNode.h
index 40b8154..2619888 100644
--- a/WebCore/platform/graphics/GlyphPageTreeNode.h
+++ b/WebCore/platform/graphics/GlyphPageTreeNode.h
@@ -58,14 +58,12 @@ struct GlyphData {
// to be overriding the parent's node, but provide no additional information.
struct GlyphPage : public RefCounted<GlyphPage> {
GlyphPage()
- : RefCounted<GlyphPage>(0)
- , m_owner(0)
+ : m_owner(0)
{
}
GlyphPage(GlyphPageTreeNode* owner)
- : RefCounted<GlyphPage>(0)
- , m_owner(owner)
+ : m_owner(owner)
{
}
diff --git a/WebCore/platform/graphics/GraphicsContext.h b/WebCore/platform/graphics/GraphicsContext.h
index 732c8e3..f75c287 100644
--- a/WebCore/platform/graphics/GraphicsContext.h
+++ b/WebCore/platform/graphics/GraphicsContext.h
@@ -34,6 +34,10 @@
#include <wtf/Noncopyable.h>
#include <wtf/Platform.h>
+#ifdef ANDROID_CANVAS_IMPL
+ #include "PlatformGraphics.h"
+#endif
+
#if PLATFORM(CG)
typedef struct CGContext PlatformGraphicsContext;
#elif PLATFORM(CAIRO)
@@ -41,6 +45,10 @@ typedef struct _cairo PlatformGraphicsContext;
#elif PLATFORM(QT)
class QPainter;
typedef QPainter PlatformGraphicsContext;
+#elif PLATFORM(SGL)
+namespace WebCore {
+class PlatformGraphicsContext;
+}
#elif PLATFORM(WX)
class wxGCDC;
class wxWindowDC;
@@ -83,7 +91,6 @@ namespace WebCore {
class Font;
class GraphicsContextPrivate;
class GraphicsContextPlatformPrivate;
- class ImageBuffer;
class KURL;
class Path;
class TextRun;
@@ -130,6 +137,84 @@ namespace WebCore {
void drawEllipse(const IntRect&);
void drawConvexPolygon(size_t numPoints, const FloatPoint*, bool shouldAntialias = false);
+#ifdef ANDROID_CANVAS_IMPL
+ /** Fill the specified path using the optional gradient or pattern, using the following
+ precedence. If/when gradients/patterns are added to the graphics context, these
+ parameters can go away
+ 1) use gradient if gradient != null
+ 2) use pattern if pattern != null
+ 3) use color in the graphics context
+ */
+ void fillPath(const Path&, PlatformGradient*, PlatformPattern*);
+ /** Stroke the specified path using the optional gradient or pattern, using the following
+ precedence. If/when gradients/patterns are added to the graphics context, these
+ parameters can go away
+ 1) use gradient if gradient != null
+ 2) use pattern if pattern != null
+ 3) use color in the graphics context
+ */
+ void strokePath(const Path&, PlatformGradient*, PlatformPattern*);
+ /** Fill the specified rect using the optional gradient or pattern, using the following
+ precedence. If/when gradients/patterns are added to the graphics context, these
+ parameters can go away
+ 1) use gradient if gradient != null
+ 2) use pattern if pattern != null
+ 3) use color in the graphics context
+ */
+ void fillRect(const FloatRect&, PlatformGradient*, PlatformPattern*);
+ /** Stroke the specified rect using the optional gradient or pattern, using the following
+ precedence. If/when gradients/patterns are added to the graphics context, these
+ parameters can go away
+ 1) use gradient if gradient != null
+ 2) use pattern if pattern != null
+ 3) use color in the graphics context
+ */
+ void strokeRect(const FloatRect&, float lineWidth, PlatformGradient*, PlatformPattern*);
+
+ /** Return a platform specific linear-gradient. Use freePlatformGradient() when you are
+ done with it.
+ stopData is { stop, red, green, blue, alpha } per entry
+ */
+ static PlatformGradient* newPlatformLinearGradient(const FloatPoint& p0, const FloatPoint& p1,
+ const float stopData[5], int count);
+
+ /** Return a platform specific radial-gradient. Use freePlatformGradient() when you are
+ done with it.
+ stopData is { stop, red, green, blue, alpha } per entry
+ */
+ static PlatformGradient* newPlatformRadialGradient(const FloatPoint& p0, float r0,
+ const FloatPoint& p1, float r1,
+ const float stopData[5], int count);
+ static void freePlatformGradient(PlatformGradient*);
+
+ /** Return a platform specific pattern. Use freePlatformPattern() when you are
+ done with it.
+ */
+ static PlatformPattern* newPlatformPattern(Image* image,
+ Image::TileRule hRule, Image::TileRule vRule);
+ static void freePlatformPattern(PlatformPattern*);
+
+ /** platform-specific factory method to return a bitmap graphicscontext,
+ called by <canvas> when we need to draw offscreen. Caller is responsible for
+ deleting the context. Use drawOffscreenContext() to draw the context's image
+ onto another graphics context.
+ */
+ static GraphicsContext* createOffscreenContext(int width, int height);
+ /** Called with a context returned by createOffscreenContext. Draw the underlying
+ bitmap to the current context. Similar to drawImage(), but this hides how
+ to extract the bitmap from ctx from the portable code.
+ If srcRect is NULL, it is assumed that we want to draw the entire bitmap represented
+ by the GraphicsContext.
+ */
+ void drawOffscreenContext(GraphicsContext* ctx, const WebCore::FloatRect* srcRect,
+ const WebCore::FloatRect& dstRect);
+
+ /** Return the clip bounds in local coordinates. It can be an approximation, as long as
+ the returned bounds completely enclose the actual clip.
+ */
+ FloatRect getClipLocalBounds() const;
+#endif
+
// Arc drawing (used by border-radius in CSS) just supports stroking at the moment.
void strokeArc(const IntRect&, int startAngle, int angleSpan);
@@ -145,14 +230,11 @@ namespace WebCore {
void drawImage(Image*, const IntRect& destRect, const IntRect& srcRect, CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false);
void drawImage(Image*, const FloatRect& destRect, const FloatRect& srcRect = FloatRect(0, 0, -1, -1),
CompositeOperator = CompositeSourceOver, bool useLowQualityScale = false);
- void drawImage(ImageBuffer*, const FloatRect& srcRect, const FloatRect& destRect);
void drawTiledImage(Image*, const IntRect& destRect, const IntPoint& srcPoint, const IntSize& tileSize,
CompositeOperator = CompositeSourceOver);
void drawTiledImage(Image*, const IntRect& destRect, const IntRect& srcRect,
Image::TileRule hRule = Image::StretchTile, Image::TileRule vRule = Image::StretchTile,
CompositeOperator = CompositeSourceOver);
-
- void paintBuffer(ImageBuffer*, const IntRect&);
#if PLATFORM(CG)
void setUseLowQualityImageInterpolation(bool = true);
bool useLowQualityImageInterpolation() const;
diff --git a/WebCore/platform/graphics/Image.h b/WebCore/platform/graphics/Image.h
index 6ffe163..4ef5bf7 100644
--- a/WebCore/platform/graphics/Image.h
+++ b/WebCore/platform/graphics/Image.h
@@ -54,6 +54,10 @@ typedef struct HBITMAP__ *HBITMAP;
#include <QPixmap>
#endif
+#if PLATFORM(SGL)
+class SkBitmapRef;
+#endif
+
namespace WebCore {
class AffineTransform;
@@ -133,6 +137,11 @@ public:
virtual bool getHBITMAPOfSize(HBITMAP, LPSIZE) { return false; }
#endif
+#if PLATFORM(SGL)
+ virtual SkBitmapRef* getBitmap() { return 0; }
+ virtual void setURL(const String& str) {}
+#endif
+
protected:
static void fillWithSolidColor(GraphicsContext* ctxt, const FloatRect& dstRect, const Color& color, CompositeOperator op);
diff --git a/WebCore/platform/graphics/ImageBuffer.h b/WebCore/platform/graphics/ImageBuffer.h
index 2ac2b4e..c815c8d 100644
--- a/WebCore/platform/graphics/ImageBuffer.h
+++ b/WebCore/platform/graphics/ImageBuffer.h
@@ -29,7 +29,6 @@
#include "IntSize.h"
#include <wtf/OwnPtr.h>
-#include <wtf/PassRefPtr.h>
#include <memory>
#if PLATFORM(CG)
@@ -41,6 +40,10 @@ typedef struct CGImage* CGImageRef;
class QPainter;
#endif
+#if PLATFORM(SGL)
+#include <memory>
+#endif
+
#if PLATFORM(CAIRO)
typedef struct _cairo_surface cairo_surface_t;
#endif
@@ -48,9 +51,6 @@ typedef struct _cairo_surface cairo_surface_t;
namespace WebCore {
class GraphicsContext;
- class ImageData;
- class IntPoint;
- class IntRect;
class RenderObject;
class ImageBuffer : Noncopyable {
@@ -68,9 +68,6 @@ namespace WebCore {
#elif PLATFORM(CAIRO)
cairo_surface_t* surface() const;
#endif
-
- PassRefPtr<ImageData> getImageData(const IntRect& rect) const;
- void putImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint);
private:
void* m_data;
@@ -89,6 +86,9 @@ namespace WebCore {
ImageBuffer(cairo_surface_t* surface);
mutable cairo_surface_t* m_surface;
#endif
+#if PLATFORM(SGL)
+ ImageBuffer(const IntSize&, std::auto_ptr<GraphicsContext>);
+#endif
};
}
diff --git a/WebCore/platform/graphics/ImageSource.h b/WebCore/platform/graphics/ImageSource.h
index 8db5cd4..c99b00f 100644
--- a/WebCore/platform/graphics/ImageSource.h
+++ b/WebCore/platform/graphics/ImageSource.h
@@ -40,6 +40,10 @@ class QPixmap;
#elif PLATFORM(CAIRO)
struct _cairo_surface;
typedef struct _cairo_surface cairo_surface_t;
+#elif PLATFORM(SGL)
+#include "SkString.h"
+class SkBitmapRef;
+class PrivateAndroidImageSourceRec;
#endif
namespace WebCore {
@@ -59,6 +63,14 @@ typedef CGImageRef NativeImagePtr;
class ImageDecoderQt;
typedef ImageDecoderQt* NativeImageSourcePtr;
typedef QPixmap* NativeImagePtr;
+#elif PLATFORM(SGL)
+class String;
+struct NativeImageSourcePtr {
+ SkString m_url;
+ PrivateAndroidImageSourceRec* m_image;
+};
+typedef const Vector<char>* NativeBytePtr;
+typedef SkBitmapRef* NativeImagePtr;
#else
class ImageDecoder;
typedef ImageDecoder* NativeImageSourcePtr;
@@ -92,6 +104,10 @@ public:
bool frameHasAlphaAtIndex(size_t); // Whether or not the frame actually used any alpha.
bool frameIsCompleteAtIndex(size_t); // Whether or not the frame is completely decoded.
+#if PLATFORM(SGL)
+ void clearURL();
+ void setURL(const String& url);
+#endif
private:
NativeImageSourcePtr m_decoder;
};
diff --git a/WebCore/platform/graphics/Path.h b/WebCore/platform/graphics/Path.h
index 5150649..d63ba0b 100644
--- a/WebCore/platform/graphics/Path.h
+++ b/WebCore/platform/graphics/Path.h
@@ -32,6 +32,9 @@ typedef struct CGPath PlatformPath;
#elif PLATFORM(QT)
class QPainterPath;
typedef QPainterPath PlatformPath;
+#elif PLATFORM(SGL)
+class SkPath;
+typedef SkPath PlatformPath;
#elif PLATFORM(WX) && USE(WXGC)
class wxGraphicsPath;
typedef wxGraphicsPath PlatformPath;
diff --git a/WebCore/platform/graphics/SimpleFontData.h b/WebCore/platform/graphics/SimpleFontData.h
index c444a6f..b2eec1f 100644
--- a/WebCore/platform/graphics/SimpleFontData.h
+++ b/WebCore/platform/graphics/SimpleFontData.h
@@ -1,7 +1,7 @@
/*
* This file is part of the internal font implementation.
*
- * Copyright (C) 2006, 2008 Apple Computer, Inc.
+ * Copyright (C) 2006 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
@@ -37,10 +37,6 @@ typedef struct OpaqueATSUStyle* ATSUStyle;
#include <usp10.h>
#endif
-#if PLATFORM(CAIRO)
-#include <cairo.h>
-#endif
-
namespace WebCore {
class FontDescription;
@@ -110,7 +106,7 @@ public:
static bool shouldApplyMacAscentHack();
#endif
-#if PLATFORM(CAIRO)
+#if PLATFORM(GTK)
void setFont(cairo_t*) const;
#endif
@@ -124,12 +120,6 @@ private:
void commonInit();
-#if PLATFORM(WIN)
- void initGDIFont();
- void platformCommonDestroy();
- float widthForGDIGlyph(Glyph glyph) const;
-#endif
-
public:
int m_ascent;
int m_descent;
diff --git a/WebCore/platform/graphics/android/AffineTransformAndroid.cpp b/WebCore/platform/graphics/android/AffineTransformAndroid.cpp
new file mode 100644
index 0000000..d00aa40
--- /dev/null
+++ b/WebCore/platform/graphics/android/AffineTransformAndroid.cpp
@@ -0,0 +1,168 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "config.h"
+#include "AffineTransform.h"
+
+#include "FloatRect.h"
+#include "IntRect.h"
+
+#include "android_graphics.h"
+
+namespace WebCore {
+
+static const double deg2rad = 0.017453292519943295769; // pi/180
+
+AffineTransform::AffineTransform()
+{
+ m_transform.reset();
+}
+
+AffineTransform::AffineTransform(double a, double b, double c, double d, double tx, double ty)
+{
+ m_transform.reset();
+
+ m_transform.set(SkMatrix::kMScaleX, SkDoubleToScalar(a));
+ m_transform.set(SkMatrix::kMSkewX, SkDoubleToScalar(b));
+ m_transform.set(SkMatrix::kMTransX, SkDoubleToScalar(tx));
+
+ m_transform.set(SkMatrix::kMScaleY, SkDoubleToScalar(d));
+ m_transform.set(SkMatrix::kMSkewX, SkDoubleToScalar(c));
+ m_transform.set(SkMatrix::kMTransX, SkDoubleToScalar(ty));
+}
+
+void AffineTransform::setMatrix(double a, double b, double c, double d, double tx, double ty)
+{
+ m_transform.set(SkMatrix::kMScaleX, SkDoubleToScalar(a));
+ m_transform.set(SkMatrix::kMSkewX, SkDoubleToScalar(b));
+ m_transform.set(SkMatrix::kMTransX, SkDoubleToScalar(tx));
+
+ m_transform.set(SkMatrix::kMScaleY, SkDoubleToScalar(d));
+ m_transform.set(SkMatrix::kMSkewX, SkDoubleToScalar(c));
+ m_transform.set(SkMatrix::kMTransX, SkDoubleToScalar(ty));
+}
+
+void AffineTransform::map(double x, double y, double *x2, double *y2) const
+{
+ SkPoint src, dst;
+ src.set(SkDoubleToScalar(x), SkDoubleToScalar(y));
+ m_transform.mapPoints(&dst, &src, 1);
+
+ *x2 = SkScalarToDouble(dst.fX);
+ *y2 = SkScalarToDouble(dst.fY);
+}
+
+IntRect AffineTransform::mapRect(const IntRect &rect) const
+{
+ SkRect src, dst;
+ SkIRect ir;
+
+ android_setrect(&src, rect);
+ m_transform.mapRect(&dst, src);
+ dst.round(&ir);
+
+ return IntRect(ir.fLeft, ir.fTop, ir.width(), ir.height());
+}
+
+FloatRect AffineTransform::mapRect(const FloatRect &rect) const
+{
+ SkRect src, dst;
+ SkIRect ir;
+
+ android_setrect(&src, rect);
+ m_transform.mapRect(&dst, src);
+ dst.round(&ir);
+
+ return IntRect(ir.fLeft, ir.fTop, ir.width(), ir.height());
+}
+
+bool AffineTransform::isIdentity() const
+{
+ return m_transform.isIdentity();
+}
+
+void AffineTransform::reset()
+{
+ m_transform.reset();
+}
+
+AffineTransform &AffineTransform::scale(double sx, double sy)
+{
+ m_transform.preScale(SkDoubleToScalar(sx), SkDoubleToScalar(sy));
+ return *this;
+}
+
+AffineTransform &AffineTransform::rotate(double d)
+{
+ m_transform.preRotate(SkDoubleToScalar(d));
+ return *this;
+}
+
+AffineTransform &AffineTransform::translate(double tx, double ty)
+{
+ m_transform.preTranslate(SkDoubleToScalar(tx), SkDoubleToScalar(ty));
+ return *this;
+}
+
+AffineTransform &AffineTransform::shear(double sx, double sy)
+{
+ m_transform.preSkew(SkDoubleToScalar(sx), SkDoubleToScalar(sy));
+ return *this;
+}
+
+double AffineTransform::det() const
+{
+ return SkScalarToDouble(m_transform[SkMatrix::kMScaleX]) * SkScalarToDouble(m_transform[SkMatrix::kMScaleY]) -
+ SkScalarToDouble(m_transform[SkMatrix::kMSkewX]) * SkScalarToDouble(m_transform[SkMatrix::kMSkewY]);
+}
+
+AffineTransform AffineTransform::inverse() const
+{
+ AffineTransform inverse;
+
+ m_transform.invert(&inverse.m_transform);
+
+ return inverse;
+}
+
+AffineTransform::operator SkMatrix() const
+{
+ return m_transform;
+}
+
+bool AffineTransform::operator==(const AffineTransform &m2) const
+{
+ return m_transform == m2.m_transform;
+}
+
+AffineTransform &AffineTransform::operator*= (const AffineTransform &m2)
+{
+ // is this the correct order???
+ m_transform.setConcat(m_transform, m2.m_transform);
+ return *this;
+}
+
+AffineTransform AffineTransform::operator* (const AffineTransform &m2)
+{
+ AffineTransform cat;
+
+ // is this the correct order???
+ cat.m_transform.setConcat(m_transform, m2.m_transform);
+ return cat;
+}
+
+}
diff --git a/WebCore/platform/graphics/android/FontAndroid.cpp b/WebCore/platform/graphics/android/FontAndroid.cpp
new file mode 100644
index 0000000..340d1c1
--- /dev/null
+++ b/WebCore/platform/graphics/android/FontAndroid.cpp
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2006 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.
+ */
+
+#include "config.h"
+#include "Font.h"
+
+#include "FontData.h"
+#include "FontFallbackList.h"
+#include "GraphicsContext.h"
+#include "GlyphBuffer.h"
+#include "PlatformGraphicsContext.h"
+#include "IntRect.h"
+
+#include "SkCanvas.h"
+#include "SkPaint.h"
+#include "SkTemplates.h"
+#include "SkTypeface.h"
+#include "SkUtils.h"
+
+namespace WebCore {
+
+void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font,
+ const GlyphBuffer& glyphBuffer, int from, int numGlyphs,
+ const FloatPoint& point) const {
+ SkCanvas* canvas = gc->platformContext()->mCanvas;
+ SkPaint paint;
+
+ font->platformData().setupPaint(&paint);
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ paint.setColor(gc->fillColor().rgb());
+
+ SkASSERT(sizeof(GlyphBufferGlyph) == sizeof(uint16_t)); // compile-time assert
+
+ const GlyphBufferGlyph* glyphs = glyphBuffer.glyphs(from);
+ SkScalar x = SkFloatToScalar(point.x());
+ SkScalar y = SkFloatToScalar(point.y());
+
+ if (glyphBuffer.hasAdjustedWidths()) {
+ const GlyphBufferAdvance* adv = glyphBuffer.advances(from);
+ SkAutoSTMalloc<32, SkPoint> storage(numGlyphs);
+ SkPoint* pos = storage.get();
+
+ for (int i = 0; i < numGlyphs; i++) {
+ pos[i].set(x, y);
+ x += SkFloatToScalar(adv[i].width());
+ y += SkFloatToScalar(adv[i].height());
+ }
+ canvas->drawPosText(glyphs, numGlyphs << 1, pos, paint);
+ } else {
+ canvas->drawText(glyphs, numGlyphs << 1, x, y, paint);
+ }
+}
+
+FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& point, int h, int, int) const
+{
+ SkPaint paint;
+ SkScalar width, left;
+ SkPaint::FontMetrics metrics;
+
+ primaryFont()->platformData().setupPaint(&paint);
+
+ width = paint.measureText(run.characters(), run.length() << 1);
+ SkScalar spacing = paint.getFontMetrics(&metrics);
+
+ return FloatRect(point.x(),
+ point.y() - floorf(SkScalarToFloat(-metrics.fAscent)),
+ roundf(SkScalarToFloat(width)),
+ roundf(SkScalarToFloat(spacing)));
+}
+
+void Font::drawComplexText(GraphicsContext* gc, TextRun const& run, FloatPoint const& point, int, int) const
+{
+ SkCanvas* canvas = gc->platformContext()->mCanvas;
+ SkPaint paint;
+
+ primaryFont()->platformData().setupPaint(&paint);
+ paint.setColor(gc->fillColor().rgb());
+
+#if 0
+ int n = run.to() - run.from();
+printf("------------- complex draw %d chars", n);
+ for (int i = 0; i < n; i++)
+ printf(" %04X", run.data(run.from())[i]);
+ printf("\n");
+#endif
+
+ canvas->drawText(run.characters(), run.length() << 1,
+ SkFloatToScalar(point.x()), SkFloatToScalar(point.y()),
+ paint);
+}
+
+float Font::floatWidthForComplexText(const TextRun& run) const
+{
+ SkPaint paint;
+
+ primaryFont()->platformData().setupPaint(&paint);
+
+//printf("--------- complext measure %d chars\n", run.to() - run.from());
+
+ SkScalar width = paint.measureText(run.characters(), run.length() << 1);
+ return SkScalarToFloat(width);
+}
+
+int Font::offsetForPositionForComplexText(const TextRun& run, int x, bool includePartialGlyphs) const
+{
+ SkPaint paint;
+ int count = run.length();
+ SkAutoSTMalloc<64, SkScalar> storage(count);
+ SkScalar* widths = storage.get();
+
+ primaryFont()->platformData().setupPaint(&paint);
+
+ count = paint.getTextWidths(run.characters(), count << 1, widths);
+
+ if (count > 0)
+ {
+ SkScalar pos = 0;
+ for (int i = 0; i < count; i++)
+ {
+ if (x < SkScalarRound(pos + SkScalarHalf(widths[i])))
+ return i;
+ pos += widths[i];
+ }
+ }
+ return count;
+}
+
+}
diff --git a/WebCore/platform/graphics/android/FontCacheAndroid.cpp b/WebCore/platform/graphics/android/FontCacheAndroid.cpp
new file mode 100644
index 0000000..903159e
--- /dev/null
+++ b/WebCore/platform/graphics/android/FontCacheAndroid.cpp
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2006 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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.
+ */
+
+#include "config.h"
+#include "FontCache.h"
+#include "FontPlatformData.h"
+#include "Font.h"
+
+#include "SkPaint.h"
+#include "SkTypeface.h"
+#include "SkUtils.h"
+
+namespace WebCore {
+
+void FontCache::platformInit()
+{
+}
+
+const SimpleFontData* FontCache::getFontDataForCharacters(const Font& font, const UChar* characters, int length)
+{
+ return font.primaryFont(); // do I need to make a copy (i.e. does the caller delete what I return?
+
+#if 0
+ // IMLangFontLink::MapFont Method does what we want.
+ IMLangFontLink2* langFontLink = getFontLinkInterface();
+ if (!langFontLink)
+ return 0;
+
+ FontData* fontData = 0;
+ HDC hdc = GetDC(0);
+ DWORD fontCodePages;
+ langFontLink->GetFontCodePages(hdc, font.primaryFont()->m_font.hfont(), &fontCodePages);
+
+ DWORD actualCodePages;
+ long cchActual;
+ langFontLink->GetStrCodePages(characters, length, fontCodePages, &actualCodePages, &cchActual);
+ if (cchActual) {
+ HFONT result;
+ if (langFontLink->MapFont(hdc, actualCodePages, characters[0], &result) == S_OK) {
+ fontData = new FontData(FontPlatformData(result, font.fontDescription().computedPixelSize()));
+ fontData->setIsMLangFont();
+ }
+ }
+
+ ReleaseDC(0, hdc);
+ return fontData;
+#endif
+}
+
+FontPlatformData* FontCache::getSimilarFontPlatformData(const Font& font)
+{
+ return 0;
+}
+
+FontPlatformData* FontCache::getLastResortFallbackFont(const FontDescription& font)
+{
+ static AtomicString str("sans-serif");
+ return getCachedFontPlatformData(font, str);
+}
+
+static char* AtomicStringToUTF8String(const AtomicString& utf16)
+{
+ SkASSERT(sizeof(uint16_t) == sizeof(utf16.characters()[0]));
+ const uint16_t* uni = (uint16_t*)utf16.characters();
+
+ size_t bytes = SkUTF16_ToUTF8(uni, utf16.length(), NULL);
+ char* utf8 = (char*)sk_malloc_throw(bytes + 1);
+
+ (void)SkUTF16_ToUTF8(uni, utf16.length(), utf8);
+ utf8[bytes] = 0;
+ return utf8;
+}
+
+bool FontCache::fontExists(const FontDescription& fontDescription, const AtomicString& family)
+{
+ ASSERT(0); // FIXME HACK unimplemented
+ return false;
+}
+
+FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& family)
+{
+ char* storage = 0;
+ const char* name = 0;
+
+ if (family.length() == 0) {
+ static const struct {
+ FontDescription::GenericFamilyType mType;
+ const char* mName;
+ } gNames[] = {
+ { FontDescription::SerifFamily, "serif" },
+ { FontDescription::SansSerifFamily, "sans-serif" },
+ { FontDescription::MonospaceFamily, "monospace" },
+ { FontDescription::CursiveFamily, "cursive" },
+ { FontDescription::FantasyFamily, "fantasy" }
+ };
+
+ FontDescription::GenericFamilyType type = fontDescription.genericFamily();
+ for (unsigned i = 0; i < SK_ARRAY_COUNT(gNames); i++)
+ {
+ if (type == gNames[i].mType)
+ {
+ name = gNames[i].mName;
+ break;
+ }
+ }
+ // if we fall out of the loop, its ok for name to still be 0
+ }
+ else { // convert the name to utf8
+ storage = AtomicStringToUTF8String(family);
+ name = storage;
+ }
+
+ int style = SkTypeface::kNormal;
+ if (fontDescription.weight() >= cBoldWeight)
+ style |= SkTypeface::kBold;
+ if (fontDescription.italic())
+ style |= SkTypeface::kItalic;
+
+ SkTypeface* tf = SkTypeface::Create(name, (SkTypeface::Style)style);
+
+ FontPlatformData* result = new FontPlatformData(tf,
+ fontDescription.computedSize(),
+ (style & SkTypeface::kBold) && !tf->isBold(),
+ (style & SkTypeface::kItalic) && !tf->isItalic());
+ tf->unref();
+ sk_free(storage);
+ return result;
+}
+
+}
+
diff --git a/WebCore/platform/graphics/android/FontCustomPlatformData.cpp b/WebCore/platform/graphics/android/FontCustomPlatformData.cpp
new file mode 100644
index 0000000..eea5e36
--- /dev/null
+++ b/WebCore/platform/graphics/android/FontCustomPlatformData.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "config.h"
+#include "FontCustomPlatformData.h"
+
+#include "SkTypeface.h"
+#include "SkStream.h"
+#include "SharedBuffer.h"
+#include "FontPlatformData.h"
+
+namespace WebCore {
+
+FontCustomPlatformData::FontCustomPlatformData(SkTypeface* face)
+{
+ face->safeRef();
+ m_typeface = face;
+}
+
+FontCustomPlatformData::~FontCustomPlatformData()
+{
+ m_typeface->safeUnref();
+ // the unref is enough to release the font data...
+}
+
+FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic)
+{
+ // turn bold/italic into fakeBold/fakeItalic
+ if (m_typeface != NULL) {
+ if (m_typeface->isBold() == bold)
+ bold = false;
+ if (m_typeface->isItalic() == italic)
+ italic = false;
+ }
+ return FontPlatformData(m_typeface, size, bold, italic);
+}
+
+FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
+{
+ // pass true until we know how we can share the data, and not have to
+ // make a copy of it.
+ SkStream* stream = new SkMemoryStream(buffer->data(), buffer->size(), true);
+ SkTypeface* face = SkTypeface::CreateFromStream(stream);
+ if (NULL == face) {
+ SkDebugf("--------- SkTypeface::CreateFromBuffer failed %d\n",
+ buffer->size());
+ return NULL;
+ }
+
+ SkAutoUnref aur(face);
+
+ return new FontCustomPlatformData(face);
+}
+
+}
diff --git a/WebCore/platform/graphics/android/FontCustomPlatformData.h b/WebCore/platform/graphics/android/FontCustomPlatformData.h
new file mode 100644
index 0000000..f072b6f
--- /dev/null
+++ b/WebCore/platform/graphics/android/FontCustomPlatformData.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FontCustomPlatformData_h_
+#define FontCustomPlatformData_h_
+
+#include <wtf/Noncopyable.h>
+
+class SkTypeface;
+
+namespace WebCore {
+
+ class SharedBuffer;
+ class FontPlatformData;
+
+ class FontCustomPlatformData : Noncopyable {
+ public:
+ FontCustomPlatformData(SkTypeface* face);
+ ~FontCustomPlatformData();
+
+ SkTypeface* typeface() const { return m_typeface; }
+
+ FontPlatformData fontPlatformData(int size, bool bold, bool italic);
+
+ private:
+ SkTypeface* m_typeface;
+ };
+
+ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer);
+
+} // namespace WebCore
+
+#endif // FontCustomPlatformData_h_
+
diff --git a/WebCore/platform/graphics/android/FontDataAndroid.cpp b/WebCore/platform/graphics/android/FontDataAndroid.cpp
new file mode 100644
index 0000000..a90f536
--- /dev/null
+++ b/WebCore/platform/graphics/android/FontDataAndroid.cpp
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2006 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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.
+ */
+
+#include "config.h"
+#include "Font.h"
+#include "FontCache.h"
+#include "SimpleFontData.h"
+#include "FloatRect.h"
+#include "FontDescription.h"
+
+#include "SkPaint.h"
+#include "SkTypeface.h"
+#include "SkTime.h"
+
+namespace WebCore {
+
+void SimpleFontData::platformInit()
+{
+ SkPaint paint;
+ SkPaint::FontMetrics metrics;
+
+ m_font.setupPaint(&paint);
+ (void)paint.getFontMetrics(&metrics);
+
+ // use ceil instead of round to favor descent, given a lot of accidental
+ // clipping of descenders (e.g. 14pt 'g') in textedit fields
+ int d = SkScalarCeil(metrics.fDescent);
+ int s = SkScalarRound(metrics.fDescent - metrics.fAscent);
+ int a = s - d;
+
+ m_ascent = a;
+ m_descent = d;
+ m_xHeight = SkScalarToFloat(-metrics.fAscent) * 0.56f; // hack I stole from the window's port
+ m_lineSpacing = a + d;
+ m_lineGap = SkScalarRound(metrics.fLeading);
+}
+
+void SimpleFontData::platformDestroy()
+{
+ delete m_smallCapsFontData;
+}
+
+SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const
+{
+ if (!m_smallCapsFontData) {
+ m_smallCapsFontData = new SimpleFontData(FontPlatformData(m_font, fontDescription.computedSize() * 0.7f));
+ }
+ return m_smallCapsFontData;
+}
+
+#define kMaxBufferCount 64
+
+bool SimpleFontData::containsCharacters(const UChar* characters, int length) const
+{
+ SkPaint paint;
+ uint16_t glyphs[kMaxBufferCount];
+
+ m_font.setupPaint(&paint);
+ paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
+
+ while (length > 0) {
+ int n = SkMin32(length, SK_ARRAY_COUNT(glyphs));
+
+ int count = paint.textToGlyphs(characters, n << 1, glyphs);
+ for (int i = 0; i < count; i++) {
+ if (0 == glyphs[i]) {
+ return false; // missing glyph
+ }
+ }
+
+ characters += n;
+ length -= n;
+ }
+ return true;
+}
+
+void SimpleFontData::determinePitch()
+{
+ m_treatAsFixedPitch = false;
+}
+
+float SimpleFontData::platformWidthForGlyph(Glyph glyph) const
+{
+ SkASSERT(sizeof(glyph) == 2); // compile-time assert
+
+ SkPaint paint;
+
+ m_font.setupPaint(&paint);
+
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ SkScalar width = paint.measureText(&glyph, 2);
+
+ return SkScalarToFloat(width);
+}
+
+}
diff --git a/WebCore/platform/graphics/android/FontPlatformData.h b/WebCore/platform/graphics/android/FontPlatformData.h
new file mode 100644
index 0000000..d6933d9
--- /dev/null
+++ b/WebCore/platform/graphics/android/FontPlatformData.h
@@ -0,0 +1,104 @@
+/*
+ * This file is part of the internal font implementation. It should not be included by anyone other than
+ * FontMac.cpp, FontWin.cpp and Font.cpp.
+ *
+ * Copyright (C) 2006 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef FontPlatformData_H
+#define FontPlatformData_H
+
+class SkPaint;
+class SkTypeface;
+
+namespace WebCore {
+
+class FontPlatformData
+{
+public:
+ static FontPlatformData Deleted()
+ {
+ return FontPlatformData(NULL, -1, false, false);
+ }
+
+ FontPlatformData();
+ FontPlatformData(const FontPlatformData&);
+ FontPlatformData(SkTypeface*, float textSize, bool fakeBold, bool fakeItalic);
+ FontPlatformData(const FontPlatformData& src, float textSize);
+ ~FontPlatformData();
+
+ FontPlatformData& operator=(const FontPlatformData&);
+ bool operator==(const FontPlatformData& a) const;
+
+ void setupPaint(SkPaint*) const;
+ unsigned hash() const;
+
+private:
+ SkTypeface* mTypeface;
+ float mTextSize;
+ bool mFakeBold;
+ bool mFakeItalic;
+};
+
+#if 0 // windows port
+class FontPlatformData
+{
+public:
+ class Deleted {};
+
+ // Used for deleted values in the font cache's hash tables.
+ FontPlatformData(Deleted)
+ : m_font((HFONT)-1), m_fontFace(0), m_scaledFont(0), m_size(0)
+ {}
+
+ FontPlatformData()
+ : m_font(0), m_fontFace(0), m_scaledFont(0), m_size(0)
+ {}
+
+ FontPlatformData(HFONT, int size);
+ ~FontPlatformData();
+
+ HFONT hfont() const { return m_font; }
+ cairo_font_face_t* fontFace() const { return m_fontFace; }
+ cairo_scaled_font_t* scaledFont() const { return m_scaledFont; }
+
+ int size() const { return m_size; }
+
+ unsigned hash() const
+ {
+ return StringImpl::computeHash((UChar*)(&m_font), sizeof(HFONT) / sizeof(UChar));
+ }
+
+ bool operator==(const FontPlatformData& other) const
+ {
+ return m_font == other.m_font && m_fontFace == other.m_fontFace &&
+ m_scaledFont == other.m_scaledFont && m_size == other.m_size;
+ }
+
+private:
+ HFONT m_font;
+ cairo_font_face_t* m_fontFace;
+ cairo_scaled_font_t* m_scaledFont;
+ int m_size;
+};
+#endif
+
+}
+
+#endif
diff --git a/WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp b/WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp
new file mode 100644
index 0000000..4b4186a
--- /dev/null
+++ b/WebCore/platform/graphics/android/FontPlatformDataAndroid.cpp
@@ -0,0 +1,151 @@
+/*
+ * This file is part of the internal font implementation. It should not be included by anyone other than
+ * FontMac.cpp, FontWin.cpp and Font.cpp.
+ *
+ * Copyright (C) 2006 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
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+#include "FontPlatformData.h"
+
+#include "SkPaint.h"
+#include "SkTypeface.h"
+
+//#define TRACE_FONTPLATFORMDATA_LIFE
+//#define COUNT_FONTPLATFORMDATA_LIFE
+
+#ifdef COUNT_FONTPLATFORMDATA_LIFE
+static int gCount;
+static int gMaxCount;
+
+static void inc_count()
+{
+ if (++gCount > gMaxCount)
+ {
+ gMaxCount = gCount;
+ SkDebugf("---------- FontPlatformData %d\n", gMaxCount);
+ }
+}
+
+static void dec_count() { --gCount; }
+#else
+ #define inc_count()
+ #define dec_count()
+#endif
+
+#ifdef TRACE_FONTPLATFORMDATA_LIFE
+ #define trace(num) SkDebugf("FontPlatformData%d %p %g %d %d\n", num, mTypeface, mTextSize, mFakeBold, mFakeItalic)
+#else
+ #define trace(num)
+#endif
+
+namespace WebCore {
+
+FontPlatformData::FontPlatformData()
+ : mTypeface(NULL), mTextSize(0), mFakeBold(false), mFakeItalic(false)
+{
+ inc_count();
+ trace(1);
+}
+
+FontPlatformData::FontPlatformData(const FontPlatformData& src)
+{
+ src.mTypeface->safeRef();
+ mTypeface = src.mTypeface;
+
+ mTextSize = src.mTextSize;
+ mFakeBold = src.mFakeBold;
+ mFakeItalic = src.mFakeItalic;
+
+ inc_count();
+ trace(2);
+}
+
+FontPlatformData::FontPlatformData(SkTypeface* tf, float textSize, bool fakeBold, bool fakeItalic)
+ : mTypeface(tf), mTextSize(textSize), mFakeBold(fakeBold), mFakeItalic(fakeItalic)
+{
+ mTypeface->safeRef();
+
+ inc_count();
+ trace(3);
+}
+
+FontPlatformData::FontPlatformData(const FontPlatformData& src, float textSize)
+ : mTypeface(src.mTypeface), mTextSize(textSize), mFakeBold(src.mFakeBold), mFakeItalic(src.mFakeItalic)
+{
+ mTypeface->safeRef();
+
+ inc_count();
+ trace(4);
+}
+
+FontPlatformData::~FontPlatformData()
+{
+ dec_count();
+#ifdef TRACE_FONTPLATFORMDATA_LIFE
+ SkDebugf("----------- ~FontPlatformData\n");
+#endif
+
+ mTypeface->safeUnref();
+}
+
+FontPlatformData& FontPlatformData::operator=(const FontPlatformData& src)
+{
+ SkRefCnt_SafeAssign(mTypeface, src.mTypeface);
+
+ mTextSize = src.mTextSize;
+ mFakeBold = src.mFakeBold;
+ mFakeItalic = src.mFakeItalic;
+
+ return *this;
+}
+
+void FontPlatformData::setupPaint(SkPaint* paint) const
+{
+ float ts = mTextSize;
+ if (!(ts > 0))
+ ts = 12;
+
+ paint->setAntiAlias(true);
+ paint->setSubpixelText(true);
+ paint->setTextSize(SkFloatToScalar(ts));
+ paint->setTypeface(mTypeface);
+ paint->setFakeBoldText(mFakeBold);
+ paint->setTextSkewX(mFakeItalic ? -SK_Scalar1/4 : 0);
+ paint->setTextEncoding(SkPaint::kUTF16_TextEncoding);
+}
+
+bool FontPlatformData::operator==(const FontPlatformData& a) const
+{
+ return SkTypeface::Equal(mTypeface, a.mTypeface) &&
+ mTextSize == a.mTextSize &&
+ mFakeBold == a.mFakeBold &&
+ mFakeItalic == a.mFakeItalic;
+}
+
+unsigned FontPlatformData::hash() const
+{
+ unsigned h = SkTypeface::UniqueID(mTypeface);
+ h ^= 0x01010101 * (((int)mFakeBold << 1) | (int)mFakeItalic);
+ h ^= *(uint32_t*)&mTextSize;
+ return h;
+}
+
+}
+
diff --git a/WebCore/platform/graphics/win/GlyphPageTreeNodeCairoWin.cpp b/WebCore/platform/graphics/android/GlyphMapAndroid.cpp
index b679ced..9b77348 100644
--- a/WebCore/platform/graphics/win/GlyphPageTreeNodeCairoWin.cpp
+++ b/WebCore/platform/graphics/android/GlyphMapAndroid.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 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
@@ -28,45 +28,42 @@
#include "config.h"
#include "GlyphPageTreeNode.h"
-
#include "SimpleFontData.h"
+#include "SkTemplates.h"
+#include "SkPaint.h"
+#include "SkUtils.h"
+
namespace WebCore {
+#define NO_BREAK_SPACE_UNICHAR 0xA0
+
bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData)
{
- // bufferLength will be greater than the requested number of glyphs if the buffer contains surrogate pairs.
- // We won't support this for now.
- if (bufferLength > length)
+ if (SkUTF16_IsHighSurrogate(buffer[bufferLength-1])) {
+ SkDebugf("%s last char is high-surrogate", __FUNCTION__);
+ return false;
+ }
+
+ SkPaint paint;
+ fontData->platformData().setupPaint(&paint);
+ paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
+
+ SkAutoSTMalloc <GlyphPage::size, uint16_t> glyphStorage(length);
+ uint16_t* glyphs = glyphStorage.get();
+ unsigned count = paint.textToGlyphs(buffer, bufferLength << 1, glyphs);
+ if (count != length) {
+ SkDebugf("%s count != length\n", __FUNCTION__);
return false;
-
- bool haveGlyphs = false;
-
- HDC dc = GetDC((HWND)0);
- SaveDC(dc);
- SelectObject(dc, fontData->platformData().hfont());
-
- TEXTMETRIC tm;
- GetTextMetrics(dc, &tm);
-
- WORD localGlyphBuffer[GlyphPage::size * 2];
- DWORD result = GetGlyphIndices(dc, buffer, bufferLength, localGlyphBuffer, 0);
- bool success = result != GDI_ERROR && static_cast<unsigned>(result) == bufferLength;
- if (success) {
- for (unsigned i = 0; i < length; i++) {
- Glyph glyph = localGlyphBuffer[i];
- if (!glyph)
- setGlyphDataForIndex(offset + i, 0, 0);
- else {
- setGlyphDataForIndex(offset + i, glyph, fontData);
- haveGlyphs = true;
- }
- }
}
- RestoreDC(dc, -1);
- ReleaseDC(0, dc);
- return haveGlyphs;
+ unsigned allGlyphs = 0; // track if any of the glyphIDs are non-zero
+ for (unsigned i = 0; i < length; i++) {
+ setGlyphDataForIndex(offset + i, glyphs[i], fontData);
+ allGlyphs |= glyphs[i];
+ }
+ return allGlyphs != 0;
}
}
+
diff --git a/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp b/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp
new file mode 100644
index 0000000..23ac51d
--- /dev/null
+++ b/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp
@@ -0,0 +1,1114 @@
+/*
+ *
+ * Copyright 2006, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "config.h"
+#include "GraphicsContext.h"
+#include "NotImplemented.h"
+#include "Path.h"
+
+#include "SkBlurDrawLooper.h"
+#include "SkCanvas.h"
+#include "SkColorPriv.h"
+#include "SkDashPathEffect.h"
+#include "SkDevice.h"
+#include "SkPaint.h"
+#include "SkPorterDuff.h"
+#include "WebCoreViewBridge.h"
+#include "PlatformGraphicsContext.h"
+#include "AffineTransform.h"
+
+#include "android_graphics.h"
+#include "SkGradientShader.h"
+#include "SkBitmapRef.h"
+#include "SkString.h"
+
+using namespace std;
+
+#define GC2Canvas(ctx) (ctx)->m_data->mPgc->mCanvas
+
+namespace WebCore {
+
+static int RoundToInt(float x)
+{
+ return (int)roundf(x);
+}
+
+/* TODO / questions
+
+ mAlpha: how does this interact with the alpha in Color? multiply them together?
+ mPorterDuffMode: do I always respect this? If so, then
+ the rgb() & 0xFF000000 check will abort drawing too often
+ Is Color premultiplied or not? If it is, then I can't blindly pass it to paint.setColor()
+*/
+
+class GraphicsContextPlatformPrivate {
+public:
+ GraphicsContext* mCG; // back-ptr to our parent
+ PlatformGraphicsContext* mPgc;
+
+ struct State {
+ float mMiterLimit;
+ float mAlpha;
+ SkDrawLooper* mLooper;
+ SkPaint::Cap mLineCap;
+ SkPaint::Join mLineJoin;
+ SkPorterDuff::Mode mPorterDuffMode;
+ int mDashRatio; //ratio of the length of a dash to its width
+
+ State()
+ {
+ mMiterLimit = 4;
+ mAlpha = 1;
+ mLooper = NULL;
+ mLineCap = SkPaint::kDefault_Cap;
+ mLineJoin = SkPaint::kDefault_Join;
+ mPorterDuffMode = SkPorterDuff::kSrcOver_Mode;
+ mDashRatio = 3;
+ }
+
+ State(const State& other)
+ {
+ other.mLooper->safeRef();
+ memcpy(this, &other, sizeof(State));
+ }
+
+ ~State()
+ {
+ mLooper->safeUnref();
+ }
+
+ SkDrawLooper* setDrawLooper(SkDrawLooper* dl)
+ {
+ SkRefCnt_SafeAssign(mLooper, dl);
+ return dl;
+ }
+
+ SkColor applyAlpha(SkColor c) const
+ {
+ int s = RoundToInt(mAlpha * 256);
+ if (s >= 256)
+ return c;
+ if (s < 0)
+ return 0;
+
+ int a = SkAlphaMul(SkColorGetA(c), s);
+ return (c & 0x00FFFFFF) | (a << 24);
+ }
+ };
+
+ SkDeque mStateStack;
+ State* mState;
+
+ GraphicsContextPlatformPrivate(GraphicsContext* cg, PlatformGraphicsContext* pgc)
+ : mCG(cg)
+ , mPgc(pgc), mStateStack(sizeof(State))
+
+ {
+ State* state = (State*)mStateStack.push_back();
+ new (state) State();
+ mState = state;
+ }
+
+ ~GraphicsContextPlatformPrivate()
+ {
+ if (mPgc && mPgc->deleteUs())
+ delete mPgc;
+
+ // we force restores so we don't leak any subobjects owned by our
+ // stack of State records.
+ while (mStateStack.count() > 0)
+ this->restore();
+ }
+
+ void save()
+ {
+ State* newState = (State*)mStateStack.push_back();
+ new (newState) State(*mState);
+ mState = newState;
+ }
+
+ void restore()
+ {
+ mState->~State();
+ mStateStack.pop_back();
+ mState = (State*)mStateStack.back();
+ }
+
+ void setup_paint_common(SkPaint* paint) const
+ {
+#ifdef SK_DEBUGx
+ {
+ SkPaint defaultPaint;
+
+ SkASSERT(*paint == defaultPaint);
+ }
+#endif
+
+ paint->setAntiAlias(true);
+ paint->setDither(true);
+ paint->setPorterDuffXfermode(mState->mPorterDuffMode);
+ paint->setLooper(mState->mLooper);
+ }
+
+ void setup_paint_fill(SkPaint* paint) const
+ {
+ this->setup_paint_common(paint);
+
+ paint->setColor(mState->applyAlpha(mCG->fillColor().rgb()));
+ }
+
+ /* sets up the paint for stroking. Returns true if the style is really
+ just a dash of squares (the size of the paint's stroke-width.
+ */
+ bool setup_paint_stroke(SkPaint* paint, SkRect* rect) {
+ this->setup_paint_common(paint);
+
+ float width = mCG->strokeThickness();
+
+ //this allows dashing and dotting to work properly for hairline strokes
+ if (0 == width) {
+ width = 1;
+ }
+
+ paint->setColor(mState->applyAlpha(mCG->strokeColor().rgb()));
+ paint->setStyle(SkPaint::kStroke_Style);
+ paint->setStrokeWidth(SkFloatToScalar(width));
+ paint->setStrokeCap(mState->mLineCap);
+ paint->setStrokeJoin(mState->mLineJoin);
+ paint->setStrokeMiter(SkFloatToScalar(mState->mMiterLimit));
+
+ if (rect != NULL && (RoundToInt(width) & 1)) {
+ rect->inset(-SK_ScalarHalf, -SK_ScalarHalf);
+ }
+
+ switch (mCG->strokeStyle()) {
+ case NoStroke:
+ case SolidStroke:
+ width = 0;
+ break;
+ case DashedStroke:
+ width = mState->mDashRatio * width;
+ break;
+ /* no break */
+ case DottedStroke:
+ break;
+ }
+
+ if (width > 0) {
+ SkScalar intervals[] = { width, width };
+ SkPathEffect* pe = new SkDashPathEffect(intervals, 2, 0);
+ paint->setPathEffect(pe)->unref();
+ // return true if we're basically a dotted dash of squares
+ return RoundToInt(width) == RoundToInt(paint->getStrokeWidth());
+ }
+ return false;
+ }
+
+private:
+ // not supported yet
+ State& operator=(const State&);
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////
+
+GraphicsContext* GraphicsContext::createOffscreenContext(int width, int height)
+{
+ PlatformGraphicsContext* pgc = new PlatformGraphicsContext();
+
+ SkBitmap bitmap;
+
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
+ bitmap.allocPixels();
+ bitmap.eraseColor(0);
+ pgc->mCanvas->setBitmapDevice(bitmap);
+
+ GraphicsContext* ctx = new GraphicsContext(pgc);
+//printf("-------- create offscreen <canvas> %p\n", ctx);
+ return ctx;
+}
+
+void GraphicsContext::drawOffscreenContext(GraphicsContext* ctx, const FloatRect* srcRect, const FloatRect& dstRect)
+{
+ const SkBitmap& bm = GC2Canvas(ctx)->getDevice()->accessBitmap(false);
+ SkIRect src;
+ SkRect dst;
+ SkPaint paint;
+
+ paint.setFilterBitmap(true);
+
+ GC2Canvas(this)->drawBitmapRect(bm,
+ srcRect ? android_setrect(&src, *srcRect) : NULL,
+ *android_setrect(&dst, dstRect),
+ &paint);
+}
+
+FloatRect GraphicsContext::getClipLocalBounds() const
+{
+ SkRect r;
+
+ if (!GC2Canvas(this)->getClipBounds(&r))
+ r.setEmpty();
+
+ return FloatRect(SkScalarToFloat(r.fLeft), SkScalarToFloat(r.fTop),
+ SkScalarToFloat(r.width()), SkScalarToFloat(r.height()));
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////
+
+GraphicsContext::GraphicsContext(PlatformGraphicsContext *gc)
+ : m_common(createGraphicsContextPrivate())
+ , m_data(new GraphicsContextPlatformPrivate(this, gc))
+{
+ setPaintingDisabled(NULL == gc || NULL == gc->mCanvas);
+}
+
+GraphicsContext::~GraphicsContext()
+{
+ delete m_data;
+ this->destroyGraphicsContextPrivate(m_common);
+}
+
+void GraphicsContext::savePlatformState()
+{
+ // save our private State
+ m_data->save();
+ // save our native canvas
+ GC2Canvas(this)->save();
+}
+
+void GraphicsContext::restorePlatformState()
+{
+ // restore our native canvas
+ GC2Canvas(this)->restore();
+ // restore our private State
+ m_data->restore();
+}
+
+// Draws a filled rectangle with a stroked border.
+void GraphicsContext::drawRect(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ SkPaint paint;
+ SkRect r;
+
+ android_setrect(&r, rect);
+
+ if (fillColor().alpha()) {
+ m_data->setup_paint_fill(&paint);
+ GC2Canvas(this)->drawRect(r, paint);
+ }
+
+ if (strokeStyle() != NoStroke && strokeColor().alpha()) {
+ paint.reset();
+ m_data->setup_paint_stroke(&paint, &r);
+ GC2Canvas(this)->drawRect(r, paint);
+ }
+}
+
+// This is only used to draw borders.
+void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
+{
+ if (paintingDisabled())
+ return;
+
+ StrokeStyle style = strokeStyle();
+ if (style == NoStroke)
+ return;
+
+ SkPaint paint;
+ SkCanvas* canvas = GC2Canvas(this);
+ const int idx = SkAbs32(point2.x() - point1.x());
+ const int idy = SkAbs32(point2.y() - point1.y());
+
+ // special-case horizontal and vertical lines that are really just dots
+ if (m_data->setup_paint_stroke(&paint, NULL) && (0 == idx || 0 == idy)) {
+ const SkScalar diameter = paint.getStrokeWidth();
+ const SkScalar radius = SkScalarHalf(diameter);
+ SkScalar x = SkIntToScalar(SkMin32(point1.x(), point2.x()));
+ SkScalar y = SkIntToScalar(SkMin32(point1.y(), point2.y()));
+ SkScalar dx, dy;
+ int count;
+ SkRect bounds;
+
+ if (0 == idy) { // horizontal
+ bounds.set(x, y - radius, x + SkIntToScalar(idx), y + radius);
+ x += radius;
+ dx = diameter * 2;
+ dy = 0;
+ count = idx;
+ } else { // vertical
+ bounds.set(x - radius, y, x + radius, y + SkIntToScalar(idy));
+ y += radius;
+ dx = 0;
+ dy = diameter * 2;
+ count = idy;
+ }
+
+ // the actual count is the number of ONs we hit alternating
+ // ON(diameter), OFF(diameter), ...
+ {
+ SkScalar width = SkScalarDiv(SkIntToScalar(count), diameter);
+ // now computer the number of cells (ON and OFF)
+ count = SkScalarRound(width);
+ // now compute the number of ONs
+ count = (count + 1) >> 1;
+ }
+
+ SkAutoMalloc storage(count * sizeof(SkPoint));
+ SkPoint* verts = (SkPoint*)storage.get();
+ // now build the array of vertices to past to drawPoints
+ for (int i = 0; i < count; i++) {
+ verts[i].set(x, y);
+ x += dx;
+ y += dy;
+ }
+
+ paint.setStyle(SkPaint::kFill_Style);
+ paint.setPathEffect(NULL);
+
+ // clipping to bounds is not required for correctness, but it does
+ // allow us to reject the entire array of points if we are completely
+ // offscreen. This is common in a webpage for android, where most of
+ // the content is clipped out. If drawPoints took an (optional) bounds
+ // parameter, that might even be better, as we would *just* use it for
+ // culling, and not both wacking the canvas' save/restore stack.
+ canvas->save(SkCanvas::kClip_SaveFlag);
+ canvas->clipRect(bounds);
+ canvas->drawPoints(SkCanvas::kPoints_PointMode, count, verts, paint);
+ canvas->restore();
+ } else {
+ SkPoint pts[2];
+ android_setpt(&pts[0], point1);
+ android_setpt(&pts[1], point2);
+ canvas->drawLine(pts[0].fX, pts[0].fY, pts[1].fX, pts[1].fY, paint);
+ }
+}
+
+static void setrect_for_underline(SkRect* r, GraphicsContext* context, const IntPoint& point, int yOffset, int width)
+{
+ float lineThickness = context->strokeThickness();
+// if (lineThickness < 1) // do we really need/want this?
+// lineThickness = 1;
+
+ yOffset += 1; // we add 1 to have underlines appear below the text
+
+ r->fLeft = SkIntToScalar(point.x());
+ r->fTop = SkIntToScalar(point.y() + yOffset);
+ r->fRight = r->fLeft + SkIntToScalar(width);
+ r->fBottom = r->fTop + SkFloatToScalar(lineThickness);
+}
+
+void GraphicsContext::drawLineForText(IntPoint const& pt, int width, bool)
+{
+ if (paintingDisabled())
+ return;
+
+ SkRect r;
+ setrect_for_underline(&r, this, pt, 0, width);
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setColor(this->strokeColor().rgb());
+
+ GC2Canvas(this)->drawRect(r, paint);
+}
+
+void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& pt, int width, bool grammar)
+{
+ if (paintingDisabled())
+ return;
+
+ SkRect r;
+ setrect_for_underline(&r, this, pt, 0, width);
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setColor(SK_ColorRED); // is this specified somewhere?
+
+ GC2Canvas(this)->drawRect(r, paint);
+}
+
+// This method is only used to draw the little circles used in lists.
+void GraphicsContext::drawEllipse(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ SkPaint paint;
+ SkRect oval;
+
+ android_setrect(&oval, rect);
+
+ if (fillColor().rgb() & 0xFF000000) {
+ m_data->setup_paint_fill(&paint);
+ GC2Canvas(this)->drawOval(oval, paint);
+ }
+ if (strokeStyle() != NoStroke) {
+ paint.reset();
+ m_data->setup_paint_stroke(&paint, &oval);
+ GC2Canvas(this)->drawOval(oval, paint);
+ }
+}
+
+static inline int fast_mod(int value, int max)
+{
+ int sign = SkExtractSign(value);
+
+ value = SkApplySign(value, sign);
+ if (value >= max) {
+ value %= max;
+ }
+ return SkApplySign(value, sign);
+}
+
+void GraphicsContext::strokeArc(const IntRect& r, int startAngle, int angleSpan)
+{
+ if (paintingDisabled())
+ return;
+
+ SkPath path;
+ SkPaint paint;
+ SkRect oval;
+
+ android_setrect(&oval, r);
+
+ if (strokeStyle() == NoStroke) {
+ m_data->setup_paint_fill(&paint); // we want the fill color
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(SkFloatToScalar(this->strokeThickness()));
+ }
+ else {
+ m_data->setup_paint_stroke(&paint, NULL);
+ }
+
+ // we do this before converting to scalar, so we don't overflow SkFixed
+ startAngle = fast_mod(startAngle, 360);
+ angleSpan = fast_mod(angleSpan, 360);
+
+ path.addArc(oval, SkIntToScalar(-startAngle), SkIntToScalar(-angleSpan));
+ GC2Canvas(this)->drawPath(path, paint);
+}
+
+void GraphicsContext::drawConvexPolygon(size_t numPoints, const FloatPoint* points, bool shouldAntialias)
+{
+ if (paintingDisabled())
+ return;
+
+ if (numPoints <= 1)
+ return;
+
+ SkPaint paint;
+ SkPath path;
+
+ path.incReserve(numPoints);
+ path.moveTo(SkFloatToScalar(points[0].x()), SkFloatToScalar(points[0].y()));
+ for (size_t i = 1; i < numPoints; i++)
+ path.lineTo(SkFloatToScalar(points[i].x()), SkFloatToScalar(points[i].y()));
+
+ if (fillColor().rgb() & 0xFF000000) {
+ m_data->setup_paint_fill(&paint);
+ GC2Canvas(this)->drawPath(path, paint);
+ }
+
+ if (strokeStyle() != NoStroke) {
+ paint.reset();
+ m_data->setup_paint_stroke(&paint, NULL);
+ GC2Canvas(this)->drawPath(path, paint);
+ }
+}
+
+#ifdef ANDROID_CANVAS_IMPL
+
+static void check_set_shader(SkPaint* paint, SkShader* s0, SkShader* s1)
+{
+ if (s0) {
+ paint->setShader(s0);
+ }
+ else if (s1) {
+ paint->setShader(s1);
+ }
+}
+
+void GraphicsContext::fillPath(const Path& webCorePath, PlatformGradient* grad, PlatformPattern* pat)
+{
+ if (paintingDisabled())
+ return;
+
+ SkPaint paint;
+
+ m_data->setup_paint_fill(&paint);
+ check_set_shader(&paint, grad, pat);
+
+ const SkPath& path = *webCorePath.platformPath();
+
+#if 0
+ SkDebugf("---- fillPath\n");
+ SkPath::Iter iter(path, false);
+ SkPoint pts[4];
+ for (;;) {
+ SkString str;
+ const SkPoint* p = &pts[1];
+ int n = 0;
+ const char* name = "";
+ switch (iter.next(pts)) {
+ case SkPath::kMove_Verb:
+ name = " M";
+ p = &pts[0];
+ n = 1;
+ break;
+ case SkPath::kLine_Verb:
+ name = " L";
+ n = 1;
+ break;
+ case SkPath::kQuad_Verb:
+ name = " Q";
+ n = 2;
+ break;
+ case SkPath::kCubic_Verb:
+ name = " C";
+ n = 3;
+ break;
+ case SkPath::kClose_Verb:
+ name = " X";
+ n = 0;
+ break;
+ case SkPath::kDone_Verb:
+ goto DONE;
+ }
+ str.append(name);
+ for (int i = 0; i < n; i++) {
+ str.append(" ");
+ str.appendScalar(p[i].fX);
+ str.append(" ");
+ str.appendScalar(p[i].fY);
+ }
+ SkDebugf("\"%s\"\n", str.c_str());
+ }
+DONE:
+#endif
+
+ GC2Canvas(this)->drawPath(path, paint);
+}
+
+void GraphicsContext::strokePath(const Path& webCorePath, PlatformGradient* grad, PlatformPattern* pat)
+{
+ if (paintingDisabled())
+ return;
+
+ SkPaint paint;
+
+ m_data->setup_paint_stroke(&paint, NULL);
+ check_set_shader(&paint, grad, pat);
+
+ GC2Canvas(this)->drawPath(*webCorePath.platformPath(), paint);
+}
+
+void GraphicsContext::fillRect(const FloatRect& rect, PlatformGradient* grad, PlatformPattern* pat)
+{
+ if (paintingDisabled())
+ return;
+
+ SkRect r;
+ SkPaint paint;
+
+ m_data->setup_paint_fill(&paint);
+ check_set_shader(&paint, grad, pat);
+
+ GC2Canvas(this)->drawRect(*android_setrect(&r, rect), paint);
+}
+
+void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight,
+ const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color)
+{
+ if (paintingDisabled())
+ return;
+
+ SkPaint paint;
+ SkPath path;
+ SkScalar radii[8];
+ SkRect r;
+
+ radii[0] = SkIntToScalar(topLeft.width());
+ radii[1] = SkIntToScalar(topLeft.height());
+ radii[2] = SkIntToScalar(topRight.width());
+ radii[3] = SkIntToScalar(topRight.height());
+ radii[4] = SkIntToScalar(bottomRight.width());
+ radii[5] = SkIntToScalar(bottomRight.height());
+ radii[6] = SkIntToScalar(bottomLeft.width());
+ radii[7] = SkIntToScalar(bottomLeft.height());
+ path.addRoundRect(*android_setrect(&r, rect), radii);
+
+ m_data->setup_paint_fill(&paint);
+ GC2Canvas(this)->drawPath(path, paint);
+}
+
+void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth, PlatformGradient* grad, PlatformPattern* pat)
+{
+ if (paintingDisabled())
+ return;
+
+ SkRect r;
+ SkPaint paint;
+
+ m_data->setup_paint_stroke(&paint, NULL);
+ paint.setStrokeWidth(SkFloatToScalar(lineWidth));
+ check_set_shader(&paint, grad, pat);
+
+ GC2Canvas(this)->drawRect(*android_setrect(&r, rect), paint);
+}
+
+static U8CPU F2B(float x)
+{
+ return (int)(x * 255);
+}
+
+static SkColor make_color(float a, float r, float g, float b)
+{
+ return SkColorSetARGB(F2B(a), F2B(r), F2B(g), F2B(b));
+}
+
+PlatformGradient* GraphicsContext::newPlatformLinearGradient(const FloatPoint& p0, const FloatPoint& p1,
+ const float stopData[5], int count)
+{
+ SkPoint pts[2];
+
+ android_setpt(&pts[0], p0);
+ android_setpt(&pts[1], p1);
+
+ SkAutoMalloc storage(count * (sizeof(SkColor) + sizeof(SkScalar)));
+ SkColor* colors = (SkColor*)storage.get();
+ SkScalar* pos = (SkScalar*)(colors + count);
+
+ for (int i = 0; i < count; i++)
+ {
+ pos[i] = SkFloatToScalar(stopData[0]);
+ colors[i] = make_color(stopData[4], stopData[1], stopData[2], stopData[3]);
+ stopData += 5;
+ }
+
+ return SkGradientShader::CreateLinear(pts, colors, pos, count,
+ SkShader::kClamp_TileMode);
+}
+
+PlatformGradient* GraphicsContext::newPlatformRadialGradient(const FloatPoint& p0, float r0,
+ const FloatPoint& p1, float r1,
+ const float stopData[5], int count)
+{
+ SkPoint center;
+
+ android_setpt(&center, p1);
+
+ SkAutoMalloc storage(count * (sizeof(SkColor) + sizeof(SkScalar)));
+ SkColor* colors = (SkColor*)storage.get();
+ SkScalar* pos = (SkScalar*)(colors + count);
+
+ for (int i = 0; i < count; i++)
+ {
+ pos[i] = SkFloatToScalar(stopData[0]);
+ colors[i] = make_color(stopData[4], stopData[1], stopData[2], stopData[3]);
+ stopData += 5;
+ }
+
+ return SkGradientShader::CreateRadial(center, SkFloatToScalar(r1),
+ colors, pos, count,
+ SkShader::kClamp_TileMode);
+}
+
+void GraphicsContext::freePlatformGradient(PlatformGradient* shader)
+{
+ shader->safeUnref();
+}
+
+PlatformPattern* GraphicsContext::newPlatformPattern(Image* image,
+ Image::TileRule hRule,
+ Image::TileRule vRule)
+{
+//printf("----------- Image %p, [%d %d] %d %d\n", image, image->width(), image->height(), hRule, vRule);
+ if (NULL == image)
+ return NULL;
+
+ SkBitmapRef* bm = image->nativeImageForCurrentFrame();
+ if (NULL == bm)
+ return NULL;
+
+ return SkShader::CreateBitmapShader(bm->bitmap(),
+ android_convert_TileRule(hRule),
+ android_convert_TileRule(vRule));
+}
+
+void GraphicsContext::freePlatformPattern(PlatformPattern* shader)
+{
+ shader->safeUnref();
+}
+
+#endif
+
+#if 0
+static int getBlendedColorComponent(int c, int a)
+{
+ // We use white.
+ float alpha = (float)(a) / 255;
+ int whiteBlend = 255 - a;
+ c -= whiteBlend;
+ return (int)(c/alpha);
+}
+#endif
+
+void GraphicsContext::fillRect(const IntRect& rect, const Color& color)
+{
+ if (paintingDisabled())
+ return;
+
+ if (color.rgb() & 0xFF000000) {
+ SkPaint paint;
+ SkRect r;
+
+ android_setrect(&r, rect);
+ m_data->setup_paint_common(&paint);
+ paint.setColor(color.rgb());
+ GC2Canvas(this)->drawRect(r, paint);
+ }
+}
+
+void GraphicsContext::fillRect(const FloatRect& rect, const Color& color)
+{
+ if (paintingDisabled())
+ return;
+
+ if (color.rgb() & 0xFF000000) {
+ SkPaint paint;
+ SkRect r;
+
+ android_setrect(&r, rect);
+ m_data->setup_paint_common(&paint);
+ paint.setColor(color.rgb());
+ GC2Canvas(this)->drawRect(r, paint);
+ }
+}
+
+void GraphicsContext::clip(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ SkRect r;
+
+ GC2Canvas(this)->clipRect(*android_setrect(&r, rect));
+}
+
+void GraphicsContext::clip(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+
+// path.platformPath()->dump(false, "clip path");
+
+ GC2Canvas(this)->clipPath(*path.platformPath());
+}
+
+void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness)
+{
+ if (paintingDisabled())
+ return;
+
+//printf("-------- addInnerRoundedRectClip: [%d %d %d %d] thickness=%d\n", rect.x(), rect.y(), rect.width(), rect.height(), thickness);
+
+ SkPath path;
+ SkRect r;
+ android_setrect(&r, rect);
+ path.addOval(r, SkPath::kCW_Direction);
+ // only perform the inset if we won't invert r
+ if (2*thickness < rect.width() && 2*thickness < rect.height())
+ {
+ r.inset(SkIntToScalar(thickness) ,SkIntToScalar(thickness));
+ path.addOval(r, SkPath::kCCW_Direction);
+ }
+ GC2Canvas(this)->clipPath(path);
+}
+
+void GraphicsContext::clipOut(const IntRect& r)
+{
+ if (paintingDisabled())
+ return;
+
+ SkRect rect;
+
+ GC2Canvas(this)->clipRect(*android_setrect(&rect, r), SkRegion::kDifference_Op);
+}
+
+void GraphicsContext::clipOutEllipseInRect(const IntRect& r)
+{
+ if (paintingDisabled())
+ return;
+
+ SkRect oval;
+ SkPath path;
+
+ path.addOval(*android_setrect(&oval, r), SkPath::kCCW_Direction);
+ GC2Canvas(this)->clipPath(path, SkRegion::kDifference_Op);
+}
+
+void GraphicsContext::clipOut(const Path& p)
+{
+ if (paintingDisabled())
+ return;
+
+ GC2Canvas(this)->clipPath(*p.platformPath(), SkRegion::kDifference_Op);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+#if SVG_SUPPORT
+KRenderingDeviceContext* GraphicsContext::createRenderingDeviceContext()
+{
+ return new KRenderingDeviceContextQuartz(platformContext());
+}
+#endif
+
+void GraphicsContext::beginTransparencyLayer(float opacity)
+{
+ if (paintingDisabled())
+ return;
+
+ SkCanvas* canvas = GC2Canvas(this);
+
+ if (opacity < 1)
+ {
+ canvas->saveLayerAlpha(NULL, (int)(opacity * 255), SkCanvas::kHasAlphaLayer_SaveFlag);
+ }
+ else
+ canvas->save();
+}
+
+void GraphicsContext::endTransparencyLayer()
+{
+ if (paintingDisabled())
+ return;
+
+ GC2Canvas(this)->restore();
+}
+
+void GraphicsContext::setShadow(const IntSize& size, int blur, const Color& color)
+{
+ if (paintingDisabled())
+ return;
+
+ if (blur > 0)
+ {
+ SkColor c;
+
+ if (color.isValid())
+ c = color.rgb();
+ else
+ c = SkColorSetARGB(0xFF/3, 0, 0, 0); // "std" Apple shadow color
+
+ SkDrawLooper* dl = new SkBlurDrawLooper(SkIntToScalar(blur),
+ SkIntToScalar(size.width()),
+ SkIntToScalar(size.height()),
+ c);
+ m_data->mState->setDrawLooper(dl)->unref();
+ }
+ else
+ m_data->mState->setDrawLooper(NULL);
+}
+
+void GraphicsContext::clearShadow()
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->mState->setDrawLooper(NULL);
+}
+
+void GraphicsContext::drawFocusRing(const Color& color)
+{
+ // Do nothing, since we draw the focus ring independently.
+}
+
+PlatformGraphicsContext* GraphicsContext::platformContext() const
+{
+ ASSERT(!paintingDisabled());
+ return m_data->mPgc;
+}
+
+void GraphicsContext::setMiterLimit(float limit)
+{
+ m_data->mState->mMiterLimit = limit;
+}
+
+void GraphicsContext::setAlpha(float alpha)
+{
+ m_data->mState->mAlpha = alpha;
+}
+
+void GraphicsContext::setCompositeOperation(CompositeOperator op)
+{
+ m_data->mState->mPorterDuffMode = android_convert_compositeOp(op);
+}
+
+void GraphicsContext::clearRect(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ SkPaint paint;
+ SkRect r;
+
+ android_setrect(&r, rect);
+ m_data->setup_paint_fill(&paint);
+ paint.setPorterDuffXfermode(SkPorterDuff::kClear_Mode);
+ GC2Canvas(this)->drawRect(r, paint);
+}
+
+void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth)
+{
+ if (paintingDisabled())
+ return;
+
+ SkPaint paint;
+ SkRect r;
+
+ android_setrect(&r, rect);
+
+ m_data->setup_paint_stroke(&paint, NULL);
+ paint.setStrokeWidth(SkFloatToScalar(lineWidth));
+ GC2Canvas(this)->drawRect(r, paint);
+}
+
+void GraphicsContext::setLineCap(LineCap cap)
+{
+ switch (cap) {
+ case ButtCap:
+ m_data->mState->mLineCap = SkPaint::kButt_Cap;
+ break;
+ case RoundCap:
+ m_data->mState->mLineCap = SkPaint::kRound_Cap;
+ break;
+ case SquareCap:
+ m_data->mState->mLineCap = SkPaint::kSquare_Cap;
+ break;
+ default:
+ SkDEBUGF(("GraphicsContext::setLineCap: unknown LineCap %d\n", cap));
+ break;
+ }
+}
+
+void GraphicsContext::setLineJoin(LineJoin join)
+{
+ switch (join) {
+ case MiterJoin:
+ m_data->mState->mLineJoin = SkPaint::kMiter_Join;
+ break;
+ case RoundJoin:
+ m_data->mState->mLineJoin = SkPaint::kRound_Join;
+ break;
+ case BevelJoin:
+ m_data->mState->mLineJoin = SkPaint::kBevel_Join;
+ break;
+ default:
+ SkDEBUGF(("GraphicsContext::setLineJoin: unknown LineJoin %d\n", join));
+ break;
+ }
+}
+
+void GraphicsContext::scale(const FloatSize& size)
+{
+ if (paintingDisabled())
+ return;
+ GC2Canvas(this)->scale(SkFloatToScalar(size.width()), SkFloatToScalar(size.height()));
+}
+
+void GraphicsContext::rotate(float angleInRadians)
+{
+ if (paintingDisabled())
+ return;
+ GC2Canvas(this)->rotate(SkFloatToScalar(angleInRadians * (180.0f / 3.14159265f)));
+}
+
+void GraphicsContext::translate(float x, float y)
+{
+ if (paintingDisabled())
+ return;
+ GC2Canvas(this)->translate(SkFloatToScalar(x), SkFloatToScalar(y));
+}
+
+void GraphicsContext::concatCTM(const AffineTransform& xform)
+{
+ if (paintingDisabled())
+ return;
+
+//printf("-------------- GraphicsContext::concatCTM\n");
+ GC2Canvas(this)->concat((SkMatrix) xform);
+}
+
+FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return FloatRect();
+
+ const SkMatrix& matrix = GC2Canvas(this)->getTotalMatrix();
+ SkRect r;
+ android_setrect(&r, rect);
+ matrix.mapRect(&r);
+ FloatRect result(SkScalarToFloat(r.fLeft), SkScalarToFloat(r.fTop), SkScalarToFloat(r.width()), SkScalarToFloat(r.height()));
+ return result;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+
+void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
+{
+ // appears to be PDF specific, so we ignore it
+#if 0
+ if (paintingDisabled())
+ return;
+
+ CFURLRef urlRef = link.createCFURL();
+ if (urlRef) {
+ CGContextRef context = platformContext();
+
+ // Get the bounding box to handle clipping.
+ CGRect box = CGContextGetClipBoundingBox(context);
+
+ IntRect intBox((int)box.origin.x, (int)box.origin.y, (int)box.size.width, (int)box.size.height);
+ IntRect rect = destRect;
+ rect.intersect(intBox);
+
+ CGPDFContextSetURLForRect(context, urlRef,
+ CGRectApplyAffineTransform(rect, CGContextGetCTM(context)));
+
+ CFRelease(urlRef);
+ }
+#endif
+}
+
+// we don't need to push these down, since we query the current state and build our paint at draw-time
+
+void GraphicsContext::setPlatformStrokeColor(const Color&) {}
+void GraphicsContext::setPlatformStrokeThickness(float) {}
+void GraphicsContext::setPlatformFillColor(const Color&) {}
+
+
+// functions new to Feb-19 tip of tree merge:
+AffineTransform GraphicsContext::getCTM() const {
+ notImplemented();
+ return AffineTransform();
+}
+
+}
diff --git a/WebCore/platform/graphics/android/ImageAndroid.cpp b/WebCore/platform/graphics/android/ImageAndroid.cpp
new file mode 100644
index 0000000..00145af
--- /dev/null
+++ b/WebCore/platform/graphics/android/ImageAndroid.cpp
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2004, 2005, 2006 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.
+ */
+
+#include "config.h"
+#include "AffineTransform.h"
+#include "BitmapImage.h"
+#include "Image.h"
+#include "FloatRect.h"
+#include "GraphicsContext.h"
+#include "PlatformGraphicsContext.h"
+#include "PlatformString.h"
+#include "SharedBuffer.h"
+
+#include "android_graphics.h"
+#include "SkBitmapRef.h"
+#include "SkCanvas.h"
+#include "SkColorPriv.h"
+#include "SkShader.h"
+#include "SkString.h"
+
+#include <utils/AssetManager.h>
+
+//#define TRACE_SUBSAMPLED_BITMAPS
+
+android::AssetManager* gGlobalAssetMgr;
+
+namespace WebCore {
+
+void FrameData::clear()
+{
+ if (m_frame) {
+ m_frame->unref();
+ m_frame = 0;
+ m_duration = 0.;
+ m_hasAlpha = true;
+ }
+}
+
+SkBitmapRef* BitmapImage::getBitmap()
+{
+ return m_bitmapRef;
+}
+
+void BitmapImage::initPlatformData()
+{
+ m_bitmapRef = NULL;
+ m_source.clearURL();
+}
+
+void BitmapImage::invalidatePlatformData()
+{
+ if (m_bitmapRef) {
+ m_bitmapRef->unref();
+ m_bitmapRef = NULL;
+ }
+}
+
+void BitmapImage::checkForSolidColor()
+{
+ m_isSolidColor = false;
+ if (this->frameCount() > 1) {
+ if (!m_bitmapRef) {
+ return;
+ }
+
+ const SkBitmap& bm = m_bitmapRef->bitmap();
+
+ if (bm.width() == 1 && bm.height() == 1) {
+ SkAutoLockPixels alp(bm);
+ if (bm.getPixels() == NULL) {
+ return;
+ }
+
+ SkPMColor color;
+ switch (bm.getConfig()) {
+ case SkBitmap::kARGB_8888_Config:
+ color = *bm.getAddr32(0, 0);
+ break;
+ case SkBitmap::kRGB_565_Config:
+ color = SkPixel16ToPixel32(*bm.getAddr16(0, 0));
+ break;
+ case SkBitmap::kIndex8_Config: {
+ SkColorTable* ctable = bm.getColorTable();
+ if (!ctable) {
+ return;
+ }
+ color = (*ctable)[*bm.getAddr8(0, 0)];
+ break;
+ }
+ default: // don't check other configs
+ return;
+ }
+ m_isSolidColor = true;
+ m_solidColor = android_SkPMColorToWebCoreColor(color);
+ }
+ }
+}
+
+void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dstRect,
+ const FloatRect& srcRect, CompositeOperator compositeOp)
+{
+ SkBitmapRef* image = this->nativeImageForCurrentFrame();
+ if (!image) { // If it's too early we won't have an image yet.
+ return;
+ }
+
+ // in case we get called with an incomplete bitmap
+ const SkBitmap& bitmap = image->bitmap();
+ if (bitmap.getPixels() == NULL && bitmap.pixelRef() == NULL) {
+ return;
+ }
+
+ SkIRect srcR;
+ SkRect dstR;
+ float invScaleX = (float)bitmap.width() / image->origWidth();
+ float invScaleY = (float)bitmap.height() / image->origHeight();
+
+ android_setrect(&dstR, dstRect);
+ android_setrect_scaled(&srcR, srcRect, invScaleX, invScaleY);
+ if (srcR.isEmpty() || dstR.isEmpty()) {
+ return;
+ }
+
+ SkCanvas* canvas = ctxt->platformContext()->mCanvas;
+ SkPaint paint;
+
+ paint.setFilterBitmap(true);
+ paint.setPorterDuffXfermode(android_convert_compositeOp(compositeOp));
+ canvas->drawBitmapRect(bitmap, &srcR, dstR, &paint);
+
+ startAnimation();
+
+#ifdef TRACE_SUBSAMPLED_BITMAPS
+ if (bitmap.width() != image->origWidth() ||
+ bitmap.height() != image->origHeight()) {
+ SkDebugf("--- BitmapImage::draw [%d %d] orig [%d %d]\n",
+ bitmap.width(), bitmap.height(),
+ image->origWidth(), image->origHeight());
+ }
+#endif
+}
+
+void BitmapImage::setURL(const String& str)
+{
+ m_source.setURL(str);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect,
+ const AffineTransform& patternTransform,
+ const FloatPoint& phase, CompositeOperator compositeOp,
+ const FloatRect& destRect)
+{
+ SkBitmapRef* image = this->nativeImageForCurrentFrame();
+ if (!image) { // If it's too early we won't have an image yet.
+ return;
+ }
+
+ // in case we get called with an incomplete bitmap
+ const SkBitmap& bitmap = image->bitmap();
+ if (bitmap.getPixels() == NULL && bitmap.pixelRef() == NULL) {
+ return;
+ }
+
+ SkRect dstR;
+ android_setrect(&dstR, destRect);
+ if (dstR.isEmpty()) {
+ return;
+ }
+
+ SkCanvas* canvas = ctxt->platformContext()->mCanvas;
+ SkPaint paint;
+
+ SkShader* shader = SkShader::CreateBitmapShader(bitmap,
+ SkShader::kRepeat_TileMode,
+ SkShader::kRepeat_TileMode);
+ paint.setShader(shader)->unref();
+ // now paint is the only owner of shader
+ paint.setPorterDuffXfermode(android_convert_compositeOp(compositeOp));
+ paint.setFilterBitmap(true);
+
+ SkMatrix matrix(patternTransform);
+
+ float scaleX = (float)image->origWidth() / bitmap.width();
+ float scaleY = (float)image->origHeight() / bitmap.height();
+ matrix.preScale(SkFloatToScalar(scaleX), SkFloatToScalar(scaleY));
+
+ matrix.postTranslate(SkFloatToScalar(phase.x()),
+ SkFloatToScalar(phase.y()));
+ shader->setLocalMatrix(matrix);
+ canvas->drawRect(dstR, paint);
+
+#ifdef TRACE_SUBSAMPLED_BITMAPS
+ if (bitmap.width() != image->origWidth() ||
+ bitmap.height() != image->origHeight()) {
+ SkDebugf("--- Image::drawPattern [%d %d] orig [%d %d] dst [%g %g]\n",
+ bitmap.width(), bitmap.height(),
+ image->origWidth(), image->origHeight(),
+ SkScalarToFloat(dstR.width()), SkScalarToFloat(dstR.height()));
+ }
+#endif
+}
+
+// missingImage, textAreaResizeCorner
+Image* Image::loadPlatformResource(const char *name)
+{
+ if (NULL == gGlobalAssetMgr) {
+ gGlobalAssetMgr = new android::AssetManager();
+ gGlobalAssetMgr->addDefaultAssets();
+ }
+
+ SkString path("webkit/");
+ path.append(name);
+ path.append(".png");
+
+ android::Asset* a = gGlobalAssetMgr->open(path.c_str(),
+ android::Asset::ACCESS_BUFFER);
+ if (a == NULL) {
+ SkDebugf("---------------- failed to open image asset %s\n", name);
+ return NULL;
+ }
+
+ Image* image = new BitmapImage;
+ RefPtr<SharedBuffer> buffer =
+ new SharedBuffer((const char*)a->getBuffer(false), a->getLength());
+ image->setData(buffer, true);
+ delete a;
+ return image;
+}
+
+}
diff --git a/WebCore/platform/graphics/android/ImageBufferAndroid.cpp b/WebCore/platform/graphics/android/ImageBufferAndroid.cpp
new file mode 100644
index 0000000..65fb7cd
--- /dev/null
+++ b/WebCore/platform/graphics/android/ImageBufferAndroid.cpp
@@ -0,0 +1,53 @@
+/* ImageBufferAndroid.cpp
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "config.h"
+#include "ImageBuffer.h"
+
+#include "GraphicsContext.h"
+
+using namespace std;
+
+namespace WebCore {
+
+auto_ptr<ImageBuffer> ImageBuffer::create(const IntSize& size, bool grayScale)
+{
+ // Ignore grayScale for now, since SkBitmap doesn't support it... yet
+
+ GraphicsContext* ctx = GraphicsContext::createOffscreenContext(size.width(), size.height());
+
+ auto_ptr<GraphicsContext> context(ctx);
+
+ return auto_ptr<ImageBuffer>(new ImageBuffer(size, context));
+}
+
+
+ImageBuffer::ImageBuffer(const IntSize& size, auto_ptr<GraphicsContext> context)
+ : m_data(NULL), m_size(size), m_context(context.release())
+{
+}
+
+ImageBuffer::~ImageBuffer()
+{
+}
+
+GraphicsContext* ImageBuffer::context() const
+{
+ return m_context.get();
+}
+
+}
diff --git a/WebCore/platform/graphics/android/ImageSourceAndroid.cpp b/WebCore/platform/graphics/android/ImageSourceAndroid.cpp
new file mode 100644
index 0000000..144968d
--- /dev/null
+++ b/WebCore/platform/graphics/android/ImageSourceAndroid.cpp
@@ -0,0 +1,336 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "config.h"
+#include "ImageDecoder.h"
+#include "ImageSource.h"
+#include "IntSize.h"
+#include "SharedBuffer.h"
+#include "PlatformString.h"
+
+#include "JavaSharedClient.h"
+
+#include "SkBitmapRef.h"
+#include "SkImageRef.h"
+#include "SkImageDecoder.h"
+#include "SkStream.h"
+#include "SkTemplates.h"
+
+SkPixelRef* SkCreateRLEPixelRef(const SkBitmap& src);
+
+//#define TRACE_SUBSAMPLE_BITMAPS
+//#define TRACE_RLE_BITMAPS
+
+#include "SkImageRef_GlobalPool.h"
+#include "SkImageRef_ashmem.h"
+
+// made this up, so we don't waste a file-descriptor on small images, plus
+// we don't want to lose too much on the round-up to a page size (4K)
+#define MIN_ASHMEM_ALLOC_SIZE (32*1024)
+
+static bool should_use_ashmem(const SkBitmap& bm) {
+ return bm.getSize() >= MIN_ASHMEM_ALLOC_SIZE;
+}
+
+/* Images larger than this should be subsampled. Using ashmem, the decoded
+ pixels will be purged as needed, so this value can be pretty large. Making
+ it too small hurts image quality (e.g. abc.com background). 2Meg works for
+ the sites I've tested, but if we hit important sites that need more, we
+ should try increasing it and see if it has negative impact on performance
+ (i.e. we end up thrashing because we need to keep decoding images that have
+ been purged.
+
+ Perhaps this value should be some fraction of the available RAM...
+*/
+static size_t computeMaxBitmapSizeForCache() {
+ return 2*1024*1024;
+}
+
+/* 8bit images larger than this should be recompressed in RLE, to reduce
+ on the imageref cache.
+
+ Downside: performance, since we have to decode/encode
+ and then rle-decode when we draw.
+*/
+static bool shouldReencodeAsRLE(const SkBitmap& bm) {
+ const SkBitmap::Config c = bm.config();
+ return (SkBitmap::kIndex8_Config == c || SkBitmap::kA8_Config == c)
+ &&
+ bm.width() >= 64 // narrower than this won't compress well in RLE
+ &&
+ bm.getSize() > (250*1024);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+class PrivateAndroidImageSourceRec : public SkBitmapRef {
+public:
+ PrivateAndroidImageSourceRec(const SkBitmap& bm, int origWidth,
+ int origHeight, int sampleSize)
+ : SkBitmapRef(bm), fSampleSize(sampleSize), fAllDataReceived(false) {
+ this->setOrigSize(origWidth, origHeight);
+ }
+
+ int fSampleSize;
+ bool fAllDataReceived;
+};
+
+namespace WebCore {
+
+class SharedBufferStream : public SkMemoryStream {
+public:
+ SharedBufferStream(SharedBuffer* buffer)
+ : SkMemoryStream(buffer->data(), buffer->size(), false) {
+ fBuffer = buffer;
+ buffer->ref();
+ }
+
+ virtual ~SharedBufferStream() {
+ // we can't necessarily call fBuffer->deref() here, as we may be
+ // in a different thread from webkit, and SharedBuffer is not
+ // threadsafe. Therefore we defer it until it can be executed in the
+ // webkit thread.
+// SkDebugf("-------- enqueue buffer %p for deref\n", fBuffer);
+ JavaSharedClient::EnqueueFunctionPtr(CallDeref, fBuffer);
+ }
+
+private:
+ // don't allow this to change our data. should not get called, but we
+ // override here just to be sure
+ virtual void setMemory(const void* data, size_t length, bool copyData) {
+ sk_throw();
+ }
+
+ // we share ownership of this with webkit
+ SharedBuffer* fBuffer;
+
+ // will be invoked in the webkit thread
+ static void CallDeref(void* buffer) {
+// SkDebugf("-------- call deref on buffer %p\n", buffer);
+ ((SharedBuffer*)buffer)->deref();
+ }
+};
+
+
+///////////////////////////////////////////////////////////////////////////////
+
+ImageSource::ImageSource() {
+ m_decoder.m_image = NULL;
+}
+
+ImageSource::~ImageSource() {
+ delete m_decoder.m_image;
+}
+
+bool ImageSource::initialized() const {
+ return m_decoder.m_image != NULL;
+}
+
+static int computeSampleSize(const SkBitmap& bitmap) {
+ const size_t maxSize = computeMaxBitmapSizeForCache();
+ size_t size = bitmap.getSize();
+ int sampleSize = 1;
+
+ while (size > maxSize) {
+ sampleSize <<= 1;
+ size >>= 2;
+ }
+
+#ifdef TRACE_SUBSAMPLE_BITMAPS
+ if (sampleSize > 1) {
+ SkDebugf("------- bitmap [%d %d] config=%d origSize=%d predictSize=%d sampleSize=%d\n",
+ bitmap.width(), bitmap.height(), bitmap.config(),
+ bitmap.getSize(), size, sampleSize);
+ }
+#endif
+ return sampleSize;
+}
+
+static SkPixelRef* convertToRLE(SkBitmap* bm, const void* data, size_t len) {
+ if (!shouldReencodeAsRLE(*bm)) {
+ return NULL;
+ }
+
+ SkBitmap tmp;
+
+ if (!SkImageDecoder::DecodeMemory(data, len, &tmp) || !tmp.getPixels()) {
+ return NULL;
+ }
+
+ SkPixelRef* ref = SkCreateRLEPixelRef(tmp);
+ if (NULL == ref) {
+ return NULL;
+ }
+
+#ifdef TRACE_RLE_BITMAPS
+ SkDebugf("---- reencode bitmap as RLE: [%d %d] encodeSize=%d\n",
+ tmp.width(), tmp.height(), len);
+#endif
+
+ bm->setConfig(SkBitmap::kRLE_Index8_Config, tmp.width(), tmp.height());
+ return ref;
+}
+
+void ImageSource::clearURL()
+{
+ m_decoder.m_url.reset();
+}
+
+void ImageSource::setURL(const String& url)
+{
+ if (url.startsWith("data:")) {
+ clearURL();
+ } else {
+ m_decoder.m_url.setUTF16(url.characters(), url.length());
+ }
+}
+
+void ImageSource::setData(SharedBuffer* data, bool allDataReceived)
+{
+ if (NULL == m_decoder.m_image) {
+ SkBitmap tmp;
+
+ SkMemoryStream stream(data->data(), data->size(), false);
+ SkImageDecoder* codec = SkImageDecoder::Factory(&stream);
+ SkAutoTDelete<SkImageDecoder> ad(codec);
+
+ if (!codec || !codec->decode(&stream, &tmp, SkBitmap::kNo_Config,
+ SkImageDecoder::kDecodeBounds_Mode)) {
+ return;
+ }
+
+ int origW = tmp.width();
+ int origH = tmp.height();
+ int sampleSize = computeSampleSize(tmp);
+ if (sampleSize > 1) {
+ codec->setSampleSize(sampleSize);
+ stream.rewind();
+ if (!codec->decode(&stream, &tmp, SkBitmap::kNo_Config,
+ SkImageDecoder::kDecodeBounds_Mode)) {
+ return;
+ }
+ }
+
+ m_decoder.m_image = new PrivateAndroidImageSourceRec(tmp, origW, origH,
+ sampleSize);
+ }
+
+ PrivateAndroidImageSourceRec* decoder = m_decoder.m_image;
+ if (allDataReceived && !decoder->fAllDataReceived) {
+ decoder->fAllDataReceived = true;
+
+ SkBitmap* bm = &decoder->bitmap();
+ SkPixelRef* ref = convertToRLE(bm, data->data(), data->size());
+
+ if (NULL == ref) {
+ SkStream* strm = new SharedBufferStream(data);
+ // imageref now owns the stream object
+ if (should_use_ashmem(*bm)) {
+// SkDebugf("---- use ashmem for image [%d %d]\n", bm.width(), bm.height());
+ ref = new SkImageRef_ashmem(strm, bm->config(), decoder->fSampleSize);
+ } else {
+// SkDebugf("---- use globalpool for image [%d %d]\n", bm.width(), bm.height());
+ ref = new SkImageRef_GlobalPool(strm, bm->config(), decoder->fSampleSize);
+ }
+
+ // SkDebugf("----- allDataReceived [%d %d]\n", bm->width(), bm->height());
+ }
+
+ // we promise to never change the pixels (makes picture recording fast)
+ ref->setImmutable();
+ // give it the URL if we have one
+ ref->setURI(m_decoder.m_url);
+ // our bitmap is now the only owner of the imageref
+ bm->setPixelRef(ref)->unref();
+ }
+}
+
+bool ImageSource::isSizeAvailable()
+{
+ return m_decoder.m_image != NULL;
+}
+
+IntSize ImageSource::size() const
+{
+ if (m_decoder.m_image) {
+ return IntSize(m_decoder.m_image->origWidth(), m_decoder.m_image->origHeight());
+ }
+ return IntSize(0, 0);
+}
+
+int ImageSource::repetitionCount()
+{
+ return 1;
+ // A property with value 0 means loop forever.
+}
+
+size_t ImageSource::frameCount() const
+{
+ // i.e. 0 frames if we're not decoded, or 1 frame if we are
+ return m_decoder.m_image != NULL;
+}
+
+SkBitmapRef* ImageSource::createFrameAtIndex(size_t index)
+{
+ SkASSERT(index == 0);
+ SkASSERT(m_decoder.m_image != NULL);
+ m_decoder.m_image->ref();
+ return m_decoder.m_image;
+}
+
+float ImageSource::frameDurationAtIndex(size_t index)
+{
+ SkASSERT(index == 0);
+ float duration = 0;
+
+ // Many annoying ads specify a 0 duration to make an image flash as quickly as possible.
+ // We follow Firefox's behavior and use a duration of 100 ms for any frames that specify
+ // a duration of <= 10 ms. See gfxImageFrame::GetTimeout in Gecko or Radar 4051389 for more.
+ if (duration <= 0.010f)
+ duration = 0.100f;
+ return duration;
+}
+
+bool ImageSource::frameHasAlphaAtIndex(size_t index)
+{
+ SkASSERT(0 == index);
+
+ if (NULL == m_decoder.m_image)
+ return true; // if we're not sure, assume the worse-case
+ const PrivateAndroidImageSourceRec& decoder = *m_decoder.m_image;
+ // if we're 16bit, we know even without all the data available
+ if (decoder.bitmap().getConfig() == SkBitmap::kRGB_565_Config)
+ return false;
+
+ if (!decoder.fAllDataReceived)
+ return true; // if we're not sure, assume the worse-case
+
+ return !decoder.bitmap().isOpaque();
+}
+
+bool ImageSource::frameIsCompleteAtIndex(size_t index)
+{
+ SkASSERT(0 == index);
+ return m_decoder.m_image && m_decoder.m_image->fAllDataReceived;
+}
+
+void ImageSource::clear()
+{
+ // do nothing, since the cache is managed elsewhere
+}
+
+}
diff --git a/WebCore/platform/graphics/android/PathAndroid.cpp b/WebCore/platform/graphics/android/PathAndroid.cpp
new file mode 100644
index 0000000..68f4c0d
--- /dev/null
+++ b/WebCore/platform/graphics/android/PathAndroid.cpp
@@ -0,0 +1,231 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "config.h"
+#include "Path.h"
+#include "FloatRect.h"
+#include "AffineTransform.h"
+
+#include "SkPath.h"
+#include "SkRegion.h"
+
+#include "android_graphics.h"
+
+namespace WebCore {
+
+Path::Path()
+{
+ m_path = new SkPath;
+// m_path->setFlags(SkPath::kWinding_FillType);
+}
+
+Path::Path(const Path& other)
+{
+ m_path = new SkPath(*other.m_path);
+}
+
+Path::~Path()
+{
+ delete m_path;
+}
+
+Path& Path::operator=(const Path& other)
+{
+ *m_path = *other.m_path;
+ return *this;
+}
+
+bool Path::isEmpty() const
+{
+ return m_path->isEmpty();
+}
+
+bool Path::contains(const FloatPoint& point, WindRule rule) const
+{
+ SkRegion rgn, clip;
+
+ int x = (int)floorf(point.x());
+ int y = (int)floorf(point.y());
+ clip.setRect(x, y, x + 1, y + 1);
+
+ SkPath::FillType ft = m_path->getFillType(); // save
+ m_path->setFillType(rule == RULE_NONZERO ? SkPath::kWinding_FillType : SkPath::kEvenOdd_FillType);
+
+ bool contains = rgn.setPath(*m_path, clip);
+
+ m_path->setFillType(ft); // restore
+ return contains;
+}
+
+void Path::translate(const FloatSize& size)
+{
+ m_path->offset(SkFloatToScalar(size.width()), SkFloatToScalar(size.height()));
+}
+
+FloatRect Path::boundingRect() const
+{
+ SkRect r;
+
+ m_path->computeBounds(&r, SkPath::kExact_BoundsType);
+ return FloatRect( SkScalarToFloat(r.fLeft),
+ SkScalarToFloat(r.fTop),
+ SkScalarToFloat(r.width()),
+ SkScalarToFloat(r.height()));
+}
+
+void Path::moveTo(const FloatPoint& point)
+{
+ m_path->moveTo(SkFloatToScalar(point.x()), SkFloatToScalar(point.y()));
+}
+
+void Path::addLineTo(const FloatPoint& p)
+{
+ m_path->lineTo(SkFloatToScalar(p.x()), SkFloatToScalar(p.y()));
+}
+
+void Path::addQuadCurveTo(const FloatPoint& cp, const FloatPoint& ep)
+{
+ m_path->quadTo( SkFloatToScalar(cp.x()), SkFloatToScalar(cp.y()),
+ SkFloatToScalar(ep.x()), SkFloatToScalar(ep.y()));
+}
+
+void Path::addBezierCurveTo(const FloatPoint& p1, const FloatPoint& p2, const FloatPoint& ep)
+{
+ m_path->cubicTo(SkFloatToScalar(p1.x()), SkFloatToScalar(p1.y()),
+ SkFloatToScalar(p2.x()), SkFloatToScalar(p2.y()),
+ SkFloatToScalar(ep.x()), SkFloatToScalar(ep.y()));
+}
+
+void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius)
+{
+ m_path->arcTo(SkFloatToScalar(p1.x()), SkFloatToScalar(p1.y()),
+ SkFloatToScalar(p2.x()), SkFloatToScalar(p2.y()),
+ SkFloatToScalar(radius));
+}
+
+void Path::closeSubpath()
+{
+ m_path->close();
+}
+
+static const float gPI = 3.1415926f;
+
+void Path::addArc(const FloatPoint& p, float r, float sa, float ea,
+ bool clockwise) {
+ SkScalar cx = SkFloatToScalar(p.x());
+ SkScalar cy = SkFloatToScalar(p.y());
+ SkScalar radius = SkFloatToScalar(r);
+
+ SkRect oval;
+ oval.set(cx - radius, cy - radius, cx + radius, cy + radius);
+
+ float sweep = ea - sa;
+ // check for a circle
+ if (sweep >= 2*gPI || sweep <= -2*gPI) {
+ m_path->addOval(oval);
+ } else {
+ SkScalar startDegrees = SkFloatToScalar(sa * 180 / gPI);
+ SkScalar sweepDegrees = SkFloatToScalar(sweep * 180 / gPI);
+
+ if (clockwise && sweepDegrees > 0) {
+ sweepDegrees -= SkIntToScalar(360);
+ } else if (!clockwise && sweepDegrees < 0) {
+ sweepDegrees = SkIntToScalar(360) - sweepDegrees;
+ }
+
+// SkDebugf("addArc sa=%g ea=%g cw=%d start=%g sweep=%g\n", sa, ea, clockwise,
+// SkScalarToFloat(startDegrees), SkScalarToFloat(sweepDegrees));
+
+ m_path->arcTo(oval, startDegrees, sweepDegrees, false);
+ }
+}
+
+void Path::addRect(const FloatRect& rect)
+{
+ SkRect r;
+
+ android_setrect(&r, rect);
+ m_path->addRect(r);
+}
+
+void Path::addEllipse(const FloatRect& rect)
+{
+ SkRect r;
+
+ android_setrect(&r, rect);
+ m_path->addOval(r);
+}
+
+void Path::clear()
+{
+ m_path->reset();
+}
+
+static FloatPoint* setfpts(FloatPoint dst[], const SkPoint src[], int count)
+{
+ for (int i = 0; i < count; i++)
+ {
+ dst[i].setX(SkScalarToFloat(src[i].fX));
+ dst[i].setY(SkScalarToFloat(src[i].fY));
+ }
+ return dst;
+}
+
+void Path::apply(void* info, PathApplierFunction function) const
+{
+ SkPath::Iter iter(*m_path, false);
+ SkPoint pts[4];
+
+ PathElement elem;
+ FloatPoint fpts[3];
+
+ for (;;)
+ {
+ switch (iter.next(pts)) {
+ case SkPath::kMove_Verb:
+ elem.type = PathElementMoveToPoint;
+ elem.points = setfpts(fpts, &pts[0], 1);
+ break;
+ case SkPath::kLine_Verb:
+ elem.type = PathElementAddLineToPoint;
+ elem.points = setfpts(fpts, &pts[1], 1);
+ break;
+ case SkPath::kQuad_Verb:
+ elem.type = PathElementAddQuadCurveToPoint;
+ elem.points = setfpts(fpts, &pts[1], 2);
+ break;
+ case SkPath::kCubic_Verb:
+ elem.type = PathElementAddCurveToPoint;
+ elem.points = setfpts(fpts, &pts[1], 3);
+ break;
+ case SkPath::kClose_Verb:
+ elem.type = PathElementCloseSubpath;
+ elem.points = NULL;
+ break;
+ case SkPath::kDone_Verb:
+ return;
+ }
+ function(info, &elem);
+ }
+}
+
+void Path::transform(const AffineTransform& xform)
+{
+ m_path->transform(xform);
+}
+
+}
diff --git a/WebCore/platform/graphics/android/PlatformGraphics.h b/WebCore/platform/graphics/android/PlatformGraphics.h
new file mode 100644
index 0000000..6efdb43
--- /dev/null
+++ b/WebCore/platform/graphics/android/PlatformGraphics.h
@@ -0,0 +1,25 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef PlatformGraphics_d
+#define PlatformGraphics_d
+
+typedef class SkShader PlatformGradient;
+typedef class SkShader PlatformPattern;
+
+#endif
+
diff --git a/WebCore/platform/graphics/android/PlatformGraphicsContext.cpp b/WebCore/platform/graphics/android/PlatformGraphicsContext.cpp
new file mode 100644
index 0000000..af443b8
--- /dev/null
+++ b/WebCore/platform/graphics/android/PlatformGraphicsContext.cpp
@@ -0,0 +1,73 @@
+/*
+ *
+ * Copyright 2006, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "config.h"
+#include "Node.h"
+#include "PlatformGraphicsContext.h"
+#include "SkCanvas.h"
+
+namespace WebCore {
+
+PlatformGraphicsContext::PlatformGraphicsContext(SkCanvas* canvas) : mCanvas(canvas), m_deleteCanvas(false)
+{
+ // This is useful only if this Canvas is part of an SkPicture object.
+ m_buttons = new SkTDArray<Container*>;
+}
+
+PlatformGraphicsContext::PlatformGraphicsContext() : m_deleteCanvas(true)
+{
+ mCanvas = new SkCanvas;
+ // Since this is our own private SkCanvas, and has no relation to a picture
+ // storing button references would be meaningless.
+ m_buttons = NULL;
+}
+
+PlatformGraphicsContext::~PlatformGraphicsContext()
+{
+ if (m_deleteCanvas) {
+// printf("-------------------- deleting offscreen canvas\n");
+ delete mCanvas;
+ }
+ if (m_buttons != NULL) {
+ m_buttons->deleteAll();
+ delete m_buttons;
+ }
+}
+
+SkTDArray<Container*>* PlatformGraphicsContext::getAndClearButtonInfo()
+{
+ // The caller is now responsible for deleting the array
+ SkTDArray<Container*>* buttons = m_buttons;
+ m_buttons = NULL;
+ return buttons;
+}
+
+void PlatformGraphicsContext::storeButtonInfo(Node* node, const IntRect& r)
+{
+ if (m_buttons == NULL)
+ return;
+ // Initialize all of the nodes to have disabled state, so that we guarantee
+ // that we paint all of them the first time.
+ RenderSkinAndroid::State state = RenderSkinAndroid::kDisabled;
+ Container* container = new Container(node, r, state);
+ // Place a reference to our subpicture in the Picture.
+ mCanvas->drawPicture(*(container->picture()));
+ // Keep track of the information about the button.
+ *m_buttons->append() = container;
+}
+
+} // WebCore
diff --git a/WebCore/platform/graphics/android/PlatformGraphicsContext.h b/WebCore/platform/graphics/android/PlatformGraphicsContext.h
new file mode 100644
index 0000000..a2d7ebe
--- /dev/null
+++ b/WebCore/platform/graphics/android/PlatformGraphicsContext.h
@@ -0,0 +1,108 @@
+/*
+ *
+ * Copyright 2006, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef platform_graphics_context_h
+#define platform_graphics_context_h
+
+#include "IntRect.h"
+#include "RenderSkinAndroid.h"
+#include "RenderSkinButton.h"
+#include "SkCanvas.h"
+#include "SkPicture.h"
+#include "SkTDArray.h"
+
+class SkCanvas;
+class WebCore::Node;
+
+class Container {
+public:
+ Container(WebCore::Node* node, const WebCore::IntRect& r,
+ WebCore::RenderSkinAndroid::State is)
+ : m_node(node), m_rect(r), m_state(is)
+ {
+ m_picture = new SkPicture;
+ }
+
+ ~Container()
+ {
+ m_picture->unref();
+ }
+
+ bool matches(WebCore::Node* match) { return m_node == match; }
+
+ // Provide a pointer to our SkPicture.
+ SkPicture* picture() { return m_picture; }
+
+ // Update the focus state of this button, depending on whether it
+ // corresponds to the focused node passed in. If its state has changed,
+ // re-record to the subpicture, so the master picture will reflect the
+ // change.
+ void updateFocusState(WebCore::Node* focus)
+ {
+ WebCore::RenderSkinAndroid::State state = m_node == focus ?
+ WebCore::RenderSkinAndroid::kFocused : WebCore::RenderSkinAndroid::kNormal;
+ if (state == m_state)
+ return;
+ m_state = state;
+ SkCanvas* canvas = m_picture->beginRecording(m_rect.width(), m_rect.height());
+ WebCore::RenderSkinButton::Draw(canvas, m_rect, state);
+ m_picture->endRecording();
+ }
+private:
+ // Mark copy and assignment private so noone can use them.
+ Container& operator=(const Container& src) { return *this; }
+ Container(const Container& src) { }
+ // Only used for comparison, since after it is stored it will be transferred
+ // to the UI thread.
+ WebCore::Node* m_node;
+ // The rectangle representing the bounds of the button.
+ WebCore::IntRect m_rect;
+ // An SkPicture that, thanks to storeButtonInfo, is pointed to by the master
+ // picture, so that we can rerecord this button without rerecording the
+ // world.
+ SkPicture* m_picture;
+ // The state of the button - Currently kFocused or kNormal (and kDisabled
+ // as an initial value), but could be expanded to include other states.
+ WebCore::RenderSkinAndroid::State m_state;
+};
+
+namespace WebCore {
+
+class PlatformGraphicsContext {
+public:
+ PlatformGraphicsContext();
+ PlatformGraphicsContext(SkCanvas* canvas);
+ ~PlatformGraphicsContext();
+
+ SkCanvas* mCanvas;
+
+ bool deleteUs() const { return m_deleteCanvas; }
+ // If our graphicscontext has a button list, add a new container for the
+ // nod/rect, and record a new subpicture for this node/button in the current
+ // mCanvas
+ void storeButtonInfo(Node* node, const IntRect& r);
+ // Detaches button array (if any), returning it to the caller and setting our
+ // internal ptr to NULL
+ SkTDArray<Container*>* getAndClearButtonInfo();
+private:
+ bool m_deleteCanvas;
+ SkTDArray<Container*>* m_buttons;
+};
+
+}
+#endif
+
diff --git a/WebCore/platform/graphics/android/SkBitmapRef.h b/WebCore/platform/graphics/android/SkBitmapRef.h
new file mode 100644
index 0000000..77afcf3
--- /dev/null
+++ b/WebCore/platform/graphics/android/SkBitmapRef.h
@@ -0,0 +1,54 @@
+/* include/graphics/SkBitmapRef.h
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#ifndef SkBitmapRef_DEFINED
+#define SkBitmapRef_DEFINED
+
+#include "SkRefCnt.h"
+#include "SkBitmap.h"
+
+class SkBitmapRef : public SkRefCnt {
+public:
+ SkBitmapRef() : fOrigWidth(0), fOrigHeight(0), fAccessed(false) {}
+ explicit SkBitmapRef(const SkBitmap& src)
+ : fBitmap(src),
+ fOrigWidth(src.width()),
+ fOrigHeight(src.height()),
+ fAccessed(false) {}
+
+ const SkBitmap& bitmap() const { return fBitmap; }
+ SkBitmap& bitmap() { return fBitmap; }
+
+ int origWidth() const { return fOrigWidth; }
+ int origHeight() const { return fOrigHeight; }
+
+ void setOrigSize(int width, int height) {
+ fOrigWidth = width;
+ fOrigHeight = height;
+ }
+ // return true if this is not the first access
+ // mark it true so all subsequent calls return true
+ bool accessed() { bool result = fAccessed;
+ fAccessed = true; return result; }
+
+private:
+ SkBitmap fBitmap;
+ int fOrigWidth, fOrigHeight;
+ bool fAccessed;
+};
+
+#endif
diff --git a/WebCore/platform/graphics/android/android_graphics.cpp b/WebCore/platform/graphics/android/android_graphics.cpp
new file mode 100644
index 0000000..3964ee1
--- /dev/null
+++ b/WebCore/platform/graphics/android/android_graphics.cpp
@@ -0,0 +1,223 @@
+/*
+ *
+ * Copyright 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "config.h"
+#include "android_graphics.h"
+#include "IntPoint.h"
+#include "IntRect.h"
+#include "FloatPoint.h"
+#include "FloatRect.h"
+#include "SkCanvas.h"
+#include "SkColorPriv.h"
+#include "SkCornerPathEffect.h"
+#include "SkGradientShader.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+
+SkPoint* android_setpt(SkPoint* dst, const WebCore::IntPoint& src)
+{
+ dst->set(SkIntToScalar(src.x()), SkIntToScalar(src.y()));
+ return dst;
+}
+
+SkPoint* android_setpt(SkPoint* dst, const WebCore::FloatPoint& src)
+{
+ dst->set(SkFloatToScalar(src.x()), SkFloatToScalar(src.y()));
+ return dst;
+}
+
+SkRect* android_setrect(SkRect* dst, const WebCore::IntRect& src)
+{
+ dst->set(SkIntToScalar(src.x()),
+ SkIntToScalar(src.y()),
+ SkIntToScalar(src.x() + src.width()),
+ SkIntToScalar(src.y() + src.height()));
+ return dst;
+}
+
+SkIRect* android_setrect(SkIRect* dst, const WebCore::IntRect& src)
+{
+ dst->set(src.x(), src.y(),
+ src.x() + src.width(),
+ src.y() + src.height());
+ return dst;
+}
+
+SkRect* android_setrect(SkRect* dst, const WebCore::FloatRect& src)
+{
+ dst->set(SkFloatToScalar(src.x()),
+ SkFloatToScalar(src.y()),
+ SkFloatToScalar(src.x() + src.width()),
+ SkFloatToScalar(src.y() + src.height()));
+ return dst;
+}
+
+SkIRect* android_setrect(SkIRect* dst, const WebCore::FloatRect& src)
+{
+ dst->set(SkScalarRound(SkFloatToScalar(src.x())),
+ SkScalarRound(SkFloatToScalar(src.y())),
+ SkScalarRound(SkFloatToScalar(src.x() + src.width())),
+ SkScalarRound(SkFloatToScalar(src.y() + src.height())));
+ return dst;
+}
+
+SkIRect* android_setrect_scaled(SkIRect* dst, const WebCore::FloatRect& src,
+ float sx, float sy)
+{
+ dst->set(SkScalarRound(SkFloatToScalar(src.x() * sx)),
+ SkScalarRound(SkFloatToScalar(src.y() * sy)),
+ SkScalarRound(SkFloatToScalar((src.x() + src.width()) * sx)),
+ SkScalarRound(SkFloatToScalar((src.y() + src.height()) * sy)));
+ return dst;
+}
+
+static const struct CompositOpToPorterDuffMode {
+ uint8_t mCompositOp;
+ uint8_t mPorterDuffMode;
+} gMapCompositOpsToPorterDuffModes[] = {
+ { WebCore::CompositeClear, SkPorterDuff::kClear_Mode },
+ { WebCore::CompositeCopy, SkPorterDuff::kSrcOver_Mode }, // TODO
+ { WebCore::CompositeSourceOver, SkPorterDuff::kSrcOver_Mode },
+ { WebCore::CompositeSourceIn, SkPorterDuff::kSrcIn_Mode },
+ { WebCore::CompositeSourceOut, SkPorterDuff::kSrcOut_Mode },
+ { WebCore::CompositeSourceAtop, SkPorterDuff::kSrcATop_Mode },
+ { WebCore::CompositeDestinationOver, SkPorterDuff::kDstOver_Mode },
+ { WebCore::CompositeDestinationIn, SkPorterDuff::kDstIn_Mode },
+ { WebCore::CompositeDestinationOut, SkPorterDuff::kDstOut_Mode },
+ { WebCore::CompositeDestinationAtop, SkPorterDuff::kDstATop_Mode },
+ { WebCore::CompositeXOR, SkPorterDuff::kXor_Mode },
+ { WebCore::CompositePlusDarker, SkPorterDuff::kDarken_Mode },
+ { WebCore::CompositeHighlight, SkPorterDuff::kSrcOver_Mode }, // TODO
+ { WebCore::CompositePlusLighter, SkPorterDuff::kLighten_Mode }
+};
+
+SkPorterDuff::Mode android_convert_compositeOp(WebCore::CompositeOperator op)
+{
+ const CompositOpToPorterDuffMode* table = gMapCompositOpsToPorterDuffModes;
+
+ for (unsigned i = 0; i < SK_ARRAY_COUNT(gMapCompositOpsToPorterDuffModes); i++) {
+ if (table[i].mCompositOp == op) {
+ return (SkPorterDuff::Mode)table[i].mPorterDuffMode;
+ }
+ }
+
+ SkDEBUGF(("GraphicsContext::setCompositeOperation uknown CompositOperator %d\n", op));
+ return SkPorterDuff::kSrcOver_Mode; // fall-back
+}
+
+SkShader::TileMode android_convert_TileRule(WebCore::Image::TileRule rule)
+{
+ // stretch == clamp
+ // repeat == repeat
+ // RoundTile???
+
+ return WebCore::Image::RepeatTile == rule ? SkShader::kRepeat_TileMode : SkShader::kClamp_TileMode;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+static U8CPU InvScaleByte(U8CPU component, uint32_t scale)
+{
+ SkASSERT(component == (uint8_t)component);
+ return (component * scale + 0x8000) >> 16;
+}
+
+// move this guy into SkColor.h
+static SkColor SkPMColorToColor(SkPMColor pm)
+{
+ if (0 == pm)
+ return 0;
+
+ unsigned a = SkGetPackedA32(pm);
+ uint32_t scale = (255 << 16) / a;
+
+ return SkColorSetARGB(a,
+ InvScaleByte(SkGetPackedR32(pm), scale),
+ InvScaleByte(SkGetPackedG32(pm), scale),
+ InvScaleByte(SkGetPackedB32(pm), scale));
+}
+
+WebCore::Color android_SkPMColorToWebCoreColor(SkPMColor pm)
+{
+ SkColor c = SkPMColorToColor(pm);
+
+ return WebCore::Color(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c), SkColorGetA(c));
+}
+
+const static SkColor focusOuterColors[] = {
+ SkColorSetARGB(0xff, 0xB3, 0x3F, 0x08), // normal focus ring select
+ SkColorSetARGB(0xff, 0x46, 0xb0, 0x00), // fake focus ring select, for phone, email, text
+ SkColorSetARGB(0x00, 0x00, 0x00, 0x00), // no ring, for buttons
+ SkColorSetARGB(0xff, 0xb0, 0x16, 0x00), // invalid focus ring color
+ SkColorSetARGB(0xff, 0xAD, 0x5C, 0x0A), // normal focus ring pressed
+ SkColorSetARGB(0xff, 0x36, 0xc0, 0x00) // fake focus ring pressed
+};
+
+const static SkColor focusInnerColors[] = {
+ SkColorSetARGB(0xff, 0xFE, 0x92, 0x30), // normal focus ring select
+ SkColorSetARGB(0xff, 0x8c, 0xd9, 0x00), // fake focus ring select, for phone, email, text
+ SkColorSetARGB(0x00, 0x00, 0x00, 0x00), // no ring, for buttons
+ SkColorSetARGB(0xff, 0xd9, 0x2c, 0x00), // invalid focus ring color
+ SkColorSetARGB(0xff, 0xFE, 0xBD, 0x3A), // normal focus ring pressed
+ SkColorSetARGB(0xff, 0x7c, 0xe9, 0x00) // fake focus ring pressed
+};
+
+const static SkColor focusPressedColors[] = {
+ SkColorSetARGB(0x80, 0xFF, 0xC6, 0x4B), // normal focus ring pressed
+ SkColorSetARGB(0x80, 0x7c, 0xe9, 0x00), // fake focus ring pressed
+ SkColorSetARGB(0x80, 0xFF, 0xC6, 0x4B) // button focus ring pressed
+};
+
+#define FOCUS_RING_ROUNDEDNESS SkIntToScalar(5) // used to draw corners
+#define FOCUS_RING_INNER_DIAMETER SkFixedToScalar(SkIntToFixed(3)>>1) // 3/2 == 1.5
+#define FOCUS_RING_OUTER_OUTSET 2 // used to inflate rects added to region
+
+void FocusRing::DrawRing(SkCanvas* canvas,
+ const Vector<WebCore::IntRect>& rects, Flavor flavor)
+{
+ unsigned rectCount = rects.size();
+ SkRegion rgn;
+ SkPath path;
+ for (unsigned i = 0; i < rectCount; i++)
+ {
+ SkIRect r;
+
+ android_setrect(&r, rects[i]);
+ r.inset(-FOCUS_RING_OUTER_OUTSET, -FOCUS_RING_OUTER_OUTSET);
+ rgn.op(r, SkRegion::kUnion_Op);
+ }
+ rgn.getBoundaryPath(&path);
+
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setPathEffect(new SkCornerPathEffect(FOCUS_RING_ROUNDEDNESS))->unref();
+ if (flavor >= NORMAL_ANIMATING) { // pressed
+ paint.setColor(focusPressedColors[flavor - NORMAL_ANIMATING]);
+ canvas->drawPath(path, paint);
+ }
+ if (flavor == BUTTON_ANIMATING)
+ return;
+ paint.setStyle(SkPaint::kStroke_Style);
+ paint.setStrokeWidth(FOCUS_RING_OUTER_DIAMETER);
+ paint.setColor(focusOuterColors[flavor]);
+ canvas->drawPath(path, paint);
+ paint.setStrokeWidth(FOCUS_RING_INNER_DIAMETER);
+ paint.setColor(focusInnerColors[flavor]);
+ canvas->drawPath(path, paint);
+}
+
+
diff --git a/WebCore/platform/graphics/android/android_graphics.h b/WebCore/platform/graphics/android/android_graphics.h
new file mode 100644
index 0000000..91c56b7
--- /dev/null
+++ b/WebCore/platform/graphics/android/android_graphics.h
@@ -0,0 +1,80 @@
+/*
+ *
+ * Copyright 2007, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef android_graphics_DEFINED
+#define android_graphics_DEFINED
+
+#include "Color.h"
+#include "Image.h"
+#include "wtf/Vector.h"
+
+#include "SkColor.h"
+#include "SkPorterDuff.h"
+#include "SkScalar.h"
+#include "SkShader.h"
+
+class SkCanvas;
+struct SkPoint;
+struct SKRect;
+
+namespace WebCore {
+ class FloatRect;
+ class IntPoint;
+ class IntRect;
+}
+
+SkPoint* android_setpt(SkPoint* dst, const WebCore::IntPoint& src);
+SkPoint* android_setpt(SkPoint* dst, const WebCore::FloatPoint& src);
+SkRect* android_setrect(SkRect* dst, const WebCore::IntRect& src);
+SkRect* android_setrect(SkRect* dst, const WebCore::FloatRect& src);
+SkIRect* android_setrect(SkIRect* dst, const WebCore::IntRect& src);
+SkIRect* android_setrect(SkIRect* dst, const WebCore::FloatRect& src);
+SkIRect* android_setrect_scaled(SkIRect* dst, const WebCore::FloatRect& src,
+ float sx, float sy);
+
+SkPorterDuff::Mode android_convert_compositeOp(WebCore::CompositeOperator);
+SkShader::TileMode android_convert_TileRule(WebCore::Image::TileRule);
+
+WebCore::Color android_SkPMColorToWebCoreColor(SkPMColor pm);
+
+// Data and methods for focus rings
+
+// used to inflate node cache entry
+#define FOCUS_RING_HIT_TEST_RADIUS SkIntToScalar(5)
+
+// used to inval rectangle enclosing pressed state of focus ring
+#define FOCUS_RING_OUTER_DIAMETER SkFixedToScalar(SkIntToFixed(13)>>2) // 13/4 == 3.25
+
+struct FocusRing {
+public:
+ enum Flavor {
+ NORMAL_FLAVOR,
+ FAKE_FLAVOR,
+ BUTTON_NO_RING,
+ INVALID_FLAVOR,
+ NORMAL_ANIMATING,
+ FAKE_ANIMATING,
+ BUTTON_ANIMATING,
+ ANIMATING_COUNT = 2
+ };
+
+ static void DrawRing(SkCanvas* ,
+ const Vector<WebCore::IntRect>& rects, Flavor );
+};
+
+#endif
+
diff --git a/WebCore/platform/graphics/cairo/FontCairo.cpp b/WebCore/platform/graphics/cairo/FontCairo.cpp
deleted file mode 100644
index 06e926f..0000000
--- a/WebCore/platform/graphics/cairo/FontCairo.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
- * Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
- * Copyright (C) 2007, 2008 Alp Toker <alp@atoker.com>
- *
- * 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.
- */
-
-#include "config.h"
-#include "Font.h"
-
-#include "GlyphBuffer.h"
-#include "GraphicsContext.h"
-#include "SimpleFontData.h"
-
-namespace WebCore {
-
-void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer,
- int from, int numGlyphs, const FloatPoint& point) const
-{
- cairo_t* cr = graphicsContext->platformContext();
- cairo_save(cr);
-
- // Set the text color to use for drawing.
- float red, green, blue, alpha;
- Color penColor = graphicsContext->fillColor();
- penColor.getRGBA(red, green, blue, alpha);
- cairo_set_source_rgba(cr, red, green, blue, alpha);
-
- font->setFont(cr);
-
- GlyphBufferGlyph* glyphs = (GlyphBufferGlyph*)glyphBuffer.glyphs(from);
-
- float offset = point.x();
-
- for (int i = 0; i < numGlyphs; i++) {
- glyphs[i].x = offset;
- glyphs[i].y = point.y();
- offset += glyphBuffer.advanceAt(from + i);
- }
- cairo_show_glyphs(cr, glyphs, numGlyphs);
-
- cairo_restore(cr);
-}
-
-}
diff --git a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
index 90e34e9..08e8616 100644
--- a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
+++ b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
@@ -33,7 +33,6 @@
#include "CairoPath.h"
#include "FloatRect.h"
#include "Font.h"
-#include "ImageBuffer.h"
#include "IntRect.h"
#include "NotImplemented.h"
#include "Path.h"
@@ -103,13 +102,11 @@ cairo_t* GraphicsContext::platformContext() const
void GraphicsContext::savePlatformState()
{
cairo_save(m_data->cr);
- m_data->save();
}
void GraphicsContext::restorePlatformState()
{
cairo_restore(m_data->cr);
- m_data->restore();
}
// Draws a filled rectangle with a stroked border.
@@ -382,7 +379,6 @@ void GraphicsContext::clip(const IntRect& rect)
cairo_set_fill_rule(cr, CAIRO_FILL_RULE_WINDING);
cairo_clip(cr);
cairo_set_fill_rule(cr, savedFillRule);
- m_data->clip(rect);
}
void GraphicsContext::drawFocusRing(const Color& color)
@@ -434,6 +430,7 @@ void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& origin,
if (paintingDisabled())
return;
+#if PLATFORM(GTK)
cairo_t* cr = m_data->cr;
cairo_save(cr);
@@ -444,14 +441,13 @@ void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint& origin,
else
cairo_set_source_rgb(cr, 1, 0, 0);
-#if PLATFORM(GTK)
// We ignore most of the provided constants in favour of the platform style
pango_cairo_show_error_underline(cr, origin.x(), origin.y(), width, cMisspellingLineThickness);
+
+ cairo_restore(cr);
#else
notImplemented();
#endif
-
- cairo_restore(cr);
}
FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect)
@@ -484,7 +480,6 @@ void GraphicsContext::translate(float x, float y)
cairo_t* cr = m_data->cr;
cairo_translate(cr, x, y);
- m_data->translate(x, y);
}
IntPoint GraphicsContext::origin()
@@ -548,6 +543,9 @@ void GraphicsContext::setURLForRect(const KURL& link, const IntRect& destRect)
notImplemented();
}
+#if PLATFORM(GTK)
+// FIXME: This should be moved to something like GraphicsContextCairoGTK.cpp,
+// as there is a Windows implementation in platform/graphics/win/GraphicsContextCairoWin.cpp
void GraphicsContext::concatCTM(const AffineTransform& transform)
{
if (paintingDisabled())
@@ -556,8 +554,8 @@ void GraphicsContext::concatCTM(const AffineTransform& transform)
cairo_t* cr = m_data->cr;
const cairo_matrix_t* matrix = reinterpret_cast<const cairo_matrix_t*>(&transform);
cairo_transform(cr, matrix);
- m_data->concatCTM(transform);
}
+#endif
void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness)
{
@@ -601,7 +599,6 @@ void GraphicsContext::beginTransparencyLayer(float opacity)
cairo_t* cr = m_data->cr;
cairo_push_group(cr);
m_data->layers.append(opacity);
- m_data->beginTransparencyLayer();
}
void GraphicsContext::endTransparencyLayer()
@@ -614,7 +611,6 @@ void GraphicsContext::endTransparencyLayer()
cairo_pop_group_to_source(cr);
cairo_paint_with_alpha(cr, m_data->layers.last());
m_data->layers.removeLast();
- m_data->endTransparencyLayer();
}
void GraphicsContext::clearRect(const FloatRect& rect)
@@ -776,7 +772,6 @@ void GraphicsContext::clip(const Path& path)
cairo_set_fill_rule(cr, CAIRO_FILL_RULE_WINDING);
cairo_clip(cr);
cairo_set_fill_rule(cr, savedFillRule);
- m_data->clip(path);
}
void GraphicsContext::clipOut(const Path& path)
@@ -802,7 +797,6 @@ void GraphicsContext::rotate(float radians)
return;
cairo_rotate(m_data->cr, radians);
- m_data->rotate(radians);
}
void GraphicsContext::scale(const FloatSize& size)
@@ -811,7 +805,6 @@ void GraphicsContext::scale(const FloatSize& size)
return;
cairo_scale(m_data->cr, size.width(), size.height());
- m_data->scale(size);
}
void GraphicsContext::clipOut(const IntRect& r)
@@ -896,35 +889,6 @@ void GraphicsContext::setUseAntialiasing(bool enable)
cairo_set_antialias(m_data->cr, enable ? CAIRO_ANTIALIAS_DEFAULT : CAIRO_ANTIALIAS_NONE);
}
-void GraphicsContext::paintBuffer(ImageBuffer* buffer, const IntRect& r)
-{
- if (paintingDisabled())
- return;
- cairo_surface_t* image = buffer->surface();
- if (!image)
- return;
- cairo_surface_flush(image);
- cairo_surface_reference(image);
- cairo_t* cr = platformContext();
- cairo_save(cr);
- cairo_translate(cr, r.x(), r.y());
- cairo_set_source_surface(cr, image, 0, 0);
- cairo_surface_destroy(image);
- cairo_rectangle(cr, 0, 0, r.width(), r.height());
- cairo_fill(cr);
- cairo_restore(cr);
-}
-
-void GraphicsContext::drawImage(ImageBuffer* buffer, const FloatRect& srcRect, const FloatRect& dstRect)
-{
- cairo_surface_flush(buffer->surface());
- cairo_save(platformContext());
- cairo_set_source_surface(platformContext(), buffer->surface(), srcRect.x(), srcRect.y());
- cairo_rectangle(platformContext(), dstRect.x(), dstRect.y(), dstRect.width(), dstRect.height());
- cairo_fill(platformContext());
- cairo_restore(platformContext());
-}
-
} // namespace WebCore
#endif // PLATFORM(CAIRO)
diff --git a/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h b/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h
index 26db336..f0ef490 100644
--- a/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h
+++ b/WebCore/platform/graphics/cairo/GraphicsContextPlatformPrivateCairo.h
@@ -62,28 +62,8 @@ public:
#if PLATFORM(WIN)
// On Windows, we need to update the HDC for form controls to draw in the right place.
- void save();
- void restore();
- void clip(const IntRect&);
- void clip(const Path&);
- void scale(const FloatSize&);
- void rotate(float);
- void translate(float, float);
- void concatCTM(const AffineTransform&);
void beginTransparencyLayer() { m_transparencyCount++; }
void endTransparencyLayer() { m_transparencyCount--; }
-#else
- // On everything else, we do nothing.
- void save() {}
- void restore() {}
- void clip(const IntRect&) {}
- void clip(const Path&) {}
- void scale(const FloatSize&) {}
- void rotate(float) {}
- void translate(float, float) {}
- void concatCTM(const AffineTransform&) {}
- void beginTransparencyLayer() {}
- void endTransparencyLayer() {}
#endif
cairo_t* cr;
diff --git a/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
index 392e9df..776529e 100644
--- a/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
+++ b/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp
@@ -28,10 +28,8 @@
#include "ImageBuffer.h"
#include "GraphicsContext.h"
-#include "ImageData.h"
-#include "NotImplemented.h"
-
#include <cairo.h>
+#include "NotImplemented.h"
using namespace std;
@@ -74,15 +72,5 @@ cairo_surface_t* ImageBuffer::surface() const
return m_surface;
}
-PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect&) const
-{
- notImplemented();
- return 0;
-}
-
-void ImageBuffer::putImageData(ImageData*, const IntRect&, const IntPoint&)
-{
- notImplemented();
-}
}
diff --git a/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp b/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp
index 66e39ba..8cc15b3 100644
--- a/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp
+++ b/WebCore/platform/graphics/cairo/ImageSourceCairo.cpp
@@ -26,20 +26,18 @@
#include "config.h"
#include "ImageSource.h"
+#include "SharedBuffer.h"
#if PLATFORM(CAIRO)
-#include "BMPImageDecoder.h"
#include "GIFImageDecoder.h"
-#include "ICOImageDecoder.h"
#include "JPEGImageDecoder.h"
#include "PNGImageDecoder.h"
-#include "SharedBuffer.h"
-#include <cairo.h>
-
-#if !PLATFORM(WIN)
+#include "BMPImageDecoder.h"
+#include "ICOImageDecoder.h"
#include "XBMImageDecoder.h"
-#endif
+
+#include <cairo.h>
namespace WebCore {
@@ -80,20 +78,17 @@ ImageDecoder* createDecoder(const Vector<char>& data)
!memcmp(contents, "\000\000\002\000", 4))
return new ICOImageDecoder();
-#if !PLATFORM(WIN)
// XBMs require 8 bytes of info.
if (length >= 8 && strncmp(contents, "#define ", 8) == 0)
return new XBMImageDecoder();
-#endif
// Give up. We don't know what the heck this is.
return 0;
}
ImageSource::ImageSource()
- : m_decoder(0)
-{
-}
+ : m_decoder(0)
+{}
ImageSource::~ImageSource()
{
diff --git a/WebCore/platform/graphics/cairo/PathCairo.cpp b/WebCore/platform/graphics/cairo/PathCairo.cpp
index 8d17567..e4c9f72 100644
--- a/WebCore/platform/graphics/cairo/PathCairo.cpp
+++ b/WebCore/platform/graphics/cairo/PathCairo.cpp
@@ -76,15 +76,15 @@ void Path::clear()
bool Path::isEmpty() const
{
+ // FIXME: if/when the patch to get current pt return status is applied
+ // double dx,dy;
+ // return cairo_get_current_point(cr, &dx, &dy);
+
cairo_t* cr = platformPath()->m_cr;
-#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,5,10)
- return !cairo_has_current_point(cr);
-#else
cairo_path_t* p = cairo_copy_path(cr);
bool hasData = p->num_data;
cairo_path_destroy(p);
return !hasData;
-#endif
}
void Path::translate(const FloatSize& p)
diff --git a/WebCore/platform/graphics/cg/GraphicsContextCG.cpp b/WebCore/platform/graphics/cg/GraphicsContextCG.cpp
index de546ac..c490dcb 100644
--- a/WebCore/platform/graphics/cg/GraphicsContextCG.cpp
+++ b/WebCore/platform/graphics/cg/GraphicsContextCG.cpp
@@ -30,14 +30,10 @@
#include "AffineTransform.h"
#include "FloatConversion.h"
#include "GraphicsContextPlatformPrivateCG.h"
-#include "ImageBuffer.h"
#include "KURL.h"
#include "Path.h"
-#include <CoreGraphics/CGBitmapContext.h>
#include <CoreGraphics/CGPDFContext.h>
#include <wtf/MathExtras.h>
-#include <wtf/OwnArrayPtr.h>
-#include <wtf/RetainPtr.h>
using namespace std;
@@ -928,49 +924,6 @@ void GraphicsContext::setCompositeOperation(CompositeOperator mode)
CGContextSetBlendMode(platformContext(), target);
}
#endif
-
-void GraphicsContext::paintBuffer(ImageBuffer* buffer, const IntRect& r)
-{
- CGContextRef context = buffer->context()->platformContext();
- if (!context)
- return;
- CGContextFlush(context);
- if (CGImageRef image = CGBitmapContextCreateImage(context)) {
- CGContextDrawImage(platformContext(), roundToDevicePixels(r), image);
- CGImageRelease(image);
- }
-}
-
-void GraphicsContext::drawImage(ImageBuffer* buffer, const FloatRect& srcRect, const FloatRect& destRect)
-{
- CGContextRef context = buffer->context()->platformContext();
- CGContextFlush(context);
- RetainPtr<CGImageRef> image(AdoptCF, CGBitmapContextCreateImage(context));
- float iw = CGImageGetWidth(image.get());
- float ih = CGImageGetHeight(image.get());
- if (srcRect.x() == 0 && srcRect.y() == 0 && iw == srcRect.width() && ih == srcRect.height()) {
- // Fast path, yay!
- CGContextDrawImage(platformContext(), destRect, image.get());
- } else {
- // Slow path, boo!
- // FIXME: We can do this without creating a separate image
-
- size_t csw = static_cast<size_t>(ceilf(srcRect.width()));
- size_t csh = static_cast<size_t>(ceilf(srcRect.height()));
-
- RetainPtr<CGColorSpaceRef> colorSpace(AdoptCF, CGColorSpaceCreateDeviceRGB());
- size_t bytesPerRow = csw * 4;
- OwnArrayPtr<char> buffer(new char[csh * bytesPerRow]);
- RetainPtr<CGContextRef> clippedSourceContext(AdoptCF, CGBitmapContextCreate(buffer.get(), csw, csh,
- 8, bytesPerRow, colorSpace.get(), kCGImageAlphaPremultipliedLast));
- CGContextTranslateCTM(clippedSourceContext.get(), -srcRect.x(), -srcRect.y());
- CGContextDrawImage(clippedSourceContext.get(), CGRectMake(0, 0, iw, ih), image.get());
-
- RetainPtr<CGImageRef> clippedSourceImage(AdoptCF, CGBitmapContextCreateImage(clippedSourceContext.get()));
-
- CGContextDrawImage(platformContext(), destRect, clippedSourceImage.get());
- }
-}
-
+
}
diff --git a/WebCore/platform/graphics/cg/ImageBufferCG.cpp b/WebCore/platform/graphics/cg/ImageBufferCG.cpp
index 7cb28e3..2d1ac01 100644
--- a/WebCore/platform/graphics/cg/ImageBufferCG.cpp
+++ b/WebCore/platform/graphics/cg/ImageBufferCG.cpp
@@ -1,6 +1,5 @@
/*
* Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
- * Copyright (C) 2008 Apple, Inc
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -28,7 +27,6 @@
#include "ImageBuffer.h"
#include "GraphicsContext.h"
-#include "ImageData.h"
#include <ApplicationServices/ApplicationServices.h>
#include <wtf/Assertions.h>
@@ -75,7 +73,6 @@ ImageBuffer::ImageBuffer(void* imageData, const IntSize& size, auto_ptr<Graphics
, m_context(context.release())
, m_cgImage(0)
{
- ASSERT((reinterpret_cast<size_t>(imageData) & 2) == 0);
}
ImageBuffer::~ImageBuffer()
@@ -101,113 +98,4 @@ CGImageRef ImageBuffer::cgImage() const
return m_cgImage;
}
-PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect& rect) const
-{
- if (!m_data)
- return 0;
-
- PassRefPtr<ImageData> result = ImageData::create(rect.width(), rect.height());
- unsigned char* data = result->data()->data().data();
-
- if (rect.x() < 0 || rect.y() < 0 || (rect.x() + rect.width()) > m_size.width() || (rect.y() + rect.height()) > m_size.height())
- memset(data, 0, result->data()->length());
-
- int originx = rect.x();
- int destx = 0;
- if (originx < 0) {
- destx = -originx;
- originx = 0;
- }
- int endx = rect.x() + rect.width();
- if (endx > m_size.width())
- endx = m_size.width();
- int numColumns = endx - originx;
-
- int originy = rect.y();
- int desty = 0;
- if (originy < 0) {
- desty = -originy;
- originy = 0;
- }
- int endy = rect.y() + rect.height();
- if (endy > m_size.height())
- endy = m_size.height();
- int numRows = endy - originy;
-
- unsigned srcBytesPerRow = 4 * m_size.width();
- unsigned destBytesPerRow = 4 * rect.width();
-
- // m_size.height() - originy to handle the accursed flipped y axis in CG backing store
- unsigned char* srcRows = reinterpret_cast<unsigned char*>(m_data) + (m_size.height() - originy - 1) * srcBytesPerRow + originx * 4;
- unsigned char* destRows = data + desty * destBytesPerRow + destx * 4;
- for (int y = 0; y < numRows; ++y) {
- for (int x = 0; x < numColumns; x++) {
- int basex = x * 4;
- if (unsigned char alpha = srcRows[basex + 3]) {
- destRows[0] = (srcRows[basex] * 255) / alpha;
- destRows[1] = (srcRows[basex + 1] * 255) / alpha;
- destRows[2] = (srcRows[basex + 2] * 255) / alpha;
- destRows[3] = alpha;
- } else {
- reinterpret_cast<uint32_t*>(destRows)[0] = reinterpret_cast<uint32_t*>(srcRows)[0];
- }
- destRows += 4;
- }
- srcRows -= srcBytesPerRow;
- }
- return result;
-}
-
-void ImageBuffer::putImageData(ImageData* source, const IntRect& sourceRect, const IntPoint& destPoint)
-{
- ASSERT(sourceRect.width() > 0);
- ASSERT(sourceRect.height() > 0);
-
- int originx = sourceRect.x();
- int destx = destPoint.x() + sourceRect.x();
- ASSERT(destx >= 0);
- ASSERT(destx < m_size.width());
- ASSERT(originx >= 0);
- ASSERT(originx <= sourceRect.right());
-
- int endx = destPoint.x() + sourceRect.right();
- ASSERT(endx <= m_size.width());
-
- int numColumns = endx - destx;
-
- int originy = sourceRect.y();
- int desty = destPoint.y() + sourceRect.y();
- ASSERT(desty >= 0);
- ASSERT(desty < m_size.height());
- ASSERT(originy >= 0);
- ASSERT(originy <= sourceRect.bottom());
-
- int endy = destPoint.y() + sourceRect.bottom();
- ASSERT(endy <= m_size.height());
- int numRows = endy - desty;
-
- unsigned srcBytesPerRow = 4 * source->width();
- unsigned destBytesPerRow = 4 * m_size.width();
-
- unsigned char* srcRows = source->data()->data().data() + originy * srcBytesPerRow + originx * 4;
-
- // -desty to handle the accursed flipped y axis
- unsigned char* destRows = reinterpret_cast<unsigned char*>(m_data) + (m_size.height() - desty - 1) * destBytesPerRow + destx * 4;
- for (int y = 0; y < numRows; ++y) {
- for (int x = 0; x < numColumns; x++) {
- unsigned char alpha = srcRows[x * 4 + 3];
- if (alpha != 255) {
- destRows[x * 4 + 0] = (srcRows[0] * alpha) / 255;
- destRows[x * 4 + 1] = (srcRows[1] * alpha) / 255;
- destRows[x * 4 + 2] = (srcRows[2] * alpha) / 255;
- destRows[x * 4 + 3] = alpha;
- } else {
- reinterpret_cast<uint32_t*>(destRows + x * 4)[0] = reinterpret_cast<uint32_t*>(srcRows + x * 4)[0];
- }
- }
- destRows -= destBytesPerRow;
- srcRows += srcBytesPerRow;
- }
-}
-
}
diff --git a/WebCore/platform/graphics/cg/ImageSourceCG.cpp b/WebCore/platform/graphics/cg/ImageSourceCG.cpp
index 08e8172..2bfc204 100644
--- a/WebCore/platform/graphics/cg/ImageSourceCG.cpp
+++ b/WebCore/platform/graphics/cg/ImageSourceCG.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004, 2005, 2006, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2004, 2005, 2006 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
@@ -25,17 +25,15 @@
#include "config.h"
#include "ImageSource.h"
+#include "SharedBuffer.h"
#if PLATFORM(CG)
#include "IntSize.h"
-#include "SharedBuffer.h"
#include <ApplicationServices/ApplicationServices.h>
namespace WebCore {
-static const CFStringRef kCGImageSourceShouldPreferRGB32 = CFSTR("kCGImageSourceShouldPreferRGB32");
-
ImageSource::ImageSource()
: m_decoder(0)
{
@@ -54,13 +52,15 @@ void ImageSource::clear()
}
}
+const CFStringRef kCGImageSourceShouldPreferRGB32 = CFSTR("kCGImageSourceShouldPreferRGB32");
+
CFDictionaryRef imageSourceOptions()
{
static CFDictionaryRef options;
if (!options) {
- const void* keys[2] = { kCGImageSourceShouldCache, kCGImageSourceShouldPreferRGB32 };
- const void* values[2] = { kCFBooleanTrue, kCFBooleanTrue };
+ const void *keys[2] = { kCGImageSourceShouldCache, kCGImageSourceShouldPreferRGB32 };
+ const void *values[2] = { kCFBooleanTrue, kCFBooleanTrue };
options = CFDictionaryCreate(NULL, keys, values, 2,
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
}
@@ -154,20 +154,7 @@ size_t ImageSource::frameCount() const
CGImageRef ImageSource::createFrameAtIndex(size_t index)
{
- CGImageRef image = CGImageSourceCreateImageAtIndex(m_decoder, index, imageSourceOptions());
- CFStringRef imageUTI = CGImageSourceGetType(m_decoder);
- static const CFStringRef xbmUTI = CFSTR("public.xbitmap-image");
- if (!imageUTI || !CFEqual(imageUTI, xbmUTI))
- return image;
-
- // If it is an xbm image, mask out all the white areas to render them transparent.
- const CGFloat maskingColors[6] = {255, 255, 255, 255, 255, 255};
- CGImageRef maskedImage = CGImageCreateWithMaskingColors(image, maskingColors);
- if (!maskedImage)
- return image;
-
- CGImageRelease(image);
- return maskedImage;
+ return CGImageSourceCreateImageAtIndex(m_decoder, index, imageSourceOptions());
}
bool ImageSource::frameIsCompleteAtIndex(size_t index)
diff --git a/WebCore/platform/graphics/gtk/FontGtk.cpp b/WebCore/platform/graphics/gtk/FontGtk.cpp
index 387b61c..5d50c6e 100644
--- a/WebCore/platform/graphics/gtk/FontGtk.cpp
+++ b/WebCore/platform/graphics/gtk/FontGtk.cpp
@@ -159,6 +159,34 @@ static void setPangoAttributes(const Font* font, const TextRun& run, PangoLayout
pango_context_set_base_dir(pangoContext, direction);
}
+void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer,
+ int from, int numGlyphs, const FloatPoint& point) const
+{
+ cairo_t* cr = graphicsContext->platformContext();
+ cairo_save(cr);
+
+ // Set the text color to use for drawing.
+ float red, green, blue, alpha;
+ Color penColor = graphicsContext->fillColor();
+ penColor.getRGBA(red, green, blue, alpha);
+ cairo_set_source_rgba(cr, red, green, blue, alpha);
+
+ font->setFont(cr);
+
+ GlyphBufferGlyph* glyphs = (GlyphBufferGlyph*)glyphBuffer.glyphs(from);
+
+ float offset = point.x();
+
+ for (int i = 0; i < numGlyphs; i++) {
+ glyphs[i].x = offset;
+ glyphs[i].y = point.y();
+ offset += glyphBuffer.advanceAt(from + i);
+ }
+ cairo_show_glyphs(cr, glyphs, numGlyphs);
+
+ cairo_restore(cr);
+}
+
void Font::drawComplexText(GraphicsContext* context, const TextRun& run, const FloatPoint& point, int from, int to) const
{
cairo_t* cr = context->platformContext();
diff --git a/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp b/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp
index b28146f..ef5cb4a 100644
--- a/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp
+++ b/WebCore/platform/graphics/gtk/FontPlatformDataGtk.cpp
@@ -42,7 +42,7 @@ FontPlatformData::FontPlatformData(const FontDescription& fontDescription, const
{
FontPlatformData::init();
- CString familyNameString = familyName.string().utf8();
+ CString familyNameString = familyName.domString().utf8();
const char* fcfamily = familyNameString.data();
int fcslant = FC_SLANT_ROMAN;
int fcweight = FC_WEIGHT_NORMAL;
diff --git a/WebCore/platform/graphics/gtk/IconGtk.cpp b/WebCore/platform/graphics/gtk/IconGtk.cpp
index a8e6536..c6e9a14 100644
--- a/WebCore/platform/graphics/gtk/IconGtk.cpp
+++ b/WebCore/platform/graphics/gtk/IconGtk.cpp
@@ -41,8 +41,7 @@
namespace WebCore {
Icon::Icon()
- : RefCounted<Icon>(0)
- , m_icon(0)
+ : m_icon(0)
{
notImplemented();
}
diff --git a/WebCore/platform/graphics/mac/IconMac.mm b/WebCore/platform/graphics/mac/IconMac.mm
index b630ba6..cda73a0 100644
--- a/WebCore/platform/graphics/mac/IconMac.mm
+++ b/WebCore/platform/graphics/mac/IconMac.mm
@@ -29,13 +29,11 @@
namespace WebCore {
Icon::Icon()
- : RefCounted<Icon>(0)
{
}
Icon::Icon(NSImage *image)
- : RefCounted<Icon>(0)
- , m_nsImage(image)
+ : m_nsImage(image)
{
// Need this because WebCore uses AppKit's flipped coordinate system exclusively.
[image setFlipped:YES];
diff --git a/WebCore/platform/graphics/mac/ImageMac.mm b/WebCore/platform/graphics/mac/ImageMac.mm
index 121eb78..0b14d71 100644
--- a/WebCore/platform/graphics/mac/ImageMac.mm
+++ b/WebCore/platform/graphics/mac/ImageMac.mm
@@ -31,6 +31,7 @@
#import "GraphicsContext.h"
#import "PlatformString.h"
#import "WebCoreFrameBridge.h"
+#import "WebCoreSystemInterface.h"
namespace WebCore {
diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm
index 541d5f6..85c7a9e 100644
--- a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm
+++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -163,12 +163,11 @@ void MediaPlayerPrivate::createQTMovie(const String& url)
m_qtMovie = 0;
// Disable streaming support for now, <rdar://problem/5693967>
- if (protocolIs(url, "rtsp"))
+ if (url.startsWith("rtsp:"))
return;
-
- NSURL *cocoaURL = KURL(url);
- NSDictionary *movieAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
- cocoaURL, QTMovieURLAttribute,
+
+ NSDictionary* movieAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
+ KURL(url.deprecatedString()).getNSURL(), QTMovieURLAttribute,
[NSNumber numberWithBool:YES], QTMoviePreventExternalURLLinksAttribute,
[NSNumber numberWithBool:YES], QTSecurityPolicyNoCrossSiteAttribute,
nil];
@@ -177,7 +176,7 @@ void MediaPlayerPrivate::createQTMovie(const String& url)
m_qtMovie.adoptNS([[QTMovie alloc] initWithAttributes:movieAttributes error:&error]);
// FIXME: Find a proper way to detect streaming content.
- m_isStreaming = protocolIs(url, "rtsp");
+ m_isStreaming = url.startsWith("rtsp:");
if (!m_qtMovie)
return;
diff --git a/WebCore/platform/graphics/mac/SimpleFontDataMac.mm b/WebCore/platform/graphics/mac/SimpleFontDataMac.mm
index 5d90514..1f45c94 100644
--- a/WebCore/platform/graphics/mac/SimpleFontDataMac.mm
+++ b/WebCore/platform/graphics/mac/SimpleFontDataMac.mm
@@ -62,7 +62,7 @@ bool initFontData(SimpleFontData* fontData)
ATSUStyle fontStyle;
if (ATSUCreateStyle(&fontStyle) != noErr)
return false;
-
+
ATSUFontID fontId = fontData->m_font.m_atsuFontID;
if (!fontId) {
ATSUDisposeStyle(fontStyle);
@@ -96,45 +96,6 @@ static NSString *webFallbackFontFamily(void)
return webFallbackFontFamily.get();
}
-#if !ERROR_DISABLED
-#ifdef __LP64__
-static NSString* pathFromFont(NSFont*)
-{
- // FMGetATSFontRefFromFont is not available in 64-bit. As pathFromFont is only used for debugging
- // purposes, returning nil is acceptable.
- return nil;
-}
-#else
-static NSString* pathFromFont(NSFont *font)
-{
- ATSFontRef atsFont = FMGetATSFontRefFromFont(wkGetNSFontATSUFontId(font));
- FSRef fileRef;
-
-#ifndef BUILDING_ON_TIGER
- OSStatus status = ATSFontGetFileReference(atsFont, &fileRef);
- if (status != noErr)
- return nil;
-#else
- FSSpec oFile;
- OSStatus status = ATSFontGetFileSpecification(atsFont, &oFile);
- if (status != noErr)
- return nil;
-
- status = FSpMakeFSRef(&oFile, &fileRef);
- if (status != noErr)
- return nil;
-#endif
-
- UInt8 filePathBuffer[PATH_MAX];
- status = FSRefMakePath(&fileRef, filePathBuffer, PATH_MAX);
- if (status == noErr)
- return [NSString stringWithUTF8String:(const char*)filePathBuffer];
-
- return nil;
-}
-#endif // __LP64__
-#endif // !ERROR_DISABLED
-
void SimpleFontData::platformInit()
{
m_styleGroup = 0;
@@ -167,7 +128,7 @@ void SimpleFontData::platformInit()
#endif
m_font.setFont([[NSFontManager sharedFontManager] convertFont:m_font.font() toFamily:fallbackFontFamily]);
#if !ERROR_DISABLED
- NSString *filePath = pathFromFont(initialFont.get());
+ NSString *filePath = wkPathFromFont(initialFont.get());
if (!filePath)
filePath = @"not known";
#endif
@@ -204,15 +165,7 @@ void SimpleFontData::platformInit()
int iAscent;
int iDescent;
int iLineGap;
-#ifdef BUILDING_ON_TIGER
- wkGetFontMetrics(m_font.m_cgFont, &iAscent, &iDescent, &iLineGap, &m_unitsPerEm);
-#else
- iAscent = CGFontGetAscent(m_font.m_cgFont);
- iDescent = CGFontGetDescent(m_font.m_cgFont);
- iLineGap = CGFontGetLeading(m_font.m_cgFont);
- m_unitsPerEm = CGFontGetUnitsPerEm(m_font.m_cgFont);
-#endif
-
+ wkGetFontMetrics(m_font.m_cgFont, &iAscent, &iDescent, &iLineGap, &m_unitsPerEm);
float pointSize = m_font.m_size;
float fAscent = scaleEmToUnits(iAscent, m_unitsPerEm) * pointSize;
float fDescent = -scaleEmToUnits(iDescent, m_unitsPerEm) * pointSize;
diff --git a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
index ec35d96..cf097c8 100644
--- a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
+++ b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
@@ -36,7 +36,6 @@
#include "Path.h"
#include "Color.h"
#include "GraphicsContext.h"
-#include "ImageBuffer.h"
#include "Font.h"
#include "Pen.h"
#include "NotImplemented.h"
@@ -46,7 +45,6 @@
#include <QPolygonF>
#include <QPainterPath>
#include <QPaintDevice>
-#include <QPixmap>
#include <QDebug>
#ifndef M_PI
@@ -907,37 +905,6 @@ void GraphicsContext::setUseAntialiasing(bool enable)
m_data->p()->setRenderHint(QPainter::Antialiasing, enable);
}
-void GraphicsContext::paintBuffer(ImageBuffer* buffer, const IntRect& r)
-{
- if (paintingDisabled())
- return;
- QPixmap pixmap = *buffer->pixmap();
- if (pixmap.isNull())
- return;
- QPainter* painter = platformContext();
- QPen currentPen = painter->pen();
- qreal currentOpacity = painter->opacity();
- QBrush currentBrush = painter->brush();
- QBrush currentBackground = painter->background();
- if (painter->isActive())
- painter->end();
- static_cast<QPainter*>(painter)->drawPixmap(r, pixmap);
- painter->begin(&pixmap);
- painter->setPen(currentPen);
- painter->setBrush(currentBrush);
- painter->setOpacity(currentOpacity);
- painter->setBackground(currentBackground);
-}
-
-void GraphicsContext::drawImage(ImageBuffer* buffer, const FloatRect& srcRect, const FloatRect& dstRect)
-{
- QPainter* painter = static_cast<QPainter*>(platformContext());
- QPixmap px = *buffer->pixmap();
- if (px.isNull())
- return;
- painter->drawPixmap(dstRect, px, srcRect);
-}
-
}
// vim: ts=4 sw=4 et
diff --git a/WebCore/platform/graphics/qt/IconQt.cpp b/WebCore/platform/graphics/qt/IconQt.cpp
index c9c900b..e39d161 100644
--- a/WebCore/platform/graphics/qt/IconQt.cpp
+++ b/WebCore/platform/graphics/qt/IconQt.cpp
@@ -22,6 +22,7 @@
#include "Icon.h"
#include "GraphicsContext.h"
+#include "DeprecatedString.h"
#include "PlatformString.h"
#include "IntRect.h"
#include "NotImplemented.h"
@@ -34,7 +35,6 @@
namespace WebCore {
Icon::Icon()
- : RefCounted<Icon>(0)
{
}
diff --git a/WebCore/platform/graphics/qt/ImageBufferQt.cpp b/WebCore/platform/graphics/qt/ImageBufferQt.cpp
index 449677e..c95d8c8 100644
--- a/WebCore/platform/graphics/qt/ImageBufferQt.cpp
+++ b/WebCore/platform/graphics/qt/ImageBufferQt.cpp
@@ -27,8 +27,6 @@
#include "ImageBuffer.h"
#include "GraphicsContext.h"
-#include "ImageData.h"
-#include "NotImplemented.h"
#include <QPainter>
#include <QPixmap>
@@ -71,15 +69,4 @@ QPixmap* ImageBuffer::pixmap() const
return &m_pixmap;
}
-PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect&) const
-{
- notImplemented();
- return 0;
-}
-
-void ImageBuffer::putImageData(ImageData*, const IntRect&, const IntPoint&)
-{
- notImplemented();
-}
-
}
diff --git a/WebCore/platform/graphics/win/FontCacheWin.cpp b/WebCore/platform/graphics/win/FontCacheWin.cpp
index 1ee6818..502863b 100644
--- a/WebCore/platform/graphics/win/FontCacheWin.cpp
+++ b/WebCore/platform/graphics/win/FontCacheWin.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -35,10 +35,8 @@
#include "UnicodeRange.h"
#include <windows.h>
#include <mlang.h>
-#if PLATFORM(CG)
#include <ApplicationServices/ApplicationServices.h>
#include <WebKitSystemInterface/WebKitSystemInterface.h>
-#endif
using std::min;
@@ -47,9 +45,7 @@ namespace WebCore
void FontCache::platformInit()
{
-#if PLATFORM(CG)
wkSetUpFontCache(1536 * 1024 * 4); // This size matches Mac.
-#endif
}
IMLangFontLink2* FontCache::getFontLinkInterface()
@@ -418,14 +414,7 @@ FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD
FontPlatformData* result = new FontPlatformData(hfont, fontDescription.computedPixelSize(),
fontDescription.bold(), fontDescription.italic(), useGDI);
-
-#if PLATFORM(CG)
- bool fontCreationFailed = !result->cgFont();
-#elif PLATFORM(CAIRO)
- bool fontCreationFailed = !result->fontFace();
-#endif
-
- if (fontCreationFailed) {
+ if (!result->cgFont()) {
// The creation of the CGFontRef failed for some reason. We already asserted in debug builds, but to make
// absolutely sure that we don't use this font, go ahead and return 0 so that we can fall back to the next
// font.
diff --git a/WebCore/platform/wx/wxcode/non-kerned-drawing.h b/WebCore/platform/graphics/win/FontCairoWin.cpp
index d005985..302e79d 100644
--- a/WebCore/platform/wx/wxcode/non-kerned-drawing.h
+++ b/WebCore/platform/graphics/win/FontCairoWin.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Kevin Watters, Kevin Ollivier. All rights reserved.
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -20,17 +20,23 @@
* 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.
- */
-
-#include "Font.h"
-#include "GlyphBuffer.h"
-
-#include <wx/defs.h>
-#include <wx/dcclient.h>
-
-namespace WebCore {
-
-extern void drawTextWithSpacing(GraphicsContext* graphicsContext, const SimpleFontData* font, const wxColour& color, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point);
-
-}
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Font.h"
+
+#include "GlyphBuffer.h"
+#include "GraphicsContext.h"
+#include "NotImplemented.h"
+#include "SimpleFontData.h"
+
+namespace WebCore {
+
+void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* font, const GlyphBuffer& glyphBuffer,
+ int from, int numGlyphs, const FloatPoint& point) const
+{
+ notImplemented();
+}
+
+}
diff --git a/WebCore/platform/graphics/win/FontCustomPlatformData.h b/WebCore/platform/graphics/win/FontCustomPlatformData.h
index 909b79e..9f30424 100644
--- a/WebCore/platform/graphics/win/FontCustomPlatformData.h
+++ b/WebCore/platform/graphics/win/FontCustomPlatformData.h
@@ -32,9 +32,8 @@ class SharedBuffer;
struct FontCustomPlatformData : Noncopyable {
FontCustomPlatformData(CGFontRef cgFont)
- : m_cgFont(cgFont)
- {
- }
+ : m_cgFont(cgFont)
+ {}
~FontCustomPlatformData();
FontPlatformData fontPlatformData(int size, bool bold, bool italic);
@@ -42,7 +41,7 @@ struct FontCustomPlatformData : Noncopyable {
CGFontRef m_cgFont;
};
-FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer*);
+FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer);
}
diff --git a/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.cpp b/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.cpp
deleted file mode 100644
index e54d85a..0000000
--- a/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.cpp
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2007, 2008 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
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#include "config.h"
-#include "FontCustomPlatformDataCairo.h"
-
-#include "SharedBuffer.h"
-#include "FontPlatformData.h"
-#include <wtf/RetainPtr.h>
-
-namespace WebCore {
-
-FontCustomPlatformDataCairo::~FontCustomPlatformDataCairo()
-{
- cairo_font_face_destroy(m_fontFace);
-}
-
-FontPlatformData FontCustomPlatformDataCairo::fontPlatformData(int size, bool bold, bool italic)
-{
- return FontPlatformData(m_fontFace, size, bold, italic);
-}
-
-static void releaseData(void* data)
-{
- static_cast<SharedBuffer*>(data)->deref();
-}
-
-FontCustomPlatformDataCairo* createFontCustomPlatformData(SharedBuffer* buffer)
-{
- ASSERT_ARG(buffer, buffer);
-
- buffer->ref();
- HFONT font = reinterpret_cast<HFONT>(buffer);
- cairo_font_face_t* fontFace = cairo_win32_font_face_create_for_hfont(font);
- if (!fontFace)
- return 0;
-
- static cairo_user_data_key_t bufferKey;
- cairo_font_face_set_user_data(fontFace, &bufferKey, buffer, releaseData);
-
- return new FontCustomPlatformDataCairo(fontFace);
-}
-
-}
diff --git a/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.h b/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.h
deleted file mode 100644
index 87794b5..0000000
--- a/WebCore/platform/graphics/win/FontCustomPlatformDataCairo.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2007 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
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef FontCustomPlatformDataCairo_h
-#define FontCustomPlatformDataCairo_h
-
-#include <wtf/Noncopyable.h>
-
-#include <cairo.h>
-
-namespace WebCore {
-
-class FontPlatformData;
-class SharedBuffer;
-
-struct FontCustomPlatformDataCairo : Noncopyable {
- FontCustomPlatformDataCairo(cairo_font_face_t* fontFace)
- : m_fontFace(fontFace)
- {
- }
- ~FontCustomPlatformDataCairo();
-
- FontPlatformData fontPlatformData(int size, bool bold, bool italic);
-
- cairo_font_face_t* m_fontFace;
-};
-
-FontCustomPlatformDataCairo* createFontCustomPlatformData(SharedBuffer*);
-
-}
-
-#endif
diff --git a/WebCore/platform/graphics/win/FontPlatformData.h b/WebCore/platform/graphics/win/FontPlatformData.h
index 5bbda2f..15d23cd 100644
--- a/WebCore/platform/graphics/win/FontPlatformData.h
+++ b/WebCore/platform/graphics/win/FontPlatformData.h
@@ -2,7 +2,7 @@
* This file is part of the internal font implementation. It should not be included by anyone other than
* FontMac.cpp, FontWin.cpp and Font.cpp.
*
- * Copyright (C) 2006, 2007, 2008 Apple Inc.
+ * Copyright (C) 2006, 2007 Apple Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -26,12 +26,8 @@
#include "StringImpl.h"
-#if PLATFORM(CAIRO)
-#include <cairo-win32.h>
-#endif
-
-typedef struct HFONT__* HFONT;
-typedef struct CGFont* CGFontRef;
+typedef struct HFONT__ *HFONT;
+typedef struct CGFont *CGFontRef;
namespace WebCore {
@@ -44,53 +40,30 @@ public:
// Used for deleted values in the font cache's hash tables.
FontPlatformData(Deleted)
- : m_font((HFONT)-1)
-#if PLATFORM(CG)
- , m_cgFont(0)
-#elif PLATFORM(CAIRO)
- , m_fontFace(0)
-#endif
- , m_size(0)
- , m_syntheticBold(false)
- , m_syntheticOblique(false)
- , m_useGDI(false)
- {
- }
+ : m_font((HFONT)-1)
+ , m_cgFont(NULL)
+ , m_size(0)
+ , m_syntheticBold(false)
+ , m_syntheticOblique(false)
+ , m_useGDI(false)
+ {}
FontPlatformData()
- : m_font(0)
-#if PLATFORM(CG)
- , m_cgFont(0)
-#elif PLATFORM(CAIRO)
- , m_fontFace(0)
-#endif
- , m_size(0)
- , m_syntheticBold(false)
- , m_syntheticOblique(false)
- , m_useGDI(false)
- {
- }
+ : m_font(0)
+ , m_cgFont(NULL)
+ , m_size(0)
+ , m_syntheticBold(false)
+ , m_syntheticOblique(false)
+ , m_useGDI(false)
+ {}
FontPlatformData(HFONT, float size, bool bold, bool oblique, bool useGDI);
FontPlatformData(float size, bool bold, bool oblique);
-
-#if PLATFORM(CG)
FontPlatformData(CGFontRef, float size, bool bold, bool oblique);
-#elif PLATFORM(CAIRO)
- FontPlatformData(cairo_font_face_t*, float size, bool bold, bool oblique);
-#endif
~FontPlatformData();
- void platformDataInit(HFONT font, float size, HDC hdc, WCHAR* faceName);
-
HFONT hfont() const { return m_font; }
-#if PLATFORM(CG)
CGFontRef cgFont() const { return m_cgFont; }
-#elif PLATFORM(CAIRO)
- void setFont(cairo_t* ft) const;
- cairo_font_face_t* fontFace() const { return m_fontFace; }
- cairo_scaled_font_t* scaledFont() const { return m_scaledFont; }
-#endif
float size() const { return m_size; }
void setSize(float size) { m_size = size; }
@@ -105,26 +78,14 @@ public:
bool operator==(const FontPlatformData& other) const
{
- return m_font == other.m_font &&
-#if PLATFORM(CG)
- m_cgFont == other.m_cgFont &&
-#elif PLATFORM(CAIRO)
- m_fontFace == other.m_fontFace &&
- m_scaledFont == other.m_scaledFont &&
-#endif
- m_size == other.m_size &&
+ return m_font == other.m_font && m_cgFont ==other.m_cgFont && m_size == other.m_size &&
m_syntheticBold == other.m_syntheticBold && m_syntheticOblique == other.m_syntheticOblique &&
m_useGDI == other.m_useGDI;
}
private:
HFONT m_font;
-#if PLATFORM(CG)
CGFontRef m_cgFont;
-#elif PLATFORM(CAIRO)
- cairo_font_face_t* m_fontFace;
- cairo_scaled_font_t* m_scaledFont;
-#endif
float m_size;
bool m_syntheticBold;
diff --git a/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp b/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp
deleted file mode 100644
index ddd3104..0000000
--- a/WebCore/platform/graphics/win/FontPlatformDataCGWin.cpp
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * This file is part of the internal font implementation. It should not be included by anyone other than
- * FontMac.cpp, FontWin.cpp and Font.cpp.
- *
- * Copyright (C) 2006, 2007, 2008 Apple Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#include "config.h"
-#include "FontPlatformData.h"
-
-#include "PlatformString.h"
-#include "StringHash.h"
-#include <ApplicationServices/ApplicationServices.h>
-#include <wtf/HashMap.h>
-#include <wtf/RetainPtr.h>
-#include <wtf/Vector.h>
-
-using std::min;
-
-namespace WebCore {
-
-static inline USHORT readBigEndianWord(const BYTE* word) { return (word[0] << 8) | word[1]; }
-
-static CFStringRef getPostScriptName(CFStringRef faceName, HDC dc)
-{
- const DWORD cMaxNameTableSize = 1024 * 1024;
-
- static HashMap<String, RetainPtr<CFStringRef> > nameMap;
-
- // Check our hash first.
- String faceString(faceName);
- RetainPtr<CFStringRef> result = nameMap.get(faceString);
- if (result)
- return result.get();
-
- // We need to obtain the PostScript name from the name table and use it instead,.
- DWORD bufferSize = GetFontData(dc, 'eman', 0, NULL, 0); // "name" backwards
- if (bufferSize == 0 || bufferSize == GDI_ERROR || bufferSize > cMaxNameTableSize)
- return NULL;
-
- Vector<BYTE> bufferVector(bufferSize);
- BYTE* buffer = bufferVector.data();
- if (GetFontData(dc, 'eman', 0, buffer, bufferSize) == GDI_ERROR)
- return NULL;
-
- if (bufferSize < 6)
- return NULL;
-
- USHORT numberOfRecords = readBigEndianWord(buffer + 2);
- UINT stringsOffset = readBigEndianWord(buffer + 4);
- if (bufferSize < stringsOffset)
- return NULL;
-
- BYTE* strings = buffer + stringsOffset;
-
- // Now walk each name record looking for a Mac or Windows PostScript name.
- UINT offset = 6;
- for (int i = 0; i < numberOfRecords; i++) {
- if (bufferSize < offset + 12)
- return NULL;
-
- USHORT platformID = readBigEndianWord(buffer + offset);
- USHORT encodingID = readBigEndianWord(buffer + offset + 2);
- USHORT languageID = readBigEndianWord(buffer + offset + 4);
- USHORT nameID = readBigEndianWord(buffer + offset + 6);
- USHORT length = readBigEndianWord(buffer + offset + 8);
- USHORT nameOffset = readBigEndianWord(buffer + offset + 10);
-
- if (platformID == 3 && encodingID == 1 && languageID == 0x409 && nameID == 6) {
- // This is a Windows PostScript name and is therefore UTF-16.
- // Pass Big Endian as the encoding.
- if (bufferSize < stringsOffset + nameOffset + length)
- return NULL;
- result.adoptCF(CFStringCreateWithBytes(NULL, strings + nameOffset, length, kCFStringEncodingUTF16BE, false));
- break;
- } else if (platformID == 1 && encodingID == 0 && languageID == 0 && nameID == 6) {
- // This is a Mac PostScript name and is therefore ASCII.
- // See http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html
- if (bufferSize < stringsOffset + nameOffset + length)
- return NULL;
- result.adoptCF(CFStringCreateWithBytes(NULL, strings + nameOffset, length, kCFStringEncodingASCII, false));
- break;
- }
-
- offset += 12;
- }
-
- if (result)
- nameMap.set(faceString, result);
- return result.get();
-}
-
-void FontPlatformData::platformDataInit(HFONT font, float size, HDC hdc, WCHAR* faceName)
-{
- // Try the face name first. Windows may end up localizing this name, and CG doesn't know about
- // the localization. If the create fails, we'll try the PostScript name.
- RetainPtr<CFStringRef> fullName(AdoptCF, CFStringCreateWithCharacters(NULL, (const UniChar*)faceName, wcslen(faceName)));
- m_cgFont = CGFontCreateWithFontName(fullName.get());
- if (!m_cgFont) {
- CFStringRef postScriptName = getPostScriptName(fullName.get(), hdc);
- if (postScriptName) {
- m_cgFont = CGFontCreateWithFontName(postScriptName);
- ASSERT(m_cgFont);
- }
- }
-}
-
-FontPlatformData::FontPlatformData(CGFontRef font, float size, bool bold, bool oblique)
- : m_font(0)
- , m_size(size)
- , m_cgFont(font)
- , m_syntheticBold(bold)
- , m_syntheticOblique(oblique)
- , m_useGDI(false)
-{
-}
-
-}
diff --git a/WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp b/WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp
deleted file mode 100644
index 438d0a9..0000000
--- a/WebCore/platform/graphics/win/FontPlatformDataCairoWin.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * This file is part of the internal font implementation. It should not be included by anyone other than
- * FontMac.cpp, FontWin.cpp and Font.cpp.
- *
- * Copyright (C) 2006, 2007, 2008 Apple Inc.
- * Copyright (C) 2007 Alp Toker
- * Copyright (C) 2008 Brent Fulgham
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#include "config.h"
-#include "FontPlatformData.h"
-
-#include "PlatformString.h"
-#include "StringHash.h"
-#include <wtf/HashMap.h>
-#include <wtf/RetainPtr.h>
-#include <wtf/Vector.h>
-
-#include <cairo-win32.h>
-
-using std::min;
-
-namespace WebCore {
-
-void FontPlatformData::platformDataInit(HFONT font, float size, HDC hdc, WCHAR* faceName)
-{
- m_fontFace = cairo_win32_font_face_create_for_hfont(font);
- cairo_matrix_t sizeMatrix, ctm;
- cairo_matrix_init_identity(&ctm);
- cairo_matrix_init_scale(&sizeMatrix, size, size);
-
- static cairo_font_options_t* fontOptions = 0;
- if (!fontOptions)
- {
- fontOptions = cairo_font_options_create();
- cairo_font_options_set_antialias(fontOptions, CAIRO_ANTIALIAS_SUBPIXEL);
- }
-
- m_scaledFont = cairo_scaled_font_create(m_fontFace, &sizeMatrix, &ctm, fontOptions);
-}
-
-FontPlatformData::FontPlatformData(cairo_font_face_t* fontFace, float size, bool bold, bool oblique)
- : m_font(0)
- , m_size(size)
- , m_fontFace(fontFace)
- , m_scaledFont(0)
- , m_syntheticBold(bold)
- , m_syntheticOblique(oblique)
- , m_useGDI(false)
-{
- cairo_matrix_t fontMatrix;
- cairo_matrix_init_scale(&fontMatrix, size, size);
- cairo_matrix_t ctm;
- cairo_matrix_init_identity(&ctm);
- cairo_font_options_t* options = cairo_font_options_create();
-
- // We force antialiasing and disable hinting to provide consistent
- // typographic qualities for custom fonts on all platforms.
- cairo_font_options_set_hint_style(options, CAIRO_HINT_STYLE_NONE);
- cairo_font_options_set_antialias(options, CAIRO_ANTIALIAS_GRAY);
-
- m_scaledFont = cairo_scaled_font_create(fontFace, &fontMatrix, &ctm, options);
- cairo_font_options_destroy(options);
-}
-
-void FontPlatformData::setFont(cairo_t* cr) const
-{
- ASSERT(m_scaledFont);
-
- cairo_set_scaled_font(cr, m_scaledFont);
-}
-
-}
diff --git a/WebCore/platform/graphics/win/FontPlatformDataWin.cpp b/WebCore/platform/graphics/win/FontPlatformDataWin.cpp
index f209dbf..a5fab36 100644
--- a/WebCore/platform/graphics/win/FontPlatformDataWin.cpp
+++ b/WebCore/platform/graphics/win/FontPlatformDataWin.cpp
@@ -2,8 +2,7 @@
* This file is part of the internal font implementation. It should not be included by anyone other than
* FontMac.cpp, FontWin.cpp and Font.cpp.
*
- * Copyright (C) 2006, 2007, 2008 Apple Inc.
- * Copyright (C) 2008 Brent Fulgham
+ * Copyright (C) 2006, 2007 Apple Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -27,6 +26,7 @@
#include "PlatformString.h"
#include "StringHash.h"
+#include <ApplicationServices/ApplicationServices.h>
#include <wtf/HashMap.h>
#include <wtf/RetainPtr.h>
#include <wtf/Vector.h>
@@ -39,6 +39,77 @@ static const int Bold = (1 << 0);
static const int Italic = (1 << 1);
static const int BoldOblique = (1 << 2);
+static inline USHORT readBigEndianWord(const BYTE* word) { return (word[0] << 8) | word[1]; }
+
+static CFStringRef getPostScriptName(CFStringRef faceName, HDC dc)
+{
+ const DWORD cMaxNameTableSize = 1024 * 1024;
+
+ static HashMap<String, RetainPtr<CFStringRef> > nameMap;
+
+ // Check our hash first.
+ String faceString(faceName);
+ RetainPtr<CFStringRef> result = nameMap.get(faceString);
+ if (result)
+ return result.get();
+
+ // We need to obtain the PostScript name from the name table and use it instead,.
+ DWORD bufferSize = GetFontData(dc, 'eman', 0, NULL, 0); // "name" backwards
+ if (bufferSize == 0 || bufferSize == GDI_ERROR || bufferSize > cMaxNameTableSize)
+ return NULL;
+
+ Vector<BYTE> bufferVector(bufferSize);
+ BYTE* buffer = bufferVector.data();
+ if (GetFontData(dc, 'eman', 0, buffer, bufferSize) == GDI_ERROR)
+ return NULL;
+
+ if (bufferSize < 6)
+ return NULL;
+
+ USHORT numberOfRecords = readBigEndianWord(buffer + 2);
+ UINT stringsOffset = readBigEndianWord(buffer + 4);
+ if (bufferSize < stringsOffset)
+ return NULL;
+
+ BYTE* strings = buffer + stringsOffset;
+
+ // Now walk each name record looking for a Mac or Windows PostScript name.
+ UINT offset = 6;
+ for (int i = 0; i < numberOfRecords; i++) {
+ if (bufferSize < offset + 12)
+ return NULL;
+
+ USHORT platformID = readBigEndianWord(buffer + offset);
+ USHORT encodingID = readBigEndianWord(buffer + offset + 2);
+ USHORT languageID = readBigEndianWord(buffer + offset + 4);
+ USHORT nameID = readBigEndianWord(buffer + offset + 6);
+ USHORT length = readBigEndianWord(buffer + offset + 8);
+ USHORT nameOffset = readBigEndianWord(buffer + offset + 10);
+
+ if (platformID == 3 && encodingID == 1 && languageID == 0x409 && nameID == 6) {
+ // This is a Windows PostScript name and is therefore UTF-16.
+ // Pass Big Endian as the encoding.
+ if (bufferSize < stringsOffset + nameOffset + length)
+ return NULL;
+ result.adoptCF(CFStringCreateWithBytes(NULL, strings + nameOffset, length, kCFStringEncodingUTF16BE, false));
+ break;
+ } else if (platformID == 1 && encodingID == 0 && languageID == 0 && nameID == 6) {
+ // This is a Mac PostScript name and is therefore ASCII.
+ // See http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html
+ if (bufferSize < stringsOffset + nameOffset + length)
+ return NULL;
+ result.adoptCF(CFStringCreateWithBytes(NULL, strings + nameOffset, length, kCFStringEncodingASCII, false));
+ break;
+ }
+
+ offset += 12;
+ }
+
+ if (result)
+ nameMap.set(faceString, result);
+ return result.get();
+}
+
static int CALLBACK enumStylesCallback(const LOGFONT* logFont, const TEXTMETRIC* metrics, DWORD fontType, LPARAM lParam)
{
int *style = reinterpret_cast<int*>(lParam);
@@ -60,12 +131,7 @@ static int CALLBACK enumStylesCallback(const LOGFONT* logFont, const TEXTMETRIC*
FontPlatformData::FontPlatformData(HFONT font, float size, bool bold, bool oblique, bool useGDI)
: m_font(font)
, m_size(size)
-#if PLATFORM(CG)
, m_cgFont(0)
-#elif PLATFORM(CAIRO)
- , m_fontFace(0)
- , m_scaledFont(0)
-#endif
, m_syntheticBold(false)
, m_syntheticOblique(false)
, m_useGDI(useGDI)
@@ -113,8 +179,17 @@ FontPlatformData::FontPlatformData(HFONT font, float size, bool bold, bool obliq
m_syntheticOblique = true;
}
- platformDataInit(font, size, hdc, faceName);
-
+ // Try the face name first. Windows may end up localizing this name, and CG doesn't know about
+ // the localization. If the create fails, we'll try the PostScript name.
+ RetainPtr<CFStringRef> fullName(AdoptCF, CFStringCreateWithCharacters(NULL, (const UniChar*)faceName, wcslen(faceName)));
+ m_cgFont = CGFontCreateWithFontName(fullName.get());
+ if (!m_cgFont) {
+ CFStringRef postScriptName = getPostScriptName(fullName.get(), hdc);
+ if (postScriptName) {
+ m_cgFont = CGFontCreateWithFontName(postScriptName);
+ ASSERT(m_cgFont);
+ }
+ }
free(metrics);
}
@@ -125,12 +200,17 @@ FontPlatformData::FontPlatformData(HFONT font, float size, bool bold, bool obliq
FontPlatformData::FontPlatformData(float size, bool bold, bool oblique)
: m_font(0)
, m_size(size)
-#if PLATFORM(CG)
, m_cgFont(0)
-#elif PLATFORM(CAIRO)
- , m_fontFace(0)
- , m_scaledFont(0)
-#endif
+ , m_syntheticBold(bold)
+ , m_syntheticOblique(oblique)
+ , m_useGDI(false)
+{
+}
+
+FontPlatformData::FontPlatformData(CGFontRef font, float size, bool bold, bool oblique)
+ : m_font(0)
+ , m_size(size)
+ , m_cgFont(font)
, m_syntheticBold(bold)
, m_syntheticOblique(oblique)
, m_useGDI(false)
diff --git a/WebCore/platform/graphics/win/GlyphPageTreeNodeCGWin.cpp b/WebCore/platform/graphics/win/GlyphPageTreeNodeWin.cpp
index c11fc1b..23b756c 100644
--- a/WebCore/platform/graphics/win/GlyphPageTreeNodeCGWin.cpp
+++ b/WebCore/platform/graphics/win/GlyphPageTreeNodeWin.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -36,9 +36,9 @@ namespace WebCore {
bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData)
{
- // bufferLength will be greater than the requested number of glyphs if the buffer contains surrogate pairs.
+ // The bufferLength will be greater than the glyph page size if the buffer has Unicode supplementary characters.
// We won't support this for now.
- if (bufferLength > length)
+ if (bufferLength > GlyphPage::size)
return false;
bool haveGlyphs = false;
diff --git a/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp
index 99d528d..58829b5 100644
--- a/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp
+++ b/WebCore/platform/graphics/win/GraphicsContextCGWin.cpp
@@ -168,6 +168,77 @@ void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, boo
m_data->restore();
}
+void GraphicsContextPlatformPrivate::save()
+{
+ if (!m_hdc)
+ return;
+ SaveDC(m_hdc);
+}
+
+void GraphicsContextPlatformPrivate::restore()
+{
+ if (!m_hdc)
+ return;
+ RestoreDC(m_hdc, -1);
+}
+
+void GraphicsContextPlatformPrivate::clip(const IntRect& clipRect)
+{
+ if (!m_hdc)
+ return;
+ IntersectClipRect(m_hdc, clipRect.x(), clipRect.y(), clipRect.right(), clipRect.bottom());
+}
+
+void GraphicsContextPlatformPrivate::clip(const Path&)
+{
+ notImplemented();
+}
+
+void GraphicsContextPlatformPrivate::scale(const FloatSize& size)
+{
+ if (!m_hdc)
+ return;
+ XFORM xform;
+ xform.eM11 = size.width();
+ xform.eM12 = 0.0f;
+ xform.eM21 = 0.0f;
+ xform.eM22 = size.height();
+ xform.eDx = 0.0f;
+ xform.eDy = 0.0f;
+ ModifyWorldTransform(m_hdc, &xform, MWT_LEFTMULTIPLY);
+}
+
+static const double deg2rad = 0.017453292519943295769; // pi/180
+
+void GraphicsContextPlatformPrivate::rotate(float degreesAngle)
+{
+ float radiansAngle = degreesAngle * deg2rad;
+ float cosAngle = cosf(radiansAngle);
+ float sinAngle = sinf(radiansAngle);
+ XFORM xform;
+ xform.eM11 = cosAngle;
+ xform.eM12 = -sinAngle;
+ xform.eM21 = sinAngle;
+ xform.eM22 = cosAngle;
+ xform.eDx = 0.0f;
+ xform.eDy = 0.0f;
+ ModifyWorldTransform(m_hdc, &xform, MWT_LEFTMULTIPLY);
+}
+
+void GraphicsContextPlatformPrivate::translate(float x , float y)
+{
+ if (!m_hdc)
+ return;
+ XFORM xform;
+ xform.eM11 = 1.0f;
+ xform.eM12 = 0.0f;
+ xform.eM21 = 0.0f;
+ xform.eM22 = 1.0f;
+ xform.eDx = x;
+ xform.eDy = y;
+ ModifyWorldTransform(m_hdc, &xform, MWT_LEFTMULTIPLY);
+}
+
void GraphicsContextPlatformPrivate::concatCTM(const AffineTransform& transform)
{
if (!m_hdc)
diff --git a/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp b/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp
index 0e9c636..c3fbdd7 100644
--- a/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp
+++ b/WebCore/platform/graphics/win/GraphicsContextCairoWin.cpp
@@ -92,21 +92,21 @@ void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, boo
cairo_surface_mark_dirty(surface);
}
-void GraphicsContextPlatformPrivate::concatCTM(const AffineTransform& transform)
+void GraphicsContext::concatCTM(const AffineTransform& transform)
{
- cairo_surface_t* surface = cairo_get_target(cr);
+ cairo_surface_t* surface = cairo_get_target(platformContext());
HDC hdc = cairo_win32_surface_get_dc(surface);
SaveDC(hdc);
- const cairo_matrix_t* matrix = reinterpret_cast<const cairo_matrix_t*>(&transform);
-
+ cairo_matrix_t mat;
+ cairo_get_matrix(platformContext(), &mat);
XFORM xform;
- xform.eM11 = matrix->xx;
- xform.eM12 = matrix->xy;
- xform.eM21 = matrix->yx;
- xform.eM22 = matrix->yy;
- xform.eDx = matrix->x0;
- xform.eDy = matrix->y0;
+ xform.eM11 = mat.xx;
+ xform.eM12 = mat.xy;
+ xform.eM21 = mat.yx;
+ xform.eM22 = mat.yy;
+ xform.eDx = mat.x0;
+ xform.eDy = mat.y0;
ModifyWorldTransform(hdc, &xform, MWT_LEFTMULTIPLY);
}
diff --git a/WebCore/platform/graphics/win/GraphicsContextWin.cpp b/WebCore/platform/graphics/win/GraphicsContextWin.cpp
index 373d2cf..a8f2148 100644
--- a/WebCore/platform/graphics/win/GraphicsContextWin.cpp
+++ b/WebCore/platform/graphics/win/GraphicsContextWin.cpp
@@ -26,12 +26,6 @@
#include "config.h"
#include "GraphicsContext.h"
-#if PLATFORM(CG)
-#include "GraphicsContextPlatformPrivateCG.h"
-#elif PLATFORM(CAIRO)
-#include "GraphicsContextPlatformPrivateCairo.h"
-#endif
-
#include "AffineTransform.h"
#include "NotImplemented.h"
#include "Path.h"
@@ -43,77 +37,6 @@ namespace WebCore {
class SVGResourceImage;
-void GraphicsContextPlatformPrivate::save()
-{
- if (!m_hdc)
- return;
- SaveDC(m_hdc);
-}
-
-void GraphicsContextPlatformPrivate::restore()
-{
- if (!m_hdc)
- return;
- RestoreDC(m_hdc, -1);
-}
-
-void GraphicsContextPlatformPrivate::clip(const IntRect& clipRect)
-{
- if (!m_hdc)
- return;
- IntersectClipRect(m_hdc, clipRect.x(), clipRect.y(), clipRect.right(), clipRect.bottom());
-}
-
-void GraphicsContextPlatformPrivate::clip(const Path&)
-{
- notImplemented();
-}
-
-void GraphicsContextPlatformPrivate::scale(const FloatSize& size)
-{
- if (!m_hdc)
- return;
- XFORM xform;
- xform.eM11 = size.width();
- xform.eM12 = 0.0f;
- xform.eM21 = 0.0f;
- xform.eM22 = size.height();
- xform.eDx = 0.0f;
- xform.eDy = 0.0f;
- ModifyWorldTransform(m_hdc, &xform, MWT_LEFTMULTIPLY);
-}
-
-static const double deg2rad = 0.017453292519943295769; // pi/180
-
-void GraphicsContextPlatformPrivate::rotate(float degreesAngle)
-{
- float radiansAngle = degreesAngle * deg2rad;
- float cosAngle = cosf(radiansAngle);
- float sinAngle = sinf(radiansAngle);
- XFORM xform;
- xform.eM11 = cosAngle;
- xform.eM12 = -sinAngle;
- xform.eM21 = sinAngle;
- xform.eM22 = cosAngle;
- xform.eDx = 0.0f;
- xform.eDy = 0.0f;
- ModifyWorldTransform(m_hdc, &xform, MWT_LEFTMULTIPLY);
-}
-
-void GraphicsContextPlatformPrivate::translate(float x , float y)
-{
- if (!m_hdc)
- return;
- XFORM xform;
- xform.eM11 = 1.0f;
- xform.eM12 = 0.0f;
- xform.eM21 = 0.0f;
- xform.eM22 = 1.0f;
- xform.eDx = x;
- xform.eDy = y;
- ModifyWorldTransform(m_hdc, &xform, MWT_LEFTMULTIPLY);
-}
-
#if ENABLE(SVG)
GraphicsContext* contextForImage(SVGResourceImage*)
{
diff --git a/WebCore/platform/graphics/win/IconWin.cpp b/WebCore/platform/graphics/win/IconWin.cpp
index b6bc926..60cebe3 100644
--- a/WebCore/platform/graphics/win/IconWin.cpp
+++ b/WebCore/platform/graphics/win/IconWin.cpp
@@ -28,14 +28,12 @@
namespace WebCore {
Icon::Icon()
- : RefCounted<Icon>(0)
- , m_hIcon(0)
+ : m_hIcon(0)
{
}
Icon::Icon(HICON icon)
- : RefCounted<Icon>(0)
- , m_hIcon(icon)
+ : m_hIcon(icon)
{
}
diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp
index c7d3bf8..65b3db6 100644
--- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp
+++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp
@@ -28,6 +28,7 @@
#if ENABLE(VIDEO)
#include "MediaPlayerPrivateQuickTimeWin.h"
+#include "DeprecatedString.h"
#include "GraphicsContext.h"
#include "KURL.h"
#include "QTMovieWin.h"
diff --git a/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp b/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp
index 4040ed8..0c31672 100644
--- a/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp
+++ b/WebCore/platform/graphics/win/SimpleFontDataCGWin.cpp
@@ -54,9 +54,32 @@ void SimpleFontData::platformInit()
m_scriptCache = 0;
m_scriptFontProperties = 0;
m_isSystemFont = false;
-
- if (m_font.useGDI())
- return initGDIFont();
+
+ if (m_font.useGDI()) {
+ HDC hdc = GetDC(0);
+ HGDIOBJ oldFont = SelectObject(hdc, m_font.hfont());
+ OUTLINETEXTMETRIC metrics;
+ GetOutlineTextMetrics(hdc, sizeof(metrics), &metrics);
+ TEXTMETRIC& textMetrics = metrics.otmTextMetrics;
+ m_ascent = textMetrics.tmAscent;
+ m_descent = textMetrics.tmDescent;
+ m_lineGap = textMetrics.tmExternalLeading;
+ m_lineSpacing = m_ascent + m_descent + m_lineGap;
+ m_xHeight = m_ascent * 0.56f; // Best guess for xHeight if no x glyph is present.
+
+ GLYPHMETRICS gm;
+ MAT2 mat = { 1, 0, 0, 1 };
+ DWORD len = GetGlyphOutline(hdc, 'x', GGO_METRICS, &gm, 0, 0, &mat);
+ if (len != GDI_ERROR && gm.gmptGlyphOrigin.y > 0)
+ m_xHeight = gm.gmptGlyphOrigin.y;
+
+ m_unitsPerEm = metrics.otmEMSquare;
+
+ SelectObject(hdc, oldFont);
+ ReleaseDC(0, hdc);
+
+ return;
+ }
CGFontRef font = m_font.cgFont();
int iAscent = CGFontGetAscent(font);
@@ -121,13 +144,24 @@ void SimpleFontData::platformDestroy()
CGFontRelease(m_font.cgFont());
}
- platformCommonDestroy();
+ // We don't hash this on Win32, so it's effectively owned by us.
+ delete m_smallCapsFontData;
+
+ ScriptFreeCache(&m_scriptCache);
+ delete m_scriptFontProperties;
}
float SimpleFontData::platformWidthForGlyph(Glyph glyph) const
{
- if (m_font.useGDI())
- return widthForGDIGlyph(glyph);
+ if (m_font.useGDI()) {
+ HDC hdc = GetDC(0);
+ HGDIOBJ oldFont = SelectObject(hdc, m_font.hfont());
+ int width;
+ GetCharWidthI(hdc, glyph, 1, 0, &width);
+ SelectObject(hdc, oldFont);
+ ReleaseDC(0, hdc);
+ return width;
+ }
CGFontRef font = m_font.cgFont();
float pointSize = m_font.size();
diff --git a/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp b/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp
index fd017b4..e7b2c81 100644
--- a/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp
+++ b/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp
@@ -34,10 +34,7 @@
#include "Font.h"
#include "FontCache.h"
#include "FontDescription.h"
-#include "MathExtras.h"
#include "NotImplemented.h"
-#include <cairo.h>
-#include <cairo-win32.h>
#include <mlang.h>
#include <tchar.h>
@@ -48,83 +45,58 @@ void SimpleFontData::platformInit()
m_scriptCache = 0;
m_scriptFontProperties = 0;
m_isSystemFont = false;
+
+ if (m_font.useGDI()) {
+ HDC hdc = GetDC(0);
+ HGDIOBJ oldFont = SelectObject(hdc, m_font.hfont());
+ OUTLINETEXTMETRIC metrics;
+ GetOutlineTextMetrics(hdc, sizeof(metrics), &metrics);
+ TEXTMETRIC& textMetrics = metrics.otmTextMetrics;
+ m_ascent = textMetrics.tmAscent;
+ m_descent = textMetrics.tmDescent;
+ m_lineGap = textMetrics.tmExternalLeading;
+ m_lineSpacing = m_ascent + m_descent + m_lineGap;
+ m_xHeight = m_ascent * 0.56f; // Best guess for xHeight if no x glyph is present.
- if (m_font.useGDI())
- return initGDIFont();
-
- HDC hdc = GetDC(0);
- SaveDC(hdc);
-
- cairo_scaled_font_t* scaledFont = m_font.scaledFont();
- const double metricsMultiplier = cairo_win32_scaled_font_get_metrics_factor(scaledFont) * m_font.size();
-
- cairo_win32_scaled_font_select_font(scaledFont, hdc);
-
- TEXTMETRIC textMetrics;
- GetTextMetrics(hdc, &textMetrics);
- m_ascent = lroundf(textMetrics.tmAscent * metricsMultiplier);
- m_descent = lroundf(textMetrics.tmDescent * metricsMultiplier);
- m_xHeight = m_ascent * 0.56f; // Best guess for xHeight for non-Truetype fonts.
- m_lineGap = lroundf(textMetrics.tmExternalLeading * metricsMultiplier);
- m_lineSpacing = m_ascent + m_descent + m_lineGap;
-
- OUTLINETEXTMETRIC metrics;
- if (GetOutlineTextMetrics(hdc, sizeof(metrics), &metrics) > 0) {
- // This is a TrueType font. We might be able to get an accurate xHeight
GLYPHMETRICS gm;
MAT2 mat = { 1, 0, 0, 1 };
DWORD len = GetGlyphOutline(hdc, 'x', GGO_METRICS, &gm, 0, 0, &mat);
if (len != GDI_ERROR && gm.gmptGlyphOrigin.y > 0)
- m_xHeight = gm.gmptGlyphOrigin.y * metricsMultiplier;
- }
+ m_xHeight = gm.gmptGlyphOrigin.y;
- cairo_win32_scaled_font_done_font(scaledFont);
+ m_unitsPerEm = metrics.otmEMSquare;
- m_isSystemFont = false;
- m_scriptCache = 0;
- m_scriptFontProperties = 0;
+ SelectObject(hdc, oldFont);
+ ReleaseDC(0, hdc);
+
+ return;
+ }
- RestoreDC(hdc, -1);
- ReleaseDC(0, hdc);
+ // FIXME: This section should determine font dimensions (see CG implementation).
+ notImplemented();
}
void SimpleFontData::platformDestroy()
{
- cairo_font_face_destroy(m_font.fontFace());
- cairo_scaled_font_destroy(m_font.scaledFont());
-
- DeleteObject(m_font.hfont());
-
- platformCommonDestroy();
+ notImplemented();
}
float SimpleFontData::platformWidthForGlyph(Glyph glyph) const
{
- if (m_font.useGDI())
- return widthForGDIGlyph(glyph);
-
- HDC hdc = GetDC(0);
- SaveDC(hdc);
-
- cairo_scaled_font_t* scaledFont = m_font.scaledFont();
- cairo_win32_scaled_font_select_font(scaledFont, hdc);
-
- int width;
- GetCharWidthI(hdc, glyph, 1, 0, &width);
-
- cairo_win32_scaled_font_done_font(scaledFont);
+ if (m_font.useGDI()) {
+ HDC hdc = GetDC(0);
+ HGDIOBJ oldFont = SelectObject(hdc, m_font.hfont());
+ int width;
+ GetCharWidthI(hdc, glyph, 1, 0, &width);
+ SelectObject(hdc, oldFont);
+ ReleaseDC(0, hdc);
+ return width;
+ }
- RestoreDC(hdc, -1);
- ReleaseDC(0, hdc);
+ // FIXME: Flesh out with Cairo/win32 font implementation
+ notImplemented();
- const double metricsMultiplier = cairo_win32_scaled_font_get_metrics_factor(scaledFont) * m_font.size();
- return width * metricsMultiplier;
-}
-
-void SimpleFontData::setFont(cairo_t* cr) const
-{
- ASSERT(cr);
- m_font.setFont(cr);
+ return 0;
}
}
diff --git a/WebCore/platform/graphics/win/SimpleFontDataWin.cpp b/WebCore/platform/graphics/win/SimpleFontDataWin.cpp
index 6d1c417..344d964 100644
--- a/WebCore/platform/graphics/win/SimpleFontDataWin.cpp
+++ b/WebCore/platform/graphics/win/SimpleFontDataWin.cpp
@@ -60,42 +60,6 @@ bool SimpleFontData::shouldApplyMacAscentHack()
return g_shouldApplyMacAscentHack;
}
-void SimpleFontData::initGDIFont()
-{
- HDC hdc = GetDC(0);
- HGDIOBJ oldFont = SelectObject(hdc, m_font.hfont());
- OUTLINETEXTMETRIC metrics;
- GetOutlineTextMetrics(hdc, sizeof(metrics), &metrics);
- TEXTMETRIC& textMetrics = metrics.otmTextMetrics;
- m_ascent = textMetrics.tmAscent;
- m_descent = textMetrics.tmDescent;
- m_lineGap = textMetrics.tmExternalLeading;
- m_lineSpacing = m_ascent + m_descent + m_lineGap;
- m_xHeight = m_ascent * 0.56f; // Best guess for xHeight if no x glyph is present.
-
- GLYPHMETRICS gm;
- MAT2 mat = { 1, 0, 0, 1 };
- DWORD len = GetGlyphOutline(hdc, 'x', GGO_METRICS, &gm, 0, 0, &mat);
- if (len != GDI_ERROR && gm.gmptGlyphOrigin.y > 0)
- m_xHeight = gm.gmptGlyphOrigin.y;
-
- m_unitsPerEm = metrics.otmEMSquare;
-
- SelectObject(hdc, oldFont);
- ReleaseDC(0, hdc);
-
- return;
-}
-
-void SimpleFontData::platformCommonDestroy()
-{
- // We don't hash this on Win32, so it's effectively owned by us.
- delete m_smallCapsFontData;
-
- ScriptFreeCache(&m_scriptCache);
- delete m_scriptFontProperties;
-}
-
SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const
{
if (!m_smallCapsFontData) {
@@ -173,17 +137,6 @@ void SimpleFontData::determinePitch()
ReleaseDC(0, dc);
}
-float SimpleFontData::widthForGDIGlyph(Glyph glyph) const
-{
- HDC hdc = GetDC(0);
- HGDIOBJ oldFont = SelectObject(hdc, m_font.hfont());
- int width;
- GetCharWidthI(hdc, glyph, 1, 0, &width);
- SelectObject(hdc, oldFont);
- ReleaseDC(0, hdc);
- return width;
-}
-
SCRIPT_FONTPROPERTIES* SimpleFontData::scriptFontProperties() const
{
if (!m_scriptFontProperties) {
diff --git a/WebCore/platform/graphics/wx/FontPlatformData.h b/WebCore/platform/graphics/wx/FontPlatformData.h
index 0f4c29b..f48068b 100644
--- a/WebCore/platform/graphics/wx/FontPlatformData.h
+++ b/WebCore/platform/graphics/wx/FontPlatformData.h
@@ -76,7 +76,7 @@ public:
case UNINITIALIZED:
return 0;
case VALID:
- return computeHash();
+ return m_fontHash;
}
}
@@ -89,8 +89,9 @@ public:
}
unsigned computeHash() const {
- ASSERT(m_font.Ok());
- return reinterpret_cast<unsigned>(&m_font);
+ wxCharBuffer charBuffer(m_font.GetNativeFontInfoDesc().mb_str(wxConvUTF8));
+ const char* contents = charBuffer;
+ return StringImpl::computeHash( (UChar*)contents, strlen(contents));
}
private:
diff --git a/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp b/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp
index 8e7c621..f3fb480 100755
--- a/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp
+++ b/WebCore/platform/graphics/wx/FontPlatformDataWx.cpp
@@ -83,7 +83,7 @@ FontPlatformData::FontPlatformData(const FontDescription& desc, const AtomicStri
italicToWxFontStyle(desc.italic()),
fontWeightToWxFontWeight(desc.bold()),
false,
- family.string()
+ family.domString()
);
#else
m_font = wxFont( desc.computedPixelSize(),
@@ -91,7 +91,7 @@ FontPlatformData::FontPlatformData(const FontDescription& desc, const AtomicStri
italicToWxFontStyle(desc.italic()),
fontWeightToWxFontWeight(desc.bold()),
false,
- family.string()
+ family.domString()
);
#endif
m_fontState = VALID;
diff --git a/WebCore/platform/graphics/wx/FontWx.cpp b/WebCore/platform/graphics/wx/FontWx.cpp
index 07223e9..e94ae3b 100644
--- a/WebCore/platform/graphics/wx/FontWx.cpp
+++ b/WebCore/platform/graphics/wx/FontWx.cpp
@@ -33,9 +33,9 @@
#include "NotImplemented.h"
#include "SimpleFontData.h"
-#include <wx/dcclient.h>
#include "fontprops.h"
-#include "non-kerned-drawing.h"
+#include <wx/defs.h>
+#include <wx/dcclient.h>
namespace WebCore {
@@ -45,11 +45,33 @@ void Font::drawGlyphs(GraphicsContext* graphicsContext, const SimpleFontData* fo
// prepare DC
Color color = graphicsContext->fillColor();
- // We can't use wx drawing methods on Win/Linux because they automatically kern text
- // so we've created a function with platform dependent drawing implementations that
- // will hopefully be folded into wx once the API has solidified.
- // see platform/wx/wxcode/<platform> for the implementations.
- drawTextWithSpacing(graphicsContext, font, color, glyphBuffer, from, numGlyphs, point);
+#if USE(WXGC)
+ wxGCDC* dc = (wxGCDC*)graphicsContext->platformContext();
+ wxFont wxfont = font->getWxFont();
+ if (wxfont.IsOk())
+ dc->SetFont(wxfont);
+ dc->SetTextForeground(color);
+#else
+ wxDC* dc = graphicsContext->platformContext();
+ dc->SetTextBackground(color);
+ dc->SetTextForeground(color);
+ dc->SetFont(font->getWxFont());
+#endif
+
+ // convert glyphs to wxString
+ GlyphBufferGlyph* glyphs = const_cast<GlyphBufferGlyph*>(glyphBuffer.glyphs(from));
+ int offset = point.x();
+ wxString text = wxEmptyString;
+ for (unsigned i = 0; i < numGlyphs; i++) {
+ text = text.Append((wxChar)glyphs[i]);
+ offset += glyphBuffer.advanceAt(from + i);
+ }
+
+ // the y point is actually the bottom point of the text, turn it into the top
+ float height = font->ascent() - font->descent();
+ wxCoord ypoint = (wxCoord) (point.y() - height);
+
+ dc->DrawText(text, (wxCoord)point.x(), ypoint);
}
FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint& point, int h, int from, int to) const
diff --git a/WebCore/platform/graphics/wx/GraphicsContextWx.cpp b/WebCore/platform/graphics/wx/GraphicsContextWx.cpp
index 951d3a3..78149ad 100644
--- a/WebCore/platform/graphics/wx/GraphicsContextWx.cpp
+++ b/WebCore/platform/graphics/wx/GraphicsContextWx.cpp
@@ -227,11 +227,6 @@ void GraphicsContext::drawEllipse(const IntRect& rect)
m_data->context->DrawEllipse(rect.x(), rect.y(), rect.width(), rect.height());
}
-void GraphicsContext::drawImage(WebCore::ImageBuffer*, WebCore::FloatRect const&, WebCore::FloatRect const&)
-{
- notImplemented();
-}
-
void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSpan)
{
if (paintingDisabled())
@@ -427,16 +422,6 @@ void GraphicsContext::setCompositeOperation(CompositeOperator op)
m_data->context->SetLogicalFunction(getWxCompositingOperation(op, false));
}
-void GraphicsContext::beginPath()
-{
- notImplemented();
-}
-
-void GraphicsContext::addPath(const Path& path)
-{
- notImplemented();
-}
-
void GraphicsContext::setPlatformStrokeColor(const Color& color)
{
if (paintingDisabled())
@@ -481,11 +466,4 @@ void GraphicsContext::setUseAntialiasing(bool enable)
notImplemented();
}
-void GraphicsContext::paintBuffer(ImageBuffer* buffer, const IntRect& r)
-{
- if (paintingDisabled())
- return;
- notImplemented();
-}
-
}
diff --git a/WebCore/platform/graphics/wx/ImageBufferWx.cpp b/WebCore/platform/graphics/wx/ImageBufferWx.cpp
index 0c832ea..bc54a88 100644
--- a/WebCore/platform/graphics/wx/ImageBufferWx.cpp
+++ b/WebCore/platform/graphics/wx/ImageBufferWx.cpp
@@ -25,10 +25,7 @@
#include "config.h"
#include "ImageBuffer.h"
-
#include "GraphicsContext.h"
-#include "ImageData.h"
-#include "NotImplemented.h"
namespace WebCore {
@@ -46,15 +43,4 @@ GraphicsContext* ImageBuffer::context() const
return 0;
}
-PassRefPtr<ImageData> ImageBuffer::getImageData(const IntRect&) const
-{
- notImplemented();
- return 0;
-}
-
-void ImageBuffer::putImageData(ImageData*, const IntRect&, const IntPoint&)
-{
- notImplemented();
-}
-
}
diff --git a/WebCore/platform/graphics/wx/PathWx.cpp b/WebCore/platform/graphics/wx/PathWx.cpp
index 5ff9914..86ecb93 100644
--- a/WebCore/platform/graphics/wx/PathWx.cpp
+++ b/WebCore/platform/graphics/wx/PathWx.cpp
@@ -171,10 +171,4 @@ void Path::apply(void* info, PathApplierFunction function) const
notImplemented();
}
-bool Path::isEmpty() const
-{
- notImplemented();
- return false;
-}
-
}
diff --git a/WebCore/platform/gtk/CookieJarGtk.cpp b/WebCore/platform/gtk/CookieJarGtk.cpp
index 2f76ebc..2813a2e 100644
--- a/WebCore/platform/gtk/CookieJarGtk.cpp
+++ b/WebCore/platform/gtk/CookieJarGtk.cpp
@@ -17,6 +17,7 @@
#include "config.h"
#include "CookieJar.h"
+#include "DeprecatedString.h"
#include "KURL.h"
#include "PlatformString.h"
#include "StringHash.h"
diff --git a/WebCore/platform/gtk/CursorGtk.cpp b/WebCore/platform/gtk/CursorGtk.cpp
index 15f492f..94c6975 100644
--- a/WebCore/platform/gtk/CursorGtk.cpp
+++ b/WebCore/platform/gtk/CursorGtk.cpp
@@ -28,6 +28,7 @@
#include "config.h"
#include "CursorGtk.h"
+#include "DeprecatedString.h"
#include "NotImplemented.h"
#include <wtf/Assertions.h>
diff --git a/WebCore/platform/gtk/FileChooserGtk.cpp b/WebCore/platform/gtk/FileChooserGtk.cpp
index 10c1a5f..c41a693 100644
--- a/WebCore/platform/gtk/FileChooserGtk.cpp
+++ b/WebCore/platform/gtk/FileChooserGtk.cpp
@@ -57,8 +57,7 @@ static bool stringByAdoptingFileSystemRepresentation(gchar* systemFilename, Stri
}
FileChooser::FileChooser(FileChooserClient* client, const String& filename)
- : RefCounted<FileChooser>(0)
- , m_client(client)
+ : m_client(client)
, m_filename(filename)
, m_icon(chooseIcon(filename))
{
diff --git a/WebCore/platform/gtk/FileSystemGtk.cpp b/WebCore/platform/gtk/FileSystemGtk.cpp
index df95dde..904fe9f 100644
--- a/WebCore/platform/gtk/FileSystemGtk.cpp
+++ b/WebCore/platform/gtk/FileSystemGtk.cpp
@@ -30,8 +30,6 @@
#include <glib/gstdio.h>
#include <glib/gutils.h>
-#include <unistd.h>
-
namespace WebCore {
bool fileExists(const String& path)
@@ -115,20 +113,6 @@ bool makeAllDirectories(const String& path)
return result == 0;
}
-String homeDirectoryPath()
-{
- return String::fromUTF8(g_get_home_dir());
-}
-
-String pathGetFileName(const String& pathName)
-{
- char* baseName = g_path_get_basename(pathName.utf8().data());
- String fileName = String::fromUTF8(baseName);
- g_free(baseName);
-
- return fileName;
-}
-
CString openTemporaryFile(const char* prefix, PlatformFileHandle& handle)
{
gchar* filename = g_strdup_printf("%sXXXXXX", prefix);
@@ -168,9 +152,4 @@ int writeToFile(PlatformFileHandle handle, const char* data, int length)
return totalBytesWritten;
}
-
-bool unloadModule(PlatformModule module)
-{
- return g_module_close(module);
-}
}
diff --git a/WebCore/platform/gtk/KeyEventGtk.cpp b/WebCore/platform/gtk/KeyEventGtk.cpp
index dea0502..5d2efcf 100644
--- a/WebCore/platform/gtk/KeyEventGtk.cpp
+++ b/WebCore/platform/gtk/KeyEventGtk.cpp
@@ -2,7 +2,6 @@
* Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
* Copyright (C) 2006 Michael Emmel mike.emmel@gmail.com
* Copyright (C) 2007 Holger Hans Peter Freyther
- * Copyright (C) 2008 Collabora, Ltd. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,13 +29,13 @@
#include "config.h"
#include "PlatformKeyboardEvent.h"
+#include "DeprecatedString.h"
#include "KeyboardCodes.h"
#include "NotImplemented.h"
#include "TextEncoding.h"
#include <gdk/gdk.h>
#include <gdk/gdkkeysyms.h>
-#include <gtk/gtkversion.h>
namespace WebCore {
@@ -485,8 +484,6 @@ static String singleCharacterString(guint val)
return retVal;
}
-// Keep this in sync with the other platform event constructors
-// TODO: m_gdkEventKey should be refcounted
PlatformKeyboardEvent::PlatformKeyboardEvent(GdkEventKey* event)
: m_type((event->type == GDK_KEY_RELEASE) ? KeyUp : KeyDown)
, m_text(singleCharacterString(event->keyval))
@@ -494,29 +491,20 @@ PlatformKeyboardEvent::PlatformKeyboardEvent(GdkEventKey* event)
, m_keyIdentifier(keyIdentifierForGdkKeyCode(event->keyval))
, m_autoRepeat(false)
, m_windowsVirtualKeyCode(windowsKeyCodeForKeyEvent(event->keyval))
- , m_isKeypad(event->keyval >= GDK_KP_Space && event->keyval <= GDK_KP_9)
+ , m_isKeypad(false)
, m_shiftKey((event->state & GDK_SHIFT_MASK) || (event->keyval == GDK_3270_BackTab))
, m_ctrlKey(event->state & GDK_CONTROL_MASK)
, m_altKey(event->state & GDK_MOD1_MASK)
-#if GTK_CHECK_VERSION(2,10,0)
- , m_metaKey(event->state & GDK_META_MASK)
-#else
- // GDK_MOD2_MASK doesn't always mean meta so we can't use it
- , m_metaKey(false)
-#endif
- , m_gdkEventKey(event)
+ , m_metaKey(event->state & GDK_MOD2_MASK)
{
}
-void PlatformKeyboardEvent::disambiguateKeyDownEvent(Type type, bool backwardCompatibilityMode)
+void PlatformKeyboardEvent::disambiguateKeyDownEvent(Type type, bool)
{
// Can only change type from KeyDown to RawKeyDown or Char, as we lack information for other conversions.
ASSERT(m_type == KeyDown);
m_type = type;
- if (backwardCompatibilityMode)
- return;
-
if (type == RawKeyDown) {
m_text = String();
m_unmodifiedText = String();
@@ -532,9 +520,4 @@ bool PlatformKeyboardEvent::currentCapsLockState()
return false;
}
-GdkEventKey* PlatformKeyboardEvent::gdkEventKey() const
-{
- return m_gdkEventKey;
-}
-
}
diff --git a/WebCore/platform/gtk/LocalizedStringsGtk.cpp b/WebCore/platform/gtk/LocalizedStringsGtk.cpp
index 4be5ba1..041cd83 100644
--- a/WebCore/platform/gtk/LocalizedStringsGtk.cpp
+++ b/WebCore/platform/gtk/LocalizedStringsGtk.cpp
@@ -290,9 +290,4 @@ String unknownFileSizeText()
return String::fromUTF8(_("Unknown"));
}
-String imageTitle(const String& filename, const IntSize& size)
-{
- return String();
-}
-
}
diff --git a/WebCore/platform/gtk/MouseEventGtk.cpp b/WebCore/platform/gtk/MouseEventGtk.cpp
index f441f00..29ea371 100644
--- a/WebCore/platform/gtk/MouseEventGtk.cpp
+++ b/WebCore/platform/gtk/MouseEventGtk.cpp
@@ -31,13 +31,11 @@
#include "Assertions.h"
#include <gdk/gdk.h>
-#include <gtk/gtkversion.h>
namespace WebCore {
// FIXME: Would be even better to figure out which modifier is Alt instead of always using GDK_MOD1_MASK.
-// Keep this in sync with the other platform event constructors
PlatformMouseEvent::PlatformMouseEvent(GdkEventButton* event)
{
m_timestamp = event->time;
@@ -46,12 +44,7 @@ PlatformMouseEvent::PlatformMouseEvent(GdkEventButton* event)
m_shiftKey = event->state & GDK_SHIFT_MASK;
m_ctrlKey = event->state & GDK_CONTROL_MASK;
m_altKey = event->state & GDK_MOD1_MASK;
-#if GTK_CHECK_VERSION(2,10,0)
- m_metaKey = event->state & GDK_META_MASK;
-#else
- // GDK_MOD2_MASK doesn't always mean meta so we can't use it
- m_metaKey = false;
-#endif
+ m_metaKey = event->state & GDK_MOD2_MASK;
switch (event->type) {
case GDK_BUTTON_PRESS:
diff --git a/WebCore/platform/gtk/PasteboardGtk.cpp b/WebCore/platform/gtk/PasteboardGtk.cpp
index 15a7e64..745728c 100644
--- a/WebCore/platform/gtk/PasteboardGtk.cpp
+++ b/WebCore/platform/gtk/PasteboardGtk.cpp
@@ -102,20 +102,16 @@ void Pasteboard::setHelper(PasteboardHelper* helper)
void Pasteboard::writeSelection(Range* selectedRange, bool canSmartCopyOrDelete, Frame* frame)
{
- GtkClipboard* clipboard = m_helper->getClipboard(frame);
-#if GTK_CHECK_VERSION(2,10,0)
gchar* text = g_strdup(frame->selectedText().utf8().data());
gchar* markup = g_strdup(createMarkup(selectedRange, 0, AnnotateForInterchange).utf8().data());
PasteboardSelectionData* data = new PasteboardSelectionData(text, markup);
gint n_targets;
GtkTargetEntry* targets = gtk_target_table_new_from_list(m_helper->getCopyTargetList(frame), &n_targets);
+ GtkClipboard* clipboard = m_helper->getClipboard(frame);
gtk_clipboard_set_with_data(clipboard, targets, n_targets,
clipboard_get_contents_cb, clipboard_clear_contents_cb, data);
gtk_target_table_free(targets, n_targets);
-#else
- gtk_clipboard_set_text(clipboard, frame->selectedText().utf8().data(), frame->selectedText().utf8().length());
-#endif
}
void Pasteboard::writeURL(const KURL& url, const String&, Frame* frame)
diff --git a/WebCore/platform/gtk/PopupMenuGtk.cpp b/WebCore/platform/gtk/PopupMenuGtk.cpp
index f228c8b..b4689f6 100644
--- a/WebCore/platform/gtk/PopupMenuGtk.cpp
+++ b/WebCore/platform/gtk/PopupMenuGtk.cpp
@@ -33,8 +33,7 @@
namespace WebCore {
PopupMenu::PopupMenu(PopupMenuClient* client)
- : RefCounted<PopupMenu>(0)
- , m_popupClient(client)
+ : m_popupClient(client)
, m_popup(0)
{
}
diff --git a/WebCore/platform/gtk/TemporaryLinkStubs.cpp b/WebCore/platform/gtk/TemporaryLinkStubs.cpp
index 7abe32e..525a6f8 100644
--- a/WebCore/platform/gtk/TemporaryLinkStubs.cpp
+++ b/WebCore/platform/gtk/TemporaryLinkStubs.cpp
@@ -34,8 +34,7 @@
#include "GlobalHistory.h"
#include "KURL.h"
#include "NotImplemented.h"
-#include "PluginDatabase.h"
-#include "PluginPackage.h"
+#include "PluginInfoStore.h"
#include "SharedBuffer.h"
using namespace WebCore;
@@ -60,14 +59,12 @@ Vector<char> loadResourceIntoArray(const char* resourceName)
bool WebCore::historyContains(const UChar*, unsigned) { return false; }
-PluginSet PluginDatabase::getPluginsInPaths() const { notImplemented(); return PluginSet(); }
-Vector<String> PluginDatabase::defaultPluginPaths() { notImplemented(); return Vector<String>(); }
-bool PluginDatabase::isPreferredPluginPath(const String&) { notImplemented(); return false; }
-int PluginPackage::compare(const PluginPackage&) const { notImplemented(); return 0; }
-bool PluginPackage::fetchInfo() { notImplemented(); return false; }
-unsigned PluginPackage::hash() const { notImplemented(); return 0; }
-bool PluginPackage::equal(const PluginPackage&, const PluginPackage&) { notImplemented(); return false; }
-bool PluginPackage::load() { notImplemented(); return false; }
+PluginInfo* PluginInfoStore::createPluginInfoForPluginAtIndex(unsigned) { notImplemented(); return 0;}
+unsigned PluginInfoStore::pluginCount() const { notImplemented(); return 0; }
+String PluginInfoStore::pluginNameForMIMEType(const String& mimeType) { notImplemented(); return String(); }
+bool WebCore::PluginInfoStore::supportsMIMEType(const WebCore::String&) { notImplemented(); return false; }
+void WebCore::refreshPlugins(bool) { notImplemented(); }
+
Color WebCore::focusRingColor() { return 0xFF0000FF; }
void WebCore::setFocusRingColorChangeFunction(void (*)()) { }
diff --git a/WebCore/platform/gtk/ThreadingGtk.cpp b/WebCore/platform/gtk/ThreadingGtk.cpp
new file mode 100644
index 0000000..5ce6ba2
--- /dev/null
+++ b/WebCore/platform/gtk/ThreadingGtk.cpp
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)
+ *
+ * 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.
+ * 3. Neither the name of Apple Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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.
+ */
+
+#include "config.h"
+#include "Threading.h"
+
+#include "HashMap.h"
+#include "Logging.h"
+
+#include <glib.h>
+
+namespace WebCore {
+
+struct FunctionWithContext {
+ MainThreadFunction* function;
+ void* context;
+};
+
+static gboolean callFunctionOnMainThread(gpointer data)
+{
+ FunctionWithContext* functionWithContext = static_cast<FunctionWithContext*>(data);
+ functionWithContext->function(functionWithContext->context);
+ delete functionWithContext;
+ return FALSE;
+}
+
+void callOnMainThread(MainThreadFunction* function, void* context)
+{
+ ASSERT(function);
+ FunctionWithContext* functionWithContext = new FunctionWithContext;
+ functionWithContext->function = function;
+ functionWithContext->context = context;
+ g_timeout_add(0, callFunctionOnMainThread, functionWithContext);
+}
+
+void initializeThreading()
+{
+ if (!g_thread_supported())
+ g_thread_init(NULL);
+ ASSERT(g_thread_supported());
+}
+
+static Mutex& threadMapMutex()
+{
+ static Mutex mutex;
+ return mutex;
+}
+
+static HashMap<ThreadIdentifier, GThread*>& threadMap()
+{
+ static HashMap<ThreadIdentifier, GThread*> map;
+ return map;
+}
+
+static ThreadIdentifier establishIdentifierForThread(GThread*& thread)
+{
+ MutexLocker locker(threadMapMutex());
+
+ static ThreadIdentifier identifierCount = 1;
+
+ threadMap().add(identifierCount, thread);
+
+ return identifierCount++;
+}
+
+static ThreadIdentifier identifierByGthreadHandle(GThread*& thread)
+{
+ MutexLocker locker(threadMapMutex());
+
+ HashMap<ThreadIdentifier, GThread*>::iterator i = threadMap().begin();
+ for (; i != threadMap().end(); ++i) {
+ if (i->second == thread)
+ return i->first;
+ }
+
+ return 0;
+}
+
+static GThread* threadForIdentifier(ThreadIdentifier id)
+{
+ MutexLocker locker(threadMapMutex());
+
+ return threadMap().get(id);
+}
+
+static void clearThreadForIdentifier(ThreadIdentifier id)
+{
+ MutexLocker locker(threadMapMutex());
+
+ ASSERT(threadMap().contains(id));
+
+ threadMap().remove(id);
+}
+
+ThreadIdentifier createThread(ThreadFunction entryPoint, void* data)
+{
+ GThread* thread;
+ if (!(thread = g_thread_create(entryPoint, data, TRUE, 0))) {
+ LOG_ERROR("Failed to create thread at entry point %p with data %p", entryPoint, data);
+ return 0;
+ }
+
+ ThreadIdentifier threadID = establishIdentifierForThread(thread);
+ LOG(Threading, "Created thread with thread id %u", threadID);
+ return threadID;
+}
+
+int waitForThreadCompletion(ThreadIdentifier threadID, void** result)
+{
+ ASSERT(threadID);
+
+ GThread* thread = threadForIdentifier(threadID);
+
+ *result = g_thread_join(thread);
+
+ clearThreadForIdentifier(threadID);
+ return 0;
+}
+
+void detachThread(ThreadIdentifier)
+{
+}
+
+ThreadIdentifier currentThread()
+{
+ GThread* currentThread = g_thread_self();
+ if (ThreadIdentifier id = identifierByGthreadHandle(currentThread))
+ return id;
+ return establishIdentifierForThread(currentThread);
+}
+
+Mutex::Mutex()
+ : m_mutex(g_mutex_new())
+{
+}
+
+Mutex::~Mutex()
+{
+ g_mutex_free(m_mutex);
+}
+
+void Mutex::lock()
+{
+ g_mutex_lock(m_mutex);
+}
+
+bool Mutex::tryLock()
+{
+ return g_mutex_trylock(m_mutex);
+}
+
+void Mutex::unlock()
+{
+ g_mutex_unlock(m_mutex);
+}
+
+ThreadCondition::ThreadCondition()
+ : m_condition(g_cond_new())
+{
+}
+
+ThreadCondition::~ThreadCondition()
+{
+ g_cond_free(m_condition);
+}
+
+void ThreadCondition::wait(Mutex& mutex)
+{
+ g_cond_wait(m_condition, mutex.impl());
+}
+
+void ThreadCondition::signal()
+{
+ g_cond_signal(m_condition);
+}
+
+void ThreadCondition::broadcast()
+{
+ g_cond_broadcast(m_condition);
+}
+
+
+}
diff --git a/WebCore/platform/gtk/WheelEventGtk.cpp b/WebCore/platform/gtk/WheelEventGtk.cpp
index 08f02cc..3368f25 100644
--- a/WebCore/platform/gtk/WheelEventGtk.cpp
+++ b/WebCore/platform/gtk/WheelEventGtk.cpp
@@ -29,11 +29,9 @@
#include "PlatformWheelEvent.h"
#include <gdk/gdk.h>
-#include <gtk/gtkversion.h>
namespace WebCore {
-// Keep this in sync with the other platform event constructors
PlatformWheelEvent::PlatformWheelEvent(GdkEventScroll* event)
{
static const float delta = 1;
@@ -63,12 +61,7 @@ PlatformWheelEvent::PlatformWheelEvent(GdkEventScroll* event)
m_shiftKey = event->state & GDK_SHIFT_MASK;
m_ctrlKey = event->state & GDK_CONTROL_MASK;
m_altKey = event->state & GDK_MOD1_MASK;
-#if GTK_CHECK_VERSION(2,10,0)
- m_metaKey = event->state & GDK_META_MASK;
-#else
- // GDK_MOD2_MASK doesn't always mean meta so we can't use it
- m_metaKey = false;
-#endif
+ m_metaKey = event->state & GDK_MOD2_MASK;
m_isContinuous = false;
}
diff --git a/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp b/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp
index dc3c767..1b70cd4 100644
--- a/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp
+++ b/WebCore/platform/image-decoders/gif/GIFImageDecoder.cpp
@@ -23,7 +23,6 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "config.h"
#include "GIFImageDecoder.h"
#include "GIFImageReader.h"
diff --git a/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp b/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp
index 520e1ae..cc246e2 100644
--- a/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp
+++ b/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp
@@ -38,7 +38,6 @@
#include "config.h"
#include "JPEGImageDecoder.h"
#include <assert.h>
-#include <stdio.h>
#if PLATFORM(CAIRO) || PLATFORM(QT) || PLATFORM(WX)
diff --git a/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp b/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp
index 6dd0073..99da437 100644
--- a/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp
+++ b/WebCore/platform/image-decoders/png/PNGImageDecoder.cpp
@@ -35,7 +35,6 @@
* version of this file under any of the LGPL, the MPL or the GPL.
*/
-#include "config.h"
#include "PNGImageDecoder.h"
#include "png.h"
#include "assert.h"
diff --git a/WebCore/platform/mac/ClipboardMac.mm b/WebCore/platform/mac/ClipboardMac.mm
index efd1fcf..01ec573 100644
--- a/WebCore/platform/mac/ClipboardMac.mm
+++ b/WebCore/platform/mac/ClipboardMac.mm
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004, 2005, 2006, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2004, 2005, 2006 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
@@ -26,17 +26,27 @@
#import "config.h"
#import "ClipboardMac.h"
+#import "CachedImage.h"
+#import "Document.h"
#import "DOMElementInternal.h"
#import "DragClient.h"
#import "DragController.h"
#import "Editor.h"
+#import "EventHandler.h"
+#import "FloatRect.h"
#import "FoundationExtras.h"
+#import "Frame.h"
+#import "HTMLImageElement.h"
#import "Image.h"
#import "Page.h"
#import "Pasteboard.h"
+#import "Range.h"
#import "RenderImage.h"
+#import "WebCoreFrameBridge.h"
#import "WebCoreSystemInterface.h"
+@class WebArchive;
+
namespace WebCore {
ClipboardMac::ClipboardMac(bool forDragging, NSPasteboard *pasteboard, ClipboardAccessPolicy policy, Frame *frame)
@@ -322,7 +332,7 @@ void ClipboardMac::declareAndWriteDragImage(Element* element, const KURL& url, c
{
ASSERT(frame);
if (Page* page = frame->page())
- page->dragController()->client()->declareAndWriteDragImage(m_pasteboard.get(), [DOMElement _wrapElement:element], url, title, frame);
+ page->dragController()->client()->declareAndWriteDragImage(m_pasteboard.get(), [DOMElement _wrapElement:element], url.getNSURL(), title, frame);
}
DragImageRef ClipboardMac::createDragImage(IntPoint& loc) const
diff --git a/WebCore/platform/mac/CookieJar.mm b/WebCore/platform/mac/CookieJar.mm
index 5fe7a63..7c288ad 100644
--- a/WebCore/platform/mac/CookieJar.mm
+++ b/WebCore/platform/mac/CookieJar.mm
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003, 2006, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2006 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
@@ -26,12 +26,14 @@
#import "config.h"
#import "CookieJar.h"
-#import "BlockExceptions.h"
#import "KURL.h"
+#import "BlockExceptions.h"
+#import "PlatformString.h"
+
#import <wtf/RetainPtr.h>
#ifdef BUILDING_ON_TIGER
-typedef unsigned NSUInteger;
+typedef unsigned int NSUInteger;
#endif
namespace WebCore {
@@ -40,7 +42,7 @@ String cookies(const Document* /*document*/, const KURL& url)
{
BEGIN_BLOCK_OBJC_EXCEPTIONS;
- NSURL *cookieURL = url;
+ NSURL *cookieURL = url.getNSURL();
NSArray *cookiesForURL = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:cookieURL];
// <rdar://problem/5632883> On 10.5, NSHTTPCookieStorage would happily store an empty cookie, which would be sent as "Cookie: =".
@@ -68,14 +70,14 @@ void setCookies(Document* /*document*/, const KURL& url, const KURL& policyBaseU
if (cookieStr.isEmpty())
return;
- NSURL *cookieURL = url;
+ NSURL *cookieURL = url.getNSURL();
// <http://bugs.webkit.org/show_bug.cgi?id=6531>, <rdar://4409034>
// cookiesWithResponseHeaderFields doesn't parse cookies without a value
String cookieString = cookieStr.contains('=') ? cookieStr : cookieStr + "=";
NSArray *cookies = [NSHTTPCookie cookiesWithResponseHeaderFields:[NSDictionary dictionaryWithObject:cookieString forKey:@"Set-Cookie"] forURL:cookieURL];
- [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookies:cookies forURL:cookieURL mainDocumentURL:policyBaseURL];
+ [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookies:cookies forURL:cookieURL mainDocumentURL:policyBaseURL.getNSURL()];
END_BLOCK_OBJC_EXCEPTIONS;
}
diff --git a/WebCore/platform/network/curl/ResourceError.h b/WebCore/platform/mac/DeprecatedStringListMac.mm
index 0a8eb64..abb6329 100644
--- a/WebCore/platform/network/curl/ResourceError.h
+++ b/WebCore/platform/mac/DeprecatedStringListMac.mm
@@ -1,6 +1,5 @@
-// -*- mode: c++; c-basic-offset: 4 -*-
/*
- * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+ * 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
@@ -24,26 +23,18 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ResourceError_h
-#define ResourceError_h
-
-#include "ResourceErrorBase.h"
+#include "config.h"
+#import "DeprecatedStringList.h"
namespace WebCore {
-class ResourceError : public ResourceErrorBase
+NSArray *DeprecatedStringList::getNSArray() const
{
-public:
- ResourceError()
- {
- }
-
- ResourceError(const String& domain, int errorCode, const String& failingURL, const String& localizedDescription)
- : ResourceErrorBase(domain, errorCode, failingURL, localizedDescription)
- {
+ NSMutableArray *array = [NSMutableArray array];
+ for (ConstIterator it = begin(); it != end(); ++it) {
+ [array addObject:(*it).getNSString()];
}
-};
-
+ return array;
}
-#endif // ResourceError_h_
+}
diff --git a/WebCore/platform/mac/DeprecatedStringMac.mm b/WebCore/platform/mac/DeprecatedStringMac.mm
new file mode 100644
index 0000000..6e58eba
--- /dev/null
+++ b/WebCore/platform/mac/DeprecatedStringMac.mm
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2005, 2006 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.
+ */
+
+#include "config.h"
+#include "DeprecatedString.h"
+
+#import <wtf/Assertions.h>
+#import "TextEncoding.h"
+
+using namespace WebCore;
+
+void DeprecatedString::setBufferFromCFString(CFStringRef cfs)
+{
+ if (!cfs) {
+ return;
+ }
+ CFIndex size = CFStringGetLength(cfs);
+ UniChar fixedSizeBuffer[1024];
+ UniChar *buffer;
+ if (size > (CFIndex)(sizeof(fixedSizeBuffer) / sizeof(UniChar))) {
+ buffer = (UniChar *)fastMalloc(size * sizeof(UniChar));
+ } else {
+ buffer = fixedSizeBuffer;
+ }
+ CFStringGetCharacters(cfs, CFRangeMake (0, size), buffer);
+ setUnicode((const DeprecatedChar *)buffer, (unsigned)size);
+ if (buffer != fixedSizeBuffer) {
+ fastFree(buffer);
+ }
+}
+
+
+DeprecatedString DeprecatedString::fromCFString(CFStringRef cfs)
+{
+ DeprecatedString qs;
+ qs.setBufferFromCFString(cfs);
+ return qs;
+}
+
+DeprecatedString DeprecatedString::fromNSString(NSString *nss)
+{
+ DeprecatedString qs;
+ qs.setBufferFromCFString((CFStringRef)nss);
+ return qs;
+}
+
+NSString *DeprecatedString::getNSString() const
+{
+ // The Cocoa calls in this method don't need exceptions blocked
+ // because they are simple NSString calls that can't throw.
+
+ int length = dataHandle[0]->_length;
+ if (dataHandle[0]->_isUnicodeValid) {
+ return [NSString stringWithCharacters:(const unichar *)unicode() length:length];
+ }
+
+ if (dataHandle[0]->_isAsciiValid) {
+ return [[[NSString alloc] initWithBytes:ascii() length:length encoding:NSISOLatin1StringEncoding] autorelease];
+ }
+
+ FATAL("invalid character cache");
+ return nil;
+}
diff --git a/WebCore/platform/mac/FileChooserMac.mm b/WebCore/platform/mac/FileChooserMac.mm
index a83418c..e8f9159 100644
--- a/WebCore/platform/mac/FileChooserMac.mm
+++ b/WebCore/platform/mac/FileChooserMac.mm
@@ -93,8 +93,7 @@ using namespace WebCore;
namespace WebCore {
FileChooser::FileChooser(FileChooserClient* client, const String& filename)
- : RefCounted<FileChooser>(0)
- , m_client(client)
+ : m_client(client)
, m_filename(filename)
, m_icon(chooseIcon(filename))
, m_controller(AdoptNS, [[WebCoreOpenPanelController alloc] initWithFileChooser:this])
diff --git a/WebCore/platform/mac/KURLMac.mm b/WebCore/platform/mac/KURLMac.mm
index c913ab4..102f3a5 100644
--- a/WebCore/platform/mac/KURLMac.mm
+++ b/WebCore/platform/mac/KURLMac.mm
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004, 2008 Apple 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
@@ -23,45 +23,42 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#import "config.h"
+#include "config.h"
#import "KURL.h"
#import "FoundationExtras.h"
+#import <wtf/Assertions.h>
+#import <wtf/Vector.h>
namespace WebCore {
KURL::KURL(NSURL *url)
{
- if (!url) {
+ if (url) {
+ CFIndex bytesLength = CFURLGetBytes((CFURLRef)url, 0, 0);
+ Vector<char, 2048> buffer(bytesLength + 6); // 5 for "file:", 1 for NUL terminator
+ char *bytes = &buffer[5];
+ CFURLGetBytes((CFURLRef)url, (UInt8 *)bytes, bytesLength);
+ bytes[bytesLength] = '\0';
+ if (bytes[0] == '/') {
+ buffer[0] = 'f';
+ buffer[1] = 'i';
+ buffer[2] = 'l';
+ buffer[3] = 'e';
+ buffer[4] = ':';
+ parse(buffer.data(), 0);
+ } else
+ parse(bytes, 0);
+ } else
parse(0, 0);
- return;
- }
-
- CFIndex bytesLength = CFURLGetBytes(reinterpret_cast<CFURLRef>(url), 0, 0);
- Vector<char, 512> buffer(bytesLength + 6); // 5 for "file:", 1 for null character to end C string
- char* bytes = &buffer[5];
- CFURLGetBytes(reinterpret_cast<CFURLRef>(url), reinterpret_cast<UInt8*>(bytes), bytesLength);
- bytes[bytesLength] = '\0';
- if (bytes[0] != '/') {
- parse(bytes, 0);
- return;
- }
-
- buffer[0] = 'f';
- buffer[1] = 'i';
- buffer[2] = 'l';
- buffer[3] = 'e';
- buffer[4] = ':';
-
- parse(buffer.data(), 0);
}
-KURL::operator NSURL *() const
+NSURL *KURL::getNSURL() const
{
- if (isNull())
+ if (urlString.isNull())
return nil;
- // CFURL can't hold an empty URL, unlike NSURL.
+ // CFURL can't hold an empty URL, unlike NSURL
if (isEmpty())
return [NSURL URLWithString:@""];
diff --git a/WebCore/platform/mac/LocalizedStringsMac.mm b/WebCore/platform/mac/LocalizedStringsMac.mm
index d4af7cd..f5b208d 100644
--- a/WebCore/platform/mac/LocalizedStringsMac.mm
+++ b/WebCore/platform/mac/LocalizedStringsMac.mm
@@ -27,7 +27,6 @@
#import "LocalizedStrings.h"
#import "BlockExceptions.h"
-#import "IntSize.h"
#import "PlatformString.h"
#import "WebCoreViewFactory.h"
@@ -505,12 +504,4 @@ String unknownFileSizeText()
return String();
}
-String imageTitle(const String& filename, const IntSize& size)
-{
- BEGIN_BLOCK_OBJC_EXCEPTIONS;
- return [[WebCoreViewFactory sharedFactory] imageTitleForFilename:filename size:size];
- END_BLOCK_OBJC_EXCEPTIONS;
- return String();
-}
-
}
diff --git a/WebCore/platform/mac/PasteboardMac.mm b/WebCore/platform/mac/PasteboardMac.mm
index 1433dbd..87db2f9 100644
--- a/WebCore/platform/mac/PasteboardMac.mm
+++ b/WebCore/platform/mac/PasteboardMac.mm
@@ -40,6 +40,7 @@
#import "MIMETypeRegistry.h"
#import "RenderImage.h"
#import "WebCoreNSStringExtras.h"
+#import "WebCoreSystemInterface.h"
#import "markup.h"
#import <wtf/RetainPtr.h>
@@ -209,7 +210,7 @@ void Pasteboard::writeURL(NSPasteboard* pasteboard, NSArray* types, const KURL&
ASSERT(!url.isEmpty());
- NSURL *cocoaURL = url;
+ NSURL *cocoaURL = url.getNSURL();
NSString *userVisibleString = frame->editor()->client()->userVisibleString(cocoaURL);
NSString *title = (NSString*)titleStr;
@@ -269,7 +270,7 @@ void Pasteboard::writeImage(Node* node, const KURL& url, const String& title)
ASSERT(node);
Frame* frame = node->document()->frame();
- NSURL *cocoaURL = url;
+ NSURL *cocoaURL = url.getNSURL();
ASSERT(cocoaURL);
NSArray* types = writableTypesForImage();
diff --git a/WebCore/platform/mac/PopupMenuMac.mm b/WebCore/platform/mac/PopupMenuMac.mm
index 16cbe75..0d6565b 100644
--- a/WebCore/platform/mac/PopupMenuMac.mm
+++ b/WebCore/platform/mac/PopupMenuMac.mm
@@ -35,8 +35,7 @@ namespace WebCore {
using namespace HTMLNames;
PopupMenu::PopupMenu(PopupMenuClient* client)
- : RefCounted<PopupMenu>(0)
- , m_popupClient(client)
+ : m_popupClient(client)
{
}
diff --git a/WebCore/platform/mac/SSLKeyGeneratorMac.mm b/WebCore/platform/mac/SSLKeyGeneratorMac.mm
index 2b1190b..5c4161a 100644
--- a/WebCore/platform/mac/SSLKeyGeneratorMac.mm
+++ b/WebCore/platform/mac/SSLKeyGeneratorMac.mm
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003, 2008 Apple Inc. All rights reserved.
+ * 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
@@ -46,7 +46,7 @@ String signedPublicKeyAndChallengeString(unsigned keySizeIndex, const String& ch
{
return [[WebCoreKeyGenerator sharedGenerator] signedPublicKeyAndChallengeStringWithStrengthIndex:keySizeIndex
challenge:challengeString
- pageURL:url];
+ pageURL:url.getNSURL()];
}
}
diff --git a/WebCore/platform/mac/SharedBufferMac.mm b/WebCore/platform/mac/SharedBufferMac.mm
index d241eaf..c3753c2 100644
--- a/WebCore/platform/mac/SharedBufferMac.mm
+++ b/WebCore/platform/mac/SharedBufferMac.mm
@@ -95,8 +95,7 @@ PassRefPtr<SharedBuffer> SharedBuffer::wrapNSData(NSData *nsData)
}
SharedBuffer::SharedBuffer(NSData *nsData)
- : RefCounted<SharedBuffer>(0)
- , m_nsData(nsData)
+ : m_nsData(nsData)
{
}
diff --git a/WebCore/platform/mac/SystemTimeMac.cpp b/WebCore/platform/mac/SystemTimeMac.cpp
index dd5e500..a541b1d 100644
--- a/WebCore/platform/mac/SystemTimeMac.cpp
+++ b/WebCore/platform/mac/SystemTimeMac.cpp
@@ -26,7 +26,8 @@
#include "config.h"
#include "SystemTime.h"
-#include <CoreGraphics/CGEventSource.h>
+#include "WebCoreSystemInterface.h"
+
#include <CoreFoundation/CFDate.h>
namespace WebCore {
@@ -38,7 +39,7 @@ double currentTime()
float userIdleTime()
{
- return static_cast<float>(CGEventSourceSecondsSinceLastEventType(kCGEventSourceStateCombinedSessionState, kCGAnyInputEventType));
+ return wkSecondsSinceLastInputEvent();
}
}
diff --git a/WebCore/platform/mac/MainThreadMac.mm b/WebCore/platform/mac/Threading.mm
index 47329ef..02d39a3 100644
--- a/WebCore/platform/mac/MainThreadMac.mm
+++ b/WebCore/platform/mac/Threading.mm
@@ -27,7 +27,7 @@
*/
#import "config.h"
-#import "MainThread.h"
+#import "Threading.h"
@interface WebCoreFunctionWrapper : NSObject {
WebCore::MainThreadFunction* m_function;
diff --git a/WebCore/platform/mac/WebCoreSystemInterface.h b/WebCore/platform/mac/WebCoreSystemInterface.h
index 873d3bf..fbbacd2 100644
--- a/WebCore/platform/mac/WebCoreSystemInterface.h
+++ b/WebCore/platform/mac/WebCoreSystemInterface.h
@@ -98,6 +98,7 @@ extern OSStatus (*wkGetATSStyleGroup)(ATSUStyle, void** styleGroup);
extern CGFontRef (*wkGetCGFontFromNSFont)(NSFont*);
extern NSFont* (*wkGetFontInLanguageForRange)(NSFont*, NSString*, NSRange);
extern NSFont* (*wkGetFontInLanguageForCharacter)(NSFont*, UniChar);
+extern void (*wkGetFontMetrics)(CGFontRef, int* ascent, int* descent, int* lineGap, unsigned* unitsPerEm);
extern BOOL (*wkGetGlyphTransformedAdvances)(CGFontRef, NSFont*, CGAffineTransform*, ATSGlyphRef*, CGSize* advance);
extern ATSLayoutRecord* (*wkGetGlyphVectorFirstRecord)(void* glyphVector);
extern int (*wkGetGlyphVectorNumGlyphs)(void* glyphVector);
@@ -120,6 +121,7 @@ extern NSDate *(*wkGetNSURLResponseLastModifiedDate)(NSURLResponse *response);
extern BOOL (*wkGetNSURLResponseMustRevalidate)(NSURLResponse *response);
extern void (*wkGetWheelEventDeltas)(NSEvent*, float* deltaX, float* deltaY, BOOL* continuous);
extern OSStatus (*wkInitializeGlyphVector)(int count, void* glyphs);
+extern NSString* (*wkPathFromFont)(NSFont*);
extern void (*wkPopupMenu)(NSMenu*, NSPoint location, float width, NSView*, int selectedItem, NSFont*);
extern int (*wkQTMovieDataRate)(QTMovie*);
extern float (*wkQTMovieMaxTimeLoaded)(QTMovie*);
@@ -135,12 +137,9 @@ extern void (*wkSetUpFontCache)(size_t);
extern void (*wkSignalCFReadStreamEnd)(CFReadStreamRef stream);
extern void (*wkSignalCFReadStreamError)(CFReadStreamRef stream, CFStreamError *error);
extern void (*wkSignalCFReadStreamHasBytes)(CFReadStreamRef stream);
-
-#ifdef BUILDING_ON_TIGER
-extern void (*wkGetFontMetrics)(CGFontRef, int* ascent, int* descent, int* lineGap, unsigned* unitsPerEm);
extern BOOL (*wkSupportsMultipartXMixedReplace)(NSMutableURLRequest *);
-#endif
-
+extern Class (*wkNSURLProtocolClassForReqest)(NSURLRequest *);
+extern float (*wkSecondsSinceLastInputEvent)(void);
#ifdef __cplusplus
}
#endif
diff --git a/WebCore/platform/mac/WebCoreSystemInterface.mm b/WebCore/platform/mac/WebCoreSystemInterface.mm
index 6fea621..9e8856d 100644
--- a/WebCore/platform/mac/WebCoreSystemInterface.mm
+++ b/WebCore/platform/mac/WebCoreSystemInterface.mm
@@ -41,6 +41,7 @@ OSStatus (*wkGetATSStyleGroup)(ATSUStyle, void** styleGroup);
CGFontRef (*wkGetCGFontFromNSFont)(NSFont*);
NSFont* (*wkGetFontInLanguageForRange)(NSFont*, NSString*, NSRange);
NSFont* (*wkGetFontInLanguageForCharacter)(NSFont*, UniChar);
+void (*wkGetFontMetrics)(CGFontRef, int* ascent, int* descent, int* lineGap, unsigned* unitsPerEm);
BOOL (*wkGetGlyphTransformedAdvances)(CGFontRef, NSFont*, CGAffineTransform*, ATSGlyphRef*, CGSize* advance);
ATSLayoutRecord* (*wkGetGlyphVectorFirstRecord)(void* glyphVector);
int (*wkGetGlyphVectorNumGlyphs)(void* glyphVector);
@@ -63,6 +64,7 @@ NSDate *(*wkGetNSURLResponseLastModifiedDate)(NSURLResponse *response);
BOOL (*wkGetNSURLResponseMustRevalidate)(NSURLResponse *response);
void (*wkGetWheelEventDeltas)(NSEvent*, float* deltaX, float* deltaY, BOOL* continuous);
OSStatus (*wkInitializeGlyphVector)(int count, void* glyphs);
+NSString* (*wkPathFromFont)(NSFont*);
void (*wkPopupMenu)(NSMenu*, NSPoint location, float width, NSView*, int selectedItem, NSFont*);
int (*wkQTMovieDataRate)(QTMovie*);
float (*wkQTMovieMaxTimeLoaded)(QTMovie*);
@@ -88,8 +90,6 @@ CFReadStreamRef (*wkCreateCustomCFReadStream)(void *(*formCreate)(CFReadStreamRe
void (*wkSetNSURLConnectionDefersCallbacks)(NSURLConnection *, BOOL);
void (*wkSetNSURLRequestShouldContentSniff)(NSMutableURLRequest *, BOOL);
id (*wkCreateNSURLConnectionDelegateProxy)(void);
-
-#ifdef BUILDING_ON_TIGER
-void (*wkGetFontMetrics)(CGFontRef, int* ascent, int* descent, int* lineGap, unsigned* unitsPerEm);
BOOL (*wkSupportsMultipartXMixedReplace)(NSMutableURLRequest *);
-#endif
+Class (*wkNSURLProtocolClassForReqest)(NSURLRequest *);
+float (*wkSecondsSinceLastInputEvent)(void);
diff --git a/WebCore/platform/network/AuthenticationChallengeBase.cpp b/WebCore/platform/network/AuthenticationChallenge.cpp
index df80441..f7275f3 100644
--- a/WebCore/platform/network/AuthenticationChallengeBase.cpp
+++ b/WebCore/platform/network/AuthenticationChallenge.cpp
@@ -29,17 +29,14 @@
namespace WebCore {
-AuthenticationChallengeBase::AuthenticationChallengeBase()
+AuthenticationChallenge::AuthenticationChallenge()
: m_isNull(true)
, m_previousFailureCount(0)
{
}
-AuthenticationChallengeBase::AuthenticationChallengeBase(const ProtectionSpace& protectionSpace,
- const Credential& proposedCredential,
- unsigned previousFailureCount,
- const ResourceResponse& response,
- const ResourceError& error)
+AuthenticationChallenge::AuthenticationChallenge(const ProtectionSpace& protectionSpace, const Credential& proposedCredential,
+ unsigned previousFailureCount, const ResourceResponse& response, const ResourceError& error)
: m_isNull(false)
, m_protectionSpace(protectionSpace)
, m_proposedCredential(proposedCredential)
@@ -49,49 +46,62 @@ AuthenticationChallengeBase::AuthenticationChallengeBase(const ProtectionSpace&
{
}
-unsigned AuthenticationChallengeBase::previousFailureCount() const
+unsigned AuthenticationChallenge::previousFailureCount() const
{
return m_previousFailureCount;
}
-const Credential& AuthenticationChallengeBase::proposedCredential() const
+const Credential& AuthenticationChallenge::proposedCredential() const
{
return m_proposedCredential;
}
-const ProtectionSpace& AuthenticationChallengeBase::protectionSpace() const
+const ProtectionSpace& AuthenticationChallenge::protectionSpace() const
{
return m_protectionSpace;
}
-const ResourceResponse& AuthenticationChallengeBase::failureResponse() const
+const ResourceResponse& AuthenticationChallenge::failureResponse() const
{
return m_failureResponse;
}
-const ResourceError& AuthenticationChallengeBase::error() const
+const ResourceError& AuthenticationChallenge::error() const
{
return m_error;
}
-bool AuthenticationChallengeBase::isNull() const
+bool AuthenticationChallenge::isNull() const
{
return m_isNull;
}
-void AuthenticationChallengeBase::nullify()
+void AuthenticationChallenge::nullify()
{
m_isNull = true;
}
-bool AuthenticationChallengeBase::compare(const AuthenticationChallenge& a, const AuthenticationChallenge& b)
+bool operator==(const AuthenticationChallenge& a, const AuthenticationChallenge& b)
{
- if (a.isNull() && b.isNull())
+ if (a.isNull() != b.isNull())
+ return false;
+ if (a.isNull())
return true;
-
- if (a.isNull() || b.isNull())
+
+#if PLATFORM(MAC)
+ if (a.sender() != b.sender())
return false;
+ if (a.nsURLAuthenticationChallenge() != b.nsURLAuthenticationChallenge())
+ return false;
+#elif USE(CFNETWORK)
+ if (a.sourceHandle() != b.sourceHandle())
+ return false;
+
+ if (a.cfURLAuthChallengeRef() != b.cfURLAuthChallengeRef())
+ return false;
+#endif
+
if (a.protectionSpace() != b.protectionSpace())
return false;
@@ -107,7 +117,14 @@ bool AuthenticationChallengeBase::compare(const AuthenticationChallenge& a, cons
if (a.error() != b.error())
return false;
- return AuthenticationChallenge::platformCompare(a, b);
+ return true;
+}
+
+bool operator!=(const AuthenticationChallenge& a, const AuthenticationChallenge& b)
+{
+ return !(a == b);
}
}
+
+
diff --git a/WebCore/platform/network/mac/AuthenticationChallenge.h b/WebCore/platform/network/AuthenticationChallenge.h
index e8f3a2d..3e46ea4 100644
--- a/WebCore/platform/network/mac/AuthenticationChallenge.h
+++ b/WebCore/platform/network/AuthenticationChallenge.h
@@ -25,8 +25,15 @@
#ifndef AuthenticationChallenge_h
#define AuthenticationChallenge_h
-#include "AuthenticationChallengeBase.h"
+#include "Credential.h"
+#include "ProtectionSpace.h"
+#include "ResourceResponse.h"
+#include "ResourceError.h"
+#include <wtf/RefPtr.h>
+
+
+#if PLATFORM(MAC)
#include <wtf/RetainPtr.h>
#ifndef __OBJC__
typedef struct objc_object *id;
@@ -34,26 +41,64 @@ class NSURLAuthenticationChallenge;
#else
@class NSURLAuthenticationChallenge;
#endif
+#endif
+
+#if USE(CFNETWORK)
+typedef struct _CFURLAuthChallenge* CFURLAuthChallengeRef;
+#endif
+
namespace WebCore {
-class AuthenticationChallenge : public AuthenticationChallengeBase {
+class ResourceHandle;
+
+class AuthenticationChallenge {
+
public:
- AuthenticationChallenge() {}
+ AuthenticationChallenge();
AuthenticationChallenge(const ProtectionSpace& protectionSpace, const Credential& proposedCredential, unsigned previousFailureCount, const ResourceResponse& response, const ResourceError& error);
+#if PLATFORM(MAC)
AuthenticationChallenge(NSURLAuthenticationChallenge *);
+#elif USE(CFNETWORK)
+ AuthenticationChallenge(CFURLAuthChallengeRef, ResourceHandle* sourceHandle);
+#endif
+ unsigned previousFailureCount() const;
+ const Credential& proposedCredential() const;
+ const ProtectionSpace& protectionSpace() const;
+ const ResourceResponse& failureResponse() const;
+ const ResourceError& error() const;
+
+ bool isNull() const;
+ void nullify();
+
+#if PLATFORM(MAC)
id sender() const { return m_sender.get(); }
NSURLAuthenticationChallenge *nsURLAuthenticationChallenge() const { return m_macChallenge.get(); }
-
+#elif USE(CFNETWORK)
+ ResourceHandle* sourceHandle() const { return m_sourceHandle.get(); }
+ CFURLAuthChallengeRef cfURLAuthChallengeRef() const { return m_cfChallenge.get(); }
+#endif
private:
- friend class AuthenticationChallengeBase;
- static bool platformCompare(const AuthenticationChallenge& a, const AuthenticationChallenge& b);
+ bool m_isNull;
+ ProtectionSpace m_protectionSpace;
+ Credential m_proposedCredential;
+ unsigned m_previousFailureCount;
+ ResourceResponse m_failureResponse;
+ ResourceError m_error;
+#if PLATFORM(MAC)
RetainPtr<id> m_sender;
RetainPtr<NSURLAuthenticationChallenge *> m_macChallenge;
+#elif USE(CFNETWORK)
+ RefPtr<ResourceHandle> m_sourceHandle;
+ RetainPtr<CFURLAuthChallengeRef> m_cfChallenge;
+#endif
+
};
+bool operator==(const AuthenticationChallenge&, const AuthenticationChallenge&);
+bool operator!=(const AuthenticationChallenge&, const AuthenticationChallenge&);
}
-
#endif
+
diff --git a/WebCore/platform/network/AuthenticationChallengeBase.h b/WebCore/platform/network/AuthenticationChallengeBase.h
deleted file mode 100644
index 5810a6d..0000000
--- a/WebCore/platform/network/AuthenticationChallengeBase.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2007 Apple 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.
- */
-#ifndef AuthenticationChallengeBase_h
-#define AuthenticationChallengeBase_h
-
-#include "Credential.h"
-#include "ProtectionSpace.h"
-#include "ResourceResponse.h"
-#include "ResourceError.h"
-
-namespace WebCore {
-
-class AuthenticationChallenge;
-
-class AuthenticationChallengeBase {
-public:
- AuthenticationChallengeBase();
- AuthenticationChallengeBase(const ProtectionSpace& protectionSpace, const Credential& proposedCredential, unsigned previousFailureCount, const ResourceResponse& response, const ResourceError& error);
-
- unsigned previousFailureCount() const;
- const Credential& proposedCredential() const;
- const ProtectionSpace& protectionSpace() const;
- const ResourceResponse& failureResponse() const;
- const ResourceError& error() const;
-
- bool isNull() const;
- void nullify();
-
- static bool compare(const AuthenticationChallenge& a, const AuthenticationChallenge& b);
-
-protected:
- // The AuthenticationChallenge subclass may "shadow" this method to compare platform specific fields
- static bool platformCompare(const AuthenticationChallengeBase& a, const AuthenticationChallengeBase& b) { return true; }
-
- bool m_isNull;
- ProtectionSpace m_protectionSpace;
- Credential m_proposedCredential;
- unsigned m_previousFailureCount;
- ResourceResponse m_failureResponse;
- ResourceError m_error;
-};
-
-inline bool operator==(const AuthenticationChallenge& a, const AuthenticationChallenge& b) { return AuthenticationChallengeBase::compare(a, b); }
-inline bool operator!=(const AuthenticationChallenge& a, const AuthenticationChallenge& b) { return !(a == b); }
-
-}
-
-#endif
diff --git a/WebCore/platform/network/FormData.cpp b/WebCore/platform/network/FormData.cpp
index 3453169..ed2d811 100644
--- a/WebCore/platform/network/FormData.cpp
+++ b/WebCore/platform/network/FormData.cpp
@@ -25,45 +25,25 @@
namespace WebCore {
-inline FormData::FormData()
+FormData::FormData(const void* data, size_t size)
{
+ appendData(data, size);
}
-PassRefPtr<FormData> FormData::create()
+FormData::FormData(const CString& s)
{
- return adoptRef(new FormData);
+ appendData(s.data(), s.length());
}
-PassRefPtr<FormData> FormData::create(const void* data, size_t size)
-{
- RefPtr<FormData> result = create();
- result->appendData(data, size);
- return result.release();
-}
-
-PassRefPtr<FormData> FormData::create(const CString& string)
-{
- RefPtr<FormData> result = create();
- result->appendData(string.data(), string.length());
- return result.release();
-}
-
-PassRefPtr<FormData> FormData::create(const Vector<char>& vector)
-{
- RefPtr<FormData> result = create();
- result->appendData(vector.data(), vector.size());
- return result.release();
-}
-
-inline FormData::FormData(const FormData& data)
- : RefCounted<FormData>(1)
+FormData::FormData(const FormData& data)
+ : RefCounted<FormData>()
, m_elements(data.m_elements)
{
}
PassRefPtr<FormData> FormData::copy() const
{
- return adoptRef(new FormData(*this));
+ return new FormData(*this);
}
void FormData::appendData(const void* data, size_t size)
diff --git a/WebCore/platform/network/FormData.h b/WebCore/platform/network/FormData.h
index 168020e..c33ef52 100644
--- a/WebCore/platform/network/FormData.h
+++ b/WebCore/platform/network/FormData.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004, 2006, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2004, 2006 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
@@ -59,10 +59,9 @@ inline bool operator!=(const FormDataElement& a, const FormDataElement& b)
class FormData : public RefCounted<FormData> {
public:
- static PassRefPtr<FormData> create();
- static PassRefPtr<FormData> create(const void*, size_t);
- static PassRefPtr<FormData> create(const CString&);
- static PassRefPtr<FormData> create(const Vector<char>&);
+ FormData() { }
+ FormData(const void* data, size_t);
+ FormData(const CString&);
PassRefPtr<FormData> copy() const;
void appendData(const void* data, size_t);
@@ -75,10 +74,9 @@ public:
const Vector<FormDataElement>& elements() const { return m_elements; }
private:
- FormData();
- FormData(const FormData&);
+ FormData(const FormData&);
- Vector<FormDataElement> m_elements;
+ Vector<FormDataElement> m_elements;
};
inline bool operator==(const FormData& a, const FormData& b)
diff --git a/WebCore/platform/network/HTTPParsers.cpp b/WebCore/platform/network/HTTPParsers.cpp
index 0858fc9..e71be5f 100644
--- a/WebCore/platform/network/HTTPParsers.cpp
+++ b/WebCore/platform/network/HTTPParsers.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
- * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -103,8 +103,7 @@ bool parseHTTPRefresh(const String& refresh, bool fromHttpEquivMeta, double& del
String filenameFromHTTPContentDisposition(const String& value)
{
- Vector<String> keyValuePairs;
- value.split(';', keyValuePairs);
+ Vector<String> keyValuePairs = value.split(';');
unsigned length = keyValuePairs.size();
for (unsigned i = 0; i < length; i++) {
diff --git a/WebCore/platform/network/qt/ResourceError.h b/WebCore/platform/network/ResourceError.cpp
index 0a8eb64..fd0674c 100644
--- a/WebCore/platform/network/qt/ResourceError.h
+++ b/WebCore/platform/network/ResourceError.cpp
@@ -24,26 +24,6 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef ResourceError_h
-#define ResourceError_h
+#include "config.h"
+#include "ResourceError.h"
-#include "ResourceErrorBase.h"
-
-namespace WebCore {
-
-class ResourceError : public ResourceErrorBase
-{
-public:
- ResourceError()
- {
- }
-
- ResourceError(const String& domain, int errorCode, const String& failingURL, const String& localizedDescription)
- : ResourceErrorBase(domain, errorCode, failingURL, localizedDescription)
- {
- }
-};
-
-}
-
-#endif // ResourceError_h_
diff --git a/WebCore/platform/network/ResourceError.h b/WebCore/platform/network/ResourceError.h
new file mode 100644
index 0000000..165dccd
--- /dev/null
+++ b/WebCore/platform/network/ResourceError.h
@@ -0,0 +1,168 @@
+// -*- mode: c++; c-basic-offset: 4 -*-
+/*
+ * Copyright (C) 2006 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.
+ */
+
+#ifndef ResourceError_h
+#define ResourceError_h
+
+#include "PlatformString.h"
+
+#if PLATFORM(CF)
+#include <wtf/RetainPtr.h>
+#endif
+
+#ifdef __OBJC__
+@class NSError;
+#else
+class NSError;
+#endif
+
+#if USE(CFNETWORK)
+#include <CoreFoundation/CFStream.h>
+#endif
+
+namespace WebCore {
+
+ class ResourceError {
+ public:
+ ResourceError()
+ : m_errorCode(0)
+#if PLATFORM(CF)
+ , m_dataIsUpToDate(true)
+#endif
+ , m_isNull(true)
+ {
+ }
+
+ ResourceError(const String& domain, int errorCode, const String& failingURL, const String& localizedDescription)
+ : m_domain(domain)
+ , m_errorCode(errorCode)
+ , m_failingURL(failingURL)
+ , m_localizedDescription(localizedDescription)
+#if PLATFORM(CF)
+ , m_dataIsUpToDate(true)
+#endif
+ , m_isNull(false)
+ {
+ }
+
+#if PLATFORM(CF)
+#if PLATFORM(MAC)
+ ResourceError(NSError* error)
+#else
+ ResourceError(CFStreamError error);
+ ResourceError(CFErrorRef error)
+#endif
+ : m_dataIsUpToDate(false)
+ , m_platformError(error)
+ , m_isNull(!error)
+ {
+ }
+#endif
+
+#if 0
+ static const String CocoaErrorDomain;
+ static const String POSIXDomain;
+ static const String OSStatusDomain;
+ static const String MachDomain;
+ static const String WebKitDomain;
+#endif
+
+ bool isNull() const { return m_isNull; }
+
+ const String& domain() const { unpackPlatformErrorIfNeeded(); return m_domain; }
+ int errorCode() const { unpackPlatformErrorIfNeeded(); return m_errorCode; }
+ const String& failingURL() const { unpackPlatformErrorIfNeeded(); return m_failingURL; }
+ const String& localizedDescription() const { unpackPlatformErrorIfNeeded(); return m_localizedDescription; }
+
+#if PLATFORM(CF)
+#if PLATFORM(MAC)
+ operator NSError*() const;
+#else
+ operator CFErrorRef() const;
+ operator CFStreamError() const;
+#endif
+#endif
+
+ private:
+ void unpackPlatformErrorIfNeeded() const
+ {
+#if PLATFORM(CF)
+ if (!m_dataIsUpToDate)
+ const_cast<ResourceError*>(this)->unpackPlatformError();
+#endif
+ }
+
+#if PLATFORM(CF)
+ void unpackPlatformError();
+#endif
+
+ String m_domain;
+ int m_errorCode;
+ String m_failingURL;
+ String m_localizedDescription;
+
+#if PLATFORM(CF)
+ bool m_dataIsUpToDate;
+#endif
+#if PLATFORM(MAC)
+ mutable RetainPtr<NSError> m_platformError;
+#elif PLATFORM(CF)
+ mutable RetainPtr<CFErrorRef> m_platformError;
+#endif
+ bool m_isNull;
+};
+
+inline bool operator==(const ResourceError& a, const ResourceError& b)
+{
+ if (a.isNull() && b.isNull())
+ return true;
+ if (a.isNull() || b.isNull())
+ return false;
+ if (a.domain() != b.domain())
+ return false;
+ if (a.errorCode() != b.errorCode())
+ return false;
+ if (a.failingURL() != b.failingURL())
+ return false;
+ if (a.localizedDescription() != b.localizedDescription())
+ return false;
+#if PLATFORM(CF)
+#if PLATFORM(MAC)
+ if ((NSError *)a != (NSError *)b)
+ return false;
+#else
+ if ((CFErrorRef)a != (CFErrorRef)b)
+ return false;
+#endif
+#endif
+ return true;
+}
+
+inline bool operator!=(const ResourceError& a, const ResourceError& b) { return !(a == b); }
+
+} // namespace WebCore
+
+#endif // ResourceError_h_
diff --git a/WebCore/platform/network/ResourceErrorBase.h b/WebCore/platform/network/ResourceErrorBase.h
deleted file mode 100644
index ccdf36a..0000000
--- a/WebCore/platform/network/ResourceErrorBase.h
+++ /dev/null
@@ -1,83 +0,0 @@
-// -*- mode: c++; c-basic-offset: 4 -*-
-/*
- * Copyright (C) 2006 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.
- */
-
-#ifndef ResourceErrorBase_h
-#define ResourceErrorBase_h
-
-#include "PlatformString.h"
-
-namespace WebCore {
-
-class ResourceError;
-
-class ResourceErrorBase {
-public:
- bool isNull() const { return m_isNull; }
-
- const String& domain() const { lazyInit(); return m_domain; }
- int errorCode() const { lazyInit(); return m_errorCode; }
- const String& failingURL() const { lazyInit(); return m_failingURL; }
- const String& localizedDescription() const { lazyInit(); return m_localizedDescription; }
-
- static bool compare(const ResourceError& a, const ResourceError& b);
-
-protected:
- ResourceErrorBase()
- : m_errorCode(0)
- , m_isNull(true)
- {
- }
-
- ResourceErrorBase(const String& domain, int errorCode, const String& failingURL, const String& localizedDescription)
- : m_domain(domain)
- , m_errorCode(errorCode)
- , m_failingURL(failingURL)
- , m_localizedDescription(localizedDescription)
- , m_isNull(false)
- {
- }
-
- void lazyInit() const;
-
- // The ResourceError subclass may "shadow" this method to lazily initialize platform specific fields
- void platformLazyInit() {}
-
- // The ResourceError subclass may "shadow" this method to compare platform specific fields
- static bool platformCompare(const ResourceError& a, const ResourceError& b) { return true; }
-
- String m_domain;
- int m_errorCode;
- String m_failingURL;
- String m_localizedDescription;
- bool m_isNull;
-};
-
-inline bool operator==(const ResourceError& a, const ResourceError& b) { return ResourceErrorBase::compare(a, b); }
-inline bool operator!=(const ResourceError& a, const ResourceError& b) { return !(a == b); }
-
-} // namespace WebCore
-
-#endif // ResourceErrorBase_h_
diff --git a/WebCore/platform/network/ResourceHandle.cpp b/WebCore/platform/network/ResourceHandle.cpp
index ef07a05..969a9f6 100644
--- a/WebCore/platform/network/ResourceHandle.cpp
+++ b/WebCore/platform/network/ResourceHandle.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2004, 2006, 2007 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -43,7 +43,7 @@ ResourceHandle::ResourceHandle(const ResourceRequest& request, ResourceHandleCli
PassRefPtr<ResourceHandle> ResourceHandle::create(const ResourceRequest& request, ResourceHandleClient* client,
Frame* frame, bool defersLoading, bool shouldContentSniff, bool mightDownloadFromHandle)
{
- RefPtr<ResourceHandle> newHandle(adoptRef(new ResourceHandle(request, client, defersLoading, shouldContentSniff, mightDownloadFromHandle)));
+ RefPtr<ResourceHandle> newHandle(new ResourceHandle(request, client, defersLoading, shouldContentSniff, mightDownloadFromHandle));
if (!portAllowed(request)) {
newHandle->scheduleBlockedFailure();
@@ -172,11 +172,11 @@ bool ResourceHandle::portAllowed(const ResourceRequest& request)
return true;
// Allow ports 21 and 22 for FTP URLs, as Mozilla does.
- if ((port == 21 || port == 22) && request.url().protocolIs("ftp"))
+ if ((port == 21 || port == 22) && request.url().deprecatedString().startsWith("ftp:", false))
return true;
// Allow any port number in a file URL, since the port number is ignored.
- if (request.url().protocolIs("file"))
+ if (request.url().deprecatedString().startsWith("file:", false))
return true;
return false;
diff --git a/WebCore/platform/network/ResourceHandle.h b/WebCore/platform/network/ResourceHandle.h
index e5a8065..c94a875 100644
--- a/WebCore/platform/network/ResourceHandle.h
+++ b/WebCore/platform/network/ResourceHandle.h
@@ -134,7 +134,7 @@ public:
friend LRESULT __stdcall ResourceHandleWndProc(HWND, unsigned message, WPARAM, LPARAM);
#endif
-#if PLATFORM(GTK) || PLATFORM(QT) || PLATFORM(WX)
+#if PLATFORM(GTK) || PLATFORM(QT) || PLATFORM(WX) || defined(ANDROID)
ResourceHandleInternal* getInternal() { return d.get(); }
#endif
diff --git a/WebCore/platform/network/ResourceHandleInternal.h b/WebCore/platform/network/ResourceHandleInternal.h
index 16f960e..c4b8b25 100644
--- a/WebCore/platform/network/ResourceHandleInternal.h
+++ b/WebCore/platform/network/ResourceHandleInternal.h
@@ -60,6 +60,12 @@ class NSURLConnection;
#endif
#endif
+#ifdef ANDROID_BRIDGE
+namespace android {
+ class WebCoreResourceLoader;
+}
+#endif
+
// The allocations and releases in ResourceHandleInternal are
// Cocoa-exception-free (either simple Foundation classes or
// WebCoreResourceLoaderImp which avoids doing work in dealloc).
@@ -111,6 +117,9 @@ namespace WebCore {
#elif USE(CFNETWORK)
, m_currentCFChallenge(0)
#endif
+#ifdef ANDROID_BRIDGE
+ , m_loader(0)
+#endif
{
}
@@ -174,6 +183,9 @@ namespace WebCore {
#if USE(CFNETWORK)
CFURLAuthChallengeRef m_currentCFChallenge;
#endif
+#ifdef ANDROID_BRIDGE
+ android::WebCoreResourceLoader* m_loader;
+#endif
AuthenticationChallenge m_currentWebChallenge;
};
diff --git a/WebCore/platform/network/ResourceResponseBase.cpp b/WebCore/platform/network/ResourceResponseBase.cpp
index 0c41847..06cc5ce 100644
--- a/WebCore/platform/network/ResourceResponseBase.cpp
+++ b/WebCore/platform/network/ResourceResponseBase.cpp
@@ -30,9 +30,14 @@
namespace WebCore {
+inline const ResourceResponse& ResourceResponseBase::asResourceResponse() const
+{
+ return *static_cast<const ResourceResponse*>(this);
+}
+
bool ResourceResponseBase::isHTTP() const
{
- lazyInit();
+ updateResourceResponse();
String protocol = m_url.protocol();
@@ -41,14 +46,14 @@ bool ResourceResponseBase::isHTTP() const
const KURL& ResourceResponseBase::url() const
{
- lazyInit();
+ updateResourceResponse();
return m_url;
}
void ResourceResponseBase::setUrl(const KURL& url)
{
- lazyInit();
+ updateResourceResponse();
m_isNull = false;
m_url = url;
@@ -56,14 +61,14 @@ void ResourceResponseBase::setUrl(const KURL& url)
const String& ResourceResponseBase::mimeType() const
{
- lazyInit();
+ updateResourceResponse();
return m_mimeType;
}
void ResourceResponseBase::setMimeType(const String& mimeType)
{
- lazyInit();
+ updateResourceResponse();
m_isNull = false;
m_mimeType = mimeType;
@@ -71,14 +76,14 @@ void ResourceResponseBase::setMimeType(const String& mimeType)
long long ResourceResponseBase::expectedContentLength() const
{
- lazyInit();
+ updateResourceResponse();
return m_expectedContentLength;
}
void ResourceResponseBase::setExpectedContentLength(long long expectedContentLength)
{
- lazyInit();
+ updateResourceResponse();
m_isNull = false;
m_expectedContentLength = expectedContentLength;
@@ -86,14 +91,14 @@ void ResourceResponseBase::setExpectedContentLength(long long expectedContentLen
const String& ResourceResponseBase::textEncodingName() const
{
- lazyInit();
+ updateResourceResponse();
return m_textEncodingName;
}
void ResourceResponseBase::setTextEncodingName(const String& encodingName)
{
- lazyInit();
+ updateResourceResponse();
m_isNull = false;
m_textEncodingName = encodingName;
@@ -102,14 +107,14 @@ void ResourceResponseBase::setTextEncodingName(const String& encodingName)
// FIXME should compute this on the fly
const String& ResourceResponseBase::suggestedFilename() const
{
- lazyInit();
+ updateResourceResponse();
return m_suggestedFilename;
}
void ResourceResponseBase::setSuggestedFilename(const String& suggestedName)
{
- lazyInit();
+ updateResourceResponse();
m_isNull = false;
m_suggestedFilename = suggestedName;
@@ -117,56 +122,56 @@ void ResourceResponseBase::setSuggestedFilename(const String& suggestedName)
int ResourceResponseBase::httpStatusCode() const
{
- lazyInit();
+ updateResourceResponse();
return m_httpStatusCode;
}
void ResourceResponseBase::setHTTPStatusCode(int statusCode)
{
- lazyInit();
+ updateResourceResponse();
m_httpStatusCode = statusCode;
}
const String& ResourceResponseBase::httpStatusText() const
{
- lazyInit();
+ updateResourceResponse();
return m_httpStatusText;
}
void ResourceResponseBase::setHTTPStatusText(const String& statusText)
{
- lazyInit();
+ updateResourceResponse();
m_httpStatusText = statusText;
}
String ResourceResponseBase::httpHeaderField(const String& name) const
{
- lazyInit();
+ updateResourceResponse();
return m_httpHeaderFields.get(name);
}
void ResourceResponseBase::setHTTPHeaderField(const String& name, const String& value)
{
- lazyInit();
+ updateResourceResponse();
m_httpHeaderFields.set(name, value);
}
const HTTPHeaderMap& ResourceResponseBase::httpHeaderFields() const
{
- lazyInit();
+ updateResourceResponse();
return m_httpHeaderFields;
}
bool ResourceResponseBase::isAttachment() const
{
- lazyInit();
+ updateResourceResponse();
String value = m_httpHeaderFields.get("Content-Disposition");
int loc = value.find(';');
@@ -178,38 +183,43 @@ bool ResourceResponseBase::isAttachment() const
void ResourceResponseBase::setExpirationDate(time_t expirationDate)
{
- lazyInit();
+ updateResourceResponse();
m_expirationDate = expirationDate;
}
time_t ResourceResponseBase::expirationDate() const
{
- lazyInit();
+ updateResourceResponse();
return m_expirationDate;
}
void ResourceResponseBase::setLastModifiedDate(time_t lastModifiedDate)
{
- lazyInit();
+ updateResourceResponse();
m_lastModifiedDate = lastModifiedDate;
}
time_t ResourceResponseBase::lastModifiedDate() const
{
- lazyInit();
+ updateResourceResponse();
return m_lastModifiedDate;
}
-void ResourceResponseBase::lazyInit() const
+void ResourceResponseBase::updateResourceResponse() const
{
- const_cast<ResourceResponse*>(static_cast<const ResourceResponse*>(this))->platformLazyInit();
+ if (m_isUpToDate)
+ return;
+
+ const_cast<ResourceResponse&>(asResourceResponse()).doUpdateResourceResponse();
+
+ m_isUpToDate = true;
}
-bool ResourceResponseBase::compare(const ResourceResponse& a, const ResourceResponse& b)
+bool operator==(const ResourceResponse& a, const ResourceResponse& b)
{
if (a.isNull() != b.isNull())
return false;
@@ -231,7 +241,11 @@ bool ResourceResponseBase::compare(const ResourceResponse& a, const ResourceResp
return false;
if (a.expirationDate() != b.expirationDate())
return false;
- return ResourceResponse::platformCompare(a, b);
-}
+#if PLATFORM(MAC)
+ if (a.nsURLResponse() != b.nsURLResponse())
+ return false;
+#endif
+ return true;
+ }
}
diff --git a/WebCore/platform/network/ResourceResponseBase.h b/WebCore/platform/network/ResourceResponseBase.h
index 503156a..50b6c43 100644
--- a/WebCore/platform/network/ResourceResponseBase.h
+++ b/WebCore/platform/network/ResourceResponseBase.h
@@ -77,16 +77,21 @@ class ResourceResponseBase {
void setLastModifiedDate(time_t);
time_t lastModifiedDate() const;
- static bool compare(const ResourceResponse& a, const ResourceResponse& b);
-
- const ResourceResponse& asResourceResponse() const;
+ inline const ResourceResponse& asResourceResponse() const;
protected:
+ // Used when response is initialized from a platform representation
+ ResourceResponseBase(bool isNull)
+ : m_isUpToDate(false)
+ , m_isNull(isNull)
+ {
+ }
+
ResourceResponseBase()
: m_expectedContentLength(0)
, m_httpStatusCode(0)
, m_expirationDate(0)
- , m_lastModifiedDate(0)
+ , m_isUpToDate(true)
, m_isNull(true)
{
}
@@ -99,34 +104,29 @@ class ResourceResponseBase {
, m_suggestedFilename(filename)
, m_httpStatusCode(0)
, m_expirationDate(0)
- , m_lastModifiedDate(0)
+ , m_isUpToDate(true)
, m_isNull(false)
{
}
- void lazyInit() const;
-
- // The ResourceResponse subclass may "shadow" this method to lazily initialize platform specific fields
- void platformLazyInit() {}
-
- // The ResourceResponse subclass may "shadow" this method to compare platform specific fields
- static bool platformCompare(const ResourceResponse& a, const ResourceResponse& b) { return true; }
+ void updateResourceResponse() const;
KURL m_url;
String m_mimeType;
long long m_expectedContentLength;
String m_textEncodingName;
String m_suggestedFilename;
- int m_httpStatusCode;
+ mutable int m_httpStatusCode;
String m_httpStatusText;
HTTPHeaderMap m_httpHeaderFields;
time_t m_expirationDate;
time_t m_lastModifiedDate;
+ mutable bool m_isUpToDate;
bool m_isNull;
};
-inline bool operator==(const ResourceResponse& a, const ResourceResponse& b) { return ResourceResponseBase::compare(a, b); }
+bool operator==(const ResourceResponse& a, const ResourceResponse& b);
inline bool operator!=(const ResourceResponse& a, const ResourceResponse& b) { return !(a == b); }
} // namespace WebCore
diff --git a/WebCore/platform/network/android/ResourceHandleAndroid.cpp b/WebCore/platform/network/android/ResourceHandleAndroid.cpp
new file mode 100644
index 0000000..35b3c5b
--- /dev/null
+++ b/WebCore/platform/network/android/ResourceHandleAndroid.cpp
@@ -0,0 +1,144 @@
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include "config.h"
+#include "ResourceHandle.h"
+
+#include "DocLoader.h"
+#include "FrameAndroid.h"
+#include "ResourceHandleClient.h"
+#include "ResourceHandleInternal.h"
+#include "WebCoreFrameBridge.h"
+#include "WebCoreResourceLoader.h"
+
+// #define notImplemented() do { fprintf(stderr, "FIXME: UNIMPLEMENTED %s %s:%d\n", __PRETTY_FUNCTION__, __FILE__, __LINE__); } while(0)
+
+namespace WebCore {
+
+ResourceHandleInternal::~ResourceHandleInternal()
+{
+ Release(m_loader);
+}
+
+ResourceHandle::~ResourceHandle()
+{
+}
+
+bool ResourceHandle::start(Frame* frame)
+{
+ FrameAndroid* f = Android(frame);
+ android::WebCoreResourceLoader* loader;
+ bool highPriority = true;
+ CachedResource* r = d->m_request.getCachedResource();
+ if (r) {
+ CachedResource::Type t = r->type();
+ highPriority = !(t == CachedResource::ImageResource ||
+ t == CachedResource::FontResource);
+ }
+ loader = f->bridge()->startLoadingResource(this, d->m_request, highPriority, false);
+
+ if (loader) {
+ Release(d->m_loader);
+ d->m_loader = loader;
+ }
+
+ return loader != NULL;
+}
+
+void ResourceHandle::cancel()
+{
+ if (d->m_loader)
+ d->m_loader->cancel();
+}
+
+PassRefPtr<SharedBuffer> ResourceHandle::bufferedData()
+{
+ return 0;
+}
+
+bool ResourceHandle::supportsBufferedData()
+{
+ // We don't support buffering data on the native side.
+ return false;
+}
+
+void ResourceHandle::setDefersLoading(bool defers)
+{
+ notImplemented();
+}
+
+/*
+* This static method is called to check to see if a POST response is in
+* the cache. The JNI call through to the HTTP cache stored on the Java
+* side may be slow, but is only used during a navigation to
+* a POST response.
+*/
+bool ResourceHandle::willLoadFromCache(ResourceRequest& request)
+{
+ // set the cache policy correctly, copied from
+ // network/mac/ResourceHandleMac.mm
+ request.setCachePolicy(ReturnCacheDataDontLoad);
+ return android::WebCoreResourceLoader::willLoadFromCache(request.url());
+}
+
+bool ResourceHandle::loadsBlocked()
+{
+ // FIXME, need to check whether connection pipe is blocked.
+ // return false for now
+ return false;
+}
+
+// Class to handle synchronized loading of resources.
+class SyncLoader : public ResourceHandleClient {
+public:
+ SyncLoader(ResourceError& error, ResourceResponse& response, Vector<char>& data) {
+ m_error = &error;
+ m_response = &response;
+ m_data = &data;
+ }
+ ~SyncLoader() {}
+
+ virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse& response) {
+ *m_response = response;
+ }
+
+ virtual void didReceiveData(ResourceHandle*, const char* data, int len, int lengthReceived) {
+ m_data->append(data, len);
+ }
+
+ virtual void didFail(ResourceHandle*, const ResourceError& error) {
+ *m_error = error;
+ }
+
+private:
+ ResourceError* m_error;
+ ResourceResponse* m_response;
+ Vector<char>* m_data;
+};
+
+void ResourceHandle::loadResourceSynchronously(const ResourceRequest& request,
+ ResourceError& error, ResourceResponse& response, Vector<char>& data,
+ Frame* frame)
+{
+ FrameAndroid* f = Android(frame);
+ SyncLoader s(error, response, data);
+ ResourceHandle h(request, &s, false, false, false);
+ // This blocks until the load is finished.
+ f->bridge()->startLoadingResource(&h, request, true, true);
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/network/android/ResourceRequest.h b/WebCore/platform/network/android/ResourceRequest.h
new file mode 100644
index 0000000..33676ae
--- /dev/null
+++ b/WebCore/platform/network/android/ResourceRequest.h
@@ -0,0 +1,93 @@
+// -*- mode: c++; c-basic-offset: 4 -*-
+/*
+ * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * 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.
+ */
+
+#ifndef ResourceRequest_h
+#define ResourceRequest_h
+
+#include "CachedResource.h"
+#include "ResourceRequestBase.h"
+
+namespace WebCore {
+
+ struct ResourceRequest : ResourceRequestBase {
+
+ ResourceRequest(const String& url)
+ : ResourceRequestBase(KURL(url.deprecatedString()), UseProtocolCachePolicy)
+ , m_cachedResource(0)
+#ifdef ANDROID_USER_GESTURE
+ , m_wasUserGesture(false)
+#endif
+ {
+ }
+
+ ResourceRequest(const KURL& url)
+ : ResourceRequestBase(url, UseProtocolCachePolicy)
+ , m_cachedResource(0)
+#ifdef ANDROID_USER_GESTURE
+ , m_wasUserGesture(false)
+#endif
+ {
+ }
+
+ ResourceRequest(const KURL& url, const String& referrer, ResourceRequestCachePolicy policy = UseProtocolCachePolicy)
+ : ResourceRequestBase(url, policy)
+ , m_cachedResource(0)
+#ifdef ANDROID_USER_GESTURE
+ , m_wasUserGesture(false)
+#endif
+ {
+ setHTTPReferrer(referrer);
+ }
+
+ ResourceRequest()
+ : ResourceRequestBase(KURL(), UseProtocolCachePolicy)
+ , m_cachedResource(0)
+#ifdef ANDROID_USER_GESTURE
+ , m_wasUserGesture(false)
+#endif
+ {
+ }
+
+ void doUpdatePlatformRequest() {}
+ void doUpdateResourceRequest() {}
+ void setCachedResource(CachedResource* r) { m_cachedResource = r; }
+ CachedResource* getCachedResource() const { return m_cachedResource; }
+#ifdef ANDROID_USER_GESTURE
+ void setUserGesture(bool userGesture) { m_wasUserGesture = userGesture; }
+ bool userGesture() const { return m_wasUserGesture; }
+#endif
+ private:
+ friend class ResourceRequestBase;
+ CachedResource* m_cachedResource;
+#ifdef ANDROID_USER_GESTURE
+ bool m_wasUserGesture;
+#endif
+ };
+
+} // namespace WebCore
+
+#endif // ResourceRequest_h
diff --git a/WebCore/platform/network/ResourceErrorBase.cpp b/WebCore/platform/network/android/ResourceResponse.h
index 5dfc890..94c93f5 100644
--- a/WebCore/platform/network/ResourceErrorBase.cpp
+++ b/WebCore/platform/network/android/ResourceResponse.h
@@ -24,37 +24,37 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "config.h"
-#include "ResourceError.h"
+#ifndef ResourceResponse_h
+#define ResourceResponse_h
-namespace WebCore {
+#include "ResourceResponseBase.h"
-void ResourceErrorBase::lazyInit() const
-{
- const_cast<ResourceError*>(static_cast<const ResourceError*>(this))->platformLazyInit();
-}
+#include "NotImplemented.h"
-bool ResourceErrorBase::compare(const ResourceError& a, const ResourceError& b)
-{
- if (a.isNull() && b.isNull())
- return true;
+namespace WebCore {
- if (a.isNull() || b.isNull())
- return false;
+class ResourceResponse : public ResourceResponseBase {
+public:
+ ResourceResponse()
+ : ResourceResponseBase()
+ {
+ }
- if (a.domain() != b.domain())
- return false;
+ ResourceResponse(const KURL& url, const String& mimeType, long long expectedLength, const String& textEncodingName, const String& filename)
+ : ResourceResponseBase(url, mimeType, expectedLength, textEncodingName, filename)
+ {
+ }
- if (a.errorCode() != b.errorCode())
- return false;
+private:
+ friend class ResourceResponseBase;
- if (a.failingURL() != b.failingURL())
- return false;
+ void doUpdateResourceResponse()
+ {
+ notImplemented();
+ }
- if (a.localizedDescription() != b.localizedDescription())
- return false;
+};
- return platformCompare(a, b);
-}
+} // namespace WebCore
-}
+#endif // ResourceResponse_h
diff --git a/WebCore/platform/network/cf/AuthenticationCF.cpp b/WebCore/platform/network/cf/AuthenticationCF.cpp
index bb05a39..72a6c9a 100644
--- a/WebCore/platform/network/cf/AuthenticationCF.cpp
+++ b/WebCore/platform/network/cf/AuthenticationCF.cpp
@@ -37,42 +37,18 @@
namespace WebCore {
-AuthenticationChallenge::AuthenticationChallenge(const ProtectionSpace& protectionSpace,
- const Credential& proposedCredential,
- unsigned previousFailureCount,
- const ResourceResponse& response,
- const ResourceError& error)
- : AuthenticationChallengeBase(protectionSpace,
- proposedCredential,
- previousFailureCount,
- response,
- error)
-{
-}
-
-AuthenticationChallenge::AuthenticationChallenge(CFURLAuthChallengeRef cfChallenge,
- ResourceHandle* sourceHandle)
- : AuthenticationChallengeBase(core(CFURLAuthChallengeGetProtectionSpace(cfChallenge)),
- core(CFURLAuthChallengeGetProposedCredential(cfChallenge)),
- CFURLAuthChallengeGetPreviousFailureCount(cfChallenge),
- (CFURLResponseRef)CFURLAuthChallengeGetFailureResponse(cfChallenge),
- CFURLAuthChallengeGetError(cfChallenge))
+AuthenticationChallenge::AuthenticationChallenge(CFURLAuthChallengeRef cfChallenge, ResourceHandle* sourceHandle)
+ : m_isNull(false)
+ , m_protectionSpace(core(CFURLAuthChallengeGetProtectionSpace(cfChallenge)))
+ , m_proposedCredential(core(CFURLAuthChallengeGetProposedCredential(cfChallenge)))
+ , m_previousFailureCount(CFURLAuthChallengeGetPreviousFailureCount(cfChallenge))
+ , m_failureResponse((CFURLResponseRef)CFURLAuthChallengeGetFailureResponse(cfChallenge))
+ , m_error(CFURLAuthChallengeGetError(cfChallenge))
, m_sourceHandle(sourceHandle)
, m_cfChallenge(cfChallenge)
{
}
-bool AuthenticationChallenge::platformCompare(const AuthenticationChallenge& a, const AuthenticationChallenge& b)
-{
- if (a.sourceHandle() != b.sourceHandle())
- return false;
-
- if (a.cfURLAuthChallengeRef() != b.cfURLAuthChallengeRef())
- return false;
-
- return true;
-}
-
CFURLAuthChallengeRef createCF(const AuthenticationChallenge& coreChallenge)
{
CFURLProtectionSpaceRef protectionSpace = createCF(coreChallenge.protectionSpace());
diff --git a/WebCore/platform/network/cf/AuthenticationChallenge.h b/WebCore/platform/network/cf/AuthenticationChallenge.h
deleted file mode 100644
index 9697d7e..0000000
--- a/WebCore/platform/network/cf/AuthenticationChallenge.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2007 Apple 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.
- */
-#ifndef AuthenticationChallenge_h
-#define AuthenticationChallenge_h
-
-#include "AuthenticationChallengeBase.h"
-#include "ResourceHandle.h"
-#include <wtf/RefPtr.h>
-
-typedef struct _CFURLAuthChallenge* CFURLAuthChallengeRef;
-
-namespace WebCore {
-
-class ResourceHandle;
-
-class AuthenticationChallenge : public AuthenticationChallengeBase {
-public:
- AuthenticationChallenge() {}
- AuthenticationChallenge(const ProtectionSpace& protectionSpace, const Credential& proposedCredential, unsigned previousFailureCount, const ResourceResponse& response, const ResourceError& error);
- AuthenticationChallenge(CFURLAuthChallengeRef, ResourceHandle* sourceHandle);
-
- ResourceHandle* sourceHandle() const { return m_sourceHandle.get(); }
- CFURLAuthChallengeRef cfURLAuthChallengeRef() const { return m_cfChallenge.get(); }
-
-private:
- friend class AuthenticationChallengeBase;
- static bool platformCompare(const AuthenticationChallenge& a, const AuthenticationChallenge& b);
-
- RefPtr<ResourceHandle> m_sourceHandle;
- RetainPtr<CFURLAuthChallengeRef> m_cfChallenge;
-};
-
-}
-
-#endif
diff --git a/WebCore/platform/network/cf/FormDataStreamCFNet.cpp b/WebCore/platform/network/cf/FormDataStreamCFNet.cpp
index 71fbfe7..c2416a1 100644
--- a/WebCore/platform/network/cf/FormDataStreamCFNet.cpp
+++ b/WebCore/platform/network/cf/FormDataStreamCFNet.cpp
@@ -389,11 +389,11 @@ void setHTTPBody(CFMutableURLRequestRef request, PassRefPtr<FormData> formData)
PassRefPtr<FormData> httpBodyFromRequest(CFURLRequestRef request)
{
if (RetainPtr<CFDataRef> bodyData = CFURLRequestCopyHTTPRequestBody(request))
- return FormData::create(CFDataGetBytePtr(bodyData.get()), CFDataGetLength(bodyData.get()));
+ return new FormData(CFDataGetBytePtr(bodyData.get()), CFDataGetLength(bodyData.get()));
if (wkCanAccessCFURLRequestHTTPBodyParts()) {
if (RetainPtr<CFArrayRef> bodyParts = wkCFURLRequestCopyHTTPRequestBodyParts(request)) {
- RefPtr<FormData> formData = FormData::create();
+ RefPtr<FormData> formData = new FormData();
CFIndex count = CFArrayGetCount(bodyParts.get());
for (CFIndex i = 0; i < count; i++) {
@@ -405,8 +405,9 @@ PassRefPtr<FormData> httpBodyFromRequest(CFURLRequestRef request)
} else if (typeID == CFDataGetTypeID()) {
CFDataRef data = (CFDataRef)bodyPart;
formData->appendData(CFDataGetBytePtr(data), CFDataGetLength(data));
- } else
+ } else {
ASSERT_NOT_REACHED();
+ }
}
return formData.release();
}
diff --git a/WebCore/platform/network/cf/ResourceError.h b/WebCore/platform/network/cf/ResourceError.h
deleted file mode 100644
index 1cde47e..0000000
--- a/WebCore/platform/network/cf/ResourceError.h
+++ /dev/null
@@ -1,74 +0,0 @@
-// -*- mode: c++; c-basic-offset: 4 -*-
-/*
- * Copyright (C) 2006 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.
- */
-
-#ifndef ResourceError_h
-#define ResourceError_h
-
-#include "ResourceErrorBase.h"
-
-#include <wtf/RetainPtr.h>
-#include <CoreFoundation/CFStream.h>
-
-namespace WebCore {
-
-class ResourceError : public ResourceErrorBase {
-public:
- ResourceError()
- : m_dataIsUpToDate(true)
- {
- }
-
- ResourceError(const String& domain, int errorCode, const String& failingURL, const String& localizedDescription)
- : ResourceErrorBase(domain, errorCode, failingURL, localizedDescription)
- , m_dataIsUpToDate(true)
- {
- }
-
- ResourceError(CFStreamError error);
-
- ResourceError(CFErrorRef error)
- : m_dataIsUpToDate(false)
- , m_platformError(error)
- {
- m_isNull = !error;
- }
-
- operator CFErrorRef() const;
- operator CFStreamError() const;
-
-private:
- friend class ResourceErrorBase;
-
- void platformLazyInit();
- static bool platformCompare(const ResourceError& a, const ResourceError& b);
-
- bool m_dataIsUpToDate;
- mutable RetainPtr<CFErrorRef> m_platformError;
-};
-
-} // namespace WebCore
-
-#endif // ResourceError_h_
diff --git a/WebCore/platform/network/cf/ResourceErrorCF.cpp b/WebCore/platform/network/cf/ResourceErrorCF.cpp
index 8e82cd5..f9ad76d 100644
--- a/WebCore/platform/network/cf/ResourceErrorCF.cpp
+++ b/WebCore/platform/network/cf/ResourceErrorCF.cpp
@@ -45,11 +45,10 @@ const CFStringRef failingURLKey = CFSTR("NSErrorFailingURLKey");
// FIXME: Once <rdar://problem/5050841> is fixed we can remove this constructor.
ResourceError::ResourceError(CFStreamError error)
- : m_dataIsUpToDate(true)
+ : m_errorCode(error.error)
+ , m_isNull(false)
+ , m_dataIsUpToDate(true)
{
- m_isNull = false;
- m_errorCode = error.error;
-
switch(error.domain) {
case kCFStreamErrorDomainCustom:
m_domain ="NSCustomErrorDomain";
@@ -63,11 +62,8 @@ ResourceError::ResourceError(CFStreamError error)
}
}
-void ResourceError::platformLazyInit()
+void ResourceError::unpackPlatformError()
{
- if (m_dataIsUpToDate)
- return;
-
if (!m_platformError)
return;
@@ -106,11 +102,6 @@ void ResourceError::platformLazyInit()
m_dataIsUpToDate = true;
}
-bool ResourceError::platformCompare(const ResourceError& a, const ResourceError& b)
-{
- return (CFErrorRef)a == (CFErrorRef)b;
-}
-
ResourceError::operator CFErrorRef() const
{
if (m_isNull) {
@@ -129,7 +120,7 @@ ResourceError::operator CFErrorRef() const
if (!m_failingURL.isEmpty()) {
RetainPtr<CFStringRef> failingURLString(AdoptCF, m_failingURL.createCFString());
CFDictionarySetValue(userInfo.get(), failingURLStringKey, failingURLString.get());
- RetainPtr<CFURLRef> url(AdoptCF, KURL(m_failingURL).createCFURL());
+ RetainPtr<CFURLRef> url(AdoptCF, KURL(m_failingURL.deprecatedString()).createCFURL());
CFDictionarySetValue(userInfo.get(), failingURLKey, url.get());
}
@@ -142,7 +133,7 @@ ResourceError::operator CFErrorRef() const
ResourceError::operator CFStreamError() const
{
- lazyInit();
+ unpackPlatformErrorIfNeeded();
CFStreamError result;
result.error = m_errorCode;
diff --git a/WebCore/platform/network/cf/ResourceRequest.h b/WebCore/platform/network/cf/ResourceRequest.h
index 5c49b06..5070380 100644
--- a/WebCore/platform/network/cf/ResourceRequest.h
+++ b/WebCore/platform/network/cf/ResourceRequest.h
@@ -38,7 +38,7 @@ namespace WebCore {
struct ResourceRequest : ResourceRequestBase {
ResourceRequest(const String& url)
- : ResourceRequestBase(KURL(url), UseProtocolCachePolicy)
+ : ResourceRequestBase(KURL(url.deprecatedString()), UseProtocolCachePolicy)
{
}
diff --git a/WebCore/platform/network/cf/ResourceResponse.h b/WebCore/platform/network/cf/ResourceResponse.h
index 7e7c0fa..c930dfc 100644
--- a/WebCore/platform/network/cf/ResourceResponse.h
+++ b/WebCore/platform/network/cf/ResourceResponse.h
@@ -36,20 +36,16 @@ namespace WebCore {
class ResourceResponse : public ResourceResponseBase {
public:
ResourceResponse()
- : m_isUpToDate(true)
+ : ResourceResponseBase()
{
}
ResourceResponse(CFURLResponseRef cfResponse)
- : m_cfResponse(cfResponse)
- , m_isUpToDate(false)
- {
- m_isNull = !cfResponse;
- }
+ : ResourceResponseBase(!cfResponse)
+ , m_cfResponse(cfResponse) { }
ResourceResponse(const KURL& url, const String& mimeType, long long expectedLength, const String& textEncodingName, const String& filename)
: ResourceResponseBase(url, mimeType, expectedLength, textEncodingName, filename)
- , m_isUpToDate(true)
{
}
@@ -58,11 +54,10 @@ public:
private:
friend class ResourceResponseBase;
- void platformLazyInit();
- static bool platformCompare(const ResourceResponse& a, const ResourceResponse& b);
+ void doUpdateResourceResponse();
RetainPtr<CFURLResponseRef> m_cfResponse;
- bool m_isUpToDate;
+
};
} // namespace WebCore
diff --git a/WebCore/platform/network/cf/ResourceResponseCFNet.cpp b/WebCore/platform/network/cf/ResourceResponseCFNet.cpp
index 79efe89..d643f8e 100644
--- a/WebCore/platform/network/cf/ResourceResponseCFNet.cpp
+++ b/WebCore/platform/network/cf/ResourceResponseCFNet.cpp
@@ -62,16 +62,10 @@ static time_t toTimeT(CFAbsoluteTime time)
return min(max(minTimeAsDouble, time + kCFAbsoluteTimeIntervalSince1970), maxTimeAsDouble);
}
-void ResourceResponse::platformLazyInit()
+void ResourceResponse::doUpdateResourceResponse()
{
- if (m_isUpToDate)
+ if (!m_cfResponse.get())
return;
- m_isUpToDate = true;
-
- if (m_isNull) {
- ASSERT(!m_cfResponse.get());
- return;
- }
// FIXME: We may need to do MIME type sniffing here (unless that is done in CFURLResponseGetMIMEType).
@@ -108,10 +102,4 @@ void ResourceResponse::platformLazyInit()
m_httpStatusCode = 0;
}
-bool ResourceResponse::platformCompare(const ResourceResponse& a, const ResourceResponse& b)
-{
- return CFEqual(a.cfURLResponse(), b.cfURLResponse());
-}
-
-
}
diff --git a/WebCore/platform/network/curl/ResourceHandleManager.cpp b/WebCore/platform/network/curl/ResourceHandleManager.cpp
index b8fa696..249aa4e 100644
--- a/WebCore/platform/network/curl/ResourceHandleManager.cpp
+++ b/WebCore/platform/network/curl/ResourceHandleManager.cpp
@@ -42,20 +42,12 @@
#include <errno.h>
#include <wtf/Vector.h>
-#if PLATFORM(GTK)
- #if GLIB_CHECK_VERSION(2,12,0)
- #define USE_GLIB_BASE64
- #endif
-#endif
-
namespace WebCore {
const int selectTimeoutMS = 5;
const double pollTimeSeconds = 0.05;
const int maxRunningJobs = 5;
-static const bool ignoreSSLErrors = getenv("WEBKIT_IGNORE_SSL_ERRORS");
-
ResourceHandleManager::ResourceHandleManager()
: m_downloadTimer(this, &ResourceHandleManager::downloadTimerCallback)
, m_cookieJarFileName(0)
@@ -174,7 +166,7 @@ static size_t headerCallback(char* ptr, size_t size, size_t nmemb, void* data)
if (httpCode >= 300 && httpCode < 400) {
String location = d->m_response.httpHeaderField("location");
if (!location.isEmpty()) {
- KURL newURL = KURL(job->request().url(), location);
+ KURL newURL = KURL(job->request().url(), location.deprecatedString());
ResourceRequest redirectedRequest = job->request();
redirectedRequest.setURL(newURL);
@@ -279,17 +271,13 @@ void ResourceHandleManager::downloadTimerCallback(Timer<ResourceHandleManager>*
// Temporarily disable timers since signals may interrupt select(), raising EINTR errors on some platforms
setDeferringTimers(true);
- int rc = 0;
+ int rc;
do {
FD_ZERO(&fdread);
FD_ZERO(&fdwrite);
FD_ZERO(&fdexcep);
curl_multi_fdset(m_curlMultiHandle, &fdread, &fdwrite, &fdexcep, &maxfd);
- // When the 3 file descriptors are empty, winsock will return -1
- // and bail out, stopping the file download. So make sure we
- // have valid file descriptors before calling select.
- if (maxfd >= 0)
- rc = ::select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout);
+ rc = ::select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout);
} while (rc == -1 && errno == EINTR);
setDeferringTimers(false);
@@ -463,44 +451,35 @@ bool ResourceHandleManager::startScheduledJobs()
return started;
}
-// FIXME: This function does not deal properly with text encodings.
static void parseDataUrl(ResourceHandle* handle)
{
- String data = handle->request().url().string();
+ DeprecatedString data = handle->request().url().deprecatedString();
ASSERT(data.startsWith("data:", false));
- String header;
+ DeprecatedString header;
bool base64 = false;
int index = data.find(',');
if (index != -1) {
- header = data.substring(5, index - 5).lower();
- data = data.substring(index + 1);
+ header = data.mid(5, index - 5).lower();
+ data = data.mid(index + 1);
if (header.endsWith(";base64")) {
base64 = true;
header = header.left(header.length() - 7);
}
} else
- data = String();
-
- data = decodeURLEscapeSequences(data);
-
- size_t outLength = 0;
- char* outData = 0;
- if (base64 && !data.isEmpty()) {
- // Use the GLib Base64 if available, since WebCore's decoder isn't
- // general-purpose and fails on Acid3 test 97 (whitespace).
-#ifdef USE_GLIB_BASE64
- outData = reinterpret_cast<char*>(g_base64_decode(data.utf8().data(), &outLength));
-#else
+ data = DeprecatedString();
+
+ data = KURL::decode_string(data);
+
+ if (base64) {
Vector<char> out;
- if (base64Decode(data.latin1().data(), data.length(), out))
- data = String(out.data(), out.size());
+ if (base64Decode(data.ascii(), data.length(), out))
+ data = DeprecatedString(out.data(), out.size());
else
- data = String();
-#endif
+ data = DeprecatedString();
}
if (header.isEmpty())
@@ -512,22 +491,13 @@ static void parseDataUrl(ResourceHandle* handle)
response.setMimeType(extractMIMETypeFromMediaType(header));
response.setTextEncodingName(extractCharsetFromMediaType(header));
- if (outData)
- response.setExpectedContentLength(outLength);
- else
- response.setExpectedContentLength(data.length());
+ response.setExpectedContentLength(data.length());
response.setHTTPStatusCode(200);
client->didReceiveResponse(handle, response);
- if (outData)
- client->didReceiveData(handle, outData, outLength, 0);
- else
- client->didReceiveData(handle, data.latin1().data(), data.length(), 0);
-
-#ifdef USE_GLIB_BASE64
- g_free(outData);
-#endif
+ if (!data.isEmpty())
+ client->didReceiveData(handle, data.ascii(), data.length(), 0);
client->didFinishLoading(handle);
}
@@ -535,8 +505,9 @@ static void parseDataUrl(ResourceHandle* handle)
void ResourceHandleManager::startJob(ResourceHandle* job)
{
KURL kurl = job->request().url();
+ String protocol = kurl.protocol();
- if (kurl.protocolIs("data")) {
+ if (equalIgnoringCase(protocol, "data")) {
parseDataUrl(job);
return;
}
@@ -545,15 +516,15 @@ void ResourceHandleManager::startJob(ResourceHandle* job)
kurl.setRef("");
ResourceHandleInternal* d = job->getInternal();
- String url = kurl.string();
+ DeprecatedString url = kurl.deprecatedString();
if (kurl.isLocalFile()) {
- String query = kurl.query();
+ DeprecatedString query = kurl.query();
// Remove any query part sent to a local file.
if (!query.isEmpty())
url = url.left(url.find(query));
// Determine the MIME type based on the path.
- d->m_response.setMimeType(MIMETypeRegistry::getMIMETypeForPath(url));
+ d->m_response.setMimeType(MIMETypeRegistry::getMIMETypeForPath(String(url)));
}
d->m_handle = curl_easy_init();
@@ -573,16 +544,12 @@ void ResourceHandleManager::startJob(ResourceHandle* job)
curl_easy_setopt(d->m_handle, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
curl_easy_setopt(d->m_handle, CURLOPT_SHARE, m_curlShareHandle);
curl_easy_setopt(d->m_handle, CURLOPT_DNS_CACHE_TIMEOUT, 60 * 5); // 5 minutes
- // FIXME: Enable SSL verification when we have a way of shipping certs
- // and/or reporting SSL errors to the user.
- if (ignoreSSLErrors)
- curl_easy_setopt(d->m_handle, CURLOPT_SSL_VERIFYPEER, false);
// enable gzip and deflate through Accept-Encoding:
curl_easy_setopt(d->m_handle, CURLOPT_ENCODING, "");
// url must remain valid through the request
ASSERT(!d->m_url);
- d->m_url = strdup(url.latin1().data());
+ d->m_url = strdup(url.ascii());
curl_easy_setopt(d->m_handle, CURLOPT_URL, d->m_url);
if (m_cookieJarFileName) {
@@ -625,7 +592,7 @@ void ResourceHandleManager::startJob(ResourceHandle* job)
// timeout will occur and do curl_multi_perform
if (ret && ret != CURLM_CALL_MULTI_PERFORM) {
#ifndef NDEBUG
- printf("Error %d starting job %s\n", ret, job->request().url().string().latin1().data());
+ printf("Error %d starting job %s\n", ret, job->request().url().deprecatedString().ascii());
#endif
job->cancel();
return;
diff --git a/WebCore/platform/network/curl/ResourceRequest.h b/WebCore/platform/network/curl/ResourceRequest.h
index c7edb91..fbe2cbc 100644
--- a/WebCore/platform/network/curl/ResourceRequest.h
+++ b/WebCore/platform/network/curl/ResourceRequest.h
@@ -35,7 +35,7 @@ namespace WebCore {
struct ResourceRequest : ResourceRequestBase {
ResourceRequest(const String& url)
- : ResourceRequestBase(KURL(url), UseProtocolCachePolicy)
+ : ResourceRequestBase(KURL(url.deprecatedString()), UseProtocolCachePolicy)
{
}
diff --git a/WebCore/platform/network/curl/ResourceResponse.h b/WebCore/platform/network/curl/ResourceResponse.h
index 086eae8..ca364b6 100644
--- a/WebCore/platform/network/curl/ResourceResponse.h
+++ b/WebCore/platform/network/curl/ResourceResponse.h
@@ -34,7 +34,8 @@ namespace WebCore {
class ResourceResponse : public ResourceResponseBase {
public:
ResourceResponse()
- : m_responseFired(false)
+ : ResourceResponseBase(false),
+ m_responseFired(false)
{
}
@@ -48,7 +49,14 @@ public:
bool responseFired() { return m_responseFired; }
private:
+ friend class ResourceResponseBase;
+
+ void doUpdateResourceResponse()
+ {
+ }
+
bool m_responseFired;
+
};
} // namespace WebCore
diff --git a/WebCore/platform/network/mac/AuthenticationMac.mm b/WebCore/platform/network/mac/AuthenticationMac.mm
index 54e7681..1555cac 100644
--- a/WebCore/platform/network/mac/AuthenticationMac.mm
+++ b/WebCore/platform/network/mac/AuthenticationMac.mm
@@ -37,40 +37,18 @@
namespace WebCore {
-AuthenticationChallenge::AuthenticationChallenge(const ProtectionSpace& protectionSpace,
- const Credential& proposedCredential,
- unsigned previousFailureCount,
- const ResourceResponse& response,
- const ResourceError& error)
- : AuthenticationChallengeBase(protectionSpace,
- proposedCredential,
- previousFailureCount,
- response,
- error)
-{
-}
-
AuthenticationChallenge::AuthenticationChallenge(NSURLAuthenticationChallenge *macChallenge)
- : AuthenticationChallengeBase(core([macChallenge protectionSpace]),
- core([macChallenge proposedCredential]),
- [macChallenge previousFailureCount],
- [macChallenge failureResponse],
- [macChallenge error])
+ : m_isNull(false)
+ , m_protectionSpace(core([macChallenge protectionSpace]))
+ , m_proposedCredential(core([macChallenge proposedCredential]))
+ , m_previousFailureCount([macChallenge previousFailureCount])
+ , m_failureResponse([macChallenge failureResponse])
+ , m_error([macChallenge error])
, m_sender([macChallenge sender])
, m_macChallenge(macChallenge)
{
}
-bool AuthenticationChallenge::platformCompare(const AuthenticationChallenge& a, const AuthenticationChallenge& b)
-{
- if (a.sender() != b.sender())
- return false;
-
- if (a.nsURLAuthenticationChallenge() != b.nsURLAuthenticationChallenge())
- return false;
-
- return true;
-}
NSURLAuthenticationChallenge *mac(const AuthenticationChallenge& coreChallenge)
{
diff --git a/WebCore/platform/network/mac/ResourceErrorMac.mm b/WebCore/platform/network/mac/ResourceErrorMac.mm
index 92f4d40..90afe01 100644
--- a/WebCore/platform/network/mac/ResourceErrorMac.mm
+++ b/WebCore/platform/network/mac/ResourceErrorMac.mm
@@ -1,6 +1,6 @@
// -*- mode: c++; c-basic-offset: 4 -*-
/*
- * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 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
@@ -25,9 +25,8 @@
*/
#import "config.h"
-#import "ResourceError.h"
-
#import "KURL.h"
+#import "ResourceError.h"
#import <Foundation/Foundation.h>
@interface NSError (WebExtras)
@@ -36,11 +35,8 @@
namespace WebCore {
-void ResourceError::platformLazyInit()
+void ResourceError::unpackPlatformError()
{
- if (m_dataIsUpToDate)
- return;
-
m_domain = [m_platformError.get() domain];
m_errorCode = [m_platformError.get() code];
@@ -53,11 +49,6 @@ void ResourceError::platformLazyInit()
m_dataIsUpToDate = true;
}
-bool ResourceError::platformCompare(const ResourceError& a, const ResourceError& b)
-{
- return (NSError*)a == (NSError*)b;
-}
-
ResourceError::operator NSError*() const
{
if (m_isNull) {
@@ -72,9 +63,8 @@ ResourceError::operator NSError*() const
[userInfo.get() setValue:m_localizedDescription forKey:NSLocalizedDescriptionKey];
if (!m_failingURL.isEmpty()) {
- NSURL *cocoaURL = KURL(m_failingURL);
[userInfo.get() setValue:m_failingURL forKey:@"NSErrorFailingURLStringKey"];
- [userInfo.get() setValue:cocoaURL forKey:@"NSErrorFailingURLKey"];
+ [userInfo.get() setValue:KURL(m_failingURL.deprecatedString()).getNSURL() forKey:@"NSErrorFailingURLKey"];
}
m_platformError.adoptNS([[NSError alloc] initWithDomain:m_domain code:m_errorCode userInfo:userInfo.get()]);
@@ -84,3 +74,4 @@ ResourceError::operator NSError*() const
}
} // namespace WebCore
+
diff --git a/WebCore/platform/network/mac/ResourceRequest.h b/WebCore/platform/network/mac/ResourceRequest.h
index 6d8cb6d..9f6652a 100644
--- a/WebCore/platform/network/mac/ResourceRequest.h
+++ b/WebCore/platform/network/mac/ResourceRequest.h
@@ -1,6 +1,6 @@
// -*- mode: c++; c-basic-offset: 4 -*-
/*
- * Copyright (C) 2003, 2006, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2006 Apple Computer, Inc. All rights reserved.
* Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
*
* Redistribution and use in source and binary forms, with or without
@@ -42,7 +42,7 @@ namespace WebCore {
class ResourceRequest : public ResourceRequestBase {
public:
ResourceRequest(const String& url)
- : ResourceRequestBase(KURL(url), UseProtocolCachePolicy)
+ : ResourceRequestBase(KURL(url.deprecatedString()), UseProtocolCachePolicy)
{
}
diff --git a/WebCore/platform/network/mac/ResourceRequestMac.mm b/WebCore/platform/network/mac/ResourceRequestMac.mm
index 6735024..1fdbd4e 100644
--- a/WebCore/platform/network/mac/ResourceRequestMac.mm
+++ b/WebCore/platform/network/mac/ResourceRequestMac.mm
@@ -59,7 +59,7 @@ void ResourceRequest::doUpdateResourceRequest()
m_httpHeaderFields.set(name, [headers objectForKey:name]);
if (NSData* bodyData = [m_nsRequest.get() HTTPBody])
- m_httpBody = FormData::create([bodyData bytes], [bodyData length]);
+ m_httpBody = new FormData([bodyData bytes], [bodyData length]);
else if (NSInputStream* bodyStream = [m_nsRequest.get() HTTPBodyStream])
if (FormData* formData = httpBodyFromStream(bodyStream))
m_httpBody = formData;
@@ -75,17 +75,15 @@ void ResourceRequest::doUpdatePlatformRequest()
NSMutableURLRequest* nsRequest = [m_nsRequest.get() mutableCopy];
if (nsRequest)
- [nsRequest setURL:url()];
+ [nsRequest setURL:url().getNSURL()];
else
- nsRequest = [[NSMutableURLRequest alloc] initWithURL:url()];
-
-#ifdef BUILDING_ON_TIGER
+ nsRequest = [[NSMutableURLRequest alloc] initWithURL:url().getNSURL()];
+
wkSupportsMultipartXMixedReplace(nsRequest);
-#endif
[nsRequest setCachePolicy:(NSURLRequestCachePolicy)cachePolicy()];
[nsRequest setTimeoutInterval:timeoutInterval()];
- [nsRequest setMainDocumentURL:mainDocumentURL()];
+ [nsRequest setMainDocumentURL:mainDocumentURL().getNSURL()];
if (!httpMethod().isEmpty())
[nsRequest setHTTPMethod:httpMethod()];
[nsRequest setHTTPShouldHandleCookies:allowHTTPCookies()];
diff --git a/WebCore/platform/network/mac/ResourceResponse.h b/WebCore/platform/network/mac/ResourceResponse.h
index 1313bae..be4f8dc 100644
--- a/WebCore/platform/network/mac/ResourceResponse.h
+++ b/WebCore/platform/network/mac/ResourceResponse.h
@@ -41,20 +41,16 @@ namespace WebCore {
class ResourceResponse : public ResourceResponseBase {
public:
ResourceResponse()
- : m_isUpToDate(true)
+ : ResourceResponseBase()
{
}
ResourceResponse(NSURLResponse* nsResponse)
- : m_nsResponse(nsResponse)
- , m_isUpToDate(false)
- {
- m_isNull = !nsResponse;
- }
+ : ResourceResponseBase(!nsResponse)
+ , m_nsResponse(nsResponse) { }
ResourceResponse(const KURL& url, const String& mimeType, long long expectedLength, const String& textEncodingName, const String& filename)
: ResourceResponseBase(url, mimeType, expectedLength, textEncodingName, filename)
- , m_isUpToDate(true)
{
}
@@ -63,11 +59,10 @@ public:
private:
friend class ResourceResponseBase;
- void platformLazyInit();
- static bool platformCompare(const ResourceResponse& a, const ResourceResponse& b);
+ void doUpdateResourceResponse();
RetainPtr<NSURLResponse> m_nsResponse;
- bool m_isUpToDate;
+
};
} // namespace WebCore
diff --git a/WebCore/platform/network/mac/ResourceResponseMac.mm b/WebCore/platform/network/mac/ResourceResponseMac.mm
index 0af5b32..58e9cf8 100644
--- a/WebCore/platform/network/mac/ResourceResponseMac.mm
+++ b/WebCore/platform/network/mac/ResourceResponseMac.mm
@@ -52,17 +52,13 @@ NSURLResponse *ResourceResponse::nsURLResponse() const
expectedContentLength = -1;
else
expectedContentLength = static_cast<NSInteger>(m_expectedContentLength);
- const_cast<ResourceResponse*>(this)->m_nsResponse.adoptNS([[NSURLResponse alloc] initWithURL:m_url MIMEType:m_mimeType expectedContentLength:expectedContentLength textEncodingName:m_textEncodingName]);
+ const_cast<ResourceResponse*>(this)->m_nsResponse.adoptNS([[NSURLResponse alloc] initWithURL:m_url.getNSURL() MIMEType:m_mimeType expectedContentLength:expectedContentLength textEncodingName:m_textEncodingName]);
}
return m_nsResponse.get();
}
-void ResourceResponse::platformLazyInit()
+void ResourceResponse::doUpdateResourceResponse()
{
- if (m_isUpToDate)
- return;
- m_isUpToDate = true;
-
if (m_isNull) {
ASSERT(!m_nsResponse);
return;
@@ -108,9 +104,4 @@ void ResourceResponse::platformLazyInit()
}
}
-bool ResourceResponse::platformCompare(const ResourceResponse& a, const ResourceResponse& b)
-{
- return a.nsURLResponse() == b.nsURLResponse();
-}
-
}
diff --git a/WebCore/platform/network/qt/ResourceHandleQt.cpp b/WebCore/platform/network/qt/ResourceHandleQt.cpp
index 3b25f25..9037401 100644
--- a/WebCore/platform/network/qt/ResourceHandleQt.cpp
+++ b/WebCore/platform/network/qt/ResourceHandleQt.cpp
@@ -31,6 +31,7 @@
#include "Frame.h"
#include "DocLoader.h"
#include "ResourceHandle.h"
+#include "DeprecatedString.h"
#include "ResourceHandleClient.h"
#include "ResourceHandleInternal.h"
#include "qwebpage_p.h"
diff --git a/WebCore/platform/network/qt/ResourceRequest.h b/WebCore/platform/network/qt/ResourceRequest.h
index 6b40639..dab4ffa 100644
--- a/WebCore/platform/network/qt/ResourceRequest.h
+++ b/WebCore/platform/network/qt/ResourceRequest.h
@@ -37,7 +37,7 @@ namespace WebCore {
struct ResourceRequest : ResourceRequestBase {
ResourceRequest(const String& url)
- : ResourceRequestBase(KURL(url), UseProtocolCachePolicy)
+ : ResourceRequestBase(KURL(url.deprecatedString()), UseProtocolCachePolicy)
{
}
diff --git a/WebCore/platform/network/qt/ResourceResponse.h b/WebCore/platform/network/qt/ResourceResponse.h
index 36b67ea..fb658c9 100644
--- a/WebCore/platform/network/qt/ResourceResponse.h
+++ b/WebCore/platform/network/qt/ResourceResponse.h
@@ -29,11 +29,14 @@
#include "ResourceResponseBase.h"
+#include "NotImplemented.h"
+
namespace WebCore {
class ResourceResponse : public ResourceResponseBase {
public:
ResourceResponse()
+ : ResourceResponseBase(false)
{
}
@@ -41,6 +44,15 @@ public:
: ResourceResponseBase(url, mimeType, expectedLength, textEncodingName, filename)
{
}
+
+private:
+ friend class ResourceResponseBase;
+
+ void doUpdateResourceResponse()
+ {
+ notImplemented();
+ }
+
};
} // namespace WebCore
diff --git a/WebCore/platform/network/win/CookieJarWin.cpp b/WebCore/platform/network/win/CookieJarWin.cpp
index 9eedcb0..2c1d58b 100644
--- a/WebCore/platform/network/win/CookieJarWin.cpp
+++ b/WebCore/platform/network/win/CookieJarWin.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -24,10 +24,9 @@
*/
#include "config.h"
-#include "CookieJar.h"
-
#include "KURL.h"
#include "PlatformString.h"
+#include "DeprecatedString.h"
#include "Document.h"
#include "ResourceHandle.h"
#include <windows.h>
@@ -39,9 +38,8 @@
#include <Wininet.h>
#endif
-// FIXME: This should be broken up into CookieJarCFNet.cpp and CookieJarWin.cpp or CookieJarWinINet.cpp.
-
-namespace WebCore {
+namespace WebCore
+{
#if USE(CFNETWORK)
static const CFStringRef s_setCookieKeyCF = CFSTR("Set-Cookie");
@@ -77,9 +75,11 @@ void setCookies(Document* /*document*/, const KURL& url, const KURL& policyURL,
CFHTTPCookieStorageSetCookies(defaultCookieStorage, cookiesCF.get(), urlCF.get(), policyURLCF.get());
#else
// FIXME: Deal with the policy URL.
- String str = url.string();
- String val = value;
- InternetSetCookie(str.charactersWithNullTermination(), 0, val.charactersWithNullTermination());
+ DeprecatedString str = url.deprecatedString();
+ str.append((UChar)'\0');
+ DeprecatedString val = value.deprecatedString();
+ val.append((UChar)'\0');
+ InternetSetCookie((UChar*)str.unicode(), 0, (UChar*)val.unicode());
#endif
}
@@ -110,17 +110,19 @@ String cookies(const Document* /*document*/, const KURL& url)
return (CFStringRef)CFDictionaryGetValue(headerCF.get(), s_cookieCF);
#else
- String str = url.string();
+ DeprecatedString str = url.deprecatedString();
+ str.append((UChar)'\0');
- DWORD count = str.length() + 1;
- InternetGetCookie(str.charactersWithNullTermination(), 0, 0, &count);
+ DWORD count = str.length();
+ InternetGetCookie((UChar*)str.unicode(), 0, 0, &count);
if (count <= 1) // Null terminator counts as 1.
return String();
- Vector<UChar> buffer(count);
- InternetGetCookie(buffer.data(), 0, buffer, &count);
- buffer.shrink(count - 1); // Ignore the null terminator.
- return String::adopt(buffer);
+ UChar* buffer = new UChar[count];
+ InternetGetCookie((UChar*)str.unicode(), 0, buffer, &count);
+ String& result = String(buffer, count-1); // Ignore the null terminator.
+ delete[] buffer;
+ return result;
#endif
}
diff --git a/WebCore/platform/network/win/ResourceHandleWin.cpp b/WebCore/platform/network/win/ResourceHandleWin.cpp
index 337b752..260652e 100644
--- a/WebCore/platform/network/win/ResourceHandleWin.cpp
+++ b/WebCore/platform/network/win/ResourceHandleWin.cpp
@@ -146,13 +146,13 @@ void ResourceHandle::onHandleCreated(LPARAM lParam)
if (method() == "POST") {
// FIXME: Too late to set referrer properly.
- String urlStr = url().path();
+ DeprecatedString urlStr = url().path();
int fragmentIndex = urlStr.find('#');
if (fragmentIndex != -1)
urlStr = urlStr.left(fragmentIndex);
static LPCSTR accept[2]={"*/*", NULL};
HINTERNET urlHandle = HttpOpenRequestA(d->m_resourceHandle,
- "POST", urlStr.latin1().data(), 0, 0, accept,
+ "POST", urlStr.latin1(), 0, 0, accept,
INTERNET_FLAG_KEEP_CONNECTION |
INTERNET_FLAG_FORMS_SUBMIT |
INTERNET_FLAG_RELOAD |
@@ -328,12 +328,11 @@ bool ResourceHandle::start(Frame* frame)
{
ref();
if (url().isLocalFile()) {
- String path = url().path();
+ DeprecatedString path = url().path();
// windows does not enjoy a leading slash on paths
if (path[0] == '/')
- path = path.substring(1);
- // FIXME: This is wrong. Need to use wide version of this call.
- d->m_fileHandle = CreateFileA(path.utf8().data(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ path = path.mid(1);
+ d->m_fileHandle = CreateFileA(path.ascii(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
// FIXME: perhaps this error should be reported asynchronously for
// consistency.
@@ -373,15 +372,16 @@ bool ResourceHandle::start(Frame* frame)
String referrer = frame->loader()->referrer();
if (method() == "POST") {
d->m_postReferrer = referrer;
- String host = url().host();
- urlHandle = InternetConnectA(internetHandle, host.latin1().data(),
+ DeprecatedString host = url().host();
+ host += "\0";
+ urlHandle = InternetConnectA(internetHandle, host.ascii(),
url().port(),
NULL, // no username
NULL, // no password
INTERNET_SERVICE_HTTP,
flags, (DWORD_PTR)d->m_jobId);
} else {
- String urlStr = url().string();
+ DeprecatedString urlStr = url().deprecatedString();
int fragmentIndex = urlStr.find('#');
if (fragmentIndex != -1)
urlStr = urlStr.left(fragmentIndex);
@@ -389,8 +389,8 @@ bool ResourceHandle::start(Frame* frame)
if (!referrer.isEmpty())
headers += String("Referer: ") + referrer + "\r\n";
- urlHandle = InternetOpenUrlA(internetHandle, urlStr.latin1().data(),
- headers.latin1().data(), headers.length(),
+ urlHandle = InternetOpenUrlA(internetHandle, urlStr.ascii(),
+ headers.latin1(), headers.length(),
flags, (DWORD_PTR)d->m_jobId);
}
diff --git a/WebCore/platform/pthreads/ThreadingPthreads.cpp b/WebCore/platform/pthreads/ThreadingPthreads.cpp
new file mode 100644
index 0000000..c12fd92
--- /dev/null
+++ b/WebCore/platform/pthreads/ThreadingPthreads.cpp
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)
+ *
+ * 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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.
+ */
+#include "config.h"
+#include "Threading.h"
+
+#include "Logging.h"
+#include <wtf/HashMap.h>
+
+#include <errno.h>
+
+namespace WebCore {
+
+static Mutex& threadMapMutex()
+{
+ static Mutex mutex;
+ return mutex;
+}
+
+static HashMap<ThreadIdentifier, pthread_t>& threadMap()
+{
+ static HashMap<ThreadIdentifier, pthread_t> map;
+ return map;
+}
+
+static ThreadIdentifier establishIdentifierForPthreadHandle(pthread_t& pthreadHandle)
+{
+ MutexLocker locker(threadMapMutex());
+
+ static ThreadIdentifier identifierCount = 1;
+
+ threadMap().add(identifierCount, pthreadHandle);
+
+ return identifierCount++;
+}
+
+static ThreadIdentifier identifierByPthreadHandle(const pthread_t& pthreadHandle)
+{
+ MutexLocker locker(threadMapMutex());
+
+ HashMap<ThreadIdentifier, pthread_t>::iterator i = threadMap().begin();
+ for (; i != threadMap().end(); ++i) {
+ if (pthread_equal(i->second, pthreadHandle))
+ return i->first;
+ }
+
+ return 0;
+}
+
+static pthread_t pthreadHandleForIdentifier(ThreadIdentifier id)
+{
+ MutexLocker locker(threadMapMutex());
+
+ return threadMap().get(id);
+}
+
+static void clearPthreadHandleForIdentifier(ThreadIdentifier id)
+{
+ MutexLocker locker(threadMapMutex());
+
+ ASSERT(threadMap().contains(id));
+
+ threadMap().remove(id);
+}
+
+ThreadIdentifier createThread(ThreadFunction entryPoint, void* data)
+{
+ pthread_t threadHandle;
+ if (pthread_create(&threadHandle, NULL, entryPoint, data)) {
+ LOG_ERROR("Failed to create pthread at entry point %p with data %p", entryPoint, data);
+ return 0;
+ }
+
+ ThreadIdentifier threadID = establishIdentifierForPthreadHandle(threadHandle);
+ LOG(Threading, "Created thread with thread id %u", threadID);
+ return threadID;
+}
+
+int waitForThreadCompletion(ThreadIdentifier threadID, void** result)
+{
+ ASSERT(threadID);
+
+ pthread_t pthreadHandle = pthreadHandleForIdentifier(threadID);
+
+ int joinResult = pthread_join(pthreadHandle, result);
+ if (joinResult == EDEADLK)
+ LOG_ERROR("ThreadIdentifier %u was found to be deadlocked trying to quit", threadID);
+
+ clearPthreadHandleForIdentifier(threadID);
+ return joinResult;
+}
+
+void detachThread(ThreadIdentifier threadID)
+{
+ ASSERT(threadID);
+
+ pthread_t pthreadHandle = pthreadHandleForIdentifier(threadID);
+
+ pthread_detach(pthreadHandle);
+
+ clearPthreadHandleForIdentifier(threadID);
+}
+
+ThreadIdentifier currentThread()
+{
+ pthread_t currentThread = pthread_self();
+ if (ThreadIdentifier id = identifierByPthreadHandle(currentThread))
+ return id;
+ return establishIdentifierForPthreadHandle(currentThread);
+}
+
+Mutex::Mutex()
+{
+ pthread_mutex_init(&m_mutex, NULL);
+}
+
+Mutex::~Mutex()
+{
+ pthread_mutex_destroy(&m_mutex);
+}
+
+void Mutex::lock()
+{
+ if (pthread_mutex_lock(&m_mutex) != 0)
+ ASSERT(false);
+}
+
+bool Mutex::tryLock()
+{
+ int result = pthread_mutex_trylock(&m_mutex);
+
+ if (result == 0)
+ return true;
+ else if (result == EBUSY)
+ return false;
+
+ ASSERT(false);
+ return false;
+}
+
+void Mutex::unlock()
+{
+ if (pthread_mutex_unlock(&m_mutex) != 0)
+ ASSERT(false);
+}
+
+ThreadCondition::ThreadCondition()
+{
+ pthread_cond_init(&m_condition, NULL);
+}
+
+ThreadCondition::~ThreadCondition()
+{
+ pthread_cond_destroy(&m_condition);
+}
+
+void ThreadCondition::wait(Mutex& mutex)
+{
+ if (pthread_cond_wait(&m_condition, &mutex.impl()) != 0)
+ ASSERT(false);
+}
+
+void ThreadCondition::signal()
+{
+ if (pthread_cond_signal(&m_condition) != 0)
+ ASSERT(false);
+}
+
+void ThreadCondition::broadcast()
+{
+ if (pthread_cond_broadcast(&m_condition) != 0)
+ ASSERT(false);
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/qt/ClipboardQt.cpp b/WebCore/platform/qt/ClipboardQt.cpp
index 191462c..f7c420f 100644
--- a/WebCore/platform/qt/ClipboardQt.cpp
+++ b/WebCore/platform/qt/ClipboardQt.cpp
@@ -30,6 +30,7 @@
#include "CachedImage.h"
#include "CSSHelper.h"
+#include "DeprecatedString.h"
#include "Document.h"
#include "Element.h"
#include "Frame.h"
@@ -240,12 +241,12 @@ void ClipboardQt::declareAndWriteDragImage(Element* element, const KURL& url, co
if (imageURL.isEmpty())
return;
- KURL fullURL = frame->document()->completeURL(parseURL(imageURL));
+ String fullURL = frame->document()->completeURL(parseURL(imageURL));
if (fullURL.isEmpty())
return;
QList<QUrl> urls;
- urls.append(fullURL);
+ urls.append(QUrl(fullURL));
m_writableData->setUrls(urls);
if (!isForDragging())
@@ -257,7 +258,7 @@ void ClipboardQt::writeURL(const KURL& url, const String&, Frame* frame)
ASSERT(frame);
QList<QUrl> urls;
- urls.append(frame->document()->completeURL(url.string()));
+ urls.append(QUrl(frame->document()->completeURL(url.deprecatedString())));
if (!m_writableData)
m_writableData = new QMimeData;
m_writableData->setUrls(urls);
diff --git a/WebCore/platform/qt/CookieJarQt.cpp b/WebCore/platform/qt/CookieJarQt.cpp
index 9215e9f..4138ab7 100644
--- a/WebCore/platform/qt/CookieJarQt.cpp
+++ b/WebCore/platform/qt/CookieJarQt.cpp
@@ -28,6 +28,7 @@
#include "config.h"
#include "CookieJar.h"
+#include "DeprecatedString.h"
#include "KURL.h"
#include "PlatformString.h"
diff --git a/WebCore/platform/qt/CursorQt.cpp b/WebCore/platform/qt/CursorQt.cpp
index fec150a..6d05397 100644
--- a/WebCore/platform/qt/CursorQt.cpp
+++ b/WebCore/platform/qt/CursorQt.cpp
@@ -33,6 +33,7 @@
#include "Image.h"
#include "IntPoint.h"
+#include "DeprecatedString.h"
#include "NotImplemented.h"
#include <stdio.h>
diff --git a/WebCore/platform/qt/FileChooserQt.cpp b/WebCore/platform/qt/FileChooserQt.cpp
index bf5d00f..c19301f 100644
--- a/WebCore/platform/qt/FileChooserQt.cpp
+++ b/WebCore/platform/qt/FileChooserQt.cpp
@@ -32,8 +32,7 @@
namespace WebCore {
FileChooser::FileChooser(FileChooserClient* client, const String& filename)
- : RefCounted<FileChooser>(0)
- , m_client(client)
+ : m_client(client)
, m_filename(filename)
, m_icon(chooseIcon(filename))
{
diff --git a/WebCore/platform/qt/FileSystemQt.cpp b/WebCore/platform/qt/FileSystemQt.cpp
index 529da02..7a25591 100644
--- a/WebCore/platform/qt/FileSystemQt.cpp
+++ b/WebCore/platform/qt/FileSystemQt.cpp
@@ -2,7 +2,6 @@
* Copyright (C) 2007 Staikos Computing Services Inc.
* Copyright (C) 2007 Holger Hans Peter Freyther
* Copyright (C) 2008 Apple, Inc. All rights reserved.
- * Copyright (C) 2008 Collabora, Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -29,10 +28,6 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "config.h"
-#include "FileSystem.h"
-
-#include "CString.h"
#include "NotImplemented.h"
#include "PlatformString.h"
#include <QFile>
@@ -80,18 +75,6 @@ String pathByAppendingComponent(const String& path, const String& component)
return QDir(path).filePath(component);
}
-String pathGetFileName(const String&)
-{
- notImplemented();
- return String();
-}
-
-bool unloadModule(PlatformModule)
-{
- notImplemented();
- return false;
-}
-
}
// vim: ts=4 sw=4 et
diff --git a/WebCore/platform/qt/KURLQt.cpp b/WebCore/platform/qt/KURLQt.cpp
index 350b97b..ce0d53d 100644
--- a/WebCore/platform/qt/KURLQt.cpp
+++ b/WebCore/platform/qt/KURLQt.cpp
@@ -38,13 +38,11 @@ KURL::KURL(const QUrl& url)
KURL::operator QUrl() const
{
- unsigned length = m_string.length();
-
QByteArray ba;
- ba.reserve(length);
+ ba.reserve(urlString.length());
- for (unsigned i = 0; i < length; ++i) {
- const char chr = static_cast<char>(m_string[i]);
+ for (const char *src = urlString.ascii(); *src; ++src) {
+ const char chr = *src;
switch (chr) {
case '{':
diff --git a/WebCore/platform/qt/Localizations.cpp b/WebCore/platform/qt/Localizations.cpp
index 04ff37e..67bba22 100644
--- a/WebCore/platform/qt/Localizations.cpp
+++ b/WebCore/platform/qt/Localizations.cpp
@@ -297,10 +297,5 @@ String unknownFileSizeText()
return QCoreApplication::translate("QWebPage", "Unknown", "Unknown filesize FTP directory listing item");
}
-String imageTitle(const String& filename, const IntSize& size)
-{
- return String();
-}
-
}
// vim: ts=4 sw=4 et
diff --git a/WebCore/platform/qt/PlugInInfoStoreQt.cpp b/WebCore/platform/qt/PlugInInfoStoreQt.cpp
new file mode 100644
index 0000000..57cc3a9
--- /dev/null
+++ b/WebCore/platform/qt/PlugInInfoStoreQt.cpp
@@ -0,0 +1,89 @@
+/*
+ Copyright (C) 2007 Trolltech ASA
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+ This class provides all functionality needed for loading images, style sheets and html
+ pages from the web. It has a memory cache for these objects.
+*/
+#include "PluginInfoStore.h"
+#include "qdebug.h"
+#if QT_VERSION < 0x040400
+#include "qwebobjectplugin_p.h"
+#endif
+#include "NotImplemented.h"
+
+namespace WebCore {
+
+PluginInfo* PluginInfoStore::createPluginInfoForPluginAtIndex(unsigned i)
+{
+ //qDebug() << ">>>>>>>>>>> PluginInfoStore::createPluginInfoForPluginAtIndex(" << i << ")";
+
+#if QT_VERSION < 0x040400
+ QWebFactoryLoader *loader = QWebFactoryLoader::self();
+ if (i > loader->m_pluginInfo.count())
+ return 0;
+ const QWebFactoryLoader::Info &qinfo = loader->m_pluginInfo.at(i);
+ PluginInfo *info = new PluginInfo;
+ info->name = qinfo.name;
+ info->desc = qinfo.description;
+ foreach (const QWebFactoryLoader::MimeInfo &m, qinfo.mimes) {
+ MimeClassInfo *mime = new MimeClassInfo;
+ mime->type = m.type;
+ mime->plugin = info;
+ foreach (QString ext, m.extensions)
+ mime->suffixes.append(ext);
+ info->mimes.append(mime);
+ }
+ return info;
+#else
+ return 0; // ### FIXME
+#endif
+}
+
+unsigned PluginInfoStore::pluginCount() const
+{
+#if QT_VERSION < 0x040400
+ //qDebug() << ">>>>>>>>>>> PluginInfoStore::count =" << QWebFactoryLoader::self()->keys().count();
+ return QWebFactoryLoader::self()->keys().count();
+#else
+ return 0;
+#endif
+}
+
+String PluginInfoStore::pluginNameForMIMEType(const String& mimeType)
+{
+ // FIXME: This method is stubbed out and should really return the name of a plug-in package for
+ // a given MIME type.
+ return String();
+}
+
+bool PluginInfoStore::supportsMIMEType(const WebCore::String& string)
+{
+#if QT_VERSION < 0x040400
+ bool supports = QWebFactoryLoader::self()->supportsMimeType(string);
+#else
+ bool supports = false;
+#endif
+ //qDebug() << ">>>>>>>>>>> PluginInfoStore::supportsMIMEType(" << string << ") =" << supports;
+ return supports;
+}
+
+void refreshPlugins(bool) {
+ notImplemented();
+}
+
+}
diff --git a/WebCore/platform/qt/PopupMenuQt.cpp b/WebCore/platform/qt/PopupMenuQt.cpp
index 2a70614..add4d84 100644
--- a/WebCore/platform/qt/PopupMenuQt.cpp
+++ b/WebCore/platform/qt/PopupMenuQt.cpp
@@ -43,8 +43,7 @@
namespace WebCore {
PopupMenu::PopupMenu(PopupMenuClient* client)
- : RefCounted<PopupMenu>(0)
- , m_popupClient(client)
+ : m_popupClient(client)
{
m_popup = new QWebPopup(client);
}
diff --git a/WebCore/platform/qt/RenderThemeQt.cpp b/WebCore/platform/qt/RenderThemeQt.cpp
index d17d6b5..dbf080f 100644
--- a/WebCore/platform/qt/RenderThemeQt.cpp
+++ b/WebCore/platform/qt/RenderThemeQt.cpp
@@ -126,6 +126,11 @@ bool RenderThemeQt::isControlStyled(const RenderStyle* style, const BorderData&
return RenderTheme::isControlStyled(style, border, background, backgroundColor);
}
+void RenderThemeQt::paintResizeControl(GraphicsContext*, const IntRect&)
+{
+}
+
+
Color RenderThemeQt::platformActiveSelectionBackgroundColor() const
{
QPalette pal = QApplication::palette();
diff --git a/WebCore/platform/qt/RenderThemeQt.h b/WebCore/platform/qt/RenderThemeQt.h
index 01beae5..053d825 100644
--- a/WebCore/platform/qt/RenderThemeQt.h
+++ b/WebCore/platform/qt/RenderThemeQt.h
@@ -54,6 +54,8 @@ public:
virtual bool isControlStyled(const RenderStyle*, const BorderData&,
const BackgroundLayer&, const Color&) const;
+ virtual void paintResizeControl(GraphicsContext*, const IntRect&);
+
// The platform selection color.
virtual Color platformActiveSelectionBackgroundColor() const;
virtual Color platformInactiveSelectionBackgroundColor() const;
diff --git a/WebCore/platform/qt/TemporaryLinkStubs.cpp b/WebCore/platform/qt/TemporaryLinkStubs.cpp
index 0f25245..817491e 100644
--- a/WebCore/platform/qt/TemporaryLinkStubs.cpp
+++ b/WebCore/platform/qt/TemporaryLinkStubs.cpp
@@ -4,7 +4,6 @@
* Copyright (C) 2006 George Staikos <staikos@kde.org>
* Copyright (C) 2006 Dirk Mueller <mueller@kde.org>
* Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
- * Copyright (C) 2008 Collabora, Ltd.
*
* All rights reserved.
*
@@ -60,8 +59,7 @@
#include "NotImplemented.h"
#include "Path.h"
#include "PlatformMouseEvent.h"
-#include "PluginDatabase.h"
-#include "PluginPackage.h"
+#include "PluginInfoStore.h"
#include "RenderTheme.h"
#include "SharedBuffer.h"
#include "SystemTime.h"
@@ -72,15 +70,6 @@
using namespace WebCore;
-PluginSet PluginDatabase::getPluginsInPaths() const { notImplemented(); return PluginSet(); }
-Vector<String> PluginDatabase::defaultPluginPaths() { notImplemented(); return Vector<String>(); }
-bool PluginDatabase::isPreferredPluginPath(const String&) { notImplemented(); return false; }
-int PluginPackage::compare(const PluginPackage&) const { notImplemented(); return 0; }
-bool PluginPackage::fetchInfo() { notImplemented(); return false; }
-unsigned PluginPackage::hash() const { notImplemented(); return 0; }
-bool PluginPackage::equal(const PluginPackage&, const PluginPackage&) { notImplemented(); return false; }
-bool PluginPackage::load() { notImplemented(); return false; }
-
namespace WebCore {
Vector<String> supportedKeySizes() { notImplemented(); return Vector<String>(); }
diff --git a/WebCore/platform/qt/MainThreadQt.cpp b/WebCore/platform/qt/ThreadingQt.cpp
index ab19bf7..71cd17e 100644
--- a/WebCore/platform/qt/MainThreadQt.cpp
+++ b/WebCore/platform/qt/ThreadingQt.cpp
@@ -29,7 +29,7 @@
*/
#include "config.h"
-#include "MainThread.h"
+#include "Threading.h"
#include <QtCore/QObject>
#include <QtCore/QCoreApplication>
@@ -94,4 +94,4 @@ void callOnMainThread(MainThreadFunction* function, void* context)
}
-#include "MainThreadQt.moc"
+#include "ThreadingQt.moc"
diff --git a/WebCore/platform/sql/SQLValue.h b/WebCore/platform/sql/SQLValue.h
index 7d85051..ae2432d 100644
--- a/WebCore/platform/sql/SQLValue.h
+++ b/WebCore/platform/sql/SQLValue.h
@@ -30,7 +30,7 @@
#define SQLValue_h
#include "PlatformString.h"
-#include <wtf/Threading.h>
+#include "Threading.h"
namespace WebCore {
diff --git a/WebCore/platform/sql/SQLiteAuthorizer.h b/WebCore/platform/sql/SQLiteAuthorizer.h
index 0bb0fb3..4c0e8ee 100644
--- a/WebCore/platform/sql/SQLiteAuthorizer.h
+++ b/WebCore/platform/sql/SQLiteAuthorizer.h
@@ -28,7 +28,7 @@
#ifndef SQLiteAuthorizer_h
#define SQLiteAuthorizer_h
-#include <wtf/Threading.h>
+#include "Threading.h"
namespace WebCore {
diff --git a/WebCore/platform/sql/SQLiteDatabase.h b/WebCore/platform/sql/SQLiteDatabase.h
index 20f461d..5e6ab46 100644
--- a/WebCore/platform/sql/SQLiteDatabase.h
+++ b/WebCore/platform/sql/SQLiteDatabase.h
@@ -28,7 +28,7 @@
#define SQLDatabase_h
#include "PlatformString.h"
-#include <wtf/Threading.h>
+#include "Threading.h"
#if COMPILER(MSVC)
#pragma warning(disable: 4800)
diff --git a/WebCore/platform/sql/SQLiteTransaction.cpp b/WebCore/platform/sql/SQLiteTransaction.cpp
index 5018f5a..3fb54f1 100644
--- a/WebCore/platform/sql/SQLiteTransaction.cpp
+++ b/WebCore/platform/sql/SQLiteTransaction.cpp
@@ -74,7 +74,6 @@ void SQLiteTransaction::rollback()
void SQLiteTransaction::stop()
{
m_inProgress = false;
- m_db.m_transactionInProgress = false;
}
} // namespace WebCore
diff --git a/WebCore/platform/symbian/DeprecatedStringSymbian.cpp b/WebCore/platform/symbian/DeprecatedStringSymbian.cpp
new file mode 100644
index 0000000..a1a0a45
--- /dev/null
+++ b/WebCore/platform/symbian/DeprecatedStringSymbian.cpp
@@ -0,0 +1,82 @@
+/*
+* ==============================================================================
+* Copyright (c) 2006, Nokia Corporation
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+*
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * 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.
+* * Neither the name of the Nokia Corporation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+* "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 THE COPYRIGHT
+* OWNER 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.
+*
+* ==============================================================================
+*/
+
+#include "config.h"
+#include "DeprecatedString.h"
+
+namespace WebCore {
+
+void DeprecatedString::setBufferFromDes(const TDesC& des)
+{
+ setUnicode((const DeprecatedChar *)des.Ptr(), (uint)des.Length());
+}
+
+void DeprecatedString::setBufferFromDes(const TDesC8& des)
+{
+ setLatin1((const char*)des.Ptr(), (uint)des.Length());
+}
+
+DeprecatedString DeprecatedString::fromDes(const TDesC& des)
+{
+ DeprecatedString s;
+ s.setBufferFromDes(des);
+ return s;
+}
+
+DeprecatedString DeprecatedString::fromDes(const TDesC8& des)
+{
+ DeprecatedString s;
+ s.setBufferFromDes(des);
+ return s;
+}
+
+TPtrC DeprecatedString::des() const
+{
+ if (!dataHandle[0]->_isUnicodeValid)
+ dataHandle[0]->makeUnicode();
+
+ TPtrC tstr((const TUint16*)unicode(), length() );
+
+ return tstr;
+}
+
+TPtrC8 DeprecatedString::des8() const
+{
+ TPtrC8 tstr((const TUint8*)latin1(), length());
+
+ return tstr;
+}
+
+} \ No newline at end of file
diff --git a/WebCore/platform/text/AtomicString.cpp b/WebCore/platform/text/AtomicString.cpp
index f7b3c91..c584e6c 100644
--- a/WebCore/platform/text/AtomicString.cpp
+++ b/WebCore/platform/text/AtomicString.cpp
@@ -26,6 +26,7 @@
#include "AtomicString.h"
+#include "DeprecatedString.h"
#include "StaticConstructors.h"
#include "StringHash.h"
#include <kjs/identifier.h>
@@ -73,16 +74,13 @@ bool operator==(const AtomicString& a, const char* b)
return CStringTranslator::equal(impl, b);
}
-PassRefPtr<StringImpl> AtomicString::add(const char* c)
+StringImpl* AtomicString::add(const char* c)
{
if (!c)
return 0;
if (!*c)
return StringImpl::empty();
- pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable->add<const char*, CStringTranslator>(c);
- if (!addResult.second)
- return *addResult.first;
- return adoptRef(*addResult.first);
+ return *stringTable->add<const char*, CStringTranslator>(c).first;
}
struct UCharBuffer {
@@ -137,7 +135,7 @@ struct UCharBufferTranslator {
}
};
-PassRefPtr<StringImpl> AtomicString::add(const UChar* s, int length)
+StringImpl* AtomicString::add(const UChar* s, int length)
{
if (!s)
return 0;
@@ -145,14 +143,11 @@ PassRefPtr<StringImpl> AtomicString::add(const UChar* s, int length)
if (length == 0)
return StringImpl::empty();
- UCharBuffer buf = { s, length };
- pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable->add<UCharBuffer, UCharBufferTranslator>(buf);
- if (!addResult.second)
- return *addResult.first;
- return adoptRef(*addResult.first);
+ UCharBuffer buf = {s, length};
+ return *stringTable->add<UCharBuffer, UCharBufferTranslator>(buf).first;
}
-PassRefPtr<StringImpl> AtomicString::add(const UChar* s)
+StringImpl* AtomicString::add(const UChar* s)
{
if (!s)
return 0;
@@ -165,13 +160,10 @@ PassRefPtr<StringImpl> AtomicString::add(const UChar* s)
return StringImpl::empty();
UCharBuffer buf = {s, length};
- pair<HashSet<StringImpl*>::iterator, bool> addResult = stringTable->add<UCharBuffer, UCharBufferTranslator>(buf);
- if (!addResult.second)
- return *addResult.first;
- return adoptRef(*addResult.first);
+ return *stringTable->add<UCharBuffer, UCharBufferTranslator>(buf).first;
}
-PassRefPtr<StringImpl> AtomicString::add(StringImpl* r)
+StringImpl* AtomicString::add(StringImpl* r)
{
if (!r || r->m_inTable)
return r;
@@ -190,12 +182,12 @@ void AtomicString::remove(StringImpl* r)
stringTable->remove(r);
}
-PassRefPtr<StringImpl> AtomicString::add(const KJS::Identifier& str)
+StringImpl* AtomicString::add(const KJS::Identifier& str)
{
return add(reinterpret_cast<const UChar*>(str.data()), str.size());
}
-PassRefPtr<StringImpl> AtomicString::add(const KJS::UString& str)
+StringImpl* AtomicString::add(const KJS::UString& str)
{
return add(reinterpret_cast<const UChar*>(str.data()), str.size());
}
@@ -210,6 +202,16 @@ AtomicString::operator UString() const
return m_string;
}
+AtomicString::AtomicString(const DeprecatedString& s)
+ : m_string(add(reinterpret_cast<const UChar*>(s.unicode()), s.length()))
+{
+}
+
+DeprecatedString AtomicString::deprecatedString() const
+{
+ return m_string.deprecatedString();
+}
+
DEFINE_GLOBAL(AtomicString, nullAtom)
DEFINE_GLOBAL(AtomicString, emptyAtom, "")
DEFINE_GLOBAL(AtomicString, textAtom, "#text")
diff --git a/WebCore/platform/text/AtomicString.h b/WebCore/platform/text/AtomicString.h
index 2a2ac97..4a0bb5b 100644
--- a/WebCore/platform/text/AtomicString.h
+++ b/WebCore/platform/text/AtomicString.h
@@ -43,7 +43,7 @@ public:
AtomicString(const String& s) : m_string(add(s.impl())) { }
operator const String&() const { return m_string; }
- const String& string() const { return m_string; };
+ const String& domString() const { return m_string; };
operator KJS::Identifier() const;
operator KJS::UString() const;
@@ -57,16 +57,16 @@ public:
bool contains(UChar c) const { return m_string.contains(c); }
bool contains(const AtomicString& s, bool caseSensitive = true) const
- { return m_string.contains(s.string(), caseSensitive); }
+ { return m_string.contains(s.domString(), caseSensitive); }
int find(UChar c, int start = 0) const { return m_string.find(c, start); }
int find(const AtomicString& s, int start = 0, bool caseSentitive = true) const
- { return m_string.find(s.string(), start, caseSentitive); }
+ { return m_string.find(s.domString(), start, caseSentitive); }
bool startsWith(const AtomicString& s, bool caseSensitive = true) const
- { return m_string.startsWith(s.string(), caseSensitive); }
+ { return m_string.startsWith(s.domString(), caseSensitive); }
bool endsWith(const AtomicString& s, bool caseSensitive = true) const
- { return m_string.endsWith(s.string(), caseSensitive); }
+ { return m_string.endsWith(s.domString(), caseSensitive); }
int toInt(bool* ok = 0) const { return m_string.toInt(ok); }
double toDouble(bool* ok = 0) const { return m_string.toDouble(ok); }
@@ -93,15 +93,18 @@ public:
operator QString() const { return m_string; }
#endif
+ AtomicString(const DeprecatedString&);
+ DeprecatedString deprecatedString() const;
+
private:
String m_string;
- static PassRefPtr<StringImpl> add(const char*);
- static PassRefPtr<StringImpl> add(const UChar*, int length);
- static PassRefPtr<StringImpl> add(const UChar*);
- static PassRefPtr<StringImpl> add(StringImpl*);
- static PassRefPtr<StringImpl> add(const KJS::UString&);
- static PassRefPtr<StringImpl> add(const KJS::Identifier&);
+ static StringImpl* add(const char*);
+ static StringImpl* add(const UChar*, int length);
+ static StringImpl* add(const UChar*);
+ static StringImpl* add(StringImpl*);
+ static StringImpl* add(const KJS::UString&);
+ static StringImpl* add(const KJS::Identifier&);
};
inline bool operator==(const AtomicString& a, const AtomicString& b) { return a.impl() == b.impl(); }
diff --git a/WebCore/platform/text/BidiResolver.h b/WebCore/platform/text/BidiResolver.h
index 3e545d9..d2515a9 100644
--- a/WebCore/platform/text/BidiResolver.h
+++ b/WebCore/platform/text/BidiResolver.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2000 Lars Knoll (knoll@kde.org)
- * Copyright (C) 2003, 2004, 2006, 2007, 2008 Apple Inc. All right reserved.
+ * Copyright (C) 2003, 2004, 2006, 2007 Apple Inc. All right reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -85,8 +85,6 @@ struct BidiCharacterRun {
}
}
- void destroy() { delete this; }
-
int start() const { return m_start; }
int stop() const { return m_stop; }
unsigned char level() const { return m_level; }
@@ -111,7 +109,6 @@ public :
, emptyRun(true)
, m_firstRun(0)
, m_lastRun(0)
- , m_logicallyLastRun(0)
, m_runCount(0)
{
}
@@ -137,15 +134,14 @@ public :
Run* firstRun() const { return m_firstRun; }
Run* lastRun() const { return m_lastRun; }
- Run* logicallyLastRun() const { return m_logicallyLastRun; }
- unsigned runCount() const { return m_runCount; }
+ int runCount() const { return m_runCount; }
void addRun(Run*);
void deleteRuns();
protected:
void appendRun();
- void reverseRuns(unsigned start, unsigned end);
+ void reverseRuns(int start, int end);
Iterator current;
Iterator sor;
@@ -161,28 +157,22 @@ protected:
Run* m_firstRun;
Run* m_lastRun;
- Run* m_logicallyLastRun;
- unsigned m_runCount;
+ int m_runCount;
};
template <class Iterator, class Run>
-inline void BidiResolver<Iterator, Run>::addRun(Run* run)
-{
- if (!m_firstRun)
- m_firstRun = run;
- else
- m_lastRun->m_next = run;
- m_lastRun = run;
- m_runCount++;
-}
-
-template <class Iterator, class Run>
void BidiResolver<Iterator, Run>::appendRun()
{
if (emptyRun || eor.atEnd())
return;
- addRun(new Run(sor.offset(), eor.offset() + 1, context(), m_direction));
+ Run* bidiRun = new Run(sor.offset(), eor.offset() + 1, context(), m_direction);
+ if (!m_firstRun)
+ m_firstRun = bidiRun;
+ else
+ m_lastRun->m_next = bidiRun;
+ m_lastRun = bidiRun;
+ m_runCount++;
eor.increment(*this);
sor = eor;
@@ -322,8 +312,8 @@ void BidiResolver<Iterator, Run>::deleteRuns()
Run* curr = m_firstRun;
while (curr) {
- Run* s = curr->next();
- curr->destroy();
+ Run* s = curr->m_next;
+ delete curr;
curr = s;
}
@@ -333,18 +323,18 @@ void BidiResolver<Iterator, Run>::deleteRuns()
}
template <class Iterator, class Run>
-void BidiResolver<Iterator, Run>::reverseRuns(unsigned start, unsigned end)
+void BidiResolver<Iterator, Run>::reverseRuns(int start, int end)
{
if (start >= end)
return;
- ASSERT(end < m_runCount);
+ ASSERT(start >= 0 && end < m_runCount);
// Get the item before the start of the runs to reverse and put it in
// |beforeStart|. |curr| should point to the first run to reverse.
Run* curr = m_firstRun;
Run* beforeStart = 0;
- unsigned i = 0;
+ int i = 0;
while (i < start) {
i++;
beforeStart = curr;
@@ -782,8 +772,6 @@ void BidiResolver<Iterator, Run>::createBidiRunsForLine(const Iterator& start, c
}
}
- m_logicallyLastRun = m_lastRun;
-
// reorder line according to run structure...
// do not reverse for visually ordered web sites
if (!visualOrder) {
@@ -808,22 +796,22 @@ void BidiResolver<Iterator, Run>::createBidiRunsForLine(const Iterator& start, c
if (!(levelLow % 2))
levelLow++;
- unsigned count = runCount() - 1;
+ int count = runCount() - 1;
while (levelHigh >= levelLow) {
- unsigned i = 0;
+ int i = 0;
Run* currRun = firstRun();
while (i < count) {
while (i < count && currRun && currRun->m_level < levelHigh) {
i++;
currRun = currRun->next();
}
- unsigned start = i;
+ int start = i;
while (i <= count && currRun && currRun->m_level >= levelHigh) {
i++;
currRun = currRun->next();
}
- unsigned end = i - 1;
+ int end = i-1;
reverseRuns(start, end);
}
levelHigh--;
diff --git a/WebCore/platform/text/CString.cpp b/WebCore/platform/text/CString.cpp
index f1434ad..4300b29 100644
--- a/WebCore/platform/text/CString.cpp
+++ b/WebCore/platform/text/CString.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003, 2006, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2006 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
@@ -26,8 +26,7 @@
#include "config.h"
#include "CString.h"
-
-using std::min;
+#include "DeprecatedCString.h"
namespace WebCore {
@@ -41,12 +40,17 @@ CString::CString(const char* str, unsigned length)
init(str, length);
}
+CString::CString(const DeprecatedCString& str)
+{
+ init(str.data(), str.length());
+}
+
void CString::init(const char* str, unsigned length)
{
if (!str)
return;
- m_buffer = CStringBuffer::create(length + 1);
+ m_buffer = new CStringBuffer(length + 1);
memcpy(m_buffer->data(), str, length);
m_buffer->data()[length] = '\0';
}
@@ -68,11 +72,16 @@ unsigned CString::length() const
{
return m_buffer ? m_buffer->length() - 1 : 0;
}
+
+DeprecatedCString CString::deprecatedCString() const
+{
+ return DeprecatedCString(data(), length() + 1);
+}
CString CString::newUninitialized(size_t length, char*& characterBuffer)
{
CString result;
- result.m_buffer = CStringBuffer::create(length + 1);
+ result.m_buffer = new CStringBuffer(length + 1);
char* bytes = result.m_buffer->data();
bytes[length] = '\0';
characterBuffer = bytes;
@@ -86,7 +95,7 @@ void CString::copyBufferIfNeeded()
int len = m_buffer->length();
RefPtr<CStringBuffer> m_temp = m_buffer;
- m_buffer = CStringBuffer::create(len);
+ m_buffer = new CStringBuffer(len);
memcpy(m_buffer->data(), m_temp->data(), len);
}
diff --git a/WebCore/platform/text/CString.h b/WebCore/platform/text/CString.h
index fcb4c8c..bd1e06c 100644
--- a/WebCore/platform/text/CString.h
+++ b/WebCore/platform/text/CString.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003, 2006, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2006 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
@@ -26,22 +26,23 @@
#ifndef CString_h
#define CString_h
-#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
#include <wtf/Vector.h>
+using std::min;
+
namespace WebCore {
+ class DeprecatedCString;
+
class CStringBuffer : public RefCounted<CStringBuffer> {
public:
- static PassRefPtr<CStringBuffer> create(unsigned length) { return adoptRef(new CStringBuffer(length)); }
+ CStringBuffer(unsigned length) : m_vector(length) { }
char* data() { return m_vector.data(); }
- size_t length() const { return m_vector.size(); }
+ unsigned length() const { return m_vector.size(); }
private:
- CStringBuffer(unsigned length) : m_vector(length) { }
-
Vector<char> m_vector;
};
@@ -60,6 +61,9 @@ namespace WebCore {
bool isNull() const { return !m_buffer; }
+ CString(const DeprecatedCString&);
+ DeprecatedCString deprecatedCString() const;
+
private:
void copyBufferIfNeeded();
void init(const char*, unsigned length);
@@ -69,6 +73,6 @@ namespace WebCore {
bool operator==(const CString& a, const CString& b);
inline bool operator!=(const CString& a, const CString& b) { return !(a == b); }
-} // namespace WebCore
+}
#endif // CString_h
diff --git a/WebCore/platform/text/CharacterNames.h b/WebCore/platform/text/CharacterNames.h
index bfbb5b0..5b52479 100644
--- a/WebCore/platform/text/CharacterNames.h
+++ b/WebCore/platform/text/CharacterNames.h
@@ -39,8 +39,6 @@ namespace WebCore {
const UChar bullet = 0x2022;
const UChar horizontalEllipsis = 0x2026;
const UChar ideographicSpace = 0x3000;
- const UChar ideographicComma = 0x3001;
- const UChar ideographicFullStop = 0x3002;
const UChar leftToRightMark = 0x200E;
const UChar leftToRightEmbed = 0x202A;
const UChar leftToRightOverride = 0x202D;
diff --git a/WebCore/platform/text/PlatformString.h b/WebCore/platform/text/PlatformString.h
index 9399fdd..f900513 100644
--- a/WebCore/platform/text/PlatformString.h
+++ b/WebCore/platform/text/PlatformString.h
@@ -43,6 +43,7 @@ class wxString;
namespace WebCore {
class CString;
+class DeprecatedString;
struct StringHash;
class String {
@@ -131,25 +132,17 @@ public:
static String format(const char *, ...) WTF_ATTRIBUTE_PRINTF(1, 2);
- void split(const String& separator, Vector<String>& result) const;
- void split(const String& separator, bool allowEmptyEntries, Vector<String>& result) const;
- void split(UChar separator, Vector<String>& result) const;
- void split(UChar separator, bool allowEmptyEntries, Vector<String>& result) const;
-
- int toIntStrict(bool* ok = 0, int base = 10) const;
- unsigned toUIntStrict(bool* ok = 0, int base = 10) const;
- int64_t toInt64Strict(bool* ok = 0, int base = 10) const;
- uint64_t toUInt64Strict(bool* ok = 0, int base = 10) const;
+ Vector<String> split(const String& separator, bool allowEmptyEntries = false) const;
+ Vector<String> split(UChar separator, bool allowEmptyEntries = false) const;
int toInt(bool* ok = 0) const;
- unsigned toUInt(bool* ok = 0) const;
int64_t toInt64(bool* ok = 0) const;
uint64_t toUInt64(bool* ok = 0) const;
double toDouble(bool* ok = 0) const;
float toFloat(bool* ok = 0) const;
Length* toLengthArray(int& len) const;
Length* toCoordsArray(int& len) const;
- bool percentage(int& percentage) const;
+ bool percentage(int &_percentage) const;
// Makes a deep copy. Helpful only if you need to use a String on another thread.
// Since the underlying StringImpl objects are immutable, there's no other reason
@@ -203,7 +196,10 @@ public:
// Determines the writing direction using the Unicode Bidi Algorithm rules P2 and P3.
WTF::Unicode::Direction defaultWritingDirection() const { return m_impl ? m_impl->defaultWritingDirection() : WTF::Unicode::LeftToRight; }
-
+
+ String(const DeprecatedString&);
+ DeprecatedString deprecatedString() const;
+
private:
RefPtr<StringImpl> m_impl;
};
@@ -226,30 +222,12 @@ inline bool equalIgnoringCase(const String& a, const String& b) { return equalIg
inline bool equalIgnoringCase(const String& a, const char* b) { return equalIgnoringCase(a.impl(), b); }
inline bool equalIgnoringCase(const char* a, const String& b) { return equalIgnoringCase(a, b.impl()); }
-inline bool operator!(const String& str) { return str.isNull(); }
-
-
-// String Operations
-
-bool charactersAreAllASCII(const UChar*, size_t);
-
-int charactersToIntStrict(const UChar*, size_t, bool* ok = 0, int base = 10);
-unsigned charactersToUIntStrict(const UChar*, size_t, bool* ok = 0, int base = 10);
-int64_t charactersToInt64Strict(const UChar*, size_t, bool* ok = 0, int base = 10);
-uint64_t charactersToUInt64Strict(const UChar*, size_t, bool* ok = 0, int base = 10);
-
-int charactersToInt(const UChar*, size_t, bool* ok = 0); // ignores trailing garbage
-unsigned charactersToUInt(const UChar*, size_t, bool* ok = 0); // ignores trailing garbage
-int64_t charactersToInt64(const UChar*, size_t, bool* ok = 0); // ignores trailing garbage
-uint64_t charactersToUInt64(const UChar*, size_t, bool* ok = 0); // ignores trailing garbage
+bool operator==(const String& a, const DeprecatedString& b);
+inline bool operator==(const DeprecatedString& b, const String& a) { return a == b; }
+inline bool operator!=(const String& a, const DeprecatedString& b) { return !(a == b); }
+inline bool operator!=(const DeprecatedString& b, const String& a ) { return !(a == b); }
-double charactersToDouble(const UChar*, size_t, bool* ok = 0);
-float charactersToFloat(const UChar*, size_t, bool* ok = 0);
-
-int find(const UChar*, size_t, UChar, int startPosition = 0);
-int reverseFind(const UChar*, size_t, UChar, int startPosition = -1);
-
-void append(Vector<UChar>&, const String&);
+inline bool operator!(const String& str) { return str.isNull(); }
#ifdef __OBJC__
// This is for situations in WebKit where the long standing behavior has been
@@ -258,49 +236,8 @@ void append(Vector<UChar>&, const String&);
inline NSString* nsStringNilIfEmpty(const String& str) { return str.isEmpty() ? nil : (NSString*)str; }
#endif
-inline bool charactersAreAllASCII(const UChar* characters, size_t length)
-{
- UChar ored = 0;
- for (size_t i = 0; i < length; ++i)
- ored |= characters[i];
- return !(ored & 0xFF80);
-}
-
-inline int find(const UChar* characters, size_t length, UChar character, int startPosition)
-{
- if (startPosition >= static_cast<int>(length))
- return -1;
- for (size_t i = startPosition; i < length; ++i) {
- if (characters[i] == character)
- return static_cast<int>(i);
- }
- return -1;
}
-inline int reverseFind(const UChar* characters, size_t length, UChar character, int startPosition)
-{
- if (startPosition >= static_cast<int>(length) || !length)
- return -1;
- if (startPosition < 0)
- startPosition += static_cast<int>(length);
- while (true) {
- if (characters[startPosition] == character)
- return startPosition;
- if (!startPosition)
- return -1;
- startPosition--;
- }
- ASSERT_NOT_REACHED();
- return -1;
-}
-
-inline void append(Vector<UChar>& vector, const String& string)
-{
- vector.append(string.characters(), string.length());
-}
-
-} // namespace WebCore
-
namespace WTF {
// StringHash is the default hash for String
diff --git a/WebCore/platform/text/RegularExpression.cpp b/WebCore/platform/text/RegularExpression.cpp
index 4213d75..0c26d33 100644
--- a/WebCore/platform/text/RegularExpression.cpp
+++ b/WebCore/platform/text/RegularExpression.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004, 2008 Apple 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
@@ -26,7 +26,6 @@
#include "config.h"
#include "RegularExpression.h"
-#include "PlatformString.h"
#include "Logging.h"
#include <wtf/RefCounted.h>
#include <pcre/pcre.h>
@@ -37,44 +36,73 @@ namespace WebCore {
const size_t maxSubstrings = 10;
const size_t maxOffsets = 3 * maxSubstrings;
-class RegularExpression::Private : public RefCounted<Private> {
+class RegularExpression::Private : public RefCounted<RegularExpression::Private>
+{
public:
Private();
- Private(const String& pattern, bool caseSensitive);
+ Private(DeprecatedString pattern, bool caseSensitive, bool glob);
~Private();
- void compile(bool caseSensitive);
+ void compile(bool caseSensitive, bool glob);
- String pattern;
+ DeprecatedString pattern;
JSRegExp* regex;
- String lastMatchString;
+ DeprecatedString lastMatchString;
int lastMatchOffsets[maxOffsets];
int lastMatchCount;
int lastMatchPos;
int lastMatchLength;
};
-RegularExpression::Private::Private()
- : RefCounted<Private>(0)
- , pattern("")
+RegularExpression::Private::Private() : pattern("")
{
- compile(true);
+ compile(true, false);
}
-RegularExpression::Private::Private(const String& p, bool caseSensitive)
- : RefCounted<Private>(0)
- , pattern(p)
- , lastMatchPos(-1)
- , lastMatchLength(-1)
+RegularExpression::Private::Private(DeprecatedString p, bool caseSensitive, bool glob) : pattern(p), lastMatchPos(-1), lastMatchLength(-1)
{
- compile(caseSensitive);
+ compile(caseSensitive, glob);
+}
+
+static DeprecatedString RegExpFromGlob(DeprecatedString glob)
+{
+ DeprecatedString result = glob;
+
+ // escape regexp metacharacters which are NOT glob metacharacters
+
+ result.replace(RegularExpression("\\\\"), "\\\\");
+ result.replace(RegularExpression("\\."), "\\.");
+ result.replace(RegularExpression("\\+"), "\\+");
+ result.replace(RegularExpression("\\$"), "\\$");
+ // FIXME: incorrect for ^ inside bracket group
+ result.replace(RegularExpression("\\^"), "\\^");
+
+ // translate glob metacharacters into regexp metacharacters
+ result.replace(RegularExpression("\\*"), ".*");
+ result.replace(RegularExpression("\\?"), ".");
+
+ // Require the glob to match the whole string
+ result = "^" + result + "$";
+
+ return result;
}
-void RegularExpression::Private::compile(bool caseSensitive)
+void RegularExpression::Private::compile(bool caseSensitive, bool glob)
{
+ DeprecatedString p;
+
+ if (glob) {
+ p = RegExpFromGlob(pattern);
+ } else {
+ p = pattern;
+ }
+ // Note we don't honor the Qt syntax for various character classes. If we convert
+ // to a different underlying engine, we may need to change client code that relies
+ // on the regex syntax (see FrameMac.mm for a couple examples).
+
const char* errorMessage;
- regex = jsRegExpCompile(pattern.characters(), pattern.length(),
+ regex = jsRegExpCompile(reinterpret_cast<const UChar*>(p.unicode()), p.length(),
caseSensitive ? JSRegExpDoNotIgnoreCase : JSRegExpIgnoreCase, JSRegExpSingleLine,
0, &errorMessage);
if (!regex)
@@ -87,24 +115,20 @@ RegularExpression::Private::~Private()
}
-RegularExpression::RegularExpression()
- : d(new Private)
+RegularExpression::RegularExpression() : d(new RegularExpression::Private())
{
}
-RegularExpression::RegularExpression(const String& pattern, bool caseSensitive)
- : d(new Private(pattern, caseSensitive))
+RegularExpression::RegularExpression(const DeprecatedString &pattern, bool caseSensitive, bool glob) : d(new RegularExpression::Private(pattern, caseSensitive, glob))
{
}
-RegularExpression::RegularExpression(const char* pattern)
- : d(new Private(pattern, true))
+RegularExpression::RegularExpression(const char *cpattern) : d(new RegularExpression::Private(cpattern, true, false))
{
}
-RegularExpression::RegularExpression(const RegularExpression& re)
- : d(re.d)
+RegularExpression::RegularExpression(const RegularExpression &re) : d (re.d)
{
}
@@ -112,51 +136,57 @@ RegularExpression::~RegularExpression()
{
}
-RegularExpression& RegularExpression::operator=(const RegularExpression& re)
+RegularExpression &RegularExpression::operator=(const RegularExpression &re)
{
RegularExpression tmp(re);
- tmp.d.swap(d);
+ RefPtr<RegularExpression::Private> tmpD = tmp.d;
+
+ tmp.d = d;
+ d = tmpD;
+
return *this;
}
-String RegularExpression::pattern() const
+DeprecatedString RegularExpression::pattern() const
{
return d->pattern;
}
-int RegularExpression::match(const String& str, int startFrom, int* matchLength) const
+int RegularExpression::match(const DeprecatedString &str, int startFrom, int *matchLength) const
{
d->lastMatchString = str;
// First 2 offsets are start and end offsets; 3rd entry is used internally by pcre
- d->lastMatchCount = jsRegExpExecute(d->regex, d->lastMatchString.characters(),
- d->lastMatchString.length(), startFrom, d->lastMatchOffsets, maxOffsets);
+ d->lastMatchCount = jsRegExpExecute(d->regex, reinterpret_cast<const UChar*>(d->lastMatchString.unicode()), d->lastMatchString.length(), startFrom, d->lastMatchOffsets, maxOffsets);
if (d->lastMatchCount < 0) {
if (d->lastMatchCount != JSRegExpErrorNoMatch)
LOG_ERROR("RegularExpression: pcre_exec() failed with result %d", d->lastMatchCount);
d->lastMatchPos = -1;
d->lastMatchLength = -1;
- d->lastMatchString = String();
+ d->lastMatchString = DeprecatedString();
return -1;
}
// 1 means 1 match; 0 means more than one match. First match is recorded in offsets.
+ //ASSERT(d->lastMatchCount < 2);
d->lastMatchPos = d->lastMatchOffsets[0];
d->lastMatchLength = d->lastMatchOffsets[1] - d->lastMatchOffsets[0];
- if (matchLength)
+ if (matchLength != NULL) {
*matchLength = d->lastMatchLength;
+ }
return d->lastMatchPos;
}
-int RegularExpression::search(const String& str, int startFrom) const
+int RegularExpression::search(const DeprecatedString &str, int startFrom) const
{
- if (startFrom < 0)
+ if (startFrom < 0) {
startFrom = str.length() - startFrom;
- return match(str, startFrom, 0);
+ }
+ return match(str, startFrom, NULL);
}
-int RegularExpression::searchRev(const String& str) const
+int RegularExpression::searchRev(const DeprecatedString &str) const
{
- // FIXME: Total hack for now. Search forward, return the last, greedy match
+ // FIXME: Total hack for now. Search forward, return the last, greedy match
int start = 0;
int pos;
int lastPos = -1;
@@ -165,7 +195,7 @@ int RegularExpression::searchRev(const String& str) const
int matchLength;
pos = match(str, start, &matchLength);
if (pos >= 0) {
- if (pos + matchLength > lastPos + lastMatchLength) {
+ if ((pos+matchLength) > (lastPos+lastMatchLength)) {
// replace last match if this one is later and not a subset of the last match
lastPos = pos;
lastMatchLength = matchLength;
@@ -189,19 +219,4 @@ int RegularExpression::matchedLength() const
return d->lastMatchLength;
}
-void replace(String& string, const RegularExpression& target, const String& replacement)
-{
- int index = 0;
- while (index < static_cast<int>(string.length())) {
- int matchLength;
- index = target.match(string, index, &matchLength);
- if (index < 0)
- break;
- string.replace(index, matchLength, replacement);
- index += replacement.length();
- if (!matchLength)
- break; // Avoid infinite loop on 0-length matches, e.g. [a-z]*
- }
}
-
-} // namespace WebCore
diff --git a/WebCore/platform/text/RegularExpression.h b/WebCore/platform/text/RegularExpression.h
index 5d1991e..ec1cdef 100644
--- a/WebCore/platform/text/RegularExpression.h
+++ b/WebCore/platform/text/RegularExpression.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003, 2008 Apple Inc. All rights reserved.
+ * 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
@@ -26,38 +26,34 @@
#ifndef RegularExpression_h
#define RegularExpression_h
-#include <wtf/RefPtr.h>
+#include "DeprecatedString.h"
namespace WebCore {
-class String;
-
class RegularExpression {
public:
RegularExpression();
- RegularExpression(const String&, bool caseSensitive = false);
- RegularExpression(const char*);
+ RegularExpression(const DeprecatedString &, bool caseSensitive = false, bool glob = false);
+ RegularExpression(const char *);
~RegularExpression();
- RegularExpression(const RegularExpression&);
- RegularExpression& operator=(const RegularExpression&);
+ RegularExpression(const RegularExpression &);
+ RegularExpression &operator=(const RegularExpression &);
- String pattern() const;
- int match(const String&, int startFrom = 0, int* matchLength = 0) const;
+ DeprecatedString pattern() const;
+ int match(const DeprecatedString &, int startFrom = 0, int *matchLength = 0) const;
- int search(const String&, int startFrom = 0) const;
- int searchRev(const String&) const;
+ int search(const DeprecatedString &, int startFrom = 0) const;
+ int searchRev(const DeprecatedString &) const;
int pos(int n = 0);
int matchedLength() const;
-
+
private:
class Private;
RefPtr<Private> d;
};
-void replace(String&, const RegularExpression&, const String&);
-
-} // namespace WebCore
+}
-#endif // RegularExpression_h
+#endif
diff --git a/WebCore/platform/text/SegmentedString.cpp b/WebCore/platform/text/SegmentedString.cpp
index 9f5eb26..0b3c7e9 100644
--- a/WebCore/platform/text/SegmentedString.cpp
+++ b/WebCore/platform/text/SegmentedString.cpp
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
@@ -59,10 +59,10 @@ unsigned SegmentedString::length() const
++length;
}
if (m_composite) {
- Deque<SegmentedSubstring>::const_iterator it = m_substrings.begin();
- Deque<SegmentedSubstring>::const_iterator e = m_substrings.end();
- for (; it != e; ++it)
- length += it->m_length;
+ DeprecatedValueListConstIterator<SegmentedSubstring> i = m_substrings.begin();
+ DeprecatedValueListConstIterator<SegmentedSubstring> e = m_substrings.end();
+ for (; i != e; ++i)
+ length += (*i).m_length;
}
return length;
}
@@ -70,10 +70,10 @@ unsigned SegmentedString::length() const
void SegmentedString::setExcludeLineNumbers()
{
if (m_composite) {
- Deque<SegmentedSubstring>::iterator it = m_substrings.begin();
- Deque<SegmentedSubstring>::iterator e = m_substrings.end();
- for (; it != e; ++it)
- it->setExcludeLineNumbers();
+ DeprecatedValueListIterator<SegmentedSubstring> i = m_substrings.begin();
+ DeprecatedValueListIterator<SegmentedSubstring> e = m_substrings.end();
+ for (; i != e; ++i)
+ (*i).setExcludeLineNumbers();
} else
m_currentString.setExcludeLineNumbers();
}
@@ -120,10 +120,10 @@ void SegmentedString::append(const SegmentedString &s)
ASSERT(!s.escaped());
append(s.m_currentString);
if (s.m_composite) {
- Deque<SegmentedSubstring>::const_iterator it = s.m_substrings.begin();
- Deque<SegmentedSubstring>::const_iterator e = s.m_substrings.end();
- for (; it != e; ++it)
- append(*it);
+ DeprecatedValueListConstIterator<SegmentedSubstring> i = s.m_substrings.begin();
+ DeprecatedValueListConstIterator<SegmentedSubstring> e = s.m_substrings.end();
+ for (; i != e; ++i)
+ append(*i);
}
m_currentChar = m_pushedChar1 ? &m_pushedChar1 : m_currentString.m_current;
}
@@ -133,10 +133,10 @@ void SegmentedString::prepend(const SegmentedString &s)
ASSERT(!escaped());
ASSERT(!s.escaped());
if (s.m_composite) {
- Deque<SegmentedSubstring>::const_reverse_iterator it = s.m_substrings.rbegin();
- Deque<SegmentedSubstring>::const_reverse_iterator e = s.m_substrings.rend();
- for (; it != e; ++it)
- prepend(*it);
+ DeprecatedValueListConstIterator<SegmentedSubstring> i = s.m_substrings.fromLast();
+ DeprecatedValueListConstIterator<SegmentedSubstring> e = s.m_substrings.end();
+ for (; i != e; --i)
+ prepend(*i);
}
prepend(s.m_currentString);
m_currentChar = m_pushedChar1 ? &m_pushedChar1 : m_currentString.m_current;
@@ -146,7 +146,7 @@ void SegmentedString::advanceSubstring()
{
if (m_composite) {
m_currentString = m_substrings.first();
- m_substrings.removeFirst();
+ m_substrings.remove(m_substrings.begin());
if (m_substrings.isEmpty())
m_composite = false;
} else {
@@ -164,10 +164,10 @@ String SegmentedString::toString() const
}
m_currentString.appendTo(result);
if (m_composite) {
- Deque<SegmentedSubstring>::const_iterator it = m_substrings.begin();
- Deque<SegmentedSubstring>::const_iterator e = m_substrings.end();
- for (; it != e; ++it)
- it->appendTo(result);
+ DeprecatedValueListConstIterator<SegmentedSubstring> i = m_substrings.begin();
+ DeprecatedValueListConstIterator<SegmentedSubstring> e = m_substrings.end();
+ for (; i != e; ++i)
+ (*i).appendTo(result);
}
return result;
}
diff --git a/WebCore/platform/text/SegmentedString.h b/WebCore/platform/text/SegmentedString.h
index 79ed1f0..52178d3 100644
--- a/WebCore/platform/text/SegmentedString.h
+++ b/WebCore/platform/text/SegmentedString.h
@@ -20,22 +20,20 @@
#ifndef SegmentedString_h
#define SegmentedString_h
+#include "DeprecatedValueList.h"
#include "PlatformString.h"
-#include <wtf/Deque.h>
namespace WebCore {
class SegmentedString;
class SegmentedSubstring {
-public:
+private:
+ friend class SegmentedString;
+
SegmentedSubstring() : m_length(0), m_current(0), m_doNotExcludeLineNumbers(true) {}
- SegmentedSubstring(const String& str)
- : m_length(str.length())
- , m_current(str.isEmpty() ? 0 : str.characters())
- , m_string(str)
- , m_doNotExcludeLineNumbers(true)
- {
+ SegmentedSubstring(const String& str) : m_string(str), m_length(str.length()), m_doNotExcludeLineNumbers(true) {
+ m_current = m_length == 0 ? 0 : m_string.characters();
}
SegmentedSubstring(const UChar* str, int length) : m_length(length), m_current(length == 0 ? 0 : str), m_doNotExcludeLineNumbers(true) {}
@@ -47,8 +45,7 @@ public:
void setExcludeLineNumbers() { m_doNotExcludeLineNumbers = false; }
- void appendTo(String& str) const
- {
+ void appendTo(String& str) const {
if (m_string.characters() == m_current) {
if (str.isEmpty())
str = m_string;
@@ -59,12 +56,9 @@ public:
}
}
-public:
+ String m_string;
int m_length;
const UChar* m_current;
-
-private:
- String m_string;
bool m_doNotExcludeLineNumbers;
};
@@ -83,8 +77,8 @@ public:
void clear();
- void append(const SegmentedString&);
- void prepend(const SegmentedString&);
+ void append(const SegmentedString &);
+ void prepend(const SegmentedString &);
bool excludeLineNumbers() const { return m_currentString.excludeLineNumbers(); }
void setExcludeLineNumbers();
@@ -155,8 +149,8 @@ public:
const UChar* operator->() const { return current(); }
private:
- void append(const SegmentedSubstring&);
- void prepend(const SegmentedSubstring&);
+ void append(const SegmentedSubstring &);
+ void prepend(const SegmentedSubstring &);
void advanceSlowCase();
void advanceSlowCase(int& lineNumber);
@@ -167,7 +161,7 @@ private:
UChar m_pushedChar2;
SegmentedSubstring m_currentString;
const UChar* m_currentChar;
- Deque<SegmentedSubstring> m_substrings;
+ DeprecatedValueList<SegmentedSubstring> m_substrings;
bool m_composite;
};
diff --git a/WebCore/platform/text/String.cpp b/WebCore/platform/text/String.cpp
index ee4cef4..967e7c8 100644
--- a/WebCore/platform/text/String.cpp
+++ b/WebCore/platform/text/String.cpp
@@ -22,23 +22,17 @@
#include "PlatformString.h"
#include "CString.h"
-#include "FloatConversion.h"
+#include "DeprecatedString.h"
#include "StringBuffer.h"
#include "TextEncoding.h"
-#include <kjs/dtoa.h>
#include <kjs/identifier.h>
-#include <limits>
-#include <stdarg.h>
-#include <wtf/ASCIICType.h>
#include <wtf/StringExtras.h>
#include <wtf/Vector.h>
-#include <wtf/unicode/Unicode.h>
+#include <stdarg.h>
using KJS::Identifier;
using KJS::UString;
-using namespace WTF;
-
namespace WebCore {
String::String(const UChar* str, unsigned len)
@@ -60,6 +54,13 @@ String::String(const UChar* str)
m_impl = StringImpl::create(str, len);
}
+String::String(const DeprecatedString& str)
+{
+ if (str.isNull())
+ return;
+ m_impl = StringImpl::create(reinterpret_cast<const UChar*>(str.unicode()), str.length());
+}
+
String::String(const char* str)
{
if (!str)
@@ -288,7 +289,7 @@ bool String::percentage(int& result) const
if ((*m_impl)[m_impl->length() - 1] != '%')
return false;
- result = charactersToIntStrict(m_impl->characters(), m_impl->length() - 1);
+ result = DeprecatedConstString(reinterpret_cast<const DeprecatedChar*>(m_impl->characters()), m_impl->length() - 1).string().toInt();
return true;
}
@@ -309,6 +310,15 @@ const UChar* String::charactersWithNullTermination()
return m_impl->characters();
}
+DeprecatedString String::deprecatedString() const
+{
+ if (!m_impl)
+ return DeprecatedString::null;
+ if (!m_impl->characters())
+ return DeprecatedString("", 0);
+ return DeprecatedString(reinterpret_cast<const DeprecatedChar*>(m_impl->characters()), m_impl->length());
+}
+
String String::format(const char *format, ...)
{
va_list args;
@@ -390,46 +400,6 @@ String String::number(double n)
return String::format("%.6lg", n);
}
-int String::toIntStrict(bool* ok, int base) const
-{
- if (!m_impl) {
- if (ok)
- *ok = false;
- return 0;
- }
- return m_impl->toIntStrict(ok, base);
-}
-
-unsigned String::toUIntStrict(bool* ok, int base) const
-{
- if (!m_impl) {
- if (ok)
- *ok = false;
- return 0;
- }
- return m_impl->toUIntStrict(ok, base);
-}
-
-int64_t String::toInt64Strict(bool* ok, int base) const
-{
- if (!m_impl) {
- if (ok)
- *ok = false;
- return 0;
- }
- return m_impl->toInt64Strict(ok, base);
-}
-
-uint64_t String::toUInt64Strict(bool* ok, int base) const
-{
- if (!m_impl) {
- if (ok)
- *ok = false;
- return 0;
- }
- return m_impl->toUInt64Strict(ok, base);
-}
-
int String::toInt(bool* ok) const
{
if (!m_impl) {
@@ -440,16 +410,6 @@ int String::toInt(bool* ok) const
return m_impl->toInt(ok);
}
-unsigned String::toUInt(bool* ok) const
-{
- if (!m_impl) {
- if (ok)
- *ok = false;
- return 0;
- }
- return m_impl->toUInt(ok);
-}
-
int64_t String::toInt64(bool* ok) const
{
if (!m_impl) {
@@ -475,7 +435,7 @@ double String::toDouble(bool* ok) const
if (!m_impl) {
if (ok)
*ok = false;
- return 0.0;
+ return 0;
}
return m_impl->toDouble(ok);
}
@@ -512,10 +472,10 @@ Length* String::toLengthArray(int& len) const
return m_impl ? m_impl->toLengthArray(len) : 0;
}
-void String::split(const String& separator, bool allowEmptyEntries, Vector<String>& result) const
+Vector<String> String::split(const String& separator, bool allowEmptyEntries) const
{
- result.clear();
-
+ Vector<String> result;
+
int startPos = 0;
int endPos;
while ((endPos = find(separator, startPos)) != -1) {
@@ -523,33 +483,17 @@ void String::split(const String& separator, bool allowEmptyEntries, Vector<Strin
result.append(substring(startPos, endPos - startPos));
startPos = endPos + separator.length();
}
- if (allowEmptyEntries || startPos != static_cast<int>(length()))
- result.append(substring(startPos));
-}
-
-void String::split(const String& separator, Vector<String>& result) const
-{
- return split(separator, false, result);
-}
-
-void String::split(UChar separator, bool allowEmptyEntries, Vector<String>& result) const
-{
- result.clear();
-
- int startPos = 0;
- int endPos;
- while ((endPos = find(separator, startPos)) != -1) {
- if (allowEmptyEntries || startPos != endPos)
- result.append(substring(startPos, endPos - startPos));
- startPos = endPos + 1;
- }
- if (allowEmptyEntries || startPos != static_cast<int>(length()))
+ if (allowEmptyEntries || startPos != (int)length())
result.append(substring(startPos));
+
+ return result;
}
-void String::split(UChar separator, Vector<String>& result) const
+Vector<String> String::split(UChar separator, bool allowEmptyEntries) const
{
- return split(String(&separator, 1), false, result);
+ Vector<String> result;
+
+ return split(String(&separator, 1), allowEmptyEntries);
}
#ifndef NDEBUG
@@ -588,6 +532,17 @@ String String::fromUTF8(const char* string)
return UTF8Encoding().decode(string, strlen(string));
}
+
+bool operator==(const String& a, const DeprecatedString& b)
+{
+ unsigned l = a.length();
+ if (l != b.length())
+ return false;
+ if (!memcmp(a.characters(), b.unicode(), l * sizeof(UChar)))
+ return true;
+ return false;
+}
+
String::String(const Identifier& str)
{
if (str.isNull())
@@ -616,178 +571,6 @@ String::operator UString() const
return UString(reinterpret_cast<const KJS::UChar*>(m_impl->characters()), m_impl->length());
}
-// String Operations
-
-static bool isCharacterAllowedInBase(UChar c, int base)
-{
- if (c > 0x7F)
- return false;
- if (isASCIIDigit(c))
- return c - '0' < base;
- if (isASCIIAlpha(c)) {
- if (base > 36)
- base = 36;
- return (c >= 'a' && c < 'a' + base - 10)
- || (c >= 'A' && c < 'A' + base - 10);
- }
- return false;
-}
-
-template <typename IntegralType>
-static inline IntegralType toIntegralType(const UChar* data, size_t length, bool* ok, int base)
-{
- static const IntegralType integralMax = std::numeric_limits<IntegralType>::max();
- static const bool isSigned = std::numeric_limits<IntegralType>::is_signed;
- const IntegralType maxMultiplier = integralMax / base;
-
- IntegralType value = 0;
- bool isOk = false;
- bool isNegative = false;
-
- if (!data)
- goto bye;
-
- // skip leading whitespace
- while (length && isSpaceOrNewline(*data)) {
- length--;
- data++;
- }
-
- if (isSigned && length && *data == '-') {
- length--;
- data++;
- isNegative = true;
- } else if (length && *data == '+') {
- length--;
- data++;
- }
-
- if (!length || !isCharacterAllowedInBase(*data, base))
- goto bye;
-
- while (length && isCharacterAllowedInBase(*data, base)) {
- length--;
- IntegralType digitValue;
- UChar c = *data;
- if (isASCIIDigit(c))
- digitValue = c - '0';
- else if (c >= 'a')
- digitValue = c - 'a' + 10;
- else
- digitValue = c - 'A' + 10;
-
- if (value > maxMultiplier || (value == maxMultiplier && digitValue > (integralMax % base) + isNegative))
- goto bye;
-
- value = base * value + digitValue;
- data++;
- }
-
- if (isNegative)
- value = -value;
-
- // skip trailing space
- while (length && isSpaceOrNewline(*data)) {
- length--;
- data++;
- }
-
- if (!length)
- isOk = true;
-bye:
- if (ok)
- *ok = isOk;
- return isOk ? value : 0;
-}
-
-static unsigned lengthOfCharactersAsInteger(const UChar* data, size_t length)
-{
- size_t i = 0;
-
- // Allow leading spaces.
- for (; i != length; ++i) {
- if (!isSpaceOrNewline(data[i]))
- break;
- }
-
- // Allow sign.
- if (i != length && (data[i] == '+' || data[i] == '-'))
- ++i;
-
- // Allow digits.
- for (; i != length; ++i) {
- if (!Unicode::isDigit(data[i]))
- break;
- }
-
- return i;
-}
-
-int charactersToIntStrict(const UChar* data, size_t length, bool* ok, int base)
-{
- return toIntegralType<int>(data, length, ok, base);
-}
-
-unsigned charactersToUIntStrict(const UChar* data, size_t length, bool* ok, int base)
-{
- return toIntegralType<unsigned>(data, length, ok, base);
-}
-
-int64_t charactersToInt64Strict(const UChar* data, size_t length, bool* ok, int base)
-{
- return toIntegralType<int64_t>(data, length, ok, base);
-}
-
-uint64_t charactersToUInt64Strict(const UChar* data, size_t length, bool* ok, int base)
-{
- return toIntegralType<uint64_t>(data, length, ok, base);
-}
-
-int charactersToInt(const UChar* data, size_t length, bool* ok)
-{
- return toIntegralType<int>(data, lengthOfCharactersAsInteger(data, length), ok, 10);
-}
-
-unsigned charactersToUInt(const UChar* data, size_t length, bool* ok)
-{
- return toIntegralType<unsigned>(data, lengthOfCharactersAsInteger(data, length), ok, 10);
-}
-
-int64_t charactersToInt64(const UChar* data, size_t length, bool* ok)
-{
- return toIntegralType<int64_t>(data, lengthOfCharactersAsInteger(data, length), ok, 10);
-}
-
-uint64_t charactersToUInt64(const UChar* data, size_t length, bool* ok)
-{
- return toIntegralType<uint64_t>(data, lengthOfCharactersAsInteger(data, length), ok, 10);
-}
-
-double charactersToDouble(const UChar* data, size_t length, bool* ok)
-{
- if (!length) {
- if (ok)
- *ok = false;
- return 0.0;
- }
-
- Vector<char, 256> bytes(length + 1);
- for (unsigned i = 0; i < length; ++i)
- bytes[i] = data[i] < 0x7F ? data[i] : '?';
- bytes[length] = '\0';
- char* end;
- double val = kjs_strtod(bytes.data(), &end);
- if (ok)
- *ok = (end == 0 || *end == '\0');
- return val;
-}
-
-float charactersToFloat(const UChar* data, size_t length, bool* ok)
-{
- // FIXME: This will return ok even when the string fits into a double but not a float.
- return narrowPrecisionToFloat(charactersToDouble(data, length, ok));
-}
-
} // namespace WebCore
#ifndef NDEBUG
diff --git a/WebCore/platform/text/StringImpl.cpp b/WebCore/platform/text/StringImpl.cpp
index f9087b5..0643de6 100644
--- a/WebCore/platform/text/StringImpl.cpp
+++ b/WebCore/platform/text/StringImpl.cpp
@@ -28,6 +28,7 @@
#include "AtomicString.h"
#include "CString.h"
#include "CharacterNames.h"
+#include "DeprecatedString.h"
#include "FloatConversion.h"
#include "Length.h"
#include "StringBuffer.h"
@@ -59,7 +60,8 @@ static inline void deleteUCharVector(const UChar* p)
// This constructor is used only to create the empty string.
StringImpl::StringImpl()
- : m_length(0)
+ : RefCounted<StringImpl>(1)
+ , m_length(0)
, m_data(0)
, m_hash(0)
, m_inTable(false)
@@ -71,7 +73,8 @@ StringImpl::StringImpl()
// operation. Because of that, it's the one constructor that doesn't assert the
// length is non-zero, since we support copying the empty string.
inline StringImpl::StringImpl(const UChar* characters, unsigned length)
- : m_length(length)
+ : RefCounted<StringImpl>(1)
+ , m_length(length)
, m_hash(0)
, m_inTable(false)
, m_hasTerminatingNullCharacter(false)
@@ -82,7 +85,8 @@ inline StringImpl::StringImpl(const UChar* characters, unsigned length)
}
inline StringImpl::StringImpl(const StringImpl& str, WithTerminatingNullCharacter)
- : m_length(str.m_length)
+ : RefCounted<StringImpl>(1)
+ , m_length(str.m_length)
, m_hash(str.m_hash)
, m_inTable(false)
, m_hasTerminatingNullCharacter(true)
@@ -94,7 +98,8 @@ inline StringImpl::StringImpl(const StringImpl& str, WithTerminatingNullCharacte
}
inline StringImpl::StringImpl(const char* characters, unsigned length)
- : m_length(length)
+ : RefCounted<StringImpl>(1)
+ , m_length(length)
, m_hash(0)
, m_inTable(false)
, m_hasTerminatingNullCharacter(false)
@@ -111,7 +116,8 @@ inline StringImpl::StringImpl(const char* characters, unsigned length)
}
inline StringImpl::StringImpl(UChar* characters, unsigned length, AdoptBuffer)
- : m_length(length)
+ : RefCounted<StringImpl>(1)
+ , m_length(length)
, m_data(characters)
, m_hash(0)
, m_inTable(false)
@@ -121,9 +127,15 @@ inline StringImpl::StringImpl(UChar* characters, unsigned length, AdoptBuffer)
ASSERT(length);
}
+// FIXME: These AtomicString constructors return objects with a refCount of 0,
+// even though the others return objects with a refCount of 1. That preserves
+// the historical behavior for the hash map translator call sites inside the
+// AtomicString code, but is it correct?
+
// This constructor is only for use by AtomicString.
StringImpl::StringImpl(const UChar* characters, unsigned length, unsigned hash)
- : m_length(length)
+ : RefCounted<StringImpl>(0)
+ , m_length(length)
, m_hash(hash)
, m_inTable(true)
, m_hasTerminatingNullCharacter(false)
@@ -139,7 +151,8 @@ StringImpl::StringImpl(const UChar* characters, unsigned length, unsigned hash)
// This constructor is only for use by AtomicString.
StringImpl::StringImpl(const char* characters, unsigned length, unsigned hash)
- : m_length(length)
+ : RefCounted<StringImpl>(0)
+ , m_length(length)
, m_hash(hash)
, m_inTable(true)
, m_hasTerminatingNullCharacter(false)
@@ -212,7 +225,7 @@ static Length parseLength(const UChar* data, unsigned length)
++i;
bool ok;
- int r = charactersToIntStrict(data, i, &ok);
+ int r = DeprecatedConstString(reinterpret_cast<const DeprecatedChar*>(data), i).string().toInt(&ok);
/* Skip over any remaining digits, we are not that accurate (5.5% => 5%) */
while (i < length && (Unicode::isDigit(data[i]) || data[i] == '.'))
@@ -500,54 +513,84 @@ PassRefPtr<StringImpl> StringImpl::capitalize(UChar previous)
return adopt(data);
}
-int StringImpl::toIntStrict(bool* ok, int base)
-{
- return charactersToIntStrict(m_data, m_length, ok, base);
-}
-
-unsigned StringImpl::toUIntStrict(bool* ok, int base)
-{
- return charactersToUIntStrict(m_data, m_length, ok, base);
-}
-
-int64_t StringImpl::toInt64Strict(bool* ok, int base)
-{
- return charactersToInt64Strict(m_data, m_length, ok, base);
-}
-
-uint64_t StringImpl::toUInt64Strict(bool* ok, int base)
-{
- return charactersToUInt64Strict(m_data, m_length, ok, base);
-}
-
int StringImpl::toInt(bool* ok)
{
- return charactersToInt(m_data, m_length, ok);
-}
+ unsigned i = 0;
-unsigned StringImpl::toUInt(bool* ok)
-{
- return charactersToUInt(m_data, m_length, ok);
+ // Allow leading spaces.
+ for (; i != m_length; ++i)
+ if (!isSpaceOrNewline(m_data[i]))
+ break;
+
+ // Allow sign.
+ if (i != m_length && (m_data[i] == '+' || m_data[i] == '-'))
+ ++i;
+
+ // Allow digits.
+ for (; i != m_length; ++i)
+ if (!Unicode::isDigit(m_data[i]))
+ break;
+
+ return DeprecatedConstString(reinterpret_cast<const DeprecatedChar*>(m_data), i).string().toInt(ok);
}
int64_t StringImpl::toInt64(bool* ok)
{
- return charactersToInt64(m_data, m_length, ok);
+ unsigned i = 0;
+
+ // Allow leading spaces.
+ for (; i != m_length; ++i)
+ if (!isSpaceOrNewline(m_data[i]))
+ break;
+
+ // Allow sign.
+ if (i != m_length && (m_data[i] == '+' || m_data[i] == '-'))
+ ++i;
+
+ // Allow digits.
+ for (; i != m_length; ++i)
+ if (!Unicode::isDigit(m_data[i]))
+ break;
+
+ return DeprecatedConstString(reinterpret_cast<const DeprecatedChar*>(m_data), i).string().toInt64(ok);
}
uint64_t StringImpl::toUInt64(bool* ok)
{
- return charactersToUInt64(m_data, m_length, ok);
+ unsigned i = 0;
+
+ // Allow leading spaces.
+ for (; i != m_length; ++i)
+ if (!isSpaceOrNewline(m_data[i]))
+ break;
+
+ // Allow digits.
+ for (; i != m_length; ++i)
+ if (!Unicode::isDigit(m_data[i]))
+ break;
+
+ return DeprecatedConstString(reinterpret_cast<const DeprecatedChar*>(m_data), i).string().toUInt64(ok);
}
double StringImpl::toDouble(bool* ok)
{
- return charactersToDouble(m_data, m_length, ok);
+ if (!m_length) {
+ if (ok)
+ *ok = false;
+ return 0;
+ }
+ char *end;
+ CString latin1String = Latin1Encoding().encode(characters(), length());
+ double val = kjs_strtod(latin1String.data(), &end);
+ if (ok)
+ *ok = end == 0 || *end == '\0';
+ return val;
}
float StringImpl::toFloat(bool* ok)
{
- return charactersToFloat(m_data, m_length, ok);
+ // FIXME: This will return ok even when the string fits into a double but not a float.
+ return narrowPrecisionToFloat(toDouble(ok));
}
static bool equal(const UChar* a, const char* b, int length)
@@ -614,7 +657,15 @@ int StringImpl::find(const char* chs, int index, bool caseSensitive)
int StringImpl::find(UChar c, int start)
{
- return WebCore::find(m_data, m_length, c, start);
+ unsigned index = start;
+ if (index >= m_length )
+ return -1;
+ while(index < m_length) {
+ if (m_data[index] == c)
+ return index;
+ index++;
+ }
+ return -1;
}
int StringImpl::find(StringImpl* str, int index, bool caseSensitive)
@@ -675,7 +726,18 @@ int StringImpl::find(StringImpl* str, int index, bool caseSensitive)
int StringImpl::reverseFind(UChar c, int index)
{
- return WebCore::reverseFind(m_data, m_length, c, index);
+ if (index >= (int)m_length || m_length == 0)
+ return -1;
+
+ if (index < 0)
+ index += m_length;
+ while (1) {
+ if (m_data[index] == c)
+ return index;
+ if (index == 0)
+ return -1;
+ index--;
+ }
}
int StringImpl::reverseFind(StringImpl* str, int index, bool caseSensitive)
diff --git a/WebCore/platform/text/StringImpl.h b/WebCore/platform/text/StringImpl.h
index 1fb1e95..dd50b2e 100644
--- a/WebCore/platform/text/StringImpl.h
+++ b/WebCore/platform/text/StringImpl.h
@@ -49,9 +49,6 @@ struct StringHash;
struct UCharBufferTranslator;
class StringImpl : public RefCounted<StringImpl> {
- friend class AtomicString;
- friend struct UCharBufferTranslator;
- friend struct CStringTranslator;
private:
StringImpl();
StringImpl(const UChar*, unsigned length);
@@ -102,16 +99,9 @@ public:
bool containsOnlyWhitespace();
- int toIntStrict(bool* ok = 0, int base = 10);
- unsigned toUIntStrict(bool* ok = 0, int base = 10);
- int64_t toInt64Strict(bool* ok = 0, int base = 10);
- uint64_t toUInt64Strict(bool* ok = 0, int base = 10);
-
- int toInt(bool* ok = 0); // ignores trailing garbage
- unsigned toUInt(bool* ok = 0); // ignores trailing garbage
- int64_t toInt64(bool* ok = 0); // ignores trailing garbage
- uint64_t toUInt64(bool* ok = 0); // ignores trailing garbage
-
+ int toInt(bool* ok = 0); // ignores trailing garbage, unlike DeprecatedString
+ int64_t toInt64(bool* ok = 0); // ignores trailing garbage, unlike DeprecatedString
+ uint64_t toUInt64(bool* ok = 0); // ignores trailing garbage, unlike DeprecatedString
double toDouble(bool* ok = 0);
float toFloat(bool* ok = 0);
@@ -156,6 +146,10 @@ public:
#endif
private:
+ friend class AtomicString;
+ friend struct UCharBufferTranslator;
+ friend struct CStringTranslator;
+
unsigned m_length;
const UChar* m_data;
mutable unsigned m_hash;
diff --git a/WebCore/platform/text/TextBreakIteratorICU.cpp b/WebCore/platform/text/TextBreakIteratorICU.cpp
index 9941f58..9fd2d0b 100644
--- a/WebCore/platform/text/TextBreakIteratorICU.cpp
+++ b/WebCore/platform/text/TextBreakIteratorICU.cpp
@@ -25,7 +25,6 @@
#include "TextBreakIteratorInternalICU.h"
#include <unicode/ubrk.h>
-#include <wtf/Assertions.h>
namespace WebCore {
@@ -39,7 +38,6 @@ static TextBreakIterator* setUpIterator(bool& createdIterator, TextBreakIterator
UErrorCode openStatus = U_ZERO_ERROR;
iterator = static_cast<TextBreakIterator*>(ubrk_open(type, currentTextBreakLocaleID(), 0, 0, &openStatus));
createdIterator = true;
- ASSERT_WITH_MESSAGE(U_SUCCESS(openStatus), "ICU could not open a break iterator: %s (%d)", u_errorName(openStatus), openStatus);
}
if (!iterator)
return 0;
diff --git a/WebCore/platform/text/TextCodecICU.cpp b/WebCore/platform/text/TextCodecICU.cpp
index 0299b8f..a89a74e 100644
--- a/WebCore/platform/text/TextCodecICU.cpp
+++ b/WebCore/platform/text/TextCodecICU.cpp
@@ -33,6 +33,7 @@
#include <unicode/ucnv.h>
#include <unicode/ucnv_cb.h>
#include <wtf/Assertions.h>
+#include <wtf/HashMap.h>
using std::auto_ptr;
using std::min;
@@ -85,7 +86,9 @@ void TextCodecICU::registerExtendedEncodingNames(EncodingNameRegistrar registrar
// for encoding GB_2312-80 and several others. So, we need to override this behavior, too.
if (strcmp(standardName, "GB2312") == 0 || strcmp(standardName, "GB_2312-80") == 0)
standardName = "GBK";
+#ifndef ANDROID
else
+#endif
registrar(standardName, standardName);
uint16_t numAliases = ucnv_countAliases(name, &error);
@@ -262,27 +265,23 @@ String TextCodecICU::decode(const char* bytes, size_t length, bool flush)
// We need to apply these fallbacks ourselves as they are not currently supported by ICU and
// they were provided by the old TEC encoding path
// Needed to fix <rdar://problem/4708689>
-static UChar getGbkEscape(UChar32 codePoint)
-{
- switch (codePoint) {
- case 0x01F9:
- return 0xE7C8;
- case 0x1E3F:
- return 0xE7C7;
- case 0x22EF:
- return 0x2026;
- case 0x301C:
- return 0xFF5E;
- default:
- return 0;
+static HashMap<UChar32, UChar>& gbkEscapes() {
+ static HashMap<UChar32, UChar> escapes;
+ if (escapes.isEmpty()) {
+ escapes.add(0x01F9, 0xE7C8);
+ escapes.add(0x1E3F, 0xE7C7);
+ escapes.add(0x22EF, 0x2026);
+ escapes.add(0x301C, 0xFF5E);
}
+
+ return escapes;
}
static void gbkCallbackEscape(const void* context, UConverterFromUnicodeArgs* fromUArgs, const UChar* codeUnits, int32_t length,
UChar32 codePoint, UConverterCallbackReason reason, UErrorCode* err)
{
- UChar outChar;
- if (reason == UCNV_UNASSIGNED && (outChar = getGbkEscape(codePoint))) {
+ if (codePoint && gbkEscapes().contains(codePoint)) {
+ UChar outChar = gbkEscapes().get(codePoint);
const UChar* source = &outChar;
*err = U_ZERO_ERROR;
ucnv_cbFromUWriteUChars(fromUArgs, &source, source + 1, 0, err);
@@ -294,8 +293,8 @@ static void gbkCallbackEscape(const void* context, UConverterFromUnicodeArgs* fr
static void gbkCallbackSubstitute(const void* context, UConverterFromUnicodeArgs* fromUArgs, const UChar* codeUnits, int32_t length,
UChar32 codePoint, UConverterCallbackReason reason, UErrorCode* err)
{
- UChar outChar;
- if (reason == UCNV_UNASSIGNED && (outChar = getGbkEscape(codePoint))) {
+ if (gbkEscapes().contains(codePoint)) {
+ UChar outChar = gbkEscapes().get(codePoint);
const UChar* source = &outChar;
*err = U_ZERO_ERROR;
ucnv_cbFromUWriteUChars(fromUArgs, &source, source + 1, 0, err);
diff --git a/WebCore/platform/text/TextCodecLatin1.cpp b/WebCore/platform/text/TextCodecLatin1.cpp
index 2e9d116..a687235 100644
--- a/WebCore/platform/text/TextCodecLatin1.cpp
+++ b/WebCore/platform/text/TextCodecLatin1.cpp
@@ -29,7 +29,6 @@
#include "CString.h"
#include "PlatformString.h"
#include "StringBuffer.h"
-#include <stdio.h>
using std::auto_ptr;
diff --git a/WebCore/platform/text/TextCodecUserDefined.cpp b/WebCore/platform/text/TextCodecUserDefined.cpp
index 3ef1bc9..a420992 100644
--- a/WebCore/platform/text/TextCodecUserDefined.cpp
+++ b/WebCore/platform/text/TextCodecUserDefined.cpp
@@ -29,7 +29,6 @@
#include "CString.h"
#include "PlatformString.h"
#include "StringBuffer.h"
-#include <stdio.h>
using std::auto_ptr;
diff --git a/WebCore/platform/text/TextStream.cpp b/WebCore/platform/text/TextStream.cpp
index 5aafbc0..b23e769 100644
--- a/WebCore/platform/text/TextStream.cpp
+++ b/WebCore/platform/text/TextStream.cpp
@@ -26,74 +26,145 @@
#include "config.h"
#include "TextStream.h"
+#include "DeprecatedString.h"
+#include "Logging.h"
#include "PlatformString.h"
-#include <wtf/StringExtras.h>
+#include <wtf/Vector.h>
namespace WebCore {
-static const size_t printBufferSize = 100; // large enough for any integer or floating point value in string format, including trailing null character
+const size_t integerOrPointerAsStringBufferSize = 100; // large enough for any integer or pointer in string format, including trailing null character
+const char* const precisionFormats[7] = { "%.0f", "%.1f", "%.2f", "%.3f", "%.4f", "%.5f", "%.6f"};
+const int maxPrecision = 6; // must match size of precisionFormats
+const int defaultPrecision = 6; // matches qt and sprintf(.., "%f", ...) behaviour
+
+TextStream::TextStream(DeprecatedString* s)
+ : m_hasByteArray(false), m_string(s), m_precision(defaultPrecision)
+{
+}
+
+TextStream& TextStream::operator<<(char c)
+{
+ if (m_hasByteArray)
+ m_byteArray.append(c);
+
+ if (m_string)
+ m_string->append(DeprecatedChar(c));
+ return *this;
+}
+
+TextStream& TextStream::operator<<(short i)
+{
+ char buffer[integerOrPointerAsStringBufferSize];
+ sprintf(buffer, "%d", i);
+ return *this << buffer;
+}
+
+TextStream& TextStream::operator<<(unsigned short i)
+{
+ char buffer[integerOrPointerAsStringBufferSize];
+ sprintf(buffer, "%u", i);
+ return *this << buffer;
+}
TextStream& TextStream::operator<<(int i)
{
- char buffer[printBufferSize];
- snprintf(buffer, sizeof(buffer) - 1, "%d", i);
+ char buffer[integerOrPointerAsStringBufferSize];
+ sprintf(buffer, "%d", i);
return *this << buffer;
}
TextStream& TextStream::operator<<(unsigned i)
{
- char buffer[printBufferSize];
- snprintf(buffer, sizeof(buffer) - 1, "%u", i);
+ char buffer[integerOrPointerAsStringBufferSize];
+ sprintf(buffer, "%u", i);
return *this << buffer;
}
TextStream& TextStream::operator<<(long i)
{
- char buffer[printBufferSize];
- snprintf(buffer, sizeof(buffer) - 1, "%ld", i);
+ char buffer[integerOrPointerAsStringBufferSize];
+ sprintf(buffer, "%ld", i);
return *this << buffer;
}
TextStream& TextStream::operator<<(unsigned long i)
{
- char buffer[printBufferSize];
- snprintf(buffer, sizeof(buffer) - 1, "%lu", i);
+ char buffer[integerOrPointerAsStringBufferSize];
+ sprintf(buffer, "%lu", i);
return *this << buffer;
}
TextStream& TextStream::operator<<(float f)
{
- char buffer[printBufferSize];
- snprintf(buffer, sizeof(buffer) - 1, "%.2f", f);
+ char buffer[integerOrPointerAsStringBufferSize];
+ sprintf(buffer, precisionFormats[m_precision], f);
return *this << buffer;
}
TextStream& TextStream::operator<<(double d)
{
- char buffer[printBufferSize];
- snprintf(buffer, sizeof(buffer) - 1, "%.2f", d);
+ char buffer[integerOrPointerAsStringBufferSize];
+ sprintf(buffer, precisionFormats[m_precision], d);
return *this << buffer;
}
-TextStream& TextStream::operator<<(const char* string)
+TextStream& TextStream::operator<<(const char* s)
{
- size_t stringLength = strlen(string);
- size_t textLength = m_text.size();
- m_text.grow(textLength + stringLength);
- for (size_t i = 0; i < stringLength; ++i)
- m_text[textLength + i] = string[i];
+ if (m_hasByteArray) {
+ unsigned length = strlen(s);
+ unsigned oldSize = m_byteArray.size();
+ m_byteArray.grow(oldSize + length);
+ memcpy(m_byteArray.data() + oldSize, s, length);
+ }
+ if (m_string)
+ m_string->append(s);
return *this;
}
-TextStream& TextStream::operator<<(const String& string)
+TextStream& TextStream::operator<<(const DeprecatedString& s)
{
- append(m_text, string);
+ if (m_hasByteArray) {
+ unsigned length = s.length();
+ unsigned oldSize = m_byteArray.size();
+ m_byteArray.grow(oldSize + length);
+ memcpy(m_byteArray.data() + oldSize, s.latin1(), length);
+ }
+ if (m_string)
+ m_string->append(s);
return *this;
}
-String TextStream::release()
+TextStream& TextStream::operator<<(const String& s)
+{
+ return (*this) << s.deprecatedString();
+}
+
+TextStream& TextStream::operator<<(void* p)
+{
+ char buffer[integerOrPointerAsStringBufferSize];
+ sprintf(buffer, "%p", p);
+ return *this << buffer;
+}
+
+TextStream& TextStream::operator<<(const TextStreamManipulator& m)
+{
+ return m(*this);
+}
+
+int TextStream::precision(int p)
+{
+ int oldPrecision = m_precision;
+
+ if (p >= 0 && p <= maxPrecision)
+ m_precision = p;
+
+ return oldPrecision;
+}
+
+TextStream &endl(TextStream& stream)
{
- return String::adopt(m_text);
+ return stream << '\n';
}
}
diff --git a/WebCore/platform/text/TextStream.h b/WebCore/platform/text/TextStream.h
index b4b801c..897c267 100644
--- a/WebCore/platform/text/TextStream.h
+++ b/WebCore/platform/text/TextStream.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004, 2008 Apple 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
@@ -27,14 +27,26 @@
#define TextStream_h
#include <wtf/Vector.h>
-#include <wtf/unicode/Unicode.h>
namespace WebCore {
+class DeprecatedChar;
+class DeprecatedString;
class String;
+class TextStream;
+
+typedef TextStream& (*TextStreamManipulator)(TextStream&);
+
+TextStream& endl(TextStream&);
class TextStream {
public:
+ TextStream(DeprecatedString*);
+
+ TextStream& operator<<(char);
+ TextStream& operator<<(const DeprecatedChar&);
+ TextStream& operator<<(short);
+ TextStream& operator<<(unsigned short);
TextStream& operator<<(int);
TextStream& operator<<(unsigned);
TextStream& operator<<(long);
@@ -43,11 +55,21 @@ public:
TextStream& operator<<(double);
TextStream& operator<<(const char*);
TextStream& operator<<(const String&);
+ TextStream& operator<<(const DeprecatedString&);
+ TextStream& operator<<(void*);
- String release();
+ TextStream& operator<<(const TextStreamManipulator&);
+
+ int precision(int);
private:
- Vector<UChar> m_text;
+ TextStream(const TextStream&);
+ TextStream& operator=(const TextStream&);
+
+ bool m_hasByteArray;
+ Vector<char> m_byteArray;
+ DeprecatedString* m_string;
+ int m_precision;
};
}
diff --git a/WebCore/platform/text/mac/ShapeArabic.c b/WebCore/platform/text/mac/ShapeArabic.c
index 43e149d..4706e7c 100644
--- a/WebCore/platform/text/mac/ShapeArabic.c
+++ b/WebCore/platform/text/mac/ShapeArabic.c
@@ -2,28 +2,8 @@
******************************************************************************
*
* Copyright (C) 2000-2004, International Business Machines
-* Corporation and others. All Rights Reserved.
-* Copyright (C) 2007 Apple Inc. All rights reserved.
-*
-* Permission is hereby granted, free of charge, to any person obtaining a copy of this
-* software and associated documentation files (the "Software"), to deal in the Software
-* without restriction, including without limitation the rights to use, copy, modify,
-* merge, publish, distribute, and/or sell copies of the Software, and to permit persons
-* to whom the Software is furnished to do so, provided that the above copyright notice(s)
-* and this permission notice appear in all copies of the Software and that both the above
-* copyright notice(s) and this permission notice appear in supporting documentation.
-*
-* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
-* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
-* PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER
-* OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR
-* CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
-* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
-* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-*
-* Except as contained in this notice, the name of a copyright holder shall not be used in
-* advertising or otherwise to promote the sale, use or other dealings in this Software
-* without prior written authorization of the copyright holder.
+* Corporation and others. All Rights Reserved.
+* Copyright (C) 2007 Apple Inc. All rights reserved.
*
******************************************************************************
*
diff --git a/WebCore/platform/text/qt/StringQt.cpp b/WebCore/platform/text/qt/StringQt.cpp
index de9f527..23a684b 100644
--- a/WebCore/platform/text/qt/StringQt.cpp
+++ b/WebCore/platform/text/qt/StringQt.cpp
@@ -26,6 +26,7 @@
#include "config.h"
#include "PlatformString.h"
+#include "DeprecatedString.h"
#include <QString>
@@ -43,14 +44,21 @@ String::String(const QStringRef& ref)
{
if (!ref.string())
return;
- m_impl = StringImpl::create(reinterpret_cast<const UChar*>(ref.unicode()), ref.length());
+ m_impl = StringImpl::create(reinterpret_cast<const UChar *>(ref.unicode()), ref.length());
}
+
String::operator QString() const
{
return QString(reinterpret_cast<const QChar*>(characters()), length());
}
+// DeprecatedString conversions
+DeprecatedString::operator QString() const
+{
+ return QString(reinterpret_cast<const QChar*>(unicode()), length());
+}
+
}
// vim: ts=4 sw=4 et
diff --git a/WebCore/platform/text/wx/StringWx.cpp b/WebCore/platform/text/wx/StringWx.cpp
index 50919c4..7f91dbf 100644
--- a/WebCore/platform/text/wx/StringWx.cpp
+++ b/WebCore/platform/text/wx/StringWx.cpp
@@ -27,6 +27,7 @@
#include "PlatformString.h"
#include "CString.h"
+#include "DeprecatedString.h"
#include "unicode/ustring.h"
#include <wx/defs.h>
@@ -87,6 +88,12 @@ String::operator wxString() const
return wxString(utf8().data(), wxConvUTF8);
}
+// DeprecatedString conversions
+DeprecatedString::operator wxString() const
+{
+ return wxString(utf8().data(), wxConvUTF8);
+}
+
}
// vim: ts=4 sw=4 et
diff --git a/WebCore/platform/win/BString.cpp b/WebCore/platform/win/BString.cpp
index 7d08248..6228dab 100644
--- a/WebCore/platform/win/BString.cpp
+++ b/WebCore/platform/win/BString.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -27,7 +27,7 @@
#include "BString.h"
#include "AtomicString.h"
-#include "KURL.h"
+#include "DeprecatedString.h"
#include "PlatformString.h"
#include <tchar.h>
#include <windows.h>
@@ -67,12 +67,12 @@ BString::BString(const String& s)
m_bstr = SysAllocStringLen(s.characters(), s.length());
}
-BString::BString(const KURL& url)
+BString::BString(const DeprecatedString& s)
{
- if (url.isNull())
+ if (s.isNull())
m_bstr = 0;
else
- m_bstr = SysAllocStringLen(url.string().characters(), url.string().length());
+ m_bstr = SysAllocStringLen(String(s).characters(), s.length());
}
BString::BString(const AtomicString& s)
diff --git a/WebCore/platform/win/BString.h b/WebCore/platform/win/BString.h
index 5269491..5f1d75d 100644
--- a/WebCore/platform/win/BString.h
+++ b/WebCore/platform/win/BString.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -35,7 +35,7 @@ typedef wchar_t* BSTR;
namespace WebCore {
class AtomicString;
- class KURL;
+ class DeprecatedString;
class String;
class BString {
@@ -44,8 +44,8 @@ namespace WebCore {
BString(const wchar_t*);
BString(const wchar_t*, size_t length);
BString(const String&);
+ BString(const DeprecatedString&);
BString(const AtomicString&);
- BString(const KURL&);
#if PLATFORM(CF)
BString(CFStringRef);
#endif
diff --git a/WebCore/platform/win/ClipboardUtilitiesWin.cpp b/WebCore/platform/win/ClipboardUtilitiesWin.cpp
index 7a3e5ff..066e235 100644
--- a/WebCore/platform/win/ClipboardUtilitiesWin.cpp
+++ b/WebCore/platform/win/ClipboardUtilitiesWin.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -26,12 +26,12 @@
#include "config.h"
#include "ClipboardUtilitiesWin.h"
+#include "KURL.h"
#include "CString.h"
#include "DocumentFragment.h"
-#include "KURL.h"
+#include "markup.h"
#include "PlatformString.h"
#include "TextEncoding.h"
-#include "markup.h"
#include <CoreFoundation/CoreFoundation.h>
#include <wtf/RetainPtr.h>
#include <shlwapi.h>
@@ -120,103 +120,93 @@ HGLOBAL createGlobalData(const KURL& url, const String& title)
return cbData;
}
-HGLOBAL createGlobalData(const String& str)
-{
- HGLOBAL globalData = ::GlobalAlloc(GPTR, (str.length() + 1) * sizeof(UChar));
- if (!globalData)
- return 0;
- UChar* buffer = static_cast<UChar*>(::GlobalLock(globalData));
- memcpy(buffer, str.characters(), str.length() * sizeof(UChar));
- buffer[str.length()] = 0;
- ::GlobalUnlock(globalData);
- return globalData;
-}
-
-HGLOBAL createGlobalData(const Vector<char>& vector)
-{
- HGLOBAL globalData = ::GlobalAlloc(GPTR, vector.size() + 1);
- if (!globalData)
- return 0;
- char* buffer = static_cast<char*>(::GlobalLock(globalData));
- memcpy(buffer, vector.data(), vector.size());
- buffer[vector.size()] = 0;
- ::GlobalUnlock(globalData);
- return globalData;
-}
-
-static void append(Vector<char>& vector, const char* string)
-{
- vector.append(string, strlen(string));
+HGLOBAL createGlobalData(String str)
+{
+ SIZE_T size = (str.length() + 1) * sizeof(UChar);
+ HGLOBAL cbData = ::GlobalAlloc(GPTR, size);
+ if (cbData) {
+ void* buffer = ::GlobalLock(cbData);
+ memcpy(buffer, str.charactersWithNullTermination(), size);
+ ::GlobalUnlock(cbData);
+ }
+ return cbData;
}
-static void append(Vector<char>& vector, const CString& string)
+HGLOBAL createGlobalData(CString str)
{
- vector.append(string.data(), string.length());
+ SIZE_T size = str.length() * sizeof(char);
+ HGLOBAL cbData = ::GlobalAlloc(GPTR, size + 1);
+ if (cbData) {
+ char* buffer = static_cast<char*>(::GlobalLock(cbData));
+ memcpy(buffer, str.data(), size);
+ buffer[size] = 0;
+ ::GlobalUnlock(cbData);
+ }
+ return cbData;
}
// Documentation for the CF_HTML format is available at http://msdn.microsoft.com/workshop/networking/clipboard/htmlclipboard.asp
-void markupToCF_HTML(const String& markup, const String& srcURL, Vector<char>& result)
+DeprecatedCString markupToCF_HTML(const String& markup, const String& srcURL)
{
- if (markup.isEmpty())
- return;
-
- #define MAX_DIGITS 10
- #define MAKE_NUMBER_FORMAT_1(digits) MAKE_NUMBER_FORMAT_2(digits)
- #define MAKE_NUMBER_FORMAT_2(digits) "%0" #digits "u"
- #define NUMBER_FORMAT MAKE_NUMBER_FORMAT_1(MAX_DIGITS)
+ if (!markup.length())
+ return DeprecatedCString();
- const char* header = "Version:0.9\n"
- "StartHTML:" NUMBER_FORMAT "\n"
- "EndHTML:" NUMBER_FORMAT "\n"
- "StartFragment:" NUMBER_FORMAT "\n"
- "EndFragment:" NUMBER_FORMAT "\n";
- const char* sourceURLPrefix = "SourceURL:";
+ DeprecatedCString cf_html ("Version:0.9");
+ DeprecatedCString startHTML ("\nStartHTML:");
+ DeprecatedCString endHTML ("\nEndHTML:");
+ DeprecatedCString startFragment ("\nStartFragment:");
+ DeprecatedCString endFragment ("\nEndFragment:");
+ DeprecatedCString sourceURL ("\nSourceURL:");
- const char* startMarkup = "<HTML>\n<BODY>\n<!--StartFragment-->\n";
- const char* endMarkup = "\n<!--EndFragment-->\n</BODY>\n</HTML>";
+ bool shouldFillSourceURL = !srcURL.isEmpty() && (srcURL != "about:blank");
+ if (shouldFillSourceURL)
+ sourceURL.append(srcURL.utf8().data());
- CString sourceURLUTF8 = srcURL == blankURL() ? "" : srcURL.utf8();
- CString markupUTF8 = markup.utf8();
+ DeprecatedCString startMarkup ("\n<HTML>\n<BODY>\n<!--StartFragment-->\n");
+ DeprecatedCString endMarkup ("\n<!--EndFragment-->\n</BODY>\n</HTML>");
// calculate offsets
- unsigned startHTMLOffset = strlen(header) - strlen(NUMBER_FORMAT) * 4 + MAX_DIGITS * 4;
- if (sourceURLUTF8.length())
- startHTMLOffset += strlen(sourceURLPrefix) + sourceURLUTF8.length() + 1;
- unsigned startFragmentOffset = startHTMLOffset + strlen(startMarkup);
+ const unsigned UINT_MAXdigits = 10; // number of digits in UINT_MAX in base 10
+ unsigned startHTMLOffset = cf_html.length() + startHTML.length() + endHTML.length() + startFragment.length() + endFragment.length() + (shouldFillSourceURL ? sourceURL.length() : 0) + (4*UINT_MAXdigits);
+ unsigned startFragmentOffset = startHTMLOffset + startMarkup.length();
+ CString markupUTF8 = markup.utf8();
unsigned endFragmentOffset = startFragmentOffset + markupUTF8.length();
- unsigned endHTMLOffset = endFragmentOffset + strlen(endMarkup);
-
- append(result, String::format(header, startHTMLOffset, endHTMLOffset, startFragmentOffset, endFragmentOffset).utf8());
- if (sourceURLUTF8.length()) {
- append(result, sourceURLPrefix);
- append(result, sourceURLUTF8);
- result.append('\n');
- }
- append(result, startMarkup);
- append(result, markupUTF8);
- append(result, endMarkup);
-
- #undef MAX_DIGITS
- #undef MAKE_NUMBER_FORMAT_1
- #undef MAKE_NUMBER_FORMAT_2
- #undef NUMBER_FORMAT
+ unsigned endHTMLOffset = endFragmentOffset + endMarkup.length();
+
+ // fill in needed data
+ startHTML.append(String::format("%010u", startHTMLOffset).deprecatedString().utf8());
+ endHTML.append(String::format("%010u", endHTMLOffset).deprecatedString().utf8());
+ startFragment.append(String::format("%010u", startFragmentOffset).deprecatedString().utf8());
+ endFragment.append(String::format("%010u", endFragmentOffset).deprecatedString().utf8());
+ startMarkup.append(markupUTF8.data());
+
+ // create full cf_html string from the fragments
+ cf_html.append(startHTML);
+ cf_html.append(endHTML);
+ cf_html.append(startFragment);
+ cf_html.append(endFragment);
+ if (shouldFillSourceURL)
+ cf_html.append(sourceURL);
+ cf_html.append(startMarkup);
+ cf_html.append(endMarkup);
+
+ return cf_html;
}
String urlToMarkup(const KURL& url, const String& title)
{
- Vector<UChar> markup;
- append(markup, "<a href=\"");
- append(markup, url.string());
- append(markup, "\">");
- append(markup, title);
- append(markup, "</a>");
- return String::adopt(markup);
+ String markup("<a href=\"");
+ markup.append(url.string());
+ markup.append("\">");
+ markup.append(title);
+ markup.append("</a>");
+ return markup;
}
void replaceNewlinesWithWindowsStyleNewlines(String& str)
{
static const UChar Newline = '\n';
- static const char* const WindowsNewline("\r\n");
+ static const String WindowsNewline("\r\n");
str.replace(Newline, WindowsNewline);
}
diff --git a/WebCore/platform/win/ClipboardUtilitiesWin.h b/WebCore/platform/win/ClipboardUtilitiesWin.h
index a92a4bf..49898ea 100644
--- a/WebCore/platform/win/ClipboardUtilitiesWin.h
+++ b/WebCore/platform/win/ClipboardUtilitiesWin.h
@@ -31,12 +31,14 @@
namespace WebCore {
+class CString;
+class DeprecatedCString;
class Document;
class KURL;
class String;
-HGLOBAL createGlobalData(const String&);
-HGLOBAL createGlobalData(const Vector<char>&);
+HGLOBAL createGlobalData(String str);
+HGLOBAL createGlobalData(CString str);
HGLOBAL createGlobalData(const KURL& url, const String& title);
FORMATETC* urlWFormat();
@@ -49,21 +51,21 @@ FORMATETC* htmlFormat();
FORMATETC* cfHDropFormat();
FORMATETC* smartPasteFormat();
-void markupToCF_HTML(const String& markup, const String& srcURL, Vector<char>& result);
+DeprecatedCString markupToCF_HTML(const String& markup, const String& srcURL);
String urlToMarkup(const KURL& url, const String& title);
-void replaceNewlinesWithWindowsStyleNewlines(String&);
-void replaceNBSPWithSpace(String&);
+void replaceNewlinesWithWindowsStyleNewlines(String& str);
+void replaceNBSPWithSpace(String& str);
bool containsFilenames(const IDataObject*);
-bool containsHTML(IDataObject*);
+bool containsHTML(IDataObject* data);
PassRefPtr<DocumentFragment> fragmentFromFilenames(Document*, const IDataObject*);
-PassRefPtr<DocumentFragment> fragmentFromHTML(Document*, IDataObject*);
-PassRefPtr<DocumentFragment> fragmentFromCF_HTML(Document*, const String& cf_html);
+PassRefPtr<DocumentFragment> fragmentFromHTML(Document* doc, IDataObject* data);
+PassRefPtr<DocumentFragment> fragmentFromCF_HTML(Document* doc, const String& cf_html);
-String getURL(IDataObject*, bool& success, String* title = 0);
-String getPlainText(IDataObject*, bool& success);
+String getURL(IDataObject* dataObject, bool& success, String* title = 0);
+String getPlainText(IDataObject* dataObject, bool& success);
} // namespace WebCore
diff --git a/WebCore/platform/win/ClipboardWin.cpp b/WebCore/platform/win/ClipboardWin.cpp
index 46e7695..fbbbedb 100644
--- a/WebCore/platform/win/ClipboardWin.cpp
+++ b/WebCore/platform/win/ClipboardWin.cpp
@@ -26,9 +26,11 @@
#include "config.h"
#include "ClipboardWin.h"
-#include "CString.h"
#include "CachedImage.h"
#include "ClipboardUtilitiesWin.h"
+#include "csshelper.h"
+#include "CString.h"
+#include "DeprecatedString.h"
#include "Document.h"
#include "DragData.h"
#include "Editor.h"
@@ -40,6 +42,7 @@
#include "HTMLNames.h"
#include "Image.h"
#include "MIMETypeRegistry.h"
+#include "markup.h"
#include "Page.h"
#include "Pasteboard.h"
#include "PlatformMouseEvent.h"
@@ -49,16 +52,12 @@
#include "ResourceResponse.h"
#include "StringHash.h"
#include "WCDataObject.h"
-#include "csshelper.h"
-#include "markup.h"
#include <shlwapi.h>
#include <wininet.h>
#include <wtf/RefPtr.h>
-using namespace std;
-
namespace WebCore {
using namespace HTMLNames;
@@ -141,7 +140,7 @@ static String filesystemPathFromUrlOrTitle(const String& url, const String& titl
// The filename for any content based drag should be the last element of
// the path. If we can't find it, or we're coming up with the name for a link
// we just use the entire url.
- KURL kurl(url);
+ KURL kurl(url.deprecatedString());
String lastComponent;
if (!isLink && !(lastComponent = kurl.lastPathComponent()).isEmpty()) {
len = min<DWORD>(MAX_PATH, lastComponent.length());
@@ -227,10 +226,11 @@ static HGLOBAL createGlobalHDropContent(const KURL& url, String& fileName, Share
WCHAR filePath[MAX_PATH];
if (url.isLocalFile()) {
- String localPath = url.path();
+ DeprecatedString path = url.path();
// windows does not enjoy a leading slash on paths
- if (localPath[0] == '/')
- localPath = localPath.substring(1);
+ if (path[0] == '/')
+ path = path.mid(1);
+ String localPath = path.ascii();
LPCTSTR localPathStr = localPath.charactersWithNullTermination();
if (wcslen(localPathStr) + 1 < MAX_PATH)
wcscpy_s(filePath, MAX_PATH, localPathStr);
@@ -437,9 +437,7 @@ static bool writeURL(WCDataObject *data, const KURL& url, String title, bool wit
success = true;
if (withHTML) {
- Vector<char> cfhtmlData;
- markupToCF_HTML(urlToMarkup(url, title), "", cfhtmlData);
- medium.hGlobal = createGlobalData(cfhtmlData);
+ medium.hGlobal = createGlobalData(markupToCF_HTML(urlToMarkup(url, title), ""));
if (medium.hGlobal && FAILED(data->SetData(htmlFormat(), &medium, TRUE)))
::GlobalFree(medium.hGlobal);
else
@@ -505,7 +503,7 @@ String ClipboardWin::getData(const String& type, bool& success) const
return "";
}
-bool ClipboardWin::setData(const String& type, const String& data)
+bool ClipboardWin::setData(const String &type, const String &data)
{
// FIXME: Need to be able to write to the system clipboard <rdar://problem/5015941>
ASSERT(isForDragging());
@@ -515,7 +513,7 @@ bool ClipboardWin::setData(const String& type, const String& data)
ClipboardDataType winType = clipboardTypeFromMIMEType(type);
if (winType == ClipboardDataTypeURL)
- return WebCore::writeURL(m_writableDataObject.get(), KURL(data), String(), false, true);
+ return WebCore::writeURL(m_writableDataObject.get(), data.deprecatedString(), String(), false, true);
if (winType == ClipboardDataTypeText) {
STGMEDIUM medium = {0};
@@ -678,7 +676,7 @@ void ClipboardWin::declareAndWriteDragImage(Element* element, const KURL& url, c
if (imageURL.isEmpty())
return;
- String fullURL = frame->document()->completeURL(parseURL(imageURL)).string();
+ String fullURL = frame->document()->completeURL(parseURL(imageURL));
if (fullURL.isEmpty())
return;
STGMEDIUM medium = {0};
@@ -686,9 +684,7 @@ void ClipboardWin::declareAndWriteDragImage(Element* element, const KURL& url, c
ExceptionCode ec = 0;
// Put img tag on the clipboard referencing the image
- Vector<char> data;
- markupToCF_HTML(imageToMarkup(fullURL), "", data);
- medium.hGlobal = createGlobalData(data);
+ medium.hGlobal = createGlobalData(markupToCF_HTML(imageToMarkup(fullURL), ""));
if (medium.hGlobal && FAILED(m_writableDataObject->SetData(htmlFormat(), &medium, TRUE)))
::GlobalFree(medium.hGlobal);
}
@@ -723,10 +719,7 @@ void ClipboardWin::writeRange(Range* selectedRange, Frame* frame)
medium.tymed = TYMED_HGLOBAL;
ExceptionCode ec = 0;
- Vector<char> data;
- markupToCF_HTML(createMarkup(selectedRange, 0, AnnotateForInterchange),
- selectedRange->startContainer(ec)->document()->url().string(), data);
- medium.hGlobal = createGlobalData(data);
+ medium.hGlobal = createGlobalData(markupToCF_HTML(createMarkup(selectedRange, 0, AnnotateForInterchange), selectedRange->startContainer(ec)->document()->url()));
if (medium.hGlobal && FAILED(m_writableDataObject->SetData(htmlFormat(), &medium, TRUE)))
::GlobalFree(medium.hGlobal);
diff --git a/WebCore/platform/win/DragImageCairoWin.cpp b/WebCore/platform/win/DragImageCairoWin.cpp
index 5fff64f..1c9973d 100644
--- a/WebCore/platform/win/DragImageCairoWin.cpp
+++ b/WebCore/platform/win/DragImageCairoWin.cpp
@@ -47,7 +47,8 @@ DragImageRef createDragImageFromImage(Image* img)
{
notImplemented();
- return 0;
+ DragImageRef temp;
+ return temp;
}
}
diff --git a/WebCore/platform/win/FileChooserWin.cpp b/WebCore/platform/win/FileChooserWin.cpp
index 1bc4681..905bf92 100644
--- a/WebCore/platform/win/FileChooserWin.cpp
+++ b/WebCore/platform/win/FileChooserWin.cpp
@@ -41,8 +41,7 @@
namespace WebCore {
FileChooser::FileChooser(FileChooserClient* client, const String& filename)
- : RefCounted<FileChooser>(0)
- , m_client(client)
+ : m_client(client)
, m_filename(filename)
, m_icon(chooseIcon(filename))
{
diff --git a/WebCore/platform/win/FileSystemWin.cpp b/WebCore/platform/win/FileSystemWin.cpp
index 2a6c5d1..f721f3e 100644
--- a/WebCore/platform/win/FileSystemWin.cpp
+++ b/WebCore/platform/win/FileSystemWin.cpp
@@ -126,11 +126,6 @@ String homeDirectoryPath()
return "";
}
-String pathGetFileName(const String& path)
-{
- return String(PathFindFileName(String(path).charactersWithNullTermination()));
-}
-
static String bundleName()
{
static bool initialized;
@@ -219,12 +214,6 @@ int writeToFile(PlatformFileHandle handle, const char* data, int length)
return -1;
return static_cast<int>(bytesWritten);
}
-
-bool unloadModule(PlatformModule module)
-{
- return ::FreeLibrary(module);
-}
-
String localUserSpecificStorageDirectory()
{
return cachedStorageDirectory(CSIDL_LOCAL_APPDATA);
diff --git a/WebCore/platform/win/MutexWin.cpp b/WebCore/platform/win/MutexWin.cpp
new file mode 100644
index 0000000..41d7fe4
--- /dev/null
+++ b/WebCore/platform/win/MutexWin.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Brent Fulgham
+ *
+ * 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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.
+ */
+#include "config.h"
+#include "Threading.h"
+
+namespace WebCore {
+
+Mutex::Mutex()
+{
+ m_mutex.m_recursionCount = 0;
+ ::InitializeCriticalSection(&m_mutex.m_internalMutex);
+}
+
+Mutex::~Mutex()
+{
+ ::DeleteCriticalSection(&m_mutex.m_internalMutex);
+}
+
+void Mutex::lock()
+{
+ ::EnterCriticalSection(&m_mutex.m_internalMutex);
+ ++m_mutex.m_recursionCount;
+}
+
+bool Mutex::tryLock()
+{
+ // This method is modeled after the behavior of pthread_mutex_trylock,
+ // which will return an error if the lock is already owned by the
+ // current thread. Since the primitive Win32 'TryEnterCriticalSection'
+ // treats this as a successful case, it changes the behavior of several
+ // tests in WebKit that check to see if the current thread already
+ // owned this mutex (see e.g., IconDatabase::getOrCreateIconRecord)
+ DWORD result = ::TryEnterCriticalSection(&m_mutex.m_internalMutex);
+
+ if (result != 0) { // We got the lock
+ // If this thread already had the lock, we must unlock and
+ // return false so that we mimic the behavior of POSIX's
+ // pthread_mutex_trylock:
+ if (m_mutex.m_recursionCount > 0) {
+ ::LeaveCriticalSection(&m_mutex.m_internalMutex);
+ return false;
+ }
+
+ ++m_mutex.m_recursionCount;
+ return true;
+ }
+
+ return false;
+}
+
+void Mutex::unlock()
+{
+ --m_mutex.m_recursionCount;
+ ::LeaveCriticalSection(&m_mutex.m_internalMutex);
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/win/PasteboardWin.cpp b/WebCore/platform/win/PasteboardWin.cpp
index 506cc7b..427c303 100644
--- a/WebCore/platform/win/PasteboardWin.cpp
+++ b/WebCore/platform/win/PasteboardWin.cpp
@@ -26,10 +26,11 @@
#include "config.h"
#include "Pasteboard.h"
-#include "CString.h"
#include "ClipboardUtilitiesWin.h"
-#include "Document.h"
+#include "CString.h"
+#include "DeprecatedString.h"
#include "DocumentFragment.h"
+#include "Document.h"
#include "Element.h"
#include "Frame.h"
#include "HitTestResult.h"
@@ -115,10 +116,7 @@ void Pasteboard::writeSelection(Range* selectedRange, bool canSmartCopyOrDelete,
// Put CF_HTML format on the pasteboard
if (::OpenClipboard(m_owner)) {
ExceptionCode ec = 0;
- Vector<char> data;
- markupToCF_HTML(createMarkup(selectedRange, 0, AnnotateForInterchange),
- selectedRange->startContainer(ec)->document()->url().string(), data);
- HGLOBAL cbData = createGlobalData(data);
+ HGLOBAL cbData = createGlobalData(markupToCF_HTML(createMarkup(selectedRange, 0, AnnotateForInterchange), selectedRange->startContainer(ec)->document()->url()));
if (!::SetClipboardData(HTMLClipboardFormat, cbData))
::GlobalFree(cbData);
::CloseClipboard();
@@ -168,9 +166,7 @@ void Pasteboard::writeURL(const KURL& url, const String& titleStr, Frame* frame)
// write to clipboard in format CF_HTML to be able to paste into contenteditable areas as a link
if (::OpenClipboard(m_owner)) {
- Vector<char> data;
- markupToCF_HTML(urlToMarkup(url, title), "", data);
- HGLOBAL cbData = createGlobalData(data);
+ HGLOBAL cbData = createGlobalData(markupToCF_HTML(urlToMarkup(url, title), ""));
if (!::SetClipboardData(HTMLClipboardFormat, cbData))
::GlobalFree(cbData);
::CloseClipboard();
diff --git a/WebCore/platform/win/PlatformScrollBarWin.cpp b/WebCore/platform/win/PlatformScrollBarWin.cpp
deleted file mode 100644
index f59f27a..0000000
--- a/WebCore/platform/win/PlatformScrollBarWin.cpp
+++ /dev/null
@@ -1,772 +0,0 @@
-/*
- * Copyright (C) 2007 Apple Inc. All rights reserved.
- * Copyright (C) 2008 Brent Fulgham
- *
- * 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.
- */
-
-#include "config.h"
-
-#include "PlatformScrollBar.h"
-
-#include "EventHandler.h"
-#include "FrameView.h"
-#include "Frame.h"
-#include "GraphicsContext.h"
-#include "IntRect.h"
-#include "PlatformMouseEvent.h"
-#include "SoftLinking.h"
-
-#include <windows.h>
-#include "RenderThemeWin.h"
-
-// Generic state constants
-#define TS_NORMAL 1
-#define TS_HOVER 2
-#define TS_ACTIVE 3
-#define TS_DISABLED 4
-#define TS_FOCUSED 5
-
-#define ABS_UPNORMAL 1
-#define ABS_DOWNNORMAL 5
-#define ABS_LEFTNORMAL 9
-#define ABS_RIGHTNORMAL 13
-
-static const unsigned SP_ABS_HOT_MODIFIER = 1;
-static const unsigned SP_ABS_PRESSED_MODIFIER = 2;
-static const unsigned SP_ABS_DISABLE_MODIFIER = 3;
-
-// Scrollbar constants
-#define SP_BUTTON 1
-#define SP_THUMBHOR 2
-#define SP_THUMBVERT 3
-#define SP_TRACKSTARTHOR 4
-#define SP_TRACKENDHOR 5
-#define SP_TRACKSTARTVERT 6
-#define SP_TRACKENDVERT 7
-#define SP_GRIPPERHOR 8
-#define SP_GRIPPERVERT 9
-
-using namespace std;
-
-namespace WebCore {
-
-// FIXME: We should get these numbers from SafariTheme
-static int cHorizontalWidth;
-static int cHorizontalHeight;
-static int cVerticalWidth;
-static int cVerticalHeight;
-static int cHorizontalButtonWidth;
-static int cVerticalButtonHeight;
-static int cRealButtonLength = 28;
-static int cButtonInset = 14;
-static int cButtonHitInset = 3;
-// cRealButtonLength - cButtonInset
-static int cThumbWidth;
-static int cThumbHeight;
-static int cThumbMinLength = 26;
-
-static HANDLE cScrollBarTheme = 0;
-
-// FIXME: Refactor the soft-linking code so that it can be shared with RenderThemeWin
-SOFT_LINK_LIBRARY(uxtheme)
-SOFT_LINK(uxtheme, OpenThemeData, HANDLE, WINAPI, (HWND hwnd, LPCWSTR pszClassList), (hwnd, pszClassList))
-SOFT_LINK(uxtheme, CloseThemeData, HRESULT, WINAPI, (HANDLE hTheme), (hTheme))
-SOFT_LINK(uxtheme, DrawThemeBackground, HRESULT, WINAPI, (HANDLE hTheme, HDC hdc, int iPartId, int iStateId, const RECT* pRect, const RECT* pClipRect), (hTheme, hdc, iPartId, iStateId, pRect, pClipRect))
-SOFT_LINK(uxtheme, DrawThemeEdge, HRESULT, WINAPI, (HANDLE hTheme, HDC hdc, int iPartId, int iStateId, const RECT* pRect, unsigned uEdge, unsigned uFlags, const RECT* pClipRect), (hTheme, hdc, iPartId, iStateId, pRect, uEdge, uFlags, pClipRect))
-SOFT_LINK(uxtheme, GetThemeContentRect, HRESULT, WINAPI, (HANDLE hTheme, HDC hdc, int iPartId, int iStateId, const RECT* pRect, const RECT* pContentRect), (hTheme, hdc, iPartId, iStateId, pRect, pContentRect))
-SOFT_LINK(uxtheme, GetThemePartSize, HRESULT, WINAPI, (HANDLE hTheme, HDC hdc, int iPartId, int iStateId, RECT* pRect, int ts, SIZE* psz), (hTheme, hdc, iPartId, iStateId, pRect, ts, psz))
-SOFT_LINK(uxtheme, GetThemeSysFont, HRESULT, WINAPI, (HANDLE hTheme, int iFontId, OUT LOGFONT* pFont), (hTheme, iFontId, pFont))
-SOFT_LINK(uxtheme, GetThemeColor, HRESULT, WINAPI, (HANDLE hTheme, HDC hdc, int iPartId, int iStateId, int iPropId, OUT COLORREF* pColor), (hTheme, hdc, iPartId, iStateId, iPropId, pColor))
-
-static void checkAndInitScrollbarTheme()
-{
- if (uxthemeLibrary() && !cScrollBarTheme)
- cScrollBarTheme = OpenThemeData(0, L"Scrollbar");
-}
-
-// May need to add stuff to these later, so keep the graphics context retrieval/release in some helpers.
-static HDC prepareForDrawing(GraphicsContext* g, const IntRect& r)
-{
- return g->getWindowsContext(r);
-}
-
-static void doneDrawing(GraphicsContext* g, HDC hdc, const IntRect& r)
-{
- g->releaseWindowsContext(hdc, r);
-}
-// End Copied from RenderThemeWin
-
-const double cInitialTimerDelay = 0.25;
-const double cNormalTimerDelay = 0.05;
-
-PlatformScrollbar::PlatformScrollbar(ScrollbarClient* client, ScrollbarOrientation orientation, ScrollbarControlSize size)
- : Scrollbar(client, orientation, size)
- , m_hoveredPart(NoPart)
- , m_pressedPart(NoPart)
- , m_pressedPos(0)
- , m_scrollTimer(this, &PlatformScrollbar::autoscrollTimerFired)
- , m_overlapsResizer(false)
-{
- // Obtain the correct scrollbar sizes from the system.
- // FIXME: We should update these on a WM_SETTINGSCHANGE, too.
- if (!cHorizontalHeight) {
- cHorizontalHeight = ::GetSystemMetrics(SM_CYHSCROLL);
- cHorizontalWidth = ::GetSystemMetrics(SM_CXHSCROLL);
- cVerticalHeight = ::GetSystemMetrics(SM_CYVSCROLL);
- cVerticalWidth = ::GetSystemMetrics(SM_CXVSCROLL);
- cThumbWidth = ::GetSystemMetrics(SM_CXHTHUMB);
- cThumbHeight = ::GetSystemMetrics(SM_CYVTHUMB);
- cHorizontalButtonWidth = ::GetSystemMetrics(SM_CYVSCROLL);
- cVerticalButtonHeight = ::GetSystemMetrics(SM_CXHSCROLL);
- }
-
- if (orientation == VerticalScrollbar)
- setFrameGeometry(IntRect(0, 0, cVerticalWidth, cVerticalHeight));
- else
- setFrameGeometry(IntRect(0, 0, cHorizontalWidth, cHorizontalHeight));
-}
-
-PlatformScrollbar::~PlatformScrollbar()
-{
- stopTimerIfNeeded();
-}
-
-void PlatformScrollbar::updateThumbPosition()
-{
- invalidateTrack();
-}
-
-void PlatformScrollbar::updateThumbProportion()
-{
- invalidateTrack();
-}
-
-static IntRect trackRepaintRect(const IntRect& trackRect, ScrollbarOrientation orientation, ScrollbarControlSize controlSize)
-{
- const int cButtonLength = (orientation == VerticalScrollbar) ? cVerticalButtonHeight : cHorizontalButtonWidth;
-
- IntRect paintRect(trackRect);
- if (orientation == HorizontalScrollbar)
- paintRect.inflateX(cButtonLength);
- else
- paintRect.inflateY(cButtonLength);
-
- return paintRect;
-}
-
-static IntRect buttonRepaintRect(const IntRect& buttonRect, ScrollbarOrientation orientation, ScrollbarControlSize controlSize, bool start)
-{
- IntRect paintRect(buttonRect);
- if (orientation == HorizontalScrollbar) {
- paintRect.setWidth(cRealButtonLength);
- if (!start)
- paintRect.setX(buttonRect.x() - (cRealButtonLength - buttonRect.width()));
- } else {
- paintRect.setHeight(cRealButtonLength);
- if (!start)
- paintRect.setY(buttonRect.y() - (cRealButtonLength - buttonRect.height()));
- }
-
- return paintRect;
-}
-
-void PlatformScrollbar::invalidateTrack()
-{
- IntRect rect = trackRepaintRect(trackRect(), m_orientation, controlSize());
- rect.move(-x(), -y());
- invalidateRect(rect);
-}
-
-void PlatformScrollbar::invalidatePart(ScrollbarPart part)
-{
- if (part == NoPart)
- return;
-
- IntRect result;
- switch (part) {
- case BackButtonPart:
- result = buttonRepaintRect(backButtonRect(), m_orientation, controlSize(), true);
- break;
- case ForwardButtonPart:
- result = buttonRepaintRect(forwardButtonRect(), m_orientation, controlSize(), false);
- break;
- default: {
- IntRect beforeThumbRect, thumbRect, afterThumbRect;
- splitTrack(trackRect(), beforeThumbRect, thumbRect, afterThumbRect);
- if (part == BackTrackPart)
- result = beforeThumbRect;
- else if (part == ForwardTrackPart)
- result = afterThumbRect;
- else
- result = thumbRect;
- }
- }
- result.move(-x(), -y());
- invalidateRect(result);
-}
-
-int PlatformScrollbar::width() const
-{
- return Widget::width();
-}
-
-int PlatformScrollbar::height() const
-{
- return Widget::height();
-}
-
-void PlatformScrollbar::setRect(const IntRect& rect)
-{
- // Get our window resizer rect and see if we overlap. Adjust to avoid the overlap
- // if necessary.
- IntRect adjustedRect(rect);
- if (parent() && parent()->isFrameView()) {
- bool overlapsResizer = false;
- FrameView* view = static_cast<FrameView*>(parent());
- IntRect resizerRect = view->windowResizerRect();
- resizerRect.setLocation(view->convertFromContainingWindow(resizerRect.location()));
- if (rect.intersects(resizerRect)) {
- if (orientation() == HorizontalScrollbar) {
- int overlap = rect.right() - resizerRect.x();
- if (overlap > 0 && resizerRect.right() >= rect.right()) {
- adjustedRect.setWidth(rect.width() - overlap);
- overlapsResizer = true;
- }
- } else {
- int overlap = rect.bottom() - resizerRect.y();
- if (overlap > 0 && resizerRect.bottom() >= rect.bottom()) {
- adjustedRect.setHeight(rect.height() - overlap);
- overlapsResizer = true;
- }
- }
- }
-
- if (overlapsResizer != m_overlapsResizer) {
- m_overlapsResizer = overlapsResizer;
- view->adjustOverlappingScrollbarCount(m_overlapsResizer ? 1 : -1);
- }
- }
-
- setFrameGeometry(adjustedRect);
-}
-
-void PlatformScrollbar::setParent(ScrollView* parentView)
-{
- if (!parentView && m_overlapsResizer && parent() && parent()->isFrameView())
- static_cast<FrameView*>(parent())->adjustOverlappingScrollbarCount(-1);
- Widget::setParent(parentView);
-}
-
-void PlatformScrollbar::setEnabled(bool enabled)
-{
- if (enabled != isEnabled()) {
- Widget::setEnabled(enabled);
- invalidate();
- }
-}
-
-void PlatformScrollbar::paint(GraphicsContext* graphicsContext, const IntRect& damageRect)
-{
- if (graphicsContext->updatingControlTints()) {
- invalidate();
- return;
- }
-
- if (graphicsContext->paintingDisabled())
- return;
-
- // Don't paint anything if the scrollbar doesn't intersect the damage rect.
- if (!frameGeometry().intersects(damageRect))
- return;
-
- IntRect track = trackRect();
- paintTrack(graphicsContext, track, true, damageRect);
-
- if (hasButtons()) {
- paintButton(graphicsContext, backButtonRect(), true, damageRect);
- paintButton(graphicsContext, forwardButtonRect(), false, damageRect);
- }
-
- if (hasThumb() && damageRect.intersects(track)) {
- IntRect startTrackRect, thumbRect, endTrackRect;
- splitTrack(track, startTrackRect, thumbRect, endTrackRect);
- paintThumb(graphicsContext, thumbRect, damageRect);
- }
-}
-
-bool PlatformScrollbar::hasButtons() const
-{
- return isEnabled() && (m_orientation == HorizontalScrollbar ? width() : height()) >= 2 * (cRealButtonLength - cButtonHitInset);
-}
-
-bool PlatformScrollbar::hasThumb() const
-{
- return isEnabled() && (m_orientation == HorizontalScrollbar ? width() : height()) >= 2 * cButtonInset + cThumbMinLength + 1;
-}
-
-IntRect PlatformScrollbar::backButtonRect() const
-{
- // Our actual rect will shrink to half the available space when
- // we have < 34 pixels left. This allows the scrollbar
- // to scale down and function even at tiny sizes.
- if (m_orientation == HorizontalScrollbar)
- return IntRect(x(), y(), cHorizontalButtonWidth, cHorizontalHeight);
- return IntRect(x(), y(), cVerticalWidth, cVerticalButtonHeight);
-}
-
-IntRect PlatformScrollbar::forwardButtonRect() const
-{
- // Our desired rect is essentially 17x17.
-
- // Our actual rect will shrink to half the available space when
- // we have < 34 pixels left. This allows the scrollbar
- // to scale down and function even at tiny sizes.
- if (m_orientation == HorizontalScrollbar)
- return IntRect(x() + width() - cHorizontalButtonWidth, y(), cHorizontalButtonWidth, cHorizontalHeight);
- return IntRect(x(), y() + height() - cVerticalButtonHeight, cVerticalWidth, cVerticalButtonHeight);
-}
-
-IntRect PlatformScrollbar::trackRect() const
-{
- if (m_orientation == HorizontalScrollbar) {
- if (!hasButtons())
- return IntRect(x(), y(), width(), cHorizontalHeight);
- return IntRect(x() + cHorizontalButtonWidth, y(), width() - 2 * cHorizontalButtonWidth, cHorizontalHeight);
- }
-
- if (!hasButtons())
- return IntRect(x(), y(), cVerticalWidth, height());
- return IntRect(x(), y() + cVerticalButtonHeight, cVerticalWidth, height() - 2 * cVerticalButtonHeight);
-}
-
-IntRect PlatformScrollbar::thumbRect() const
-{
- IntRect beforeThumbRect, thumbRect, afterThumbRect;
- splitTrack(trackRect(), beforeThumbRect, thumbRect, afterThumbRect);
- return thumbRect;
-}
-
-IntRect PlatformScrollbar::gripperRect(const IntRect& thumbRect) const
-{
- return IntRect();
-}
-
-void PlatformScrollbar::splitTrack(const IntRect& trackRect, IntRect& beforeThumbRect, IntRect& thumbRect, IntRect& afterThumbRect) const
-{
- // This function won't even get called unless we're big enough to have some combination of these three rects where at least
- // one of them is non-empty.
- int thumbPos = thumbPosition();
- if (m_orientation == HorizontalScrollbar) {
- thumbRect = IntRect(trackRect.x() + thumbPos, trackRect.y() + (trackRect.height() - cThumbHeight) / 2, thumbLength(), cThumbHeight);
- beforeThumbRect = IntRect(trackRect.x(), trackRect.y(), thumbPos, trackRect.height());
- afterThumbRect = IntRect(thumbRect.x() + thumbRect.width(), trackRect.y(), trackRect.right() - thumbRect.right(), trackRect.height());
- } else {
- thumbRect = IntRect(trackRect.x() + (trackRect.width() - cThumbWidth) / 2, trackRect.y() + thumbPos, cThumbWidth, thumbLength());
- beforeThumbRect = IntRect(trackRect.x(), trackRect.y(), trackRect.width(), thumbPos);
- afterThumbRect = IntRect(trackRect.x(), thumbRect.y() + thumbRect.height(), trackRect.width(), trackRect.bottom() - thumbRect.bottom());
- }
-}
-
-int PlatformScrollbar::thumbPosition() const
-{
- if (isEnabled())
- return (float)m_currentPos * (trackLength() - thumbLength()) / (m_totalSize - m_visibleSize);
- return 0;
-}
-
-int PlatformScrollbar::thumbLength() const
-{
- if (!isEnabled())
- return 0;
-
- float proportion = (float)(m_visibleSize) / m_totalSize;
- int trackLen = trackLength();
- int length = proportion * trackLen;
- int minLength = cThumbMinLength;
- length = max(length, minLength);
- if (length > trackLen)
- length = 0; // Once the thumb is below the track length, it just goes away (to make more room for the track).
- return length;
-}
-
-int PlatformScrollbar::trackLength() const
-{
- return (m_orientation == HorizontalScrollbar) ? trackRect().width() : trackRect().height();
-}
-
-void PlatformScrollbar::paintButton(GraphicsContext* context, const IntRect& rect, bool start, const IntRect& damageRect) const
-{
- IntRect paintRect = buttonRepaintRect(rect, m_orientation, controlSize(), start);
-
- if (!damageRect.intersects(paintRect))
- return;
-
- unsigned part = 0;
- unsigned state = 0;
- unsigned classicPart = 0;
- unsigned classicState = 0;
-
- if (m_orientation == HorizontalScrollbar) {
- state = start ? ABS_LEFTNORMAL : ABS_RIGHTNORMAL;
- classicPart = start ? DFCS_SCROLLLEFT : DFCS_SCROLLRIGHT;
- } else {
- state = start ? ABS_UPNORMAL : ABS_DOWNNORMAL;
- classicPart = start ? DFCS_SCROLLUP : DFCS_SCROLLDOWN;
- }
-
- if (!isEnabled()) {
- state += SP_ABS_DISABLE_MODIFIER;
- classicState |= DFCS_INACTIVE;
- } else if ((m_pressedPart == BackButtonPart && start)
- || (m_pressedPart == ForwardButtonPart && !start)) {
- state += SP_ABS_PRESSED_MODIFIER;
- classicState |= DFCS_PUSHED | DFCS_FLAT;
- } else if (m_client->isActive()) {
- state += SP_ABS_HOT_MODIFIER;
- classicState |= DFCS_HOT;
- }
-
- HDC hdc = prepareForDrawing(context, rect);
- RECT widgetRect = rect;
- checkAndInitScrollbarTheme();
-
- if (cScrollBarTheme)
- DrawThemeBackground(cScrollBarTheme, hdc, SP_BUTTON, state, &widgetRect, NULL);
- else
- DrawFrameControl(hdc, &widgetRect, classicPart, classicState);
-
- doneDrawing(context, hdc, rect);
-}
-
-void PlatformScrollbar::paintTrack(GraphicsContext* context, const IntRect& rect, bool start, const IntRect& damageRect) const
-{
- IntRect paintRect = hasButtons() ? trackRepaintRect(rect, m_orientation, controlSize()) : rect;
-
- if (!damageRect.intersects(paintRect))
- return;
-
- unsigned part = 0;
- unsigned classicPart = DFC_SCROLL;
- if (m_orientation == HorizontalScrollbar)
- part = start ? SP_TRACKSTARTHOR : SP_TRACKENDHOR;
- else
- part = start ? SP_TRACKSTARTVERT : SP_TRACKENDVERT;
-
- unsigned state = TS_DISABLED;
- unsigned classicState = DFCS_MONO;
- if (m_client->isActive())
- state |= TS_ACTIVE;
- else
- classicState |= DFCS_INACTIVE;
-
- if (hasButtons())
- state |= TS_NORMAL;
-
- HDC hdc = prepareForDrawing(context, rect);
- RECT widgetRect = rect;
- checkAndInitScrollbarTheme();
-
- if (cScrollBarTheme)
- DrawThemeBackground(cScrollBarTheme, hdc, part, state, &widgetRect, NULL);
- else
- DrawFrameControl(hdc, &widgetRect, DFC_SCROLL, classicState);
-
- doneDrawing(context, hdc, rect);
-}
-
-void PlatformScrollbar::paintThumb(GraphicsContext* context, const IntRect& rect, const IntRect& damageRect) const
-{
- if (!damageRect.intersects(rect))
- return;
-
- unsigned part = (m_orientation == HorizontalScrollbar) ? SP_THUMBHOR : SP_THUMBVERT;
- unsigned state = 0;
-
- if (!isEnabled())
- state += SP_ABS_DISABLE_MODIFIER;
- else if (m_client->isActive())
- state += SP_ABS_HOT_MODIFIER;
-
- HDC hdc = prepareForDrawing(context, rect);
- RECT widgetRect = rect;
- checkAndInitScrollbarTheme();
-
- if (cScrollBarTheme) {
- DrawThemeBackground(cScrollBarTheme, hdc, part, state, &widgetRect, NULL);
- paintGripper(hdc, widgetRect);
- } else {
- HGDIOBJ hSaveBrush = SelectObject(hdc, GetSysColorBrush(COLOR_BTNFACE));
- DrawEdge(hdc, &widgetRect, EDGE_RAISED, BF_RECT);
- SelectObject(hdc,hSaveBrush);
- }
-
- doneDrawing(context, hdc, rect);
-}
-
-void PlatformScrollbar::paintGripper(HDC hdc, const IntRect& rect) const
-{
- unsigned part = (m_orientation == HorizontalScrollbar) ? SP_GRIPPERHOR : SP_GRIPPERVERT;
- unsigned state = 0;
-
- if (m_client->isActive())
- state |= TS_ACTIVE;
-
- RECT widgetRect = rect;
- checkAndInitScrollbarTheme();
-
- if (cScrollBarTheme)
- DrawThemeBackground(cScrollBarTheme, hdc, part, state, &widgetRect, NULL);
-}
-
-ScrollbarPart PlatformScrollbar::hitTest(const PlatformMouseEvent& evt)
-{
- if (!isEnabled())
- return NoPart;
-
- IntPoint mousePosition = convertFromContainingWindow(evt.pos());
- mousePosition.move(x(), y());
-
- if (hasButtons()) {
- if (backButtonRect().contains(mousePosition))
- return BackButtonPart;
-
- if (forwardButtonRect().contains(mousePosition))
- return ForwardButtonPart;
- }
-
- if (!hasThumb())
- return NoPart;
-
- IntRect track = trackRect();
- if (track.contains(mousePosition)) {
- IntRect beforeThumbRect, thumbRect, afterThumbRect;
- splitTrack(track, beforeThumbRect, thumbRect, afterThumbRect);
- if (beforeThumbRect.contains(mousePosition))
- return BackTrackPart;
- if (thumbRect.contains(mousePosition))
- return ThumbPart;
- return ForwardTrackPart;
- }
-
- return NoPart;
-}
-
-bool PlatformScrollbar::handleMouseMoveEvent(const PlatformMouseEvent& evt)
-{
- if (m_pressedPart == ThumbPart) {
- // Drag the thumb.
- int thumbPos = thumbPosition();
- int thumbLen = thumbLength();
- int trackLen = trackLength();
- int maxPos = trackLen - thumbLen;
- int delta = 0;
- if (m_orientation == HorizontalScrollbar)
- delta = convertFromContainingWindow(evt.pos()).x() - m_pressedPos;
- else
- delta = convertFromContainingWindow(evt.pos()).y() - m_pressedPos;
-
- if (delta > 0)
- // The mouse moved down/right.
- delta = min(maxPos - thumbPos, delta);
- else if (delta < 0)
- // The mouse moved up/left.
- delta = max(-thumbPos, delta);
-
- if (delta != 0) {
- setValue((float)(thumbPos + delta) * (m_totalSize - m_visibleSize) / (trackLen - thumbLen));
- m_pressedPos += thumbPosition() - thumbPos;
- }
-
- return true;
- }
-
- if (m_pressedPart != NoPart)
- m_pressedPos = (m_orientation == HorizontalScrollbar ? convertFromContainingWindow(evt.pos()).x() : convertFromContainingWindow(evt.pos()).y());
-
- ScrollbarPart part = hitTest(evt);
- if (part != m_hoveredPart) {
- if (m_pressedPart != NoPart) {
- if (part == m_pressedPart) {
- // The mouse is moving back over the pressed part. We
- // need to start up the timer action again.
- startTimerIfNeeded(cNormalTimerDelay);
- invalidatePart(m_pressedPart);
- } else if (m_hoveredPart == m_pressedPart) {
- // The mouse is leaving the pressed part. Kill our timer
- // if needed.
- stopTimerIfNeeded();
- invalidatePart(m_pressedPart);
- }
- } else {
- invalidatePart(part);
- invalidatePart(m_hoveredPart);
- }
- m_hoveredPart = part;
- }
-
- return true;
-}
-
-bool PlatformScrollbar::handleMouseOutEvent(const PlatformMouseEvent& evt)
-{
- invalidatePart(m_hoveredPart);
- m_hoveredPart = NoPart;
-
- return true;
-}
-
-bool PlatformScrollbar::handleMousePressEvent(const PlatformMouseEvent& evt)
-{
- m_pressedPart = hitTest(evt);
- m_pressedPos = (m_orientation == HorizontalScrollbar ? convertFromContainingWindow(evt.pos()).x() : convertFromContainingWindow(evt.pos()).y());
- invalidatePart(m_pressedPart);
- autoscrollPressedPart(cInitialTimerDelay);
- return true;
-}
-
-bool PlatformScrollbar::handleMouseReleaseEvent(const PlatformMouseEvent& evt)
-{
- invalidatePart(m_pressedPart);
- m_pressedPart = NoPart;
- m_pressedPos = 0;
- stopTimerIfNeeded();
-
- if (parent() && parent()->isFrameView())
- static_cast<FrameView*>(parent())->frame()->eventHandler()->setMousePressed(false);
-
- return true;
-}
-
-void PlatformScrollbar::startTimerIfNeeded(double delay)
-{
- // Don't do anything for the thumb.
- if (m_pressedPart == ThumbPart)
- return;
-
- // Handle the track. We halt track scrolling once the thumb is level
- // with us.
- if ((m_pressedPart == BackTrackPart || m_pressedPart == ForwardTrackPart) && thumbUnderMouse()) {
- invalidatePart(m_pressedPart);
- m_hoveredPart = ThumbPart;
- return;
- }
-
- // We can't scroll if we've hit the beginning or end.
- ScrollDirection dir = pressedPartScrollDirection();
- if (dir == ScrollUp || dir == ScrollLeft) {
- if (m_currentPos == 0)
- return;
- } else {
- if (m_currentPos == m_totalSize - m_visibleSize)
- return;
- }
-
- m_scrollTimer.startOneShot(delay);
-}
-
-void PlatformScrollbar::stopTimerIfNeeded()
-{
- if (m_scrollTimer.isActive())
- m_scrollTimer.stop();
-}
-
-void PlatformScrollbar::autoscrollPressedPart(double delay)
-{
- // Don't do anything for the thumb or if nothing was pressed.
- if (m_pressedPart == ThumbPart || m_pressedPart == NoPart)
- return;
-
- // Handle the track.
- if ((m_pressedPart == BackTrackPart || m_pressedPart == ForwardTrackPart) && thumbUnderMouse()) {
- invalidatePart(m_pressedPart);
- m_hoveredPart = ThumbPart;
- return;
- }
-
- // Handle the arrows and track.
- if (scroll(pressedPartScrollDirection(), pressedPartScrollGranularity()))
- startTimerIfNeeded(delay);
-}
-
-void PlatformScrollbar::autoscrollTimerFired(Timer<PlatformScrollbar>*)
-{
- autoscrollPressedPart(cNormalTimerDelay);
-}
-
-ScrollDirection PlatformScrollbar::pressedPartScrollDirection()
-{
- if (m_orientation == HorizontalScrollbar) {
- if (m_pressedPart == BackButtonPart || m_pressedPart == BackTrackPart)
- return ScrollLeft;
- return ScrollRight;
- } else {
- if (m_pressedPart == BackButtonPart || m_pressedPart == BackTrackPart)
- return ScrollUp;
- return ScrollDown;
- }
-}
-
-ScrollGranularity PlatformScrollbar::pressedPartScrollGranularity()
-{
- if (m_pressedPart == BackButtonPart || m_pressedPart == ForwardButtonPart)
- return ScrollByLine;
- return ScrollByPage;
-}
-
-bool PlatformScrollbar::thumbUnderMouse()
-{
- // Construct a rect.
- IntRect thumb = thumbRect();
- thumb.move(-x(), -y());
- int begin = (m_orientation == HorizontalScrollbar) ? thumb.x() : thumb.y();
- int end = (m_orientation == HorizontalScrollbar) ? thumb.right() : thumb.bottom();
- return (begin <= m_pressedPos && m_pressedPos < end);
-}
-
-int PlatformScrollbar::horizontalScrollbarHeight(ScrollbarControlSize controlSize)
-{
- return cHorizontalWidth;
-}
-
-int PlatformScrollbar::verticalScrollbarWidth(ScrollbarControlSize controlSize)
-{
- return cVerticalHeight;
-}
-
-IntRect PlatformScrollbar::windowClipRect() const
-{
- IntRect clipRect(0, 0, width(), height());
-
- clipRect = convertToContainingWindow(clipRect);
- if (m_client)
- clipRect.intersect(m_client->windowClipRect());
-
- return clipRect;
-}
-
-void PlatformScrollbar::themeChanged()
-{
-}
-
-}
-
diff --git a/WebCore/platform/win/PopupMenuWin.cpp b/WebCore/platform/win/PopupMenuWin.cpp
index 466d881..c44763d 100644
--- a/WebCore/platform/win/PopupMenuWin.cpp
+++ b/WebCore/platform/win/PopupMenuWin.cpp
@@ -65,8 +65,7 @@ static inline bool isASCIIPrintable(unsigned c)
}
PopupMenu::PopupMenu(PopupMenuClient* client)
- : RefCounted<PopupMenu>(0)
- , m_popupClient(client)
+ : m_popupClient(client)
, m_scrollBar(0)
, m_popup(0)
, m_DC(0)
diff --git a/WebCore/platform/win/SharedTimerWin.cpp b/WebCore/platform/win/SharedTimerWin.cpp
index 8f00ad8..8ff7734 100644
--- a/WebCore/platform/win/SharedTimerWin.cpp
+++ b/WebCore/platform/win/SharedTimerWin.cpp
@@ -40,16 +40,6 @@
#include <windows.h>
-// These aren't in winuser.h with the MSVS 2003 Platform SDK,
-// so use default values in that case.
-#ifndef USER_TIMER_MINIMUM
-#define USER_TIMER_MINIMUM 0x0000000A
-#endif
-
-#ifndef USER_TIMER_MAXIMUM
-#define USER_TIMER_MAXIMUM 0x7FFFFFFF
-#endif
-
#if PLATFORM(WIN)
#include "PluginView.h"
#endif
diff --git a/WebCore/platform/win/ThreadConditionWin.cpp b/WebCore/platform/win/ThreadConditionWin.cpp
new file mode 100644
index 0000000..f2bdb78
--- /dev/null
+++ b/WebCore/platform/win/ThreadConditionWin.cpp
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2007 Apple 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.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "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 OR ITS 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.
+ *
+ * =============================================================================
+ * Note: The implementation of condition variables under the Windows
+ * plaform was based on that of the excellent BOOST C++ library. It
+ * has been rewritten to fit in with the WebKit architecture and to
+ * use its coding conventions.
+ * =============================================================================
+ *
+ * The Boost license is virtually identical to the Apple variation at the
+ * top of this file, but is included here for completeness:
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "config.h"
+#include "Logging.h"
+#include "Threading.h"
+#include <limits>
+#include <errno.h>
+
+namespace WebCore {
+
+static const long MaxSemaphoreCount = static_cast<long>(~0UL >> 1);
+
+ThreadCondition::ThreadCondition()
+{
+ m_condition.m_timedOut = 0;
+ m_condition.m_blocked = 0;
+ m_condition.m_waitingForRemoval = 0;
+ m_condition.m_gate = ::CreateSemaphore(0, 1, 1, 0);
+ m_condition.m_queue = ::CreateSemaphore(0, 0, MaxSemaphoreCount, 0);
+ m_condition.m_mutex = ::CreateMutex(0, 0, 0);
+
+ if (!m_condition.m_gate || !m_condition.m_queue || !m_condition.m_mutex) {
+ if (m_condition.m_gate)
+ ::CloseHandle(m_condition.m_gate);
+ if (m_condition.m_queue)
+ ::CloseHandle(m_condition.m_queue);
+ if (m_condition.m_mutex)
+ ::CloseHandle(m_condition.m_mutex);
+ }
+}
+
+ThreadCondition::~ThreadCondition()
+{
+ ::CloseHandle(m_condition.m_gate);
+ ::CloseHandle(m_condition.m_queue);
+ ::CloseHandle(m_condition.m_mutex);
+}
+
+void ThreadCondition::wait(Mutex& mutex)
+{
+ PlatformMutex& cs = mutex.impl();
+
+ // Enter the wait state.
+ DWORD res = ::WaitForSingleObject(m_condition.m_gate, INFINITE);
+ ASSERT(res == WAIT_OBJECT_0);
+ ++m_condition.m_blocked;
+ res = ::ReleaseSemaphore(m_condition.m_gate, 1, 0);
+ ASSERT(res);
+
+ ::LeaveCriticalSection(&cs.m_internalMutex);
+
+ res = ::WaitForSingleObject(m_condition.m_queue, INFINITE);
+ ASSERT(res == WAIT_OBJECT_0);
+
+ res = ::WaitForSingleObject(m_condition.m_mutex, INFINITE);
+ ASSERT(res == WAIT_OBJECT_0);
+ size_t wasWaiting = m_condition.m_waitingForRemoval;
+ size_t wasTimedOut = m_condition.m_timedOut;
+ if (wasWaiting != 0) {
+ if (--m_condition.m_waitingForRemoval == 0) {
+ if (m_condition.m_blocked != 0) {
+ res = ::ReleaseSemaphore(m_condition.m_gate, 1, 0); // open m_gate
+ ASSERT(res);
+ wasWaiting = 0;
+ }
+ else if (m_condition.m_timedOut != 0)
+ m_condition.m_timedOut = 0;
+ }
+ } else if (++m_condition.m_timedOut == ((std::numeric_limits<unsigned>::max)() / 2)) {
+ // timeout occured, normalize the m_condition.m_timedOut count
+ // this may occur if many calls to wait with a timeout are made and
+ // no call to notify_* is made
+ res = ::WaitForSingleObject(m_condition.m_gate, INFINITE);
+ ASSERT(res == WAIT_OBJECT_0);
+ m_condition.m_blocked -= m_condition.m_timedOut;
+ res = ::ReleaseSemaphore(m_condition.m_gate, 1, 0);
+ ASSERT(res);
+ m_condition.m_timedOut = 0;
+ }
+ res = ::ReleaseMutex(m_condition.m_mutex);
+ ASSERT(res);
+
+ if (wasWaiting == 1) {
+ for (/**/ ; wasTimedOut; --wasTimedOut) {
+ // better now than spurious later
+ res = ::WaitForSingleObject(m_condition.m_queue, INFINITE);
+ ASSERT(res == WAIT_OBJECT_0);
+ }
+ res = ::ReleaseSemaphore(m_condition.m_gate, 1, 0);
+ ASSERT(res);
+ }
+
+ ::EnterCriticalSection (&cs.m_internalMutex);
+}
+
+void ThreadCondition::signal()
+{
+ unsigned signals = 0;
+
+ DWORD res = ::WaitForSingleObject(m_condition.m_mutex, INFINITE);
+ ASSERT(res == WAIT_OBJECT_0);
+
+ if (m_condition.m_waitingForRemoval != 0) { // the m_gate is already closed
+ if (m_condition.m_blocked == 0) {
+ res = ::ReleaseMutex(m_condition.m_mutex);
+ ASSERT(res);
+ return;
+ }
+
+ ++m_condition.m_waitingForRemoval;
+ --m_condition.m_blocked;
+
+ signals = 1;
+ } else {
+ res = ::WaitForSingleObject(m_condition.m_gate, INFINITE);
+ ASSERT(res == WAIT_OBJECT_0);
+ if (m_condition.m_blocked > m_condition.m_timedOut) {
+ if (m_condition.m_timedOut != 0) {
+ m_condition.m_blocked -= m_condition.m_timedOut;
+ m_condition.m_timedOut = 0;
+ }
+ signals = m_condition.m_waitingForRemoval = 1;
+ --m_condition.m_blocked;
+ } else {
+ res = ::ReleaseSemaphore(m_condition.m_gate, 1, 0);
+ ASSERT(res);
+ }
+ }
+
+ res =::ReleaseMutex(m_condition.m_mutex);
+ ASSERT(res);
+
+ if (signals) {
+ res = ::ReleaseSemaphore(m_condition.m_queue, signals, 0);
+ ASSERT(res);
+ }
+}
+
+void ThreadCondition::broadcast()
+{
+ unsigned signals = 0;
+
+ WORD res = ::WaitForSingleObject(m_condition.m_mutex, INFINITE);
+ ASSERT(res == WAIT_OBJECT_0);
+
+ if (m_condition.m_waitingForRemoval != 0) { // the m_gate is already closed
+ if (m_condition.m_blocked == 0) {
+ res = ::ReleaseMutex(m_condition.m_mutex);
+ ASSERT(res);
+ return;
+ }
+
+ m_condition.m_waitingForRemoval += (signals = m_condition.m_blocked);
+ m_condition.m_blocked = 0;
+ } else {
+ res = ::WaitForSingleObject(m_condition.m_gate, INFINITE);
+ ASSERT(res == WAIT_OBJECT_0);
+ if (m_condition.m_blocked > m_condition.m_timedOut) {
+ if (m_condition.m_timedOut != 0) {
+ m_condition.m_blocked -= m_condition.m_timedOut;
+ m_condition.m_timedOut = 0;
+ }
+ signals = m_condition.m_waitingForRemoval = m_condition.m_blocked;
+ m_condition.m_blocked = 0;
+ } else {
+ res = ::ReleaseSemaphore(m_condition.m_gate, 1, 0);
+ ASSERT(res);
+ }
+ }
+
+ res = ::ReleaseMutex(m_condition.m_mutex);
+ ASSERT(res);
+
+ if (signals) {
+ res = ::ReleaseSemaphore(m_condition.m_queue, signals, 0);
+ ASSERT(res);
+ }
+}
+
+} // namespace WebCore
diff --git a/WebCore/platform/win/MainThreadWin.cpp b/WebCore/platform/win/ThreadingWin.cpp
index 6d3493c..0da3d17 100644
--- a/WebCore/platform/win/MainThreadWin.cpp
+++ b/WebCore/platform/win/ThreadingWin.cpp
@@ -27,11 +27,12 @@
*/
#include "config.h"
-#include "MainThread.h"
-
#include "Logging.h"
#include "Page.h"
+#include "Threading.h"
+#include <errno.h>
#include <windows.h>
+#include <wtf/HashMap.h>
namespace WebCore {
@@ -48,6 +49,88 @@ static UINT threadingFiredMessage = 0;
const LPCWSTR kThreadingWindowClassName = L"ThreadingWindowClass";
static bool processingCustomThreadingMessage = false;
+static Mutex& threadMapMutex()
+{
+ static Mutex mutex;
+ return mutex;
+}
+
+static HashMap<DWORD, HANDLE>& threadMap()
+{
+ static HashMap<DWORD, HANDLE> map;
+ return map;
+}
+
+static void storeThreadHandleByIdentifier(DWORD threadID, HANDLE threadHandle)
+{
+ MutexLocker locker(threadMapMutex());
+ threadMap().add(threadID, threadHandle);
+}
+
+static HANDLE threadHandleForIdentifier(ThreadIdentifier id)
+{
+ MutexLocker locker(threadMapMutex());
+ return threadMap().get(id);
+}
+
+static void clearThreadHandleForIdentifier(ThreadIdentifier id)
+{
+ MutexLocker locker(threadMapMutex());
+ ASSERT(threadMap().contains(id));
+ threadMap().remove(id);
+}
+
+ThreadIdentifier createThread(ThreadFunction entryPoint, void* data)
+{
+ DWORD threadIdentifier = 0;
+ ThreadIdentifier threadID = 0;
+ HANDLE hEvent = ::CreateEvent(0, FALSE, FALSE, 0);
+ HANDLE threadHandle = ::CreateThread(0, 0, (LPTHREAD_START_ROUTINE)entryPoint, data, 0, &threadIdentifier);
+ if (!threadHandle) {
+ LOG_ERROR("Failed to create thread at entry point %p with data %p", entryPoint, data);
+ return 0;
+ }
+
+ threadID = static_cast<ThreadIdentifier>(threadIdentifier);
+ storeThreadHandleByIdentifier(threadIdentifier, threadHandle);
+
+ LOG(Threading, "Created thread with thread id %u", threadID);
+ return threadID;
+}
+
+int waitForThreadCompletion(ThreadIdentifier threadID, void** result)
+{
+ ASSERT(threadID);
+
+ HANDLE threadHandle = threadHandleForIdentifier(threadID);
+ if (!threadHandle)
+ LOG_ERROR("ThreadIdentifier %u did not correspond to an active thread when trying to quit", threadID);
+
+ DWORD joinResult = ::WaitForSingleObject(threadHandle, INFINITE);
+ if (joinResult == WAIT_FAILED)
+ LOG_ERROR("ThreadIdentifier %u was found to be deadlocked trying to quit", threadID);
+
+ ::CloseHandle(threadHandle);
+ clearThreadHandleForIdentifier(threadID);
+
+ return joinResult;
+}
+
+void detachThread(ThreadIdentifier threadID)
+{
+ ASSERT(threadID);
+
+ HANDLE threadHandle = threadHandleForIdentifier(threadID);
+ if (threadHandle)
+ ::CloseHandle(threadHandle);
+ clearThreadHandleForIdentifier(threadID);
+}
+
+ThreadIdentifier currentThread()
+{
+ return static_cast<ThreadIdentifier>(::GetCurrentThreadId());
+}
+
static Mutex& functionQueueMutex()
{
static Mutex staticFunctionQueueMutex;
@@ -84,13 +167,11 @@ LRESULT CALLBACK ThreadingWindowWndProc(HWND hWnd, UINT message, WPARAM wParam,
return 0;
}
-void initializeThreadingAndMainThread()
+void initializeThreading()
{
if (threadingWindowHandle)
return;
-
- WTF::initializeThreading();
-
+
WNDCLASSEX wcex;
memset(&wcex, 0, sizeof(WNDCLASSEX));
wcex.cbSize = sizeof(WNDCLASSEX);
diff --git a/WebCore/platform/wx/FileSystemWx.cpp b/WebCore/platform/wx/FileSystemWx.cpp
index 7be985b..28310f2 100644
--- a/WebCore/platform/wx/FileSystemWx.cpp
+++ b/WebCore/platform/wx/FileSystemWx.cpp
@@ -1,9 +1,7 @@
/*
* Copyright (C) 2007 Kevin Ollivier
- * Copyright (C) 2008 Collabora, Ltd.
- *
* All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -77,40 +75,4 @@ String pathByAppendingComponent(const String& path, const String& component)
return String();
}
-String homeDirectoryPath()
-{
- notImplemented();
- return String();
-}
-
-String pathGetFileName(const String&)
-{
- notImplemented();
- return String();
-}
-
-CString openTemporaryFile(const char* prefix, PlatformFileHandle& handle)
-{
- notImplemented();
- handle = invalidPlatformFileHandle;
- return CString();
-}
-
-void closeFile(PlatformFileHandle&)
-{
- notImplemented();
-}
-
-int writeToFile(PlatformFileHandle, const char* data, int length)
-{
- notImplemented();
- return 0;
-}
-
-bool unloadModule(PlatformModule)
-{
- notImplemented();
- return false;
-}
-
}
diff --git a/WebCore/platform/wx/LocalizedStringsWx.cpp b/WebCore/platform/wx/LocalizedStringsWx.cpp
index 8ba5fe4..368f938 100644
--- a/WebCore/platform/wx/LocalizedStringsWx.cpp
+++ b/WebCore/platform/wx/LocalizedStringsWx.cpp
@@ -25,8 +25,6 @@
*/
#include "config.h"
-#include "LocalizedStrings.h"
-
#include "PlatformString.h"
namespace WebCore {
@@ -266,9 +264,4 @@ String unknownFileSizeText()
return String("Unknown");
}
-String imageTitle(const String& filename, const IntSize& size)
-{
- return String();
-}
-
} // namespace WebCore
diff --git a/WebCore/platform/wx/MouseWheelEventWx.cpp b/WebCore/platform/wx/MouseWheelEventWx.cpp
index 6064176..0bfbd4a 100644
--- a/WebCore/platform/wx/MouseWheelEventWx.cpp
+++ b/WebCore/platform/wx/MouseWheelEventWx.cpp
@@ -40,10 +40,6 @@ PlatformWheelEvent::PlatformWheelEvent(const wxMouseEvent& event, const wxPoint&
, m_metaKey(event.MetaDown()) // FIXME: We'll have to test other browsers
, m_deltaX(0) // wx doesn't support horizontal mouse wheel scrolling
, m_deltaY(event.GetWheelRotation() / event.GetWheelDelta())
- , m_isAccepted(false)
- , m_isContinuous(false)
- , m_continuousDeltaX(0)
- , m_continuousDeltaY(0)
{
}
diff --git a/WebCore/platform/wx/ScrollViewWx.cpp b/WebCore/platform/wx/ScrollViewWx.cpp
index 8726fc3..b6c5ae4 100644
--- a/WebCore/platform/wx/ScrollViewWx.cpp
+++ b/WebCore/platform/wx/ScrollViewWx.cpp
@@ -68,6 +68,7 @@ public:
win->Connect(wxEVT_SCROLLWIN_PAGEDOWN, wxScrollWinEventHandler(ScrollViewPrivate::OnScrollWinEvents), NULL, this);
win->Connect(wxEVT_SCROLLWIN_THUMBTRACK, wxScrollWinEventHandler(ScrollViewPrivate::OnScrollWinEvents), NULL, this);
win->Connect(wxEVT_SCROLLWIN_THUMBRELEASE, wxScrollWinEventHandler(ScrollViewPrivate::OnScrollWinEvents), NULL, this);
+ win->Connect(wxEVT_SCROLLWIN_TOP, wxScrollWinEventHandler(ScrollViewPrivate::OnScrollWinEvents), NULL, this);
}
void OnScrollWinEvents(wxScrollWinEvent& e)
@@ -83,30 +84,18 @@ public:
else
pos.y = e.GetPosition();
}
- else if (scrollType == wxEVT_SCROLLWIN_LINEDOWN) {
+ else if ( scrollType == wxEVT_SCROLLWIN_LINEDOWN ) {
if (horiz)
pos.x += LINE_STEP;
else
pos.y += LINE_STEP;
}
- else if (scrollType == wxEVT_SCROLLWIN_LINEUP) {
+ else if ( scrollType == wxEVT_SCROLLWIN_LINEUP ) {
if (horiz)
pos.x -= LINE_STEP;
else
pos.y -= LINE_STEP;
}
- else if (scrollType == wxEVT_SCROLLWIN_PAGEUP) {
- if (horiz)
- pos.x -= m_scrollView->visibleWidth() - PAGE_KEEP;
- else
- pos.y -= m_scrollView->visibleHeight() - PAGE_KEEP;
- }
- else if (scrollType == wxEVT_SCROLLWIN_PAGEDOWN) {
- if (horiz)
- pos.x += m_scrollView->visibleWidth() - PAGE_KEEP;
- else
- pos.y += m_scrollView->visibleHeight() - PAGE_KEEP;
- }
else
return e.Skip();
diff --git a/WebCore/platform/wx/TemporaryLinkStubs.cpp b/WebCore/platform/wx/TemporaryLinkStubs.cpp
index b44ed9a..cd328c6 100755
--- a/WebCore/platform/wx/TemporaryLinkStubs.cpp
+++ b/WebCore/platform/wx/TemporaryLinkStubs.cpp
@@ -1,6 +1,5 @@
/*
* Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
- * Copyright (C) 2008 Collabora, Ltd. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -64,8 +63,7 @@
#include "PlatformMenuDescription.h"
#include "PlatformMouseEvent.h"
#include "PlatformScrollBar.h"
-#include "PluginDatabase.h"
-#include "PluginPackage.h"
+#include "PluginInfoStore.h"
#include "PopupMenu.h"
#include "RenderTheme.h"
#include "ResourceHandle.h"
@@ -119,14 +117,11 @@ namespace WebCore {
void WebCore::findWordBoundary(UChar const* str,int len,int position,int* start, int* end) { notImplemented(); *start=position; *end=position; }
-PluginSet PluginDatabase::getPluginsInPaths() const { notImplemented(); return PluginSet(); }
-Vector<String> PluginDatabase::defaultPluginPaths() { notImplemented(); return Vector<String>(); }
-bool PluginDatabase::isPreferredPluginPath(const String&) { notImplemented(); return false; }
-int PluginPackage::compare(const PluginPackage&) const { notImplemented(); return 0; }
-bool PluginPackage::fetchInfo() { notImplemented(); return false; }
-unsigned PluginPackage::hash() const { notImplemented(); return 0; }
-bool PluginPackage::equal(const PluginPackage&, const PluginPackage&) { notImplemented(); return false; }
-bool PluginPackage::load() { notImplemented(); return false; }
+PluginInfo*PluginInfoStore::createPluginInfoForPluginAtIndex(unsigned) { notImplemented(); return 0;}
+unsigned PluginInfoStore::pluginCount() const { notImplemented(); return 0; }
+bool WebCore::PluginInfoStore::supportsMIMEType(const WebCore::String&) { notImplemented(); return false; }
+String PluginInfoStore::pluginNameForMIMEType(const String& mimeType) { notImplemented(); return String(); }
+void WebCore::refreshPlugins(bool) { notImplemented(); }
void Widget::setIsSelected(bool) { notImplemented(); }
@@ -156,13 +151,13 @@ void PlatformScrollbar::updateThumbPosition() { notImplemented(); }
void PlatformScrollbar::updateThumbProportion() { notImplemented(); }
void PlatformScrollbar::setRect(const IntRect&) { notImplemented(); }
-FileChooser::FileChooser(FileChooserClient*, const String& initialFilename) : RefCounted<FileChooser>(0) { notImplemented(); }
+FileChooser::FileChooser(FileChooserClient*, const String& initialFilename) { notImplemented(); }
//PassRefPtr<FileChooser> FileChooser::create(FileChooserClient*, const String& initialFilename) { notImplemented(); return PassRefPtr<FileChooser>(); }
FileChooser::~FileChooser() { notImplemented(); }
void FileChooser::openFileChooser(Document*) { notImplemented(); }
String FileChooser::basenameForWidth(const Font&, int width) const { notImplemented(); return String(); }
-PopupMenu::PopupMenu(PopupMenuClient*) : RefCounted<PopupMenu>(0) { notImplemented(); }
+PopupMenu::PopupMenu(PopupMenuClient*) { notImplemented(); }
PopupMenu::~PopupMenu() { notImplemented(); }
void PopupMenu::show(const IntRect&, FrameView*, int index) { notImplemented(); }
@@ -170,7 +165,7 @@ void PopupMenu::hide() { notImplemented(); }
void PopupMenu::updateFromElement() { notImplemented(); }
bool PopupMenu::itemWritingDirectionIsNatural() { notImplemented(); return false; }
-Icon::Icon() : RefCounted<Icon>(0) { notImplemented(); }
+Icon::Icon() { notImplemented(); }
Icon::~Icon() { notImplemented(); }
PassRefPtr<Icon> Icon::newIconForFile(const String& filename) { notImplemented(); return PassRefPtr<Icon>(new Icon()); }
void Icon::paint(GraphicsContext*, const IntRect&) { notImplemented(); }
diff --git a/WebCore/platform/wx/MainThreadWx.cpp b/WebCore/platform/wx/ThreadingWx.cpp
index b49cb62..7cb90ff 100644
--- a/WebCore/platform/wx/MainThreadWx.cpp
+++ b/WebCore/platform/wx/ThreadingWx.cpp
@@ -28,7 +28,7 @@
#include "config.h"
#include "NotImplemented.h"
-#include "MainThread.h"
+#include "Threading.h"
namespace WebCore {
diff --git a/WebCore/platform/wx/wxcode/mac/carbon/non-kerned-drawing.cpp b/WebCore/platform/wx/wxcode/mac/carbon/non-kerned-drawing.cpp
deleted file mode 100644
index b86a9bc..0000000
--- a/WebCore/platform/wx/wxcode/mac/carbon/non-kerned-drawing.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2007 Kevin Watters, Kevin Ollivier. 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.
- */
-
-#include "config.h"
-#include "GlyphBuffer.h"
-#include "GraphicsContext.h"
-#include "SimpleFontData.h"
-
-#include <wx/defs.h>
-#include <wx/dcclient.h>
-#include <wx/gdicmn.h>
-#include <vector>
-
-namespace WebCore {
-
-void drawTextWithSpacing(GraphicsContext* graphicsContext, const SimpleFontData* font, const wxColour& color, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point)
-{
-#if USE(WXGC)
- wxGCDC* dc = static_cast<wxGCDC*>(graphicsContext->platformContext());
-#else
- wxDC* dc = graphicsContext->platformContext();
-#endif
-
- wxFont wxfont = font->getWxFont();
- if (wxfont.IsOk())
- dc->SetFont(wxfont);
- dc->SetTextForeground(color);
-
- // convert glyphs to wxString
- GlyphBufferGlyph* glyphs = const_cast<GlyphBufferGlyph*>(glyphBuffer.glyphs(from));
- int offset = point.x();
- wxString text = wxEmptyString;
- for (unsigned i = 0; i < numGlyphs; i++) {
- text = text.Append((wxChar)glyphs[i]);
- offset += glyphBuffer.advanceAt(from + i);
- }
-
- // the y point is actually the bottom point of the text, turn it into the top
- float height = font->ascent() - font->descent();
- wxCoord ypoint = (wxCoord) (point.y() - height);
-
- dc->DrawText(text, (wxCoord)point.x(), ypoint);
-}
-
-}
diff --git a/WebCore/platform/wx/wxcode/win/non-kerned-drawing.cpp b/WebCore/platform/wx/wxcode/win/non-kerned-drawing.cpp
deleted file mode 100644
index f05923a..0000000
--- a/WebCore/platform/wx/wxcode/win/non-kerned-drawing.cpp
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2007 Kevin Watters, Kevin Ollivier. 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.
- */
-
-#include "config.h"
-#include "GlyphBuffer.h"
-#include "GraphicsContext.h"
-#include "SimpleFontData.h"
-
-#include <wx/defs.h>
-#include <wx/dcclient.h>
-#include <wx/gdicmn.h>
-#include <vector>
-
-using namespace std;
-
-//-----------------------------------------------------------------------------
-// constants
-//-----------------------------------------------------------------------------
-
-const double RAD2DEG = 180.0 / M_PI;
-
-//-----------------------------------------------------------------------------
-// Local functions
-//-----------------------------------------------------------------------------
-
-static inline double dmin(double a, double b) { return a < b ? a : b; }
-static inline double dmax(double a, double b) { return a > b ? a : b; }
-
-static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; }
-static inline double RadToDeg(double deg) { return (deg * 180.0) / M_PI; }
-
-#include "wx/msw/private.h"
-
-// TODO remove this dependency (gdiplus needs the macros)
-
-#ifndef max
-#define max(a,b) (((a) > (b)) ? (a) : (b))
-#endif
-
-#ifndef min
-#define min(a,b) (((a) < (b)) ? (a) : (b))
-#endif
-
-#include "gdiplus.h"
-
-
-namespace WebCore {
-
-void drawTextWithSpacing(GraphicsContext* graphicsContext, const SimpleFontData* font, const wxColour& color, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point)
-{
-#if USE(WXGC)
- wxGCDC* dc = static_cast<wxGCDC*>(graphicsContext->platformContext());
-#else
- wxDC* dc = graphicsContext->platformContext();
-#endif
-
- // get the native HDC handle to draw using native APIs
- HDC hdc = 0;
-#if USE(WXGC)
- wxGraphicsContext* gc = dc->GetGraphicsContext();
- Gdiplus::Graphics* g;
- if (gc) {
- g = (Gdiplus::Graphics*)gc->GetNativeContext();
- hdc = g->GetHDC();
- }
-#else
- hdc = static_cast<HDC>(dc->GetHDC());
-#endif
-
- // ExtTextOut wants the offsets as an array of ints, so extract them
- // from the glyph buffer
- const GlyphBufferGlyph* glyphs = glyphBuffer.glyphs(from);
- const GlyphBufferAdvance* advances = glyphBuffer.advances(from);
-
- float y = point.y() - font->ascent();
- float x = point.x();
-
- int* spacing = new int[numGlyphs - from];
- for (unsigned i = 0; i < numGlyphs; ++i)
- spacing[i] = advances[i].width();
-
- ::SelectObject(hdc, GetHfontOf(font->getWxFont()));
-
- if (color.Ok())
- ::SetTextColor(hdc, color.GetPixel());
-
- // do not draw background behind characters
- ::SetBkMode(hdc, TRANSPARENT);
-
- // draw text with optional character widths array
- wxString string = wxString((wxChar*)(&glyphs[from]), numGlyphs);
- ::ExtTextOut(hdc, x, y, 0, NULL, string.c_str(), string.length(), spacing);
-
- ::SetBkMode(hdc, TRANSPARENT);
-
- #if USE(WXGC)
- g->ReleaseHDC(hdc);
- #endif
-
- delete [] spacing;
-}
-
-}